[LSASRV]
[reactos.git] / reactos / dll / win32 / lsasrv / database.c
1 /*
2 * PROJECT: Local Security Authority Server DLL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/lsasrv/database.c
5 * PURPOSE: LSA object database
6 * COPYRIGHT: Copyright 2011 Eric Kohl
7 */
8
9 /* INCLUDES ****************************************************************/
10
11 #include "lsasrv.h"
12
13 WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);
14
15
16 /* GLOBALS *****************************************************************/
17
18 static HANDLE SecurityKeyHandle = NULL;
19
20
21 /* FUNCTIONS ***************************************************************/
22
23 static NTSTATUS
24 LsapOpenServiceKey(VOID)
25 {
26 OBJECT_ATTRIBUTES ObjectAttributes;
27 UNICODE_STRING KeyName;
28 NTSTATUS Status;
29
30 RtlInitUnicodeString(&KeyName,
31 L"\\Registry\\Machine\\SECURITY");
32
33 InitializeObjectAttributes(&ObjectAttributes,
34 &KeyName,
35 OBJ_CASE_INSENSITIVE,
36 NULL,
37 NULL);
38
39 Status = RtlpNtOpenKey(&SecurityKeyHandle,
40 KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
41 &ObjectAttributes,
42 0);
43
44 return Status;
45 }
46
47
48 static BOOLEAN
49 LsapIsDatabaseInstalled(VOID)
50 {
51 OBJECT_ATTRIBUTES ObjectAttributes;
52 UNICODE_STRING KeyName;
53 HANDLE KeyHandle;
54 NTSTATUS Status;
55
56 RtlInitUnicodeString(&KeyName,
57 L"Policy");
58
59 InitializeObjectAttributes(&ObjectAttributes,
60 &KeyName,
61 OBJ_CASE_INSENSITIVE,
62 SecurityKeyHandle,
63 NULL);
64
65 Status = RtlpNtOpenKey(&KeyHandle,
66 KEY_READ,
67 &ObjectAttributes,
68 0);
69 if (!NT_SUCCESS(Status))
70 return FALSE;
71
72 NtClose(KeyHandle);
73
74 return TRUE;
75 }
76
77
78 static NTSTATUS
79 LsapCreateDatabaseKeys(VOID)
80 {
81 OBJECT_ATTRIBUTES ObjectAttributes;
82 UNICODE_STRING KeyName;
83 HANDLE PolicyKeyHandle = NULL;
84 HANDLE AccountsKeyHandle = NULL;
85 HANDLE DomainsKeyHandle = NULL;
86 HANDLE SecretsKeyHandle = NULL;
87 NTSTATUS Status = STATUS_SUCCESS;
88
89 TRACE("LsapInstallDatabase()\n");
90
91 /* Create the 'Policy' key */
92 RtlInitUnicodeString(&KeyName,
93 L"Policy");
94
95 InitializeObjectAttributes(&ObjectAttributes,
96 &KeyName,
97 OBJ_CASE_INSENSITIVE,
98 SecurityKeyHandle,
99 NULL);
100
101 Status = NtCreateKey(&PolicyKeyHandle,
102 KEY_ALL_ACCESS,
103 &ObjectAttributes,
104 0,
105 NULL,
106 0,
107 NULL);
108 if (!NT_SUCCESS(Status))
109 {
110 ERR("Failed to create the 'Policy' key (Status: 0x%08lx)\n", Status);
111 goto Done;
112 }
113
114 /* Create the 'Accounts' key */
115 RtlInitUnicodeString(&KeyName,
116 L"Accounts");
117
118 InitializeObjectAttributes(&ObjectAttributes,
119 &KeyName,
120 OBJ_CASE_INSENSITIVE,
121 PolicyKeyHandle,
122 NULL);
123
124 Status = NtCreateKey(&AccountsKeyHandle,
125 KEY_ALL_ACCESS,
126 &ObjectAttributes,
127 0,
128 NULL,
129 0,
130 NULL);
131 if (!NT_SUCCESS(Status))
132 {
133 ERR("Failed to create the 'Accounts' key (Status: 0x%08lx)\n", Status);
134 goto Done;
135 }
136
137 /* Create the 'Domains' key */
138 RtlInitUnicodeString(&KeyName,
139 L"Domains");
140
141 InitializeObjectAttributes(&ObjectAttributes,
142 &KeyName,
143 OBJ_CASE_INSENSITIVE,
144 PolicyKeyHandle,
145 NULL);
146
147 Status = NtCreateKey(&DomainsKeyHandle,
148 KEY_ALL_ACCESS,
149 &ObjectAttributes,
150 0,
151 NULL,
152 0,
153 NULL);
154 if (!NT_SUCCESS(Status))
155 {
156 ERR("Failed to create the 'Domains' key (Status: 0x%08lx)\n", Status);
157 goto Done;
158 }
159
160 /* Create the 'Secrets' key */
161 RtlInitUnicodeString(&KeyName,
162 L"Secrets");
163
164 InitializeObjectAttributes(&ObjectAttributes,
165 &KeyName,
166 OBJ_CASE_INSENSITIVE,
167 PolicyKeyHandle,
168 NULL);
169
170 Status = NtCreateKey(&SecretsKeyHandle,
171 KEY_ALL_ACCESS,
172 &ObjectAttributes,
173 0,
174 NULL,
175 0,
176 NULL);
177 if (!NT_SUCCESS(Status))
178 {
179 ERR("Failed to create the 'Secrets' key (Status: 0x%08lx)\n", Status);
180 goto Done;
181 }
182
183 Done:
184 if (SecretsKeyHandle != NULL)
185 NtClose(SecretsKeyHandle);
186
187 if (DomainsKeyHandle != NULL)
188 NtClose(DomainsKeyHandle);
189
190 if (AccountsKeyHandle != NULL)
191 NtClose(AccountsKeyHandle);
192
193 if (PolicyKeyHandle != NULL)
194 NtClose(PolicyKeyHandle);
195
196 TRACE("LsapInstallDatabase() done (Status: 0x%08lx)\n", Status);
197
198 return Status;
199 }
200
201
202 static NTSTATUS
203 LsapCreateRandomDomainSid(OUT PSID *Sid)
204 {
205 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
206 LARGE_INTEGER SystemTime;
207 PULONG Seed;
208
209 NtQuerySystemTime(&SystemTime);
210 Seed = &SystemTime.u.LowPart;
211
212 return RtlAllocateAndInitializeSid(&SystemAuthority,
213 4,
214 SECURITY_NT_NON_UNIQUE,
215 RtlUniform(Seed),
216 RtlUniform(Seed),
217 RtlUniform(Seed),
218 SECURITY_NULL_RID,
219 SECURITY_NULL_RID,
220 SECURITY_NULL_RID,
221 SECURITY_NULL_RID,
222 Sid);
223 }
224
225
226 static NTSTATUS
227 LsapCreateDatabaseObjects(VOID)
228 {
229 PLSAP_POLICY_AUDIT_EVENTS_DATA AuditEventsInfo = NULL;
230 POLICY_DEFAULT_QUOTA_INFO QuotaInfo;
231 POLICY_MODIFICATION_INFO ModificationInfo;
232 POLICY_AUDIT_FULL_QUERY_INFO AuditFullInfo = {FALSE, FALSE};
233 POLICY_AUDIT_LOG_INFO AuditLogInfo;
234 GUID DnsDomainGuid;
235 PLSA_DB_OBJECT PolicyObject = NULL;
236 PSID AccountDomainSid = NULL;
237 ULONG AuditEventsCount;
238 ULONG AuditEventsSize;
239 ULONG i;
240 NTSTATUS Status;
241
242 /* Initialize the default quota limits */
243 QuotaInfo.QuotaLimits.PagedPoolLimit = 0x2000000;
244 QuotaInfo.QuotaLimits.NonPagedPoolLimit = 0x100000;
245 QuotaInfo.QuotaLimits.MinimumWorkingSetSize = 0x10000;
246 QuotaInfo.QuotaLimits.MaximumWorkingSetSize = 0xF000000;
247 QuotaInfo.QuotaLimits.PagefileLimit = 0;
248 QuotaInfo.QuotaLimits.TimeLimit.QuadPart = 0;
249
250 /* Initialize the audit log attribute */
251 AuditLogInfo.AuditLogPercentFull = 0;
252 AuditLogInfo.MaximumLogSize = 0; // DWORD
253 AuditLogInfo.AuditRetentionPeriod.QuadPart = 0; // LARGE_INTEGER
254 AuditLogInfo.AuditLogFullShutdownInProgress = 0; // BYTE
255 AuditLogInfo.TimeToShutdown.QuadPart = 0; // LARGE_INTEGER
256 AuditLogInfo.NextAuditRecordId = 0; // DWORD
257
258 /* Initialize the Audit Events attribute */
259 AuditEventsCount = AuditCategoryAccountLogon - AuditCategorySystem + 1;
260 AuditEventsSize = sizeof(LSAP_POLICY_AUDIT_EVENTS_DATA) + AuditEventsCount * sizeof(DWORD);
261 AuditEventsInfo = RtlAllocateHeap(RtlGetProcessHeap(),
262 0,
263 AuditEventsSize);
264 if (AuditEventsInfo == NULL)
265 return STATUS_INSUFFICIENT_RESOURCES;
266
267 AuditEventsInfo->AuditingMode = FALSE;
268 AuditEventsInfo->MaximumAuditEventCount = AuditEventsCount;
269 for (i = 0; i < AuditEventsCount; i++)
270 AuditEventsInfo->AuditEvents[i] = 0;
271
272 /* Initialize the DNS Domain GUID attribute */
273 memset(&DnsDomainGuid, 0, sizeof(GUID));
274
275 /* Initialize the modification attribute */
276 ModificationInfo.ModifiedId.QuadPart = 0;
277 NtQuerySystemTime(&ModificationInfo.DatabaseCreationTime);
278
279 /* Create a random domain SID */
280 Status = LsapCreateRandomDomainSid(&AccountDomainSid);
281 if (!NT_SUCCESS(Status))
282 goto done;
283
284 /* Open the 'Policy' object */
285 Status = LsapOpenDbObject(NULL,
286 NULL,
287 L"Policy",
288 LsaDbPolicyObject,
289 0,
290 &PolicyObject);
291 if (!NT_SUCCESS(Status))
292 goto done;
293
294 LsapSetObjectAttribute(PolicyObject,
295 L"PolPrDmN",
296 NULL,
297 0);
298
299 LsapSetObjectAttribute(PolicyObject,
300 L"PolPrDmS",
301 NULL,
302 0);
303
304 LsapSetObjectAttribute(PolicyObject,
305 L"PolAcDmN",
306 NULL,
307 0);
308
309 LsapSetObjectAttribute(PolicyObject,
310 L"PolAcDmS",
311 AccountDomainSid,
312 RtlLengthSid(AccountDomainSid));
313
314 /* Set the default quota limits attribute */
315 LsapSetObjectAttribute(PolicyObject,
316 L"DefQuota",
317 &QuotaInfo,
318 sizeof(POLICY_DEFAULT_QUOTA_INFO));
319
320 /* Set the modification attribute */
321 LsapSetObjectAttribute(PolicyObject,
322 L"PolMod",
323 &ModificationInfo,
324 sizeof(POLICY_MODIFICATION_INFO));
325
326 /* Set the audit full attribute */
327 LsapSetObjectAttribute(PolicyObject,
328 L"PolAdtFl",
329 &AuditFullInfo,
330 sizeof(POLICY_AUDIT_FULL_QUERY_INFO));
331
332 /* Set the audit log attribute */
333 LsapSetObjectAttribute(PolicyObject,
334 L"PolAdtLg",
335 &AuditLogInfo,
336 sizeof(POLICY_AUDIT_LOG_INFO));
337
338 /* Set the audit events attribute */
339 LsapSetObjectAttribute(PolicyObject,
340 L"PolAdtEv",
341 &AuditEventsInfo,
342 AuditEventsSize);
343
344 /* Set the DNS Domain Name attribute */
345 LsapSetObjectAttribute(PolicyObject,
346 L"PolDnDDN",
347 NULL,
348 0);
349
350 /* Set the DNS Forest Name attribute */
351 LsapSetObjectAttribute(PolicyObject,
352 L"PolDnTrN",
353 NULL,
354 0);
355
356 /* Set the DNS Domain GUID attribute */
357 LsapSetObjectAttribute(PolicyObject,
358 L"PolDnDmG",
359 &DnsDomainGuid,
360 sizeof(GUID));
361
362 done:
363 if (AuditEventsInfo != NULL)
364 RtlFreeHeap(RtlGetProcessHeap(), 0, AuditEventsInfo);
365
366 if (PolicyObject != NULL)
367 LsapCloseDbObject(PolicyObject);
368
369 if (AccountDomainSid != NULL)
370 RtlFreeSid(AccountDomainSid);
371
372 return Status;
373 }
374
375
376 static NTSTATUS
377 LsapUpdateDatabase(VOID)
378 {
379 return STATUS_SUCCESS;
380 }
381
382
383 NTSTATUS
384 LsapInitDatabase(VOID)
385 {
386 NTSTATUS Status;
387
388 TRACE("LsapInitDatabase()\n");
389
390 Status = LsapOpenServiceKey();
391 if (!NT_SUCCESS(Status))
392 {
393 ERR("Failed to open the service key (Status: 0x%08lx)\n", Status);
394 return Status;
395 }
396
397 if (!LsapIsDatabaseInstalled())
398 {
399 Status = LsapCreateDatabaseKeys();
400 if (!NT_SUCCESS(Status))
401 {
402 ERR("Failed to create the LSA database keys (Status: 0x%08lx)\n", Status);
403 return Status;
404 }
405
406 Status = LsapCreateDatabaseObjects();
407 if (!NT_SUCCESS(Status))
408 {
409 ERR("Failed to create the LSA database objects (Status: 0x%08lx)\n", Status);
410 return Status;
411 }
412 }
413 else
414 {
415 Status = LsapUpdateDatabase();
416 if (!NT_SUCCESS(Status))
417 {
418 ERR("Failed to update the LSA database (Status: 0x%08lx)\n", Status);
419 return Status;
420 }
421 }
422
423 TRACE("LsapInitDatabase() done\n");
424
425 return STATUS_SUCCESS;
426 }
427
428
429 NTSTATUS
430 LsapCreateDbObject(IN PLSA_DB_OBJECT ParentObject,
431 IN LPWSTR ContainerName,
432 IN LPWSTR ObjectName,
433 IN LSA_DB_OBJECT_TYPE ObjectType,
434 IN ACCESS_MASK DesiredAccess,
435 OUT PLSA_DB_OBJECT *DbObject)
436 {
437 PLSA_DB_OBJECT NewObject;
438 OBJECT_ATTRIBUTES ObjectAttributes;
439 UNICODE_STRING KeyName;
440 HANDLE ParentKeyHandle;
441 HANDLE ContainerKeyHandle = NULL;
442 HANDLE ObjectKeyHandle = NULL;
443 NTSTATUS Status;
444
445 if (DbObject == NULL)
446 return STATUS_INVALID_PARAMETER;
447
448 if (ParentObject == NULL)
449 ParentKeyHandle = SecurityKeyHandle;
450 else
451 ParentKeyHandle = ParentObject->KeyHandle;
452
453 if (ContainerName != NULL)
454 {
455 /* Open the container key */
456 RtlInitUnicodeString(&KeyName,
457 ContainerName);
458
459 InitializeObjectAttributes(&ObjectAttributes,
460 &KeyName,
461 OBJ_CASE_INSENSITIVE,
462 ParentKeyHandle,
463 NULL);
464
465 Status = NtOpenKey(&ContainerKeyHandle,
466 KEY_ALL_ACCESS,
467 &ObjectAttributes);
468 if (!NT_SUCCESS(Status))
469 {
470 return Status;
471 }
472
473 /* Open the object key */
474 RtlInitUnicodeString(&KeyName,
475 ObjectName);
476
477 InitializeObjectAttributes(&ObjectAttributes,
478 &KeyName,
479 OBJ_CASE_INSENSITIVE,
480 ContainerKeyHandle,
481 NULL);
482
483 Status = NtCreateKey(&ObjectKeyHandle,
484 KEY_ALL_ACCESS,
485 &ObjectAttributes,
486 0,
487 NULL,
488 0,
489 NULL);
490
491 NtClose(ContainerKeyHandle);
492
493 if (!NT_SUCCESS(Status))
494 {
495 return Status;
496 }
497 }
498 else
499 {
500 RtlInitUnicodeString(&KeyName,
501 ObjectName);
502
503 InitializeObjectAttributes(&ObjectAttributes,
504 &KeyName,
505 OBJ_CASE_INSENSITIVE,
506 ParentKeyHandle,
507 NULL);
508
509 Status = NtCreateKey(&ObjectKeyHandle,
510 KEY_ALL_ACCESS,
511 &ObjectAttributes,
512 0,
513 NULL,
514 0,
515 NULL);
516 if (!NT_SUCCESS(Status))
517 {
518 return Status;
519 }
520 }
521
522 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
523 0,
524 sizeof(LSA_DB_OBJECT));
525 if (NewObject == NULL)
526 {
527 NtClose(ObjectKeyHandle);
528 return STATUS_NO_MEMORY;
529 }
530
531 NewObject->Signature = LSAP_DB_SIGNATURE;
532 NewObject->RefCount = 1;
533 NewObject->ObjectType = ObjectType;
534 NewObject->Access = DesiredAccess;
535 NewObject->KeyHandle = ObjectKeyHandle;
536 NewObject->ParentObject = ParentObject;
537
538 if (ParentObject != NULL)
539 ParentObject->RefCount++;
540
541 *DbObject = NewObject;
542
543 return STATUS_SUCCESS;
544 }
545
546
547 NTSTATUS
548 LsapOpenDbObject(IN PLSA_DB_OBJECT ParentObject,
549 IN LPWSTR ContainerName,
550 IN LPWSTR ObjectName,
551 IN LSA_DB_OBJECT_TYPE ObjectType,
552 IN ACCESS_MASK DesiredAccess,
553 OUT PLSA_DB_OBJECT *DbObject)
554 {
555 PLSA_DB_OBJECT NewObject;
556 OBJECT_ATTRIBUTES ObjectAttributes;
557 UNICODE_STRING KeyName;
558 HANDLE ParentKeyHandle;
559 HANDLE ContainerKeyHandle = NULL;
560 HANDLE ObjectKeyHandle = NULL;
561 NTSTATUS Status;
562
563 if (DbObject == NULL)
564 return STATUS_INVALID_PARAMETER;
565
566 if (ParentObject == NULL)
567 ParentKeyHandle = SecurityKeyHandle;
568 else
569 ParentKeyHandle = ParentObject->KeyHandle;
570
571 if (ContainerName != NULL)
572 {
573 /* Open the container key */
574 RtlInitUnicodeString(&KeyName,
575 ContainerName);
576
577 InitializeObjectAttributes(&ObjectAttributes,
578 &KeyName,
579 OBJ_CASE_INSENSITIVE,
580 ParentKeyHandle,
581 NULL);
582
583 Status = NtOpenKey(&ContainerKeyHandle,
584 KEY_ALL_ACCESS,
585 &ObjectAttributes);
586 if (!NT_SUCCESS(Status))
587 {
588 return Status;
589 }
590
591 /* Open the object key */
592 RtlInitUnicodeString(&KeyName,
593 ObjectName);
594
595 InitializeObjectAttributes(&ObjectAttributes,
596 &KeyName,
597 OBJ_CASE_INSENSITIVE,
598 ContainerKeyHandle,
599 NULL);
600
601 Status = NtOpenKey(&ObjectKeyHandle,
602 KEY_ALL_ACCESS,
603 &ObjectAttributes);
604
605 NtClose(ContainerKeyHandle);
606
607 if (!NT_SUCCESS(Status))
608 {
609 return Status;
610 }
611 }
612 else
613 {
614 /* Open the object key */
615 RtlInitUnicodeString(&KeyName,
616 ObjectName);
617
618 InitializeObjectAttributes(&ObjectAttributes,
619 &KeyName,
620 OBJ_CASE_INSENSITIVE,
621 ParentKeyHandle,
622 NULL);
623
624 Status = NtOpenKey(&ObjectKeyHandle,
625 KEY_ALL_ACCESS,
626 &ObjectAttributes);
627 if (!NT_SUCCESS(Status))
628 {
629 return Status;
630 }
631 }
632
633 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
634 0,
635 sizeof(LSA_DB_OBJECT));
636 if (NewObject == NULL)
637 {
638 NtClose(ObjectKeyHandle);
639 return STATUS_NO_MEMORY;
640 }
641
642 NewObject->Signature = LSAP_DB_SIGNATURE;
643 NewObject->RefCount = 1;
644 NewObject->ObjectType = ObjectType;
645 NewObject->Access = DesiredAccess;
646 NewObject->KeyHandle = ObjectKeyHandle;
647 NewObject->ParentObject = ParentObject;
648
649 if (ParentObject != NULL)
650 ParentObject->RefCount++;
651
652 *DbObject = NewObject;
653
654 return STATUS_SUCCESS;
655 }
656
657
658 NTSTATUS
659 LsapValidateDbObject(LSAPR_HANDLE Handle,
660 LSA_DB_OBJECT_TYPE ObjectType,
661 ACCESS_MASK DesiredAccess,
662 PLSA_DB_OBJECT *DbObject)
663 {
664 PLSA_DB_OBJECT LocalObject = (PLSA_DB_OBJECT)Handle;
665 BOOLEAN bValid = FALSE;
666
667 _SEH2_TRY
668 {
669 if (LocalObject->Signature == LSAP_DB_SIGNATURE)
670 {
671 if ((ObjectType == LsaDbIgnoreObject) ||
672 (LocalObject->ObjectType == ObjectType))
673 bValid = TRUE;
674 }
675 }
676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
677 {
678 bValid = FALSE;
679 }
680 _SEH2_END;
681
682 if (bValid == FALSE)
683 return STATUS_INVALID_HANDLE;
684
685 if (DesiredAccess != 0)
686 {
687 /* Check for granted access rights */
688 if ((LocalObject->Access & DesiredAccess) != DesiredAccess)
689 {
690 ERR("LsapValidateDbObject access check failed %08lx %08lx\n",
691 LocalObject->Access, DesiredAccess);
692 return STATUS_ACCESS_DENIED;
693 }
694 }
695
696 if (DbObject != NULL)
697 *DbObject = LocalObject;
698
699 return STATUS_SUCCESS;
700 }
701
702
703 NTSTATUS
704 LsapCloseDbObject(PLSA_DB_OBJECT DbObject)
705 {
706 PLSA_DB_OBJECT ParentObject = NULL;
707 NTSTATUS Status = STATUS_SUCCESS;
708
709 DbObject->RefCount--;
710
711 if (DbObject->RefCount > 0)
712 return STATUS_SUCCESS;
713
714 if (DbObject->KeyHandle != NULL)
715 NtClose(DbObject->KeyHandle);
716
717 if (DbObject->ParentObject != NULL)
718 ParentObject = DbObject->ParentObject;
719
720 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
721
722 if (ParentObject != NULL)
723 {
724 ParentObject->RefCount--;
725
726 if (ParentObject->RefCount == 0)
727 Status = LsapCloseDbObject(ParentObject);
728 }
729
730 return Status;
731 }
732
733
734 NTSTATUS
735 LsapSetObjectAttribute(PLSA_DB_OBJECT DbObject,
736 LPWSTR AttributeName,
737 LPVOID AttributeData,
738 ULONG AttributeSize)
739 {
740 OBJECT_ATTRIBUTES ObjectAttributes;
741 UNICODE_STRING KeyName;
742 HANDLE AttributeKey;
743 NTSTATUS Status;
744
745 RtlInitUnicodeString(&KeyName,
746 AttributeName);
747
748 InitializeObjectAttributes(&ObjectAttributes,
749 &KeyName,
750 OBJ_CASE_INSENSITIVE,
751 DbObject->KeyHandle,
752 NULL);
753
754 Status = NtCreateKey(&AttributeKey,
755 KEY_SET_VALUE,
756 &ObjectAttributes,
757 0,
758 NULL,
759 REG_OPTION_NON_VOLATILE,
760 NULL);
761 if (!NT_SUCCESS(Status))
762 {
763
764 return Status;
765 }
766
767 Status = RtlpNtSetValueKey(AttributeKey,
768 REG_NONE,
769 AttributeData,
770 AttributeSize);
771
772 NtClose(AttributeKey);
773
774 return Status;
775 }
776
777
778 NTSTATUS
779 LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject,
780 LPWSTR AttributeName,
781 LPVOID AttributeData,
782 PULONG AttributeSize)
783 {
784 OBJECT_ATTRIBUTES ObjectAttributes;
785 UNICODE_STRING KeyName;
786 HANDLE AttributeKey;
787 ULONG ValueSize;
788 NTSTATUS Status;
789
790 RtlInitUnicodeString(&KeyName,
791 AttributeName);
792
793 InitializeObjectAttributes(&ObjectAttributes,
794 &KeyName,
795 OBJ_CASE_INSENSITIVE,
796 DbObject->KeyHandle,
797 NULL);
798
799 Status = NtOpenKey(&AttributeKey,
800 KEY_QUERY_VALUE,
801 &ObjectAttributes);
802 if (!NT_SUCCESS(Status))
803 {
804 return Status;
805 }
806
807 ValueSize = *AttributeSize;
808 Status = RtlpNtQueryValueKey(AttributeKey,
809 NULL,
810 NULL,
811 &ValueSize,
812 0);
813 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
814 {
815 goto Done;
816 }
817
818 if (AttributeData == NULL || *AttributeSize == 0)
819 {
820 *AttributeSize = ValueSize;
821 Status = STATUS_SUCCESS;
822 goto Done;
823 }
824 else if (*AttributeSize < ValueSize)
825 {
826 *AttributeSize = ValueSize;
827 Status = STATUS_BUFFER_OVERFLOW;
828 goto Done;
829 }
830
831 Status = RtlpNtQueryValueKey(AttributeKey,
832 NULL,
833 AttributeData,
834 &ValueSize,
835 0);
836 if (NT_SUCCESS(Status))
837 {
838 *AttributeSize = ValueSize;
839 }
840
841 Done:
842 NtClose(AttributeKey);
843
844 return Status;
845 }
846
847 /* EOF */
848