1 /* 2 * PROJECT: Local Security Authority Server DLL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/samsrv/database.c 5 * PURPOSE: SAM object database 6 * COPYRIGHT: Copyright 2012 Eric Kohl 7 */ 8 9 #include "samsrv.h" 10 11 #include <pseh/pseh2.h> 12 13 /* GLOBALS *****************************************************************/ 14 15 static HANDLE SamKeyHandle = NULL; 16 17 18 /* FUNCTIONS ***************************************************************/ 19 20 NTSTATUS 21 SampInitDatabase(VOID) 22 { 23 NTSTATUS Status; 24 25 TRACE("SampInitDatabase()\n"); 26 27 Status = SampRegOpenKey(NULL, 28 L"\\Registry\\Machine\\SAM", 29 KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS, 30 &SamKeyHandle); 31 if (!NT_SUCCESS(Status)) 32 { 33 ERR("Failed to open the SAM key (Status: 0x%08lx)\n", Status); 34 return Status; 35 } 36 37 TRACE("SampInitDatabase() done\n"); 38 39 return STATUS_SUCCESS; 40 } 41 42 43 NTSTATUS 44 SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject, 45 IN LPWSTR ContainerName, 46 IN LPWSTR ObjectName, 47 IN ULONG RelativeId, 48 IN SAM_DB_OBJECT_TYPE ObjectType, 49 IN ACCESS_MASK DesiredAccess, 50 OUT PSAM_DB_OBJECT *DbObject) 51 { 52 PSAM_DB_OBJECT NewObject = NULL; 53 HANDLE ParentKeyHandle; 54 HANDLE ContainerKeyHandle = NULL; 55 HANDLE ObjectKeyHandle = NULL; 56 HANDLE MembersKeyHandle = NULL; 57 NTSTATUS Status; 58 59 if (DbObject == NULL) 60 return STATUS_INVALID_PARAMETER; 61 62 *DbObject = NULL; 63 64 if (ParentObject == NULL) 65 ParentKeyHandle = SamKeyHandle; 66 else 67 ParentKeyHandle = ParentObject->KeyHandle; 68 69 if (ContainerName != NULL) 70 { 71 /* Open the container key */ 72 Status = SampRegOpenKey(ParentKeyHandle, 73 ContainerName, 74 KEY_ALL_ACCESS, 75 &ContainerKeyHandle); 76 if (!NT_SUCCESS(Status)) 77 { 78 goto done; 79 } 80 81 /* Create the object key */ 82 Status = SampRegCreateKey(ContainerKeyHandle, 83 ObjectName, 84 KEY_ALL_ACCESS, 85 &ObjectKeyHandle); 86 if (!NT_SUCCESS(Status)) 87 { 88 goto done; 89 } 90 91 if (ObjectType == SamDbAliasObject) 92 { 93 /* Create the object key */ 94 Status = SampRegCreateKey(ContainerKeyHandle, 95 L"Members", 96 KEY_ALL_ACCESS, 97 &MembersKeyHandle); 98 if (!NT_SUCCESS(Status)) 99 { 100 goto done; 101 } 102 } 103 } 104 else 105 { 106 /* Create the object key */ 107 Status = SampRegCreateKey(ParentKeyHandle, 108 ObjectName, 109 KEY_ALL_ACCESS, 110 &ObjectKeyHandle); 111 if (!NT_SUCCESS(Status)) 112 { 113 goto done; 114 } 115 } 116 117 NewObject = RtlAllocateHeap(RtlGetProcessHeap(), 118 HEAP_ZERO_MEMORY, 119 sizeof(SAM_DB_OBJECT)); 120 if (NewObject == NULL) 121 { 122 Status = STATUS_INSUFFICIENT_RESOURCES; 123 goto done; 124 } 125 126 NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(), 127 0, 128 (wcslen(ObjectName) + 1) * sizeof(WCHAR)); 129 if (NewObject->Name == NULL) 130 { 131 Status = STATUS_INSUFFICIENT_RESOURCES; 132 goto done; 133 } 134 135 wcscpy(NewObject->Name, ObjectName); 136 137 NewObject->Signature = SAMP_DB_SIGNATURE; 138 NewObject->RefCount = 1; 139 NewObject->ObjectType = ObjectType; 140 NewObject->Access = DesiredAccess; 141 NewObject->KeyHandle = ObjectKeyHandle; 142 NewObject->MembersKeyHandle = MembersKeyHandle; 143 NewObject->RelativeId = RelativeId; 144 NewObject->ParentObject = ParentObject; 145 146 if (ParentObject != NULL) 147 NewObject->Trusted = ParentObject->Trusted; 148 149 *DbObject = NewObject; 150 151 done: 152 if (!NT_SUCCESS(Status)) 153 { 154 if (NewObject != NULL) 155 { 156 if (NewObject->Name != NULL) 157 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject->Name); 158 159 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject); 160 } 161 162 SampRegCloseKey(&MembersKeyHandle); 163 SampRegCloseKey(&ObjectKeyHandle); 164 } 165 166 SampRegCloseKey(&ContainerKeyHandle); 167 168 return Status; 169 } 170 171 172 NTSTATUS 173 SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject, 174 IN LPWSTR ContainerName, 175 IN LPWSTR ObjectName, 176 IN ULONG RelativeId, 177 IN SAM_DB_OBJECT_TYPE ObjectType, 178 IN ACCESS_MASK DesiredAccess, 179 OUT PSAM_DB_OBJECT *DbObject) 180 { 181 PSAM_DB_OBJECT NewObject = NULL; 182 HANDLE ParentKeyHandle; 183 HANDLE ContainerKeyHandle = NULL; 184 HANDLE ObjectKeyHandle = NULL; 185 HANDLE MembersKeyHandle = NULL; 186 NTSTATUS Status; 187 188 if (DbObject == NULL) 189 return STATUS_INVALID_PARAMETER; 190 191 *DbObject = NULL; 192 193 if (ParentObject == NULL) 194 ParentKeyHandle = SamKeyHandle; 195 else 196 ParentKeyHandle = ParentObject->KeyHandle; 197 198 if (ContainerName != NULL) 199 { 200 /* Open the container key */ 201 Status = SampRegOpenKey(ParentKeyHandle, 202 ContainerName, 203 KEY_ALL_ACCESS, 204 &ContainerKeyHandle); 205 if (!NT_SUCCESS(Status)) 206 { 207 goto done; 208 } 209 210 /* Open the object key */ 211 Status = SampRegOpenKey(ContainerKeyHandle, 212 ObjectName, 213 KEY_ALL_ACCESS, 214 &ObjectKeyHandle); 215 if (!NT_SUCCESS(Status)) 216 { 217 goto done; 218 } 219 220 if (ObjectType == SamDbAliasObject) 221 { 222 /* Open the object key */ 223 Status = SampRegOpenKey(ContainerKeyHandle, 224 L"Members", 225 KEY_ALL_ACCESS, 226 &MembersKeyHandle); 227 if (!NT_SUCCESS(Status)) 228 { 229 goto done; 230 } 231 } 232 } 233 else 234 { 235 /* Open the object key */ 236 Status = SampRegOpenKey(ParentKeyHandle, 237 ObjectName, 238 KEY_ALL_ACCESS, 239 &ObjectKeyHandle); 240 if (!NT_SUCCESS(Status)) 241 { 242 goto done; 243 } 244 } 245 246 NewObject = RtlAllocateHeap(RtlGetProcessHeap(), 247 HEAP_ZERO_MEMORY, 248 sizeof(SAM_DB_OBJECT)); 249 if (NewObject == NULL) 250 { 251 Status = STATUS_INSUFFICIENT_RESOURCES; 252 goto done; 253 } 254 255 NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(), 256 0, 257 (wcslen(ObjectName) + 1) * sizeof(WCHAR)); 258 if (NewObject->Name == NULL) 259 { 260 Status = STATUS_INSUFFICIENT_RESOURCES; 261 goto done; 262 } 263 264 wcscpy(NewObject->Name, ObjectName); 265 NewObject->Signature = SAMP_DB_SIGNATURE; 266 NewObject->RefCount = 1; 267 NewObject->ObjectType = ObjectType; 268 NewObject->Access = DesiredAccess; 269 NewObject->KeyHandle = ObjectKeyHandle; 270 NewObject->MembersKeyHandle = MembersKeyHandle; 271 NewObject->RelativeId = RelativeId; 272 NewObject->ParentObject = ParentObject; 273 274 if (ParentObject != NULL) 275 NewObject->Trusted = ParentObject->Trusted; 276 277 *DbObject = NewObject; 278 279 done: 280 if (!NT_SUCCESS(Status)) 281 { 282 if (NewObject != NULL) 283 { 284 if (NewObject->Name != NULL) 285 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject->Name); 286 287 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject); 288 } 289 290 SampRegCloseKey(&MembersKeyHandle); 291 SampRegCloseKey(&ObjectKeyHandle); 292 } 293 294 SampRegCloseKey(&ContainerKeyHandle); 295 296 return Status; 297 } 298 299 300 NTSTATUS 301 SampValidateDbObject(SAMPR_HANDLE Handle, 302 SAM_DB_OBJECT_TYPE ObjectType, 303 ACCESS_MASK DesiredAccess, 304 PSAM_DB_OBJECT *DbObject) 305 { 306 PSAM_DB_OBJECT LocalObject = (PSAM_DB_OBJECT)Handle; 307 BOOLEAN bValid = FALSE; 308 309 _SEH2_TRY 310 { 311 if (LocalObject->Signature == SAMP_DB_SIGNATURE) 312 { 313 if ((ObjectType == SamDbIgnoreObject) || 314 (LocalObject->ObjectType == ObjectType)) 315 bValid = TRUE; 316 } 317 } 318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 319 { 320 bValid = FALSE; 321 } 322 _SEH2_END; 323 324 if (bValid == FALSE) 325 return STATUS_INVALID_HANDLE; 326 327 if (DesiredAccess != 0) 328 { 329 /* Check for granted access rights */ 330 if ((LocalObject->Access & DesiredAccess) != DesiredAccess) 331 { 332 ERR("SampValidateDbObject access check failed %08lx %08lx\n", 333 LocalObject->Access, DesiredAccess); 334 return STATUS_ACCESS_DENIED; 335 } 336 } 337 338 if (DbObject != NULL) 339 *DbObject = LocalObject; 340 341 return STATUS_SUCCESS; 342 } 343 344 345 NTSTATUS 346 SampCloseDbObject(PSAM_DB_OBJECT DbObject) 347 { 348 NTSTATUS Status = STATUS_SUCCESS; 349 350 DbObject->RefCount--; 351 352 if (DbObject->RefCount > 0) 353 return STATUS_SUCCESS; 354 355 SampRegCloseKey(&DbObject->KeyHandle); 356 SampRegCloseKey(&DbObject->MembersKeyHandle); 357 358 if (DbObject->Name != NULL) 359 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name); 360 361 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject); 362 363 return Status; 364 } 365 366 367 NTSTATUS 368 SampDeleteAccountDbObject(PSAM_DB_OBJECT DbObject) 369 { 370 LPCWSTR ContainerName; 371 LPWSTR AccountName = NULL; 372 HANDLE ContainerKey = NULL; 373 HANDLE NamesKey = NULL; 374 ULONG Length = 0; 375 NTSTATUS Status = STATUS_SUCCESS; 376 377 TRACE("(%p)\n", DbObject); 378 379 /* Server and Domain objects cannot be deleted */ 380 switch (DbObject->ObjectType) 381 { 382 case SamDbAliasObject: 383 ContainerName = L"Aliases"; 384 break; 385 386 case SamDbGroupObject: 387 ContainerName = L"Groups"; 388 break; 389 390 case SamDbUserObject: 391 ContainerName = L"Users"; 392 break; 393 394 default: 395 return STATUS_INVALID_PARAMETER; 396 } 397 398 /* Get the account name */ 399 Status = SampGetObjectAttribute(DbObject, 400 L"Name", 401 NULL, 402 NULL, 403 &Length); 404 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 405 { 406 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status); 407 goto done; 408 } 409 410 AccountName = RtlAllocateHeap(RtlGetProcessHeap(), 411 HEAP_ZERO_MEMORY, 412 Length); 413 if (AccountName == NULL) 414 { 415 Status = STATUS_INSUFFICIENT_RESOURCES; 416 goto done; 417 } 418 419 Status = SampGetObjectAttribute(DbObject, 420 L"Name", 421 NULL, 422 (PVOID)AccountName, 423 &Length); 424 if (!NT_SUCCESS(Status)) 425 { 426 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status); 427 goto done; 428 } 429 430 SampRegCloseKey(&DbObject->KeyHandle); 431 432 if (DbObject->ObjectType == SamDbAliasObject) 433 { 434 SampRegCloseKey(&DbObject->MembersKeyHandle); 435 436 SampRegDeleteKey(DbObject->KeyHandle, 437 L"Members"); 438 } 439 440 /* Open the domain container key */ 441 Status = SampRegOpenKey(DbObject->ParentObject->KeyHandle, 442 ContainerName, 443 DELETE | KEY_SET_VALUE, 444 &ContainerKey); 445 if (!NT_SUCCESS(Status)) 446 { 447 TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status); 448 goto done; 449 } 450 451 /* Open the Names key */ 452 Status = SampRegOpenKey(ContainerKey, 453 L"Names", 454 KEY_SET_VALUE, 455 &NamesKey); 456 if (!NT_SUCCESS(Status)) 457 { 458 TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status); 459 goto done; 460 } 461 462 /* Remove the account from the Names key */ 463 Status = SampRegDeleteValue(NamesKey, 464 AccountName); 465 if (!NT_SUCCESS(Status)) 466 { 467 TRACE("SampRegDeleteValue failed (Status 0x%08lx)\n", Status); 468 goto done; 469 } 470 471 /* Remove the account key from the container */ 472 Status = SampRegDeleteKey(ContainerKey, 473 DbObject->Name); 474 if (!NT_SUCCESS(Status)) 475 { 476 TRACE("SampRegDeleteKey failed (Status 0x%08lx)\n", Status); 477 goto done; 478 } 479 480 /* Release the database object name */ 481 if (DbObject->Name != NULL) 482 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name); 483 484 /* Release the database object */ 485 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject); 486 487 Status = STATUS_SUCCESS; 488 489 done: 490 SampRegCloseKey(&NamesKey); 491 SampRegCloseKey(&ContainerKey); 492 493 if (AccountName != NULL) 494 RtlFreeHeap(RtlGetProcessHeap(), 0, AccountName); 495 496 return Status; 497 } 498 499 500 NTSTATUS 501 SampSetObjectAttribute(PSAM_DB_OBJECT DbObject, 502 LPWSTR AttributeName, 503 ULONG AttributeType, 504 LPVOID AttributeData, 505 ULONG AttributeSize) 506 { 507 return SampRegSetValue(DbObject->KeyHandle, 508 AttributeName, 509 AttributeType, 510 AttributeData, 511 AttributeSize); 512 } 513 514 515 NTSTATUS 516 SampGetObjectAttribute(PSAM_DB_OBJECT DbObject, 517 LPWSTR AttributeName, 518 PULONG AttributeType, 519 LPVOID AttributeData, 520 PULONG AttributeSize) 521 { 522 return SampRegQueryValue(DbObject->KeyHandle, 523 AttributeName, 524 AttributeType, 525 AttributeData, 526 AttributeSize); 527 } 528 529 530 NTSTATUS 531 SampGetObjectAttributeString(PSAM_DB_OBJECT DbObject, 532 LPWSTR AttributeName, 533 PRPC_UNICODE_STRING String) 534 { 535 ULONG Length = 0; 536 NTSTATUS Status; 537 538 Status = SampGetObjectAttribute(DbObject, 539 AttributeName, 540 NULL, 541 NULL, 542 &Length); 543 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 544 { 545 TRACE("Status 0x%08lx\n", Status); 546 goto done; 547 } 548 549 if (Length == 0) 550 { 551 String->Length = 0; 552 String->MaximumLength = 0; 553 String->Buffer = NULL; 554 555 Status = STATUS_SUCCESS; 556 goto done; 557 } 558 559 String->Length = (USHORT)(Length - sizeof(WCHAR)); 560 String->MaximumLength = (USHORT)Length; 561 String->Buffer = midl_user_allocate(Length); 562 if (String->Buffer == NULL) 563 { 564 Status = STATUS_INSUFFICIENT_RESOURCES; 565 goto done; 566 } 567 568 TRACE("Length: %lu\n", Length); 569 Status = SampGetObjectAttribute(DbObject, 570 AttributeName, 571 NULL, 572 (PVOID)String->Buffer, 573 &Length); 574 if (!NT_SUCCESS(Status)) 575 { 576 TRACE("Status 0x%08lx\n", Status); 577 goto done; 578 } 579 580 done: 581 if (!NT_SUCCESS(Status)) 582 { 583 if (String->Buffer != NULL) 584 { 585 midl_user_free(String->Buffer); 586 String->Buffer = NULL; 587 } 588 } 589 590 return Status; 591 } 592 593 594 NTSTATUS 595 SampSetObjectAttributeString(PSAM_DB_OBJECT DbObject, 596 LPWSTR AttributeName, 597 PRPC_UNICODE_STRING String) 598 { 599 PWCHAR Buffer = NULL; 600 USHORT Length = 0; 601 602 if ((String != NULL) && (String->Buffer != NULL)) 603 { 604 Buffer = String->Buffer; 605 Length = String->Length + sizeof(WCHAR); 606 } 607 608 return SampSetObjectAttribute(DbObject, 609 AttributeName, 610 REG_SZ, 611 Buffer, 612 Length); 613 } 614 615 616 /* EOF */ 617 618