xref: /reactos/dll/win32/lsasrv/database.c (revision b819608e)
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 #include "lsasrv.h"
10 
11 /* GLOBALS *****************************************************************/
12 
13 static HANDLE SecurityKeyHandle = NULL;
14 
15 SID_IDENTIFIER_AUTHORITY NullSidAuthority    = {SECURITY_NULL_SID_AUTHORITY};
16 SID_IDENTIFIER_AUTHORITY WorldSidAuthority   = {SECURITY_WORLD_SID_AUTHORITY};
17 SID_IDENTIFIER_AUTHORITY LocalSidAuthority   = {SECURITY_LOCAL_SID_AUTHORITY};
18 SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
19 SID_IDENTIFIER_AUTHORITY NtAuthority         = {SECURITY_NT_AUTHORITY};
20 
21 PSID BuiltinDomainSid = NULL;
22 PSID AccountDomainSid = NULL;
23 UNICODE_STRING BuiltinDomainName = {0, 0, NULL};
24 UNICODE_STRING AccountDomainName = {0, 0, NULL};
25 
26 
27 /* FUNCTIONS ***************************************************************/
28 
29 static NTSTATUS
30 LsapOpenServiceKey(VOID)
31 {
32     OBJECT_ATTRIBUTES ObjectAttributes;
33     UNICODE_STRING KeyName;
34     NTSTATUS Status;
35 
36     RtlInitUnicodeString(&KeyName,
37                          L"\\Registry\\Machine\\SECURITY");
38 
39     InitializeObjectAttributes(&ObjectAttributes,
40                                &KeyName,
41                                OBJ_CASE_INSENSITIVE,
42                                NULL,
43                                NULL);
44 
45     Status = RtlpNtOpenKey(&SecurityKeyHandle,
46                            KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
47                            &ObjectAttributes,
48                            0);
49 
50     return Status;
51 }
52 
53 
54 static BOOLEAN
55 LsapIsDatabaseInstalled(VOID)
56 {
57     OBJECT_ATTRIBUTES ObjectAttributes;
58     UNICODE_STRING KeyName;
59     HANDLE KeyHandle;
60     NTSTATUS Status;
61 
62     RtlInitUnicodeString(&KeyName,
63                          L"Policy");
64 
65     InitializeObjectAttributes(&ObjectAttributes,
66                                &KeyName,
67                                OBJ_CASE_INSENSITIVE,
68                                SecurityKeyHandle,
69                                NULL);
70 
71     Status = RtlpNtOpenKey(&KeyHandle,
72                            KEY_READ,
73                            &ObjectAttributes,
74                            0);
75     if (!NT_SUCCESS(Status))
76         return FALSE;
77 
78     NtClose(KeyHandle);
79 
80     return TRUE;
81 }
82 
83 
84 static NTSTATUS
85 LsapCreateDatabaseKeys(VOID)
86 {
87     OBJECT_ATTRIBUTES ObjectAttributes;
88     UNICODE_STRING KeyName;
89     HANDLE PolicyKeyHandle = NULL;
90     HANDLE AccountsKeyHandle = NULL;
91     HANDLE DomainsKeyHandle = NULL;
92     HANDLE SecretsKeyHandle = NULL;
93     NTSTATUS Status = STATUS_SUCCESS;
94 
95     TRACE("LsapInstallDatabase()\n");
96 
97     /* Create the 'Policy' key */
98     RtlInitUnicodeString(&KeyName,
99                          L"Policy");
100 
101     InitializeObjectAttributes(&ObjectAttributes,
102                                &KeyName,
103                                OBJ_CASE_INSENSITIVE,
104                                SecurityKeyHandle,
105                                NULL);
106 
107     Status = NtCreateKey(&PolicyKeyHandle,
108                          KEY_ALL_ACCESS,
109                          &ObjectAttributes,
110                          0,
111                          NULL,
112                          0,
113                          NULL);
114     if (!NT_SUCCESS(Status))
115     {
116         ERR("Failed to create the 'Policy' key (Status: 0x%08lx)\n", Status);
117         goto Done;
118     }
119 
120     /* Create the 'Accounts' key */
121     RtlInitUnicodeString(&KeyName,
122                          L"Accounts");
123 
124     InitializeObjectAttributes(&ObjectAttributes,
125                                &KeyName,
126                                OBJ_CASE_INSENSITIVE,
127                                PolicyKeyHandle,
128                                NULL);
129 
130     Status = NtCreateKey(&AccountsKeyHandle,
131                          KEY_ALL_ACCESS,
132                          &ObjectAttributes,
133                          0,
134                          NULL,
135                          0,
136                          NULL);
137     if (!NT_SUCCESS(Status))
138     {
139         ERR("Failed to create the 'Accounts' key (Status: 0x%08lx)\n", Status);
140         goto Done;
141     }
142 
143     /* Create the 'Domains' key */
144     RtlInitUnicodeString(&KeyName,
145                          L"Domains");
146 
147     InitializeObjectAttributes(&ObjectAttributes,
148                                &KeyName,
149                                OBJ_CASE_INSENSITIVE,
150                                PolicyKeyHandle,
151                                NULL);
152 
153     Status = NtCreateKey(&DomainsKeyHandle,
154                          KEY_ALL_ACCESS,
155                          &ObjectAttributes,
156                          0,
157                          NULL,
158                          0,
159                          NULL);
160     if (!NT_SUCCESS(Status))
161     {
162         ERR("Failed to create the 'Domains' key (Status: 0x%08lx)\n", Status);
163         goto Done;
164     }
165 
166     /* Create the 'Secrets' key */
167     RtlInitUnicodeString(&KeyName,
168                          L"Secrets");
169 
170     InitializeObjectAttributes(&ObjectAttributes,
171                                &KeyName,
172                                OBJ_CASE_INSENSITIVE,
173                                PolicyKeyHandle,
174                                NULL);
175 
176     Status = NtCreateKey(&SecretsKeyHandle,
177                          KEY_ALL_ACCESS,
178                          &ObjectAttributes,
179                          0,
180                          NULL,
181                          0,
182                          NULL);
183     if (!NT_SUCCESS(Status))
184     {
185         ERR("Failed to create the 'Secrets' key (Status: 0x%08lx)\n", Status);
186         goto Done;
187     }
188 
189 Done:
190     if (SecretsKeyHandle != NULL)
191         NtClose(SecretsKeyHandle);
192 
193     if (DomainsKeyHandle != NULL)
194         NtClose(DomainsKeyHandle);
195 
196     if (AccountsKeyHandle != NULL)
197         NtClose(AccountsKeyHandle);
198 
199     if (PolicyKeyHandle != NULL)
200         NtClose(PolicyKeyHandle);
201 
202     TRACE("LsapInstallDatabase() done (Status: 0x%08lx)\n", Status);
203 
204     return Status;
205 }
206 
207 
208 static NTSTATUS
209 LsapCreateRandomDomainSid(OUT PSID *Sid)
210 {
211     LARGE_INTEGER SystemTime;
212     PULONG Seed;
213 
214     NtQuerySystemTime(&SystemTime);
215     Seed = &SystemTime.u.LowPart;
216 
217     return RtlAllocateAndInitializeSid(&NtAuthority,
218                                        4,
219                                        SECURITY_NT_NON_UNIQUE,
220                                        RtlUniform(Seed),
221                                        RtlUniform(Seed),
222                                        RtlUniform(Seed),
223                                        SECURITY_NULL_RID,
224                                        SECURITY_NULL_RID,
225                                        SECURITY_NULL_RID,
226                                        SECURITY_NULL_RID,
227                                        Sid);
228 }
229 
230 
231 static NTSTATUS
232 LsapCreateDatabaseObjects(VOID)
233 {
234     PLSAP_POLICY_AUDIT_EVENTS_DATA AuditEventsInfo = NULL;
235     POLICY_DEFAULT_QUOTA_INFO QuotaInfo;
236     POLICY_MODIFICATION_INFO ModificationInfo;
237     POLICY_AUDIT_FULL_QUERY_INFO AuditFullInfo = {FALSE, FALSE};
238     POLICY_AUDIT_LOG_INFO AuditLogInfo;
239     GUID DnsDomainGuid;
240     PLSA_DB_OBJECT PolicyObject = NULL;
241     PSID AccountDomainSid = NULL;
242     PSECURITY_DESCRIPTOR PolicySd = NULL;
243     ULONG PolicySdSize = 0;
244     ULONG i;
245     NTSTATUS Status;
246 
247     /* Initialize the default quota limits */
248     QuotaInfo.QuotaLimits.PagedPoolLimit = 0x2000000;
249     QuotaInfo.QuotaLimits.NonPagedPoolLimit = 0x100000;
250     QuotaInfo.QuotaLimits.MinimumWorkingSetSize = 0x10000;
251     QuotaInfo.QuotaLimits.MaximumWorkingSetSize = 0xF000000;
252     QuotaInfo.QuotaLimits.PagefileLimit = 0;
253     QuotaInfo.QuotaLimits.TimeLimit.QuadPart = 0;
254 
255     /* Initialize the audit log attribute */
256     AuditLogInfo.AuditLogPercentFull = 0;
257     AuditLogInfo.MaximumLogSize = 0;			// DWORD
258     AuditLogInfo.AuditRetentionPeriod.QuadPart = 0;	// LARGE_INTEGER
259     AuditLogInfo.AuditLogFullShutdownInProgress = 0;	// BYTE
260     AuditLogInfo.TimeToShutdown.QuadPart = 0;		// LARGE_INTEGER
261     AuditLogInfo.NextAuditRecordId = 0;			// DWORD
262 
263     /* Initialize the Audit Events attribute */
264     AuditEventsInfo = RtlAllocateHeap(RtlGetProcessHeap(),
265                                       HEAP_ZERO_MEMORY,
266                                       sizeof(LSAP_POLICY_AUDIT_EVENTS_DATA));
267     if (AuditEventsInfo == NULL)
268         return STATUS_INSUFFICIENT_RESOURCES;
269 
270     AuditEventsInfo->AuditingMode = FALSE;
271     AuditEventsInfo->MaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
272     for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++)
273         AuditEventsInfo->AuditEvents[i] = 0;
274 
275     /* Initialize the DNS Domain GUID attribute */
276     memset(&DnsDomainGuid, 0, sizeof(GUID));
277 
278     /* Initialize the modification attribute */
279     ModificationInfo.ModifiedId.QuadPart = 0;
280     NtQuerySystemTime(&ModificationInfo.DatabaseCreationTime);
281 
282     /* Create a random domain SID */
283     Status = LsapCreateRandomDomainSid(&AccountDomainSid);
284     if (!NT_SUCCESS(Status))
285         goto done;
286 
287     Status = LsapCreatePolicySd(&PolicySd, &PolicySdSize);
288     if (!NT_SUCCESS(Status))
289         goto done;
290 
291     /* Open the 'Policy' object */
292     Status = LsapOpenDbObject(NULL,
293                               NULL,
294                               L"Policy",
295                               LsaDbPolicyObject,
296                               0,
297                               TRUE,
298                               &PolicyObject);
299     if (!NT_SUCCESS(Status))
300         goto done;
301 
302     LsapSetObjectAttribute(PolicyObject,
303                            L"PolPrDmN",
304                            NULL,
305                            0);
306 
307     LsapSetObjectAttribute(PolicyObject,
308                            L"PolPrDmS",
309                            NULL,
310                            0);
311 
312     LsapSetObjectAttribute(PolicyObject,
313                            L"PolAcDmN",
314                            NULL,
315                            0);
316 
317     LsapSetObjectAttribute(PolicyObject,
318                            L"PolAcDmS",
319                            AccountDomainSid,
320                            RtlLengthSid(AccountDomainSid));
321 
322     /* Set the default quota limits attribute */
323     LsapSetObjectAttribute(PolicyObject,
324                            L"DefQuota",
325                            &QuotaInfo,
326                            sizeof(POLICY_DEFAULT_QUOTA_INFO));
327 
328     /* Set the modification attribute */
329     LsapSetObjectAttribute(PolicyObject,
330                            L"PolMod",
331                            &ModificationInfo,
332                            sizeof(POLICY_MODIFICATION_INFO));
333 
334     /* Set the audit full attribute */
335     LsapSetObjectAttribute(PolicyObject,
336                            L"PolAdtFl",
337                            &AuditFullInfo,
338                            sizeof(POLICY_AUDIT_FULL_QUERY_INFO));
339 
340     /* Set the audit log attribute */
341     LsapSetObjectAttribute(PolicyObject,
342                            L"PolAdtLg",
343                            &AuditLogInfo,
344                            sizeof(POLICY_AUDIT_LOG_INFO));
345 
346     /* Set the audit events attribute */
347     LsapSetObjectAttribute(PolicyObject,
348                            L"PolAdtEv",
349                            AuditEventsInfo,
350                            sizeof(LSAP_POLICY_AUDIT_EVENTS_DATA));
351 
352     /* Set the DNS Domain Name attribute */
353     LsapSetObjectAttribute(PolicyObject,
354                            L"PolDnDDN",
355                            NULL,
356                            0);
357 
358     /* Set the DNS Forest Name attribute */
359     LsapSetObjectAttribute(PolicyObject,
360                            L"PolDnTrN",
361                            NULL,
362                            0);
363 
364     /* Set the DNS Domain GUID attribute */
365     LsapSetObjectAttribute(PolicyObject,
366                            L"PolDnDmG",
367                            &DnsDomainGuid,
368                            sizeof(GUID));
369 
370     /* Set the Sceurity Descriptor */
371     LsapSetObjectAttribute(PolicyObject,
372                            L"SecDesc",
373                            PolicySd,
374                            PolicySdSize);
375 
376 done:
377     if (AuditEventsInfo != NULL)
378         RtlFreeHeap(RtlGetProcessHeap(), 0, AuditEventsInfo);
379 
380     if (PolicyObject != NULL)
381         LsapCloseDbObject(PolicyObject);
382 
383     if (AccountDomainSid != NULL)
384         RtlFreeSid(AccountDomainSid);
385 
386     if (PolicySd != NULL)
387         RtlFreeHeap(RtlGetProcessHeap(), 0, PolicySd);
388 
389     return Status;
390 }
391 
392 
393 static NTSTATUS
394 LsapUpdateDatabase(VOID)
395 {
396     return STATUS_SUCCESS;
397 }
398 
399 
400 static NTSTATUS
401 LsapGetDomainInfo(VOID)
402 {
403     PLSA_DB_OBJECT PolicyObject = NULL;
404     PUNICODE_STRING DomainName = NULL;
405     ULONG AttributeSize;
406     LPWSTR SidString = NULL;
407     NTSTATUS Status;
408 
409     /* Get the built-in domain SID and name */
410     Status = RtlAllocateAndInitializeSid(&NtAuthority,
411                                          1,
412                                          SECURITY_BUILTIN_DOMAIN_RID,
413                                          0, 0, 0, 0, 0, 0, 0,
414                                          &BuiltinDomainSid);
415     if (!NT_SUCCESS(Status))
416         return Status;
417 
418     /**/
419     RtlInitUnicodeString(&BuiltinDomainName,
420                          L"BUILTIN");
421 
422     /* Open the 'Policy' object */
423     Status = LsapOpenDbObject(NULL,
424                               NULL,
425                               L"Policy",
426                               LsaDbPolicyObject,
427                               0,
428                               TRUE,
429                               &PolicyObject);
430     if (!NT_SUCCESS(Status))
431         goto done;
432 
433     /* Get the account domain SID */
434     AttributeSize = 0;
435     Status = LsapGetObjectAttribute(PolicyObject,
436                                     L"PolAcDmS",
437                                     NULL,
438                                     &AttributeSize);
439     if (!NT_SUCCESS(Status))
440         goto done;
441 
442     if (AttributeSize > 0)
443     {
444         AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(),
445                                            HEAP_ZERO_MEMORY,
446                                            AttributeSize);
447         if (AccountDomainSid == NULL)
448         {
449             Status = STATUS_INSUFFICIENT_RESOURCES;
450             goto done;
451         }
452 
453         Status = LsapGetObjectAttribute(PolicyObject,
454                                         L"PolAcDmS",
455                                         AccountDomainSid,
456                                         &AttributeSize);
457         if (!NT_SUCCESS(Status))
458             goto done;
459     }
460 
461     /* Get the account domain name */
462     AttributeSize = 0;
463     Status = LsapGetObjectAttribute(PolicyObject,
464                                     L"PolAcDmN",
465                                     NULL,
466                                     &AttributeSize);
467     if (!NT_SUCCESS(Status))
468         goto done;
469 
470     if (AttributeSize > 0)
471     {
472         DomainName = RtlAllocateHeap(RtlGetProcessHeap(),
473                                      HEAP_ZERO_MEMORY,
474                                      AttributeSize);
475         if (DomainName == NULL)
476         {
477             Status = STATUS_INSUFFICIENT_RESOURCES;
478             goto done;
479         }
480 
481         Status = LsapGetObjectAttribute(PolicyObject,
482                                         L"PolAcDmN",
483                                         DomainName,
484                                         &AttributeSize);
485         if (!NT_SUCCESS(Status))
486             goto done;
487 
488         DomainName->Buffer = (LPWSTR)((ULONG_PTR)DomainName + (ULONG_PTR)DomainName->Buffer);
489 
490         AccountDomainName.Length = DomainName->Length;
491         AccountDomainName.MaximumLength = DomainName->Length + sizeof(WCHAR);
492         AccountDomainName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
493                                                    HEAP_ZERO_MEMORY,
494                                                    AccountDomainName.MaximumLength);
495         if (AccountDomainName.Buffer == NULL)
496         {
497             ERR("Failed to allocate the account domain name buffer\n");
498             Status = STATUS_INSUFFICIENT_RESOURCES;
499             goto done;
500         }
501 
502         RtlCopyMemory(AccountDomainName.Buffer,
503                       DomainName->Buffer,
504                       DomainName->Length);
505     }
506 
507     ConvertSidToStringSidW(BuiltinDomainSid, &SidString);
508     TRACE("Builtin Domain SID: %S\n", SidString);
509     LocalFree(SidString);
510     SidString = NULL;
511 
512     TRACE("Builtin Domain Name: %wZ\n", &BuiltinDomainName);
513 
514     ConvertSidToStringSidW(AccountDomainSid, &SidString);
515     TRACE("Account Domain SID: %S\n", SidString);
516     LocalFree(SidString);
517     SidString = NULL;
518 
519     TRACE("Account Domain Name: %wZ\n", &AccountDomainName);
520 
521 done:
522     if (DomainName != NULL)
523         RtlFreeHeap(RtlGetProcessHeap(), 0, DomainName);
524 
525     if (PolicyObject != NULL)
526         LsapCloseDbObject(PolicyObject);
527 
528     return Status;
529 }
530 
531 
532 NTSTATUS
533 LsapInitDatabase(VOID)
534 {
535     NTSTATUS Status;
536 
537     TRACE("LsapInitDatabase()\n");
538 
539     Status = LsapOpenServiceKey();
540     if (!NT_SUCCESS(Status))
541     {
542         ERR("Failed to open the service key (Status: 0x%08lx)\n", Status);
543         return Status;
544     }
545 
546     if (!LsapIsDatabaseInstalled())
547     {
548         Status = LsapCreateDatabaseKeys();
549         if (!NT_SUCCESS(Status))
550         {
551             ERR("Failed to create the LSA database keys (Status: 0x%08lx)\n", Status);
552             return Status;
553         }
554 
555         Status = LsapCreateDatabaseObjects();
556         if (!NT_SUCCESS(Status))
557         {
558             ERR("Failed to create the LSA database objects (Status: 0x%08lx)\n", Status);
559             return Status;
560         }
561     }
562     else
563     {
564         Status = LsapUpdateDatabase();
565         if (!NT_SUCCESS(Status))
566         {
567             ERR("Failed to update the LSA database (Status: 0x%08lx)\n", Status);
568             return Status;
569         }
570     }
571 
572     Status = LsapGetDomainInfo();
573     if (!NT_SUCCESS(Status))
574     {
575         ERR("Failed to get the domain information (Status: 0x%08lx)\n", Status);
576         return Status;
577     }
578 
579     TRACE("LsapInitDatabase() done\n");
580 
581     return STATUS_SUCCESS;
582 }
583 
584 
585 NTSTATUS
586 LsapCreateDbObject(IN PLSA_DB_OBJECT ParentObject,
587                    IN LPWSTR ContainerName,
588                    IN LPWSTR ObjectName,
589                    IN LSA_DB_OBJECT_TYPE ObjectType,
590                    IN ACCESS_MASK DesiredAccess,
591                    IN BOOLEAN Trusted,
592                    OUT PLSA_DB_OBJECT *DbObject)
593 {
594     PLSA_DB_OBJECT NewObject;
595     OBJECT_ATTRIBUTES ObjectAttributes;
596     UNICODE_STRING KeyName;
597     HANDLE ParentKeyHandle;
598     HANDLE ContainerKeyHandle = NULL;
599     HANDLE ObjectKeyHandle = NULL;
600     NTSTATUS Status;
601 
602     if (DbObject == NULL)
603         return STATUS_INVALID_PARAMETER;
604 
605     if (ParentObject == NULL)
606         ParentKeyHandle = SecurityKeyHandle;
607     else
608         ParentKeyHandle = ParentObject->KeyHandle;
609 
610     if (ContainerName != NULL)
611     {
612         /* Open the container key */
613         RtlInitUnicodeString(&KeyName,
614                              ContainerName);
615 
616         InitializeObjectAttributes(&ObjectAttributes,
617                                    &KeyName,
618                                    OBJ_CASE_INSENSITIVE,
619                                    ParentKeyHandle,
620                                    NULL);
621 
622         Status = NtOpenKey(&ContainerKeyHandle,
623                            KEY_ALL_ACCESS,
624                            &ObjectAttributes);
625         if (!NT_SUCCESS(Status))
626         {
627             return Status;
628         }
629 
630         /* Open the object key */
631         RtlInitUnicodeString(&KeyName,
632                              ObjectName);
633 
634         InitializeObjectAttributes(&ObjectAttributes,
635                                    &KeyName,
636                                    OBJ_CASE_INSENSITIVE,
637                                    ContainerKeyHandle,
638                                    NULL);
639 
640         Status = NtCreateKey(&ObjectKeyHandle,
641                              KEY_ALL_ACCESS,
642                              &ObjectAttributes,
643                              0,
644                              NULL,
645                              0,
646                              NULL);
647 
648         NtClose(ContainerKeyHandle);
649 
650         if (!NT_SUCCESS(Status))
651         {
652             return Status;
653         }
654     }
655     else
656     {
657         RtlInitUnicodeString(&KeyName,
658                              ObjectName);
659 
660         InitializeObjectAttributes(&ObjectAttributes,
661                                    &KeyName,
662                                    OBJ_CASE_INSENSITIVE,
663                                    ParentKeyHandle,
664                                    NULL);
665 
666         Status = NtCreateKey(&ObjectKeyHandle,
667                              KEY_ALL_ACCESS,
668                              &ObjectAttributes,
669                              0,
670                              NULL,
671                              0,
672                              NULL);
673         if (!NT_SUCCESS(Status))
674         {
675             return Status;
676         }
677     }
678 
679     NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
680                                 0,
681                                 sizeof(LSA_DB_OBJECT));
682     if (NewObject == NULL)
683     {
684         NtClose(ObjectKeyHandle);
685         return STATUS_NO_MEMORY;
686     }
687 
688     NewObject->Signature = LSAP_DB_SIGNATURE;
689     NewObject->RefCount = 1;
690     NewObject->ObjectType = ObjectType;
691     NewObject->Access = DesiredAccess;
692     NewObject->KeyHandle = ObjectKeyHandle;
693     NewObject->ParentObject = ParentObject;
694     NewObject->Trusted = Trusted;
695 
696     if (ParentObject != NULL)
697         ParentObject->RefCount++;
698 
699     *DbObject = NewObject;
700 
701     return STATUS_SUCCESS;
702 }
703 
704 
705 NTSTATUS
706 LsapOpenDbObject(IN PLSA_DB_OBJECT ParentObject,
707                  IN LPWSTR ContainerName,
708                  IN LPWSTR ObjectName,
709                  IN LSA_DB_OBJECT_TYPE ObjectType,
710                  IN ACCESS_MASK DesiredAccess,
711                  IN BOOLEAN Trusted,
712                  OUT PLSA_DB_OBJECT *DbObject)
713 {
714     PLSA_DB_OBJECT NewObject;
715     OBJECT_ATTRIBUTES ObjectAttributes;
716     UNICODE_STRING KeyName;
717     HANDLE ParentKeyHandle;
718     HANDLE ContainerKeyHandle = NULL;
719     HANDLE ObjectKeyHandle = NULL;
720     NTSTATUS Status;
721 
722     if (DbObject == NULL)
723         return STATUS_INVALID_PARAMETER;
724 
725     if (ParentObject == NULL)
726         ParentKeyHandle = SecurityKeyHandle;
727     else
728         ParentKeyHandle = ParentObject->KeyHandle;
729 
730     if (ContainerName != NULL)
731     {
732         /* Open the container key */
733         RtlInitUnicodeString(&KeyName,
734                              ContainerName);
735 
736         InitializeObjectAttributes(&ObjectAttributes,
737                                    &KeyName,
738                                    OBJ_CASE_INSENSITIVE,
739                                    ParentKeyHandle,
740                                    NULL);
741 
742         Status = NtOpenKey(&ContainerKeyHandle,
743                            KEY_ALL_ACCESS,
744                            &ObjectAttributes);
745         if (!NT_SUCCESS(Status))
746         {
747             return Status;
748         }
749 
750         /* Open the object key */
751         RtlInitUnicodeString(&KeyName,
752                              ObjectName);
753 
754         InitializeObjectAttributes(&ObjectAttributes,
755                                    &KeyName,
756                                    OBJ_CASE_INSENSITIVE,
757                                    ContainerKeyHandle,
758                                    NULL);
759 
760         Status = NtOpenKey(&ObjectKeyHandle,
761                            KEY_ALL_ACCESS,
762                            &ObjectAttributes);
763 
764         NtClose(ContainerKeyHandle);
765 
766         if (!NT_SUCCESS(Status))
767         {
768             return Status;
769         }
770     }
771     else
772     {
773         /* Open the object key */
774         RtlInitUnicodeString(&KeyName,
775                              ObjectName);
776 
777         InitializeObjectAttributes(&ObjectAttributes,
778                                    &KeyName,
779                                    OBJ_CASE_INSENSITIVE,
780                                    ParentKeyHandle,
781                                    NULL);
782 
783         Status = NtOpenKey(&ObjectKeyHandle,
784                            KEY_ALL_ACCESS,
785                            &ObjectAttributes);
786         if (!NT_SUCCESS(Status))
787         {
788             return Status;
789         }
790     }
791 
792     NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
793                                 0,
794                                 sizeof(LSA_DB_OBJECT));
795     if (NewObject == NULL)
796     {
797         NtClose(ObjectKeyHandle);
798         return STATUS_NO_MEMORY;
799     }
800 
801     NewObject->Signature = LSAP_DB_SIGNATURE;
802     NewObject->RefCount = 1;
803     NewObject->ObjectType = ObjectType;
804     NewObject->Access = DesiredAccess;
805     NewObject->KeyHandle = ObjectKeyHandle;
806     NewObject->ParentObject = ParentObject;
807     NewObject->Trusted = Trusted;
808 
809     if (ParentObject != NULL)
810         ParentObject->RefCount++;
811 
812     *DbObject = NewObject;
813 
814     return STATUS_SUCCESS;
815 }
816 
817 
818 NTSTATUS
819 LsapValidateDbObject(LSAPR_HANDLE Handle,
820                      LSA_DB_OBJECT_TYPE ObjectType,
821                      ACCESS_MASK DesiredAccess,
822                      PLSA_DB_OBJECT *DbObject)
823 {
824     PLSA_DB_OBJECT LocalObject = (PLSA_DB_OBJECT)Handle;
825     BOOLEAN bValid = FALSE;
826 
827     _SEH2_TRY
828     {
829         if (LocalObject->Signature == LSAP_DB_SIGNATURE)
830         {
831             if ((ObjectType == LsaDbIgnoreObject) ||
832                 (LocalObject->ObjectType == ObjectType))
833                 bValid = TRUE;
834         }
835     }
836     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
837     {
838         bValid = FALSE;
839     }
840     _SEH2_END;
841 
842     if (bValid == FALSE)
843         return STATUS_INVALID_HANDLE;
844 
845     if (DesiredAccess != 0)
846     {
847         /* Check for granted access rights */
848         if ((LocalObject->Access & DesiredAccess) != DesiredAccess)
849         {
850             ERR("LsapValidateDbObject access check failed %08lx  %08lx\n",
851                 LocalObject->Access, DesiredAccess);
852             return STATUS_ACCESS_DENIED;
853         }
854     }
855 
856     if (DbObject != NULL)
857         *DbObject = LocalObject;
858 
859     return STATUS_SUCCESS;
860 }
861 
862 
863 NTSTATUS
864 LsapCloseDbObject(PLSA_DB_OBJECT DbObject)
865 {
866     PLSA_DB_OBJECT ParentObject = NULL;
867     NTSTATUS Status = STATUS_SUCCESS;
868 
869     DbObject->RefCount--;
870 
871     if (DbObject->RefCount > 0)
872         return STATUS_SUCCESS;
873 
874     if (DbObject->KeyHandle != NULL)
875         NtClose(DbObject->KeyHandle);
876 
877     if (DbObject->ParentObject != NULL)
878         ParentObject = DbObject->ParentObject;
879 
880     RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
881 
882     if (ParentObject != NULL)
883     {
884         ParentObject->RefCount--;
885 
886         if (ParentObject->RefCount == 0)
887             Status = LsapCloseDbObject(ParentObject);
888     }
889 
890     return Status;
891 }
892 
893 
894 NTSTATUS
895 LsapDeleteDbObject(IN PLSA_DB_OBJECT DbObject)
896 {
897     PLSA_DB_OBJECT ParentObject = NULL;
898     WCHAR KeyName[64];
899     ULONG Index;
900     NTSTATUS Status = STATUS_SUCCESS;
901 
902     DbObject->RefCount--;
903 
904     if (DbObject->RefCount > 0)
905         return STATUS_SUCCESS;
906 
907     if (DbObject->KeyHandle != NULL)
908     {
909         Index = 0;
910 
911         while (TRUE)
912         {
913             Status = LsapRegEnumerateSubKey(DbObject->KeyHandle,
914                                             Index,
915                                             64 * sizeof(WCHAR),
916                                             KeyName);
917             if (!NT_SUCCESS(Status))
918                 break;
919 
920             TRACE("Index: %lu\n", Index);
921             TRACE("Key name: %S\n", KeyName);
922 
923             Status = LsapRegDeleteSubKey(DbObject->KeyHandle,
924                                          KeyName);
925             if (!NT_SUCCESS(Status))
926                 break;
927         }
928 
929         if (Status == STATUS_NO_MORE_ENTRIES)
930             Status = STATUS_SUCCESS;
931 
932         LsapRegDeleteKey(DbObject->KeyHandle);
933 
934         NtClose(DbObject->KeyHandle);
935     }
936 
937     if (DbObject->ParentObject != NULL)
938         ParentObject = DbObject->ParentObject;
939 
940     RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
941 
942     if (ParentObject != NULL)
943     {
944         ParentObject->RefCount--;
945 
946         if (ParentObject->RefCount == 0)
947             Status = LsapCloseDbObject(ParentObject);
948     }
949 
950     return Status;
951 }
952 
953 
954 NTSTATUS
955 LsapSetObjectAttribute(PLSA_DB_OBJECT DbObject,
956                        LPWSTR AttributeName,
957                        LPVOID AttributeData,
958                        ULONG AttributeSize)
959 {
960     OBJECT_ATTRIBUTES ObjectAttributes;
961     UNICODE_STRING KeyName;
962     HANDLE AttributeKey;
963     NTSTATUS Status;
964 
965     RtlInitUnicodeString(&KeyName,
966                          AttributeName);
967 
968     InitializeObjectAttributes(&ObjectAttributes,
969                                &KeyName,
970                                OBJ_CASE_INSENSITIVE,
971                                DbObject->KeyHandle,
972                                NULL);
973 
974     Status = NtCreateKey(&AttributeKey,
975                          KEY_SET_VALUE,
976                          &ObjectAttributes,
977                          0,
978                          NULL,
979                          REG_OPTION_NON_VOLATILE,
980                          NULL);
981     if (!NT_SUCCESS(Status))
982     {
983         ERR("NtCreateKey failed for '%S' with status 0x%lx\n",
984             AttributeName, Status);
985         return Status;
986     }
987 
988     Status = RtlpNtSetValueKey(AttributeKey,
989                                REG_NONE,
990                                AttributeData,
991                                AttributeSize);
992 
993     NtClose(AttributeKey);
994 
995     if (!NT_SUCCESS(Status))
996     {
997         ERR("RtlpNtSetValueKey failed for '%S' with status 0x%lx\n",
998             AttributeName, Status);
999     }
1000 
1001     return Status;
1002 }
1003 
1004 
1005 NTSTATUS
1006 LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject,
1007                        LPWSTR AttributeName,
1008                        LPVOID AttributeData,
1009                        PULONG AttributeSize)
1010 {
1011     OBJECT_ATTRIBUTES ObjectAttributes;
1012     UNICODE_STRING KeyName;
1013     HANDLE AttributeKey;
1014     ULONG ValueSize;
1015     NTSTATUS Status;
1016 
1017     RtlInitUnicodeString(&KeyName,
1018                          AttributeName);
1019 
1020     InitializeObjectAttributes(&ObjectAttributes,
1021                                &KeyName,
1022                                OBJ_CASE_INSENSITIVE,
1023                                DbObject->KeyHandle,
1024                                NULL);
1025 
1026     Status = NtOpenKey(&AttributeKey,
1027                        KEY_QUERY_VALUE,
1028                        &ObjectAttributes);
1029     if (!NT_SUCCESS(Status))
1030     {
1031         return Status;
1032     }
1033 
1034     ValueSize = *AttributeSize;
1035     Status = RtlpNtQueryValueKey(AttributeKey,
1036                                  NULL,
1037                                  NULL,
1038                                  &ValueSize,
1039                                  0);
1040     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
1041     {
1042         goto Done;
1043     }
1044 
1045     if (AttributeData == NULL || *AttributeSize == 0)
1046     {
1047         *AttributeSize = ValueSize;
1048         Status = STATUS_SUCCESS;
1049         goto Done;
1050     }
1051     else if (*AttributeSize < ValueSize)
1052     {
1053         *AttributeSize = ValueSize;
1054         Status = STATUS_BUFFER_OVERFLOW;
1055         goto Done;
1056     }
1057 
1058     Status = RtlpNtQueryValueKey(AttributeKey,
1059                                  NULL,
1060                                  AttributeData,
1061                                  &ValueSize,
1062                                  0);
1063     if (NT_SUCCESS(Status))
1064     {
1065         *AttributeSize = ValueSize;
1066     }
1067 
1068 Done:
1069     NtClose(AttributeKey);
1070 
1071     return Status;
1072 }
1073 
1074 
1075 NTSTATUS
1076 LsapDeleteObjectAttribute(PLSA_DB_OBJECT DbObject,
1077                           LPWSTR AttributeName)
1078 {
1079     return LsapRegDeleteSubKey(DbObject->KeyHandle,
1080                                AttributeName);
1081 }
1082 
1083 /* EOF */
1084 
1085