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