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
9 /* INCLUDES ****************************************************************/
13 WINE_DEFAULT_DEBUG_CHANNEL(samsrv
);
16 /* GLOBALS *****************************************************************/
18 static HANDLE SamKeyHandle
= NULL
;
21 /* FUNCTIONS ***************************************************************/
26 OBJECT_ATTRIBUTES ObjectAttributes
;
27 UNICODE_STRING KeyName
;
30 RtlInitUnicodeString(&KeyName
,
31 L
"\\Registry\\Machine\\SAM");
33 InitializeObjectAttributes(&ObjectAttributes
,
39 Status
= RtlpNtOpenKey(&SamKeyHandle
,
40 KEY_READ
| KEY_CREATE_SUB_KEY
| KEY_ENUMERATE_SUB_KEYS
,
49 SampInitDatabase(VOID
)
53 TRACE("SampInitDatabase()\n");
55 Status
= SampOpenSamKey();
56 if (!NT_SUCCESS(Status
))
58 ERR("Failed to open the SAM key (Status: 0x%08lx)\n", Status
);
63 if (!LsapIsDatabaseInstalled())
65 Status
= LsapCreateDatabaseKeys();
66 if (!NT_SUCCESS(Status
))
68 ERR("Failed to create the LSA database keys (Status: 0x%08lx)\n", Status
);
72 Status
= LsapCreateDatabaseObjects();
73 if (!NT_SUCCESS(Status
))
75 ERR("Failed to create the LSA database objects (Status: 0x%08lx)\n", Status
);
81 Status
= LsapUpdateDatabase();
82 if (!NT_SUCCESS(Status
))
84 ERR("Failed to update the LSA database (Status: 0x%08lx)\n", Status
);
90 TRACE("SampInitDatabase() done\n");
92 return STATUS_SUCCESS
;
97 SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject
,
98 IN LPWSTR ContainerName
,
100 IN SAM_DB_OBJECT_TYPE ObjectType
,
101 IN ACCESS_MASK DesiredAccess
,
102 OUT PSAM_DB_OBJECT
*DbObject
)
104 PSAM_DB_OBJECT NewObject
;
105 OBJECT_ATTRIBUTES ObjectAttributes
;
106 UNICODE_STRING KeyName
;
107 HANDLE ParentKeyHandle
;
108 HANDLE ContainerKeyHandle
= NULL
;
109 HANDLE ObjectKeyHandle
= NULL
;
110 HANDLE MembersKeyHandle
= NULL
;
113 if (DbObject
== NULL
)
114 return STATUS_INVALID_PARAMETER
;
116 if (ParentObject
== NULL
)
117 ParentKeyHandle
= SamKeyHandle
;
119 ParentKeyHandle
= ParentObject
->KeyHandle
;
121 if (ContainerName
!= NULL
)
123 /* Open the container key */
124 RtlInitUnicodeString(&KeyName
,
127 InitializeObjectAttributes(&ObjectAttributes
,
129 OBJ_CASE_INSENSITIVE
,
133 Status
= NtOpenKey(&ContainerKeyHandle
,
136 if (!NT_SUCCESS(Status
))
141 /* Open the object key */
142 RtlInitUnicodeString(&KeyName
,
145 InitializeObjectAttributes(&ObjectAttributes
,
147 OBJ_CASE_INSENSITIVE
,
151 Status
= NtCreateKey(&ObjectKeyHandle
,
159 if ((ObjectType
== SamDbAliasObject
) ||
160 (ObjectType
== SamDbGroupObject
))
162 /* Open the object key */
163 RtlInitUnicodeString(&KeyName
,
166 InitializeObjectAttributes(&ObjectAttributes
,
168 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
172 Status
= NtCreateKey(&MembersKeyHandle
,
181 NtClose(ContainerKeyHandle
);
183 if (!NT_SUCCESS(Status
))
190 RtlInitUnicodeString(&KeyName
,
193 InitializeObjectAttributes(&ObjectAttributes
,
195 OBJ_CASE_INSENSITIVE
,
199 Status
= NtCreateKey(&ObjectKeyHandle
,
206 if (!NT_SUCCESS(Status
))
212 NewObject
= RtlAllocateHeap(RtlGetProcessHeap(),
214 sizeof(SAM_DB_OBJECT
));
215 if (NewObject
== NULL
)
217 if (MembersKeyHandle
!= NULL
)
218 NtClose(MembersKeyHandle
);
219 NtClose(ObjectKeyHandle
);
220 return STATUS_NO_MEMORY
;
223 NewObject
->Name
= RtlAllocateHeap(RtlGetProcessHeap(),
225 (wcslen(ObjectName
) + 1) * sizeof(WCHAR
));
226 if (NewObject
== NULL
)
228 if (MembersKeyHandle
!= NULL
)
229 NtClose(MembersKeyHandle
);
230 NtClose(ObjectKeyHandle
);
231 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject
);
232 return STATUS_NO_MEMORY
;
235 wcscpy(NewObject
->Name
, ObjectName
);
237 NewObject
->Signature
= SAMP_DB_SIGNATURE
;
238 NewObject
->RefCount
= 1;
239 NewObject
->ObjectType
= ObjectType
;
240 NewObject
->Access
= DesiredAccess
;
241 NewObject
->KeyHandle
= ObjectKeyHandle
;
242 NewObject
->MembersKeyHandle
= MembersKeyHandle
;
243 NewObject
->ParentObject
= ParentObject
;
245 if (ParentObject
!= NULL
)
246 ParentObject
->RefCount
++;
248 *DbObject
= NewObject
;
250 return STATUS_SUCCESS
;
255 SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject
,
256 IN LPWSTR ContainerName
,
257 IN LPWSTR ObjectName
,
258 IN SAM_DB_OBJECT_TYPE ObjectType
,
259 IN ACCESS_MASK DesiredAccess
,
260 OUT PSAM_DB_OBJECT
*DbObject
)
262 PSAM_DB_OBJECT NewObject
;
263 OBJECT_ATTRIBUTES ObjectAttributes
;
264 UNICODE_STRING KeyName
;
265 HANDLE ParentKeyHandle
;
266 HANDLE ContainerKeyHandle
= NULL
;
267 HANDLE ObjectKeyHandle
= NULL
;
268 HANDLE MembersKeyHandle
= NULL
;
271 if (DbObject
== NULL
)
272 return STATUS_INVALID_PARAMETER
;
274 if (ParentObject
== NULL
)
275 ParentKeyHandle
= SamKeyHandle
;
277 ParentKeyHandle
= ParentObject
->KeyHandle
;
279 if (ContainerName
!= NULL
)
281 /* Open the container key */
282 RtlInitUnicodeString(&KeyName
,
285 InitializeObjectAttributes(&ObjectAttributes
,
287 OBJ_CASE_INSENSITIVE
,
291 Status
= NtOpenKey(&ContainerKeyHandle
,
294 if (!NT_SUCCESS(Status
))
299 /* Open the object key */
300 RtlInitUnicodeString(&KeyName
,
303 InitializeObjectAttributes(&ObjectAttributes
,
305 OBJ_CASE_INSENSITIVE
,
309 Status
= NtOpenKey(&ObjectKeyHandle
,
313 if ((ObjectType
== SamDbAliasObject
) ||
314 (ObjectType
== SamDbGroupObject
))
316 /* Open the object key */
317 RtlInitUnicodeString(&KeyName
,
320 InitializeObjectAttributes(&ObjectAttributes
,
322 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
326 Status
= NtCreateKey(&MembersKeyHandle
,
335 NtClose(ContainerKeyHandle
);
337 if (!NT_SUCCESS(Status
))
344 /* Open the object key */
345 RtlInitUnicodeString(&KeyName
,
348 InitializeObjectAttributes(&ObjectAttributes
,
350 OBJ_CASE_INSENSITIVE
,
354 Status
= NtOpenKey(&ObjectKeyHandle
,
357 if (!NT_SUCCESS(Status
))
363 NewObject
= RtlAllocateHeap(RtlGetProcessHeap(),
365 sizeof(SAM_DB_OBJECT
));
366 if (NewObject
== NULL
)
368 if (MembersKeyHandle
!= NULL
)
369 NtClose(MembersKeyHandle
);
370 NtClose(ObjectKeyHandle
);
371 return STATUS_NO_MEMORY
;
374 NewObject
->Name
= RtlAllocateHeap(RtlGetProcessHeap(),
376 (wcslen(ObjectName
) + 1) * sizeof(WCHAR
));
377 if (NewObject
== NULL
)
379 if (MembersKeyHandle
!= NULL
)
380 NtClose(MembersKeyHandle
);
381 NtClose(ObjectKeyHandle
);
382 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject
);
383 return STATUS_NO_MEMORY
;
386 wcscpy(NewObject
->Name
, ObjectName
);
387 NewObject
->Signature
= SAMP_DB_SIGNATURE
;
388 NewObject
->RefCount
= 1;
389 NewObject
->ObjectType
= ObjectType
;
390 NewObject
->Access
= DesiredAccess
;
391 NewObject
->KeyHandle
= ObjectKeyHandle
;
392 NewObject
->MembersKeyHandle
= MembersKeyHandle
;
393 NewObject
->ParentObject
= ParentObject
;
395 if (ParentObject
!= NULL
)
396 ParentObject
->RefCount
++;
398 *DbObject
= NewObject
;
400 return STATUS_SUCCESS
;
405 SampValidateDbObject(SAMPR_HANDLE Handle
,
406 SAM_DB_OBJECT_TYPE ObjectType
,
407 ACCESS_MASK DesiredAccess
,
408 PSAM_DB_OBJECT
*DbObject
)
410 PSAM_DB_OBJECT LocalObject
= (PSAM_DB_OBJECT
)Handle
;
411 BOOLEAN bValid
= FALSE
;
415 if (LocalObject
->Signature
== SAMP_DB_SIGNATURE
)
417 if ((ObjectType
== SamDbIgnoreObject
) ||
418 (LocalObject
->ObjectType
== ObjectType
))
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
429 return STATUS_INVALID_HANDLE
;
431 if (DesiredAccess
!= 0)
433 /* Check for granted access rights */
434 if ((LocalObject
->Access
& DesiredAccess
) != DesiredAccess
)
436 ERR("SampValidateDbObject access check failed %08lx %08lx\n",
437 LocalObject
->Access
, DesiredAccess
);
438 return STATUS_ACCESS_DENIED
;
442 if (DbObject
!= NULL
)
443 *DbObject
= LocalObject
;
445 return STATUS_SUCCESS
;
450 SampCloseDbObject(PSAM_DB_OBJECT DbObject
)
452 PSAM_DB_OBJECT ParentObject
= NULL
;
453 NTSTATUS Status
= STATUS_SUCCESS
;
455 DbObject
->RefCount
--;
457 if (DbObject
->RefCount
> 0)
458 return STATUS_SUCCESS
;
460 if (DbObject
->KeyHandle
!= NULL
)
461 NtClose(DbObject
->KeyHandle
);
463 if (DbObject
->MembersKeyHandle
!= NULL
)
464 NtClose(DbObject
->MembersKeyHandle
);
466 if (DbObject
->ParentObject
!= NULL
)
467 ParentObject
= DbObject
->ParentObject
;
469 if (DbObject
->Name
!= NULL
)
470 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject
->Name
);
472 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject
);
474 if (ParentObject
!= NULL
)
476 ParentObject
->RefCount
--;
478 if (ParentObject
->RefCount
== 0)
479 Status
= SampCloseDbObject(ParentObject
);
487 SampSetAccountNameInDomain(IN PSAM_DB_OBJECT DomainObject
,
488 IN LPCWSTR lpContainerName
,
489 IN LPCWSTR lpAccountName
,
490 IN ULONG ulRelativeId
)
492 OBJECT_ATTRIBUTES ObjectAttributes
;
493 UNICODE_STRING KeyName
;
494 UNICODE_STRING ValueName
;
495 HANDLE ContainerKeyHandle
= NULL
;
496 HANDLE NamesKeyHandle
= NULL
;
499 TRACE("SampSetAccountNameInDomain()\n");
501 /* Open the container key */
502 RtlInitUnicodeString(&KeyName
, lpContainerName
);
504 InitializeObjectAttributes(&ObjectAttributes
,
506 OBJ_CASE_INSENSITIVE
,
507 DomainObject
->KeyHandle
,
510 Status
= NtOpenKey(&ContainerKeyHandle
,
513 if (!NT_SUCCESS(Status
))
516 /* Open the 'Names' key */
517 RtlInitUnicodeString(&KeyName
, L
"Names");
519 InitializeObjectAttributes(&ObjectAttributes
,
521 OBJ_CASE_INSENSITIVE
,
525 Status
= NtOpenKey(&NamesKeyHandle
,
528 if (!NT_SUCCESS(Status
))
531 /* Set the alias value */
532 RtlInitUnicodeString(&ValueName
, lpAccountName
);
534 Status
= NtSetValueKey(NamesKeyHandle
,
538 (LPVOID
)&ulRelativeId
,
543 NtClose(NamesKeyHandle
);
545 if (ContainerKeyHandle
)
546 NtClose(ContainerKeyHandle
);
553 SampCheckAccountNameInDomain(IN PSAM_DB_OBJECT DomainObject
,
554 IN LPWSTR lpAccountName
)
560 TRACE("SampCheckAccountNameInDomain()\n");
562 Status
= SampRegOpenKey(DomainObject
->KeyHandle
,
566 if (NT_SUCCESS(Status
))
568 Status
= SampRegOpenKey(AccountKey
,
572 if (NT_SUCCESS(Status
))
574 Status
= SampRegQueryValue(NamesKey
,
579 if (Status
== STATUS_SUCCESS
)
581 SampRegCloseKey(NamesKey
);
582 Status
= STATUS_ALIAS_EXISTS
;
584 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
585 Status
= STATUS_SUCCESS
;
588 SampRegCloseKey(AccountKey
);
591 if (!NT_SUCCESS(Status
))
593 TRACE("Checking for alias account failed (Status 0x%08lx)\n", Status
);
597 Status
= SampRegOpenKey(DomainObject
->KeyHandle
,
601 if (NT_SUCCESS(Status
))
603 Status
= SampRegOpenKey(AccountKey
,
607 if (NT_SUCCESS(Status
))
609 Status
= SampRegQueryValue(NamesKey
,
614 if (Status
== STATUS_SUCCESS
)
616 SampRegCloseKey(NamesKey
);
617 Status
= STATUS_ALIAS_EXISTS
;
619 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
620 Status
= STATUS_SUCCESS
;
623 SampRegCloseKey(AccountKey
);
626 if (!NT_SUCCESS(Status
))
628 TRACE("Checking for group account failed (Status 0x%08lx)\n", Status
);
632 Status
= SampRegOpenKey(DomainObject
->KeyHandle
,
636 if (NT_SUCCESS(Status
))
638 Status
= SampRegOpenKey(AccountKey
,
642 if (NT_SUCCESS(Status
))
644 Status
= SampRegQueryValue(NamesKey
,
649 if (Status
== STATUS_SUCCESS
)
651 SampRegCloseKey(NamesKey
);
652 Status
= STATUS_ALIAS_EXISTS
;
654 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
655 Status
= STATUS_SUCCESS
;
658 SampRegCloseKey(AccountKey
);
661 if (!NT_SUCCESS(Status
))
663 TRACE("Checking for user account failed (Status 0x%08lx)\n", Status
);
671 SampSetObjectAttribute(PSAM_DB_OBJECT DbObject
,
672 LPWSTR AttributeName
,
674 LPVOID AttributeData
,
677 UNICODE_STRING ValueName
;
679 RtlInitUnicodeString(&ValueName
,
682 return ZwSetValueKey(DbObject
->KeyHandle
,
692 SampGetObjectAttribute(PSAM_DB_OBJECT DbObject
,
693 LPWSTR AttributeName
,
694 PULONG AttributeType
,
695 LPVOID AttributeData
,
696 PULONG AttributeSize
)
698 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
699 UNICODE_STRING ValueName
;
700 ULONG BufferLength
= 0;
703 RtlInitUnicodeString(&ValueName
,
706 if (AttributeSize
!= NULL
)
707 BufferLength
= *AttributeSize
;
709 BufferLength
+= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
711 /* Allocate memory for the value */
712 ValueInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
713 if (ValueInfo
== NULL
)
714 return STATUS_NO_MEMORY
;
716 /* Query the value */
717 Status
= ZwQueryValueKey(DbObject
->KeyHandle
,
719 KeyValuePartialInformation
,
723 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_OVERFLOW
))
725 if (AttributeType
!= NULL
)
726 *AttributeType
= ValueInfo
->Type
;
728 if (AttributeSize
!= NULL
)
729 *AttributeSize
= ValueInfo
->DataLength
;
732 /* Check if the caller wanted data back, and we got it */
733 if ((NT_SUCCESS(Status
)) && (AttributeData
!= NULL
))
736 RtlMoveMemory(AttributeData
,
738 ValueInfo
->DataLength
);
741 /* Free the memory and return status */
742 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo
);
749 SampGetObjectAttributeString(PSAM_DB_OBJECT DbObject
,
750 LPWSTR AttributeName
,
751 RPC_UNICODE_STRING
*String
)
756 Status
= SampGetObjectAttribute(DbObject
,
761 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
763 TRACE("Status 0x%08lx\n", Status
);
767 String
->Length
= Length
- sizeof(WCHAR
);
768 String
->MaximumLength
= Length
;
769 String
->Buffer
= midl_user_allocate(Length
);
770 if (String
->Buffer
== NULL
)
772 Status
= STATUS_INSUFFICIENT_RESOURCES
;
776 TRACE("Length: %lu\n", Length
);
777 Status
= SampGetObjectAttribute(DbObject
,
780 (PVOID
)String
->Buffer
,
782 if (!NT_SUCCESS(Status
))
784 TRACE("Status 0x%08lx\n", Status
);
789 if (!NT_SUCCESS(Status
))
791 if (String
->Buffer
!= NULL
)
793 midl_user_free(String
->Buffer
);
794 String
->Buffer
= NULL
;