[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 L"Policy",
287 LsaDbPolicyObject,
288 0,
289 &PolicyObject);
290 if (!NT_SUCCESS(Status))
291 goto done;
292
293 LsapSetObjectAttribute(PolicyObject,
294 L"PolPrDmN",
295 NULL,
296 0);
297
298 LsapSetObjectAttribute(PolicyObject,
299 L"PolPrDmS",
300 NULL,
301 0);
302
303 LsapSetObjectAttribute(PolicyObject,
304 L"PolAcDmN",
305 NULL,
306 0);
307
308 LsapSetObjectAttribute(PolicyObject,
309 L"PolAcDmS",
310 AccountDomainSid,
311 RtlLengthSid(AccountDomainSid));
312
313 /* Set the default quota limits attribute */
314 LsapSetObjectAttribute(PolicyObject,
315 L"DefQuota",
316 &QuotaInfo,
317 sizeof(POLICY_DEFAULT_QUOTA_INFO));
318
319 /* Set the modification attribute */
320 LsapSetObjectAttribute(PolicyObject,
321 L"PolMod",
322 &ModificationInfo,
323 sizeof(POLICY_MODIFICATION_INFO));
324
325 /* Set the audit full attribute */
326 LsapSetObjectAttribute(PolicyObject,
327 L"PolAdtFl",
328 &AuditFullInfo,
329 sizeof(POLICY_AUDIT_FULL_QUERY_INFO));
330
331 /* Set the audit log attribute */
332 LsapSetObjectAttribute(PolicyObject,
333 L"PolAdtLg",
334 &AuditLogInfo,
335 sizeof(POLICY_AUDIT_LOG_INFO));
336
337 /* Set the audit events attribute */
338 LsapSetObjectAttribute(PolicyObject,
339 L"PolAdtEv",
340 &AuditEventsInfo,
341 AuditEventsSize);
342
343 /* Set the DNS Domain Name attribute */
344 LsapSetObjectAttribute(PolicyObject,
345 L"PolDnDDN",
346 NULL,
347 0);
348
349 /* Set the DNS Forest Name attribute */
350 LsapSetObjectAttribute(PolicyObject,
351 L"PolDnTrN",
352 NULL,
353 0);
354
355 /* Set the DNS Domain GUID attribute */
356 LsapSetObjectAttribute(PolicyObject,
357 L"PolDnDmG",
358 &DnsDomainGuid,
359 sizeof(GUID));
360
361 done:
362 if (AuditEventsInfo != NULL)
363 RtlFreeHeap(RtlGetProcessHeap(), 0, AuditEventsInfo);
364
365 if (PolicyObject != NULL)
366 LsapCloseDbObject(PolicyObject);
367
368 if (AccountDomainSid != NULL)
369 RtlFreeSid(AccountDomainSid);
370
371 return Status;
372 }
373
374
375 static NTSTATUS
376 LsapUpdateDatabase(VOID)
377 {
378 return STATUS_SUCCESS;
379 }
380
381
382 NTSTATUS
383 LsapInitDatabase(VOID)
384 {
385 NTSTATUS Status;
386
387 TRACE("LsapInitDatabase()\n");
388
389 Status = LsapOpenServiceKey();
390 if (!NT_SUCCESS(Status))
391 {
392 ERR("Failed to open the service key (Status: 0x%08lx)\n", Status);
393 return Status;
394 }
395
396 if (!LsapIsDatabaseInstalled())
397 {
398 Status = LsapCreateDatabaseKeys();
399 if (!NT_SUCCESS(Status))
400 {
401 ERR("Failed to create the LSA database keys (Status: 0x%08lx)\n", Status);
402 return Status;
403 }
404
405 Status = LsapCreateDatabaseObjects();
406 if (!NT_SUCCESS(Status))
407 {
408 ERR("Failed to create the LSA database objects (Status: 0x%08lx)\n", Status);
409 return Status;
410 }
411 }
412 else
413 {
414 Status = LsapUpdateDatabase();
415 if (!NT_SUCCESS(Status))
416 {
417 ERR("Failed to update the LSA database (Status: 0x%08lx)\n", Status);
418 return Status;
419 }
420 }
421
422 TRACE("LsapInitDatabase() done\n");
423
424 return STATUS_SUCCESS;
425 }
426
427
428 NTSTATUS
429 LsapCreateDbObject(IN PLSA_DB_OBJECT ParentObject,
430 IN LPWSTR ObjectName,
431 IN LSA_DB_OBJECT_TYPE ObjectType,
432 IN ACCESS_MASK DesiredAccess,
433 OUT PLSA_DB_OBJECT *DbObject)
434 {
435 PLSA_DB_OBJECT NewObject;
436 OBJECT_ATTRIBUTES ObjectAttributes;
437 UNICODE_STRING KeyName;
438 HANDLE ParentKeyHandle;
439 HANDLE ObjectKeyHandle;
440 NTSTATUS Status;
441
442 if (DbObject == NULL)
443 return STATUS_INVALID_PARAMETER;
444
445 if (ParentObject == NULL)
446 ParentKeyHandle = SecurityKeyHandle;
447 else
448 ParentKeyHandle = ParentObject->KeyHandle;
449
450 RtlInitUnicodeString(&KeyName,
451 ObjectName);
452
453 InitializeObjectAttributes(&ObjectAttributes,
454 &KeyName,
455 OBJ_CASE_INSENSITIVE,
456 ParentKeyHandle,
457 NULL);
458
459 Status = NtCreateKey(&ObjectKeyHandle,
460 KEY_ALL_ACCESS,
461 &ObjectAttributes,
462 0,
463 NULL,
464 0,
465 NULL);
466 if (!NT_SUCCESS(Status))
467 {
468 return Status;
469 }
470
471 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
472 0,
473 sizeof(LSA_DB_OBJECT));
474 if (NewObject == NULL)
475 {
476 NtClose(ObjectKeyHandle);
477 return STATUS_NO_MEMORY;
478 }
479
480 NewObject->Signature = LSAP_DB_SIGNATURE;
481 NewObject->RefCount = 1;
482 NewObject->ObjectType = ObjectType;
483 NewObject->Access = DesiredAccess;
484 NewObject->KeyHandle = ObjectKeyHandle;
485 NewObject->ParentObject = ParentObject;
486
487 if (ParentObject != NULL)
488 ParentObject->RefCount++;
489
490 *DbObject = NewObject;
491
492 return STATUS_SUCCESS;
493 }
494
495
496 NTSTATUS
497 LsapOpenDbObject(IN PLSA_DB_OBJECT ParentObject,
498 IN LPWSTR ObjectName,
499 IN LSA_DB_OBJECT_TYPE ObjectType,
500 IN ACCESS_MASK DesiredAccess,
501 OUT PLSA_DB_OBJECT *DbObject)
502 {
503 PLSA_DB_OBJECT NewObject;
504 OBJECT_ATTRIBUTES ObjectAttributes;
505 UNICODE_STRING KeyName;
506 HANDLE ParentKeyHandle;
507 HANDLE ObjectKeyHandle;
508 NTSTATUS Status;
509
510 if (DbObject == NULL)
511 return STATUS_INVALID_PARAMETER;
512
513 if (ParentObject == NULL)
514 ParentKeyHandle = SecurityKeyHandle;
515 else
516 ParentKeyHandle = ParentObject->KeyHandle;
517
518 RtlInitUnicodeString(&KeyName,
519 ObjectName);
520
521 InitializeObjectAttributes(&ObjectAttributes,
522 &KeyName,
523 OBJ_CASE_INSENSITIVE,
524 ParentKeyHandle,
525 NULL);
526
527 Status = NtOpenKey(&ObjectKeyHandle,
528 KEY_ALL_ACCESS,
529 &ObjectAttributes);
530 if (!NT_SUCCESS(Status))
531 {
532 return Status;
533 }
534
535 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
536 0,
537 sizeof(LSA_DB_OBJECT));
538 if (NewObject == NULL)
539 {
540 NtClose(ObjectKeyHandle);
541 return STATUS_NO_MEMORY;
542 }
543
544 NewObject->Signature = LSAP_DB_SIGNATURE;
545 NewObject->RefCount = 1;
546 NewObject->ObjectType = ObjectType;
547 NewObject->Access = DesiredAccess;
548 NewObject->KeyHandle = ObjectKeyHandle;
549 NewObject->ParentObject = ParentObject;
550
551 if (ParentObject != NULL)
552 ParentObject->RefCount++;
553
554 *DbObject = NewObject;
555
556 return STATUS_SUCCESS;
557 }
558
559
560 NTSTATUS
561 LsapValidateDbObject(LSAPR_HANDLE Handle,
562 LSA_DB_OBJECT_TYPE ObjectType,
563 ACCESS_MASK DesiredAccess,
564 PLSA_DB_OBJECT *DbObject)
565 {
566 PLSA_DB_OBJECT LocalObject = (PLSA_DB_OBJECT)Handle;
567 BOOLEAN bValid = FALSE;
568
569 _SEH2_TRY
570 {
571 if (LocalObject->Signature == LSAP_DB_SIGNATURE)
572 {
573 if ((ObjectType == LsaDbIgnoreObject) ||
574 (LocalObject->ObjectType == ObjectType))
575 bValid = TRUE;
576 }
577 }
578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
579 {
580 bValid = FALSE;
581 }
582 _SEH2_END;
583
584 if (bValid == FALSE)
585 return STATUS_INVALID_HANDLE;
586
587 if (DesiredAccess != 0)
588 {
589 /* Check for granted access rights */
590 if ((LocalObject->Access & DesiredAccess) != DesiredAccess)
591 {
592 ERR("LsapValidateDbObject access check failed %08lx %08lx\n",
593 LocalObject->Access, DesiredAccess);
594 return STATUS_ACCESS_DENIED;
595 }
596 }
597
598 if (DbObject != NULL)
599 *DbObject = LocalObject;
600
601 return STATUS_SUCCESS;
602 }
603
604
605 NTSTATUS
606 LsapCloseDbObject(PLSA_DB_OBJECT DbObject)
607 {
608 PLSA_DB_OBJECT ParentObject = NULL;
609 NTSTATUS Status = STATUS_SUCCESS;
610
611 DbObject->RefCount--;
612
613 if (DbObject->RefCount > 0)
614 return STATUS_SUCCESS;
615
616 if (DbObject->KeyHandle != NULL)
617 NtClose(DbObject->KeyHandle);
618
619 if (DbObject->ParentObject != NULL)
620 ParentObject = DbObject->ParentObject;
621
622 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
623
624 if (ParentObject != NULL)
625 {
626 ParentObject->RefCount--;
627
628 if (ParentObject->RefCount == 0)
629 Status = LsapCloseDbObject(ParentObject);
630 }
631
632 return Status;
633 }
634
635
636 NTSTATUS
637 LsapSetObjectAttribute(PLSA_DB_OBJECT DbObject,
638 LPWSTR AttributeName,
639 LPVOID AttributeData,
640 ULONG AttributeSize)
641 {
642 OBJECT_ATTRIBUTES ObjectAttributes;
643 UNICODE_STRING KeyName;
644 HANDLE AttributeKey;
645 NTSTATUS Status;
646
647 RtlInitUnicodeString(&KeyName,
648 AttributeName);
649
650 InitializeObjectAttributes(&ObjectAttributes,
651 &KeyName,
652 OBJ_CASE_INSENSITIVE,
653 DbObject->KeyHandle,
654 NULL);
655
656 Status = NtCreateKey(&AttributeKey,
657 KEY_SET_VALUE,
658 &ObjectAttributes,
659 0,
660 NULL,
661 REG_OPTION_NON_VOLATILE,
662 NULL);
663 if (!NT_SUCCESS(Status))
664 {
665
666 return Status;
667 }
668
669 Status = RtlpNtSetValueKey(AttributeKey,
670 REG_NONE,
671 AttributeData,
672 AttributeSize);
673
674 NtClose(AttributeKey);
675
676 return Status;
677 }
678
679
680 NTSTATUS
681 LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject,
682 LPWSTR AttributeName,
683 LPVOID AttributeData,
684 PULONG AttributeSize)
685 {
686 OBJECT_ATTRIBUTES ObjectAttributes;
687 UNICODE_STRING KeyName;
688 HANDLE AttributeKey;
689 ULONG ValueSize;
690 NTSTATUS Status;
691
692 RtlInitUnicodeString(&KeyName,
693 AttributeName);
694
695 InitializeObjectAttributes(&ObjectAttributes,
696 &KeyName,
697 OBJ_CASE_INSENSITIVE,
698 DbObject->KeyHandle,
699 NULL);
700
701 Status = NtOpenKey(&AttributeKey,
702 KEY_QUERY_VALUE,
703 &ObjectAttributes);
704 if (!NT_SUCCESS(Status))
705 {
706 return Status;
707 }
708
709 ValueSize = *AttributeSize;
710 Status = RtlpNtQueryValueKey(AttributeKey,
711 NULL,
712 NULL,
713 &ValueSize,
714 0);
715 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
716 {
717 goto Done;
718 }
719
720 if (AttributeData == NULL || *AttributeSize == 0)
721 {
722 *AttributeSize = ValueSize;
723 Status = STATUS_SUCCESS;
724 goto Done;
725 }
726 else if (*AttributeSize < ValueSize)
727 {
728 *AttributeSize = ValueSize;
729 Status = STATUS_BUFFER_OVERFLOW;
730 goto Done;
731 }
732
733 Status = RtlpNtQueryValueKey(AttributeKey,
734 NULL,
735 AttributeData,
736 &ValueSize,
737 0);
738 if (NT_SUCCESS(Status))
739 {
740 *AttributeSize = ValueSize;
741 }
742
743 Done:
744 NtClose(AttributeKey);
745
746 return Status;
747 }
748
749 /* EOF */
750