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