[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / database.c
1 /*
2 * PROJECT: Local Security Authority Server DLL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/samsrv/database.c
5 * PURPOSE: SAM object database
6 * COPYRIGHT: Copyright 2012 Eric Kohl
7 */
8
9 #include "samsrv.h"
10
11 /* GLOBALS *****************************************************************/
12
13 static HANDLE SamKeyHandle = NULL;
14
15
16 /* FUNCTIONS ***************************************************************/
17
18 NTSTATUS
19 SampInitDatabase(VOID)
20 {
21 NTSTATUS Status;
22
23 TRACE("SampInitDatabase()\n");
24
25 Status = SampRegOpenKey(NULL,
26 L"\\Registry\\Machine\\SAM",
27 KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
28 &SamKeyHandle);
29 if (!NT_SUCCESS(Status))
30 {
31 ERR("Failed to open the SAM key (Status: 0x%08lx)\n", Status);
32 return Status;
33 }
34
35 TRACE("SampInitDatabase() done\n");
36
37 return STATUS_SUCCESS;
38 }
39
40
41 NTSTATUS
42 SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject,
43 IN LPWSTR ContainerName,
44 IN LPWSTR ObjectName,
45 IN ULONG RelativeId,
46 IN SAM_DB_OBJECT_TYPE ObjectType,
47 IN ACCESS_MASK DesiredAccess,
48 OUT PSAM_DB_OBJECT *DbObject)
49 {
50 PSAM_DB_OBJECT NewObject = NULL;
51 HANDLE ParentKeyHandle;
52 HANDLE ContainerKeyHandle = NULL;
53 HANDLE ObjectKeyHandle = NULL;
54 HANDLE MembersKeyHandle = NULL;
55 NTSTATUS Status;
56
57 if (DbObject == NULL)
58 return STATUS_INVALID_PARAMETER;
59
60 *DbObject = NULL;
61
62 if (ParentObject == NULL)
63 ParentKeyHandle = SamKeyHandle;
64 else
65 ParentKeyHandle = ParentObject->KeyHandle;
66
67 if (ContainerName != NULL)
68 {
69 /* Open the container key */
70 Status = SampRegOpenKey(ParentKeyHandle,
71 ContainerName,
72 KEY_ALL_ACCESS,
73 &ContainerKeyHandle);
74 if (!NT_SUCCESS(Status))
75 {
76 goto done;
77 }
78
79 /* Create the object key */
80 Status = SampRegCreateKey(ContainerKeyHandle,
81 ObjectName,
82 KEY_ALL_ACCESS,
83 &ObjectKeyHandle);
84 if (!NT_SUCCESS(Status))
85 {
86 goto done;
87 }
88
89 if (ObjectType == SamDbAliasObject)
90 {
91 /* Create the object key */
92 Status = SampRegCreateKey(ContainerKeyHandle,
93 L"Members",
94 KEY_ALL_ACCESS,
95 &MembersKeyHandle);
96 if (!NT_SUCCESS(Status))
97 {
98 goto done;
99 }
100 }
101 }
102 else
103 {
104 /* Create the object key */
105 Status = SampRegCreateKey(ParentKeyHandle,
106 ObjectName,
107 KEY_ALL_ACCESS,
108 &ObjectKeyHandle);
109 if (!NT_SUCCESS(Status))
110 {
111 goto done;
112 }
113 }
114
115 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
116 HEAP_ZERO_MEMORY,
117 sizeof(SAM_DB_OBJECT));
118 if (NewObject == NULL)
119 {
120 Status = STATUS_INSUFFICIENT_RESOURCES;
121 goto done;
122 }
123
124 NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
125 0,
126 (wcslen(ObjectName) + 1) * sizeof(WCHAR));
127 if (NewObject->Name == NULL)
128 {
129 Status = STATUS_INSUFFICIENT_RESOURCES;
130 goto done;
131 }
132
133 wcscpy(NewObject->Name, ObjectName);
134
135 NewObject->Signature = SAMP_DB_SIGNATURE;
136 NewObject->RefCount = 1;
137 NewObject->ObjectType = ObjectType;
138 NewObject->Access = DesiredAccess;
139 NewObject->KeyHandle = ObjectKeyHandle;
140 NewObject->MembersKeyHandle = MembersKeyHandle;
141 NewObject->RelativeId = RelativeId;
142 NewObject->ParentObject = ParentObject;
143
144 if (ParentObject != NULL)
145 NewObject->Trusted = ParentObject->Trusted;
146
147 *DbObject = NewObject;
148
149 done:
150 if (!NT_SUCCESS(Status))
151 {
152 if (NewObject != NULL)
153 {
154 if (NewObject->Name != NULL)
155 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject->Name);
156
157 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject);
158 }
159
160 SampRegCloseKey(&MembersKeyHandle);
161 SampRegCloseKey(&ObjectKeyHandle);
162 }
163
164 SampRegCloseKey(&ContainerKeyHandle);
165
166 return Status;
167 }
168
169
170 NTSTATUS
171 SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject,
172 IN LPWSTR ContainerName,
173 IN LPWSTR ObjectName,
174 IN ULONG RelativeId,
175 IN SAM_DB_OBJECT_TYPE ObjectType,
176 IN ACCESS_MASK DesiredAccess,
177 OUT PSAM_DB_OBJECT *DbObject)
178 {
179 PSAM_DB_OBJECT NewObject = NULL;
180 HANDLE ParentKeyHandle;
181 HANDLE ContainerKeyHandle = NULL;
182 HANDLE ObjectKeyHandle = NULL;
183 HANDLE MembersKeyHandle = NULL;
184 NTSTATUS Status;
185
186 if (DbObject == NULL)
187 return STATUS_INVALID_PARAMETER;
188
189 *DbObject = NULL;
190
191 if (ParentObject == NULL)
192 ParentKeyHandle = SamKeyHandle;
193 else
194 ParentKeyHandle = ParentObject->KeyHandle;
195
196 if (ContainerName != NULL)
197 {
198 /* Open the container key */
199 Status = SampRegOpenKey(ParentKeyHandle,
200 ContainerName,
201 KEY_ALL_ACCESS,
202 &ContainerKeyHandle);
203 if (!NT_SUCCESS(Status))
204 {
205 goto done;
206 }
207
208 /* Open the object key */
209 Status = SampRegOpenKey(ContainerKeyHandle,
210 ObjectName,
211 KEY_ALL_ACCESS,
212 &ObjectKeyHandle);
213 if (!NT_SUCCESS(Status))
214 {
215 goto done;
216 }
217
218 if (ObjectType == SamDbAliasObject)
219 {
220 /* Open the object key */
221 Status = SampRegOpenKey(ContainerKeyHandle,
222 L"Members",
223 KEY_ALL_ACCESS,
224 &MembersKeyHandle);
225 if (!NT_SUCCESS(Status))
226 {
227 goto done;
228 }
229 }
230 }
231 else
232 {
233 /* Open the object key */
234 Status = SampRegOpenKey(ParentKeyHandle,
235 ObjectName,
236 KEY_ALL_ACCESS,
237 &ObjectKeyHandle);
238 if (!NT_SUCCESS(Status))
239 {
240 goto done;
241 }
242 }
243
244 NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
245 HEAP_ZERO_MEMORY,
246 sizeof(SAM_DB_OBJECT));
247 if (NewObject == NULL)
248 {
249 Status = STATUS_INSUFFICIENT_RESOURCES;
250 goto done;
251 }
252
253 NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
254 0,
255 (wcslen(ObjectName) + 1) * sizeof(WCHAR));
256 if (NewObject->Name == NULL)
257 {
258 Status = STATUS_INSUFFICIENT_RESOURCES;
259 goto done;
260 }
261
262 wcscpy(NewObject->Name, ObjectName);
263 NewObject->Signature = SAMP_DB_SIGNATURE;
264 NewObject->RefCount = 1;
265 NewObject->ObjectType = ObjectType;
266 NewObject->Access = DesiredAccess;
267 NewObject->KeyHandle = ObjectKeyHandle;
268 NewObject->MembersKeyHandle = MembersKeyHandle;
269 NewObject->RelativeId = RelativeId;
270 NewObject->ParentObject = ParentObject;
271
272 if (ParentObject != NULL)
273 NewObject->Trusted = ParentObject->Trusted;
274
275 *DbObject = NewObject;
276
277 done:
278 if (!NT_SUCCESS(Status))
279 {
280 if (NewObject != NULL)
281 {
282 if (NewObject->Name != NULL)
283 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject->Name);
284
285 RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject);
286 }
287
288 SampRegCloseKey(&MembersKeyHandle);
289 SampRegCloseKey(&ObjectKeyHandle);
290 }
291
292 SampRegCloseKey(&ContainerKeyHandle);
293
294 return Status;
295 }
296
297
298 NTSTATUS
299 SampValidateDbObject(SAMPR_HANDLE Handle,
300 SAM_DB_OBJECT_TYPE ObjectType,
301 ACCESS_MASK DesiredAccess,
302 PSAM_DB_OBJECT *DbObject)
303 {
304 PSAM_DB_OBJECT LocalObject = (PSAM_DB_OBJECT)Handle;
305 BOOLEAN bValid = FALSE;
306
307 _SEH2_TRY
308 {
309 if (LocalObject->Signature == SAMP_DB_SIGNATURE)
310 {
311 if ((ObjectType == SamDbIgnoreObject) ||
312 (LocalObject->ObjectType == ObjectType))
313 bValid = TRUE;
314 }
315 }
316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
317 {
318 bValid = FALSE;
319 }
320 _SEH2_END;
321
322 if (bValid == FALSE)
323 return STATUS_INVALID_HANDLE;
324
325 if (DesiredAccess != 0)
326 {
327 /* Check for granted access rights */
328 if ((LocalObject->Access & DesiredAccess) != DesiredAccess)
329 {
330 ERR("SampValidateDbObject access check failed %08lx %08lx\n",
331 LocalObject->Access, DesiredAccess);
332 return STATUS_ACCESS_DENIED;
333 }
334 }
335
336 if (DbObject != NULL)
337 *DbObject = LocalObject;
338
339 return STATUS_SUCCESS;
340 }
341
342
343 NTSTATUS
344 SampCloseDbObject(PSAM_DB_OBJECT DbObject)
345 {
346 NTSTATUS Status = STATUS_SUCCESS;
347
348 DbObject->RefCount--;
349
350 if (DbObject->RefCount > 0)
351 return STATUS_SUCCESS;
352
353 SampRegCloseKey(&DbObject->KeyHandle);
354 SampRegCloseKey(&DbObject->MembersKeyHandle);
355
356 if (DbObject->Name != NULL)
357 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name);
358
359 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
360
361 return Status;
362 }
363
364
365 NTSTATUS
366 SampDeleteAccountDbObject(PSAM_DB_OBJECT DbObject)
367 {
368 LPCWSTR ContainerName;
369 LPWSTR AccountName = NULL;
370 HANDLE ContainerKey = NULL;
371 HANDLE NamesKey = NULL;
372 ULONG Length = 0;
373 NTSTATUS Status = STATUS_SUCCESS;
374
375 TRACE("(%p)\n", DbObject);
376
377 /* Server and Domain objects cannot be deleted */
378 switch (DbObject->ObjectType)
379 {
380 case SamDbAliasObject:
381 ContainerName = L"Aliases";
382 break;
383
384 case SamDbGroupObject:
385 ContainerName = L"Groups";
386 break;
387
388 case SamDbUserObject:
389 ContainerName = L"Users";
390 break;
391
392 default:
393 return STATUS_INVALID_PARAMETER;
394 }
395
396 /* Get the account name */
397 Status = SampGetObjectAttribute(DbObject,
398 L"Name",
399 NULL,
400 NULL,
401 &Length);
402 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
403 {
404 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status);
405 goto done;
406 }
407
408 AccountName = RtlAllocateHeap(RtlGetProcessHeap(),
409 HEAP_ZERO_MEMORY,
410 Length);
411 if (AccountName == NULL)
412 {
413 Status = STATUS_INSUFFICIENT_RESOURCES;
414 goto done;
415 }
416
417 Status = SampGetObjectAttribute(DbObject,
418 L"Name",
419 NULL,
420 (PVOID)AccountName,
421 &Length);
422 if (!NT_SUCCESS(Status))
423 {
424 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status);
425 goto done;
426 }
427
428 SampRegCloseKey(&DbObject->KeyHandle);
429
430 if (DbObject->ObjectType == SamDbAliasObject)
431 {
432 SampRegCloseKey(&DbObject->MembersKeyHandle);
433
434 SampRegDeleteKey(DbObject->KeyHandle,
435 L"Members");
436 }
437
438 /* Open the domain container key */
439 Status = SampRegOpenKey(DbObject->ParentObject->KeyHandle,
440 ContainerName,
441 DELETE | KEY_SET_VALUE,
442 &ContainerKey);
443 if (!NT_SUCCESS(Status))
444 {
445 TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status);
446 goto done;
447 }
448
449 /* Open the Names key */
450 Status = SampRegOpenKey(ContainerKey,
451 L"Names",
452 KEY_SET_VALUE,
453 &NamesKey);
454 if (!NT_SUCCESS(Status))
455 {
456 TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status);
457 goto done;
458 }
459
460 /* Remove the account from the Names key */
461 Status = SampRegDeleteValue(NamesKey,
462 AccountName);
463 if (!NT_SUCCESS(Status))
464 {
465 TRACE("SampRegDeleteValue failed (Status 0x%08lx)\n", Status);
466 goto done;
467 }
468
469 /* Remove the account key from the container */
470 Status = SampRegDeleteKey(ContainerKey,
471 DbObject->Name);
472 if (!NT_SUCCESS(Status))
473 {
474 TRACE("SampRegDeleteKey failed (Status 0x%08lx)\n", Status);
475 goto done;
476 }
477
478 /* Release the database object name */
479 if (DbObject->Name != NULL)
480 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name);
481
482 /* Release the database object */
483 RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
484
485 Status = STATUS_SUCCESS;
486
487 done:
488 SampRegCloseKey(&NamesKey);
489 SampRegCloseKey(&ContainerKey);
490
491 if (AccountName != NULL)
492 RtlFreeHeap(RtlGetProcessHeap(), 0, AccountName);
493
494 return Status;
495 }
496
497
498 NTSTATUS
499 SampSetObjectAttribute(PSAM_DB_OBJECT DbObject,
500 LPWSTR AttributeName,
501 ULONG AttributeType,
502 LPVOID AttributeData,
503 ULONG AttributeSize)
504 {
505 return SampRegSetValue(DbObject->KeyHandle,
506 AttributeName,
507 AttributeType,
508 AttributeData,
509 AttributeSize);
510 }
511
512
513 NTSTATUS
514 SampGetObjectAttribute(PSAM_DB_OBJECT DbObject,
515 LPWSTR AttributeName,
516 PULONG AttributeType,
517 LPVOID AttributeData,
518 PULONG AttributeSize)
519 {
520 return SampRegQueryValue(DbObject->KeyHandle,
521 AttributeName,
522 AttributeType,
523 AttributeData,
524 AttributeSize);
525 }
526
527
528 NTSTATUS
529 SampGetObjectAttributeString(PSAM_DB_OBJECT DbObject,
530 LPWSTR AttributeName,
531 PRPC_UNICODE_STRING String)
532 {
533 ULONG Length = 0;
534 NTSTATUS Status;
535
536 Status = SampGetObjectAttribute(DbObject,
537 AttributeName,
538 NULL,
539 NULL,
540 &Length);
541 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
542 {
543 TRACE("Status 0x%08lx\n", Status);
544 goto done;
545 }
546
547 if (Length == 0)
548 {
549 String->Length = 0;
550 String->MaximumLength = 0;
551 String->Buffer = NULL;
552
553 Status = STATUS_SUCCESS;
554 goto done;
555 }
556
557 String->Length = (USHORT)(Length - sizeof(WCHAR));
558 String->MaximumLength = (USHORT)Length;
559 String->Buffer = midl_user_allocate(Length);
560 if (String->Buffer == NULL)
561 {
562 Status = STATUS_INSUFFICIENT_RESOURCES;
563 goto done;
564 }
565
566 TRACE("Length: %lu\n", Length);
567 Status = SampGetObjectAttribute(DbObject,
568 AttributeName,
569 NULL,
570 (PVOID)String->Buffer,
571 &Length);
572 if (!NT_SUCCESS(Status))
573 {
574 TRACE("Status 0x%08lx\n", Status);
575 goto done;
576 }
577
578 done:
579 if (!NT_SUCCESS(Status))
580 {
581 if (String->Buffer != NULL)
582 {
583 midl_user_free(String->Buffer);
584 String->Buffer = NULL;
585 }
586 }
587
588 return Status;
589 }
590
591
592 NTSTATUS
593 SampSetObjectAttributeString(PSAM_DB_OBJECT DbObject,
594 LPWSTR AttributeName,
595 PRPC_UNICODE_STRING String)
596 {
597 PWCHAR Buffer = NULL;
598 USHORT Length = 0;
599
600 if ((String != NULL) && (String->Buffer != NULL))
601 {
602 Buffer = String->Buffer;
603 Length = String->Length + sizeof(WCHAR);
604 }
605
606 return SampSetObjectAttribute(DbObject,
607 AttributeName,
608 REG_SZ,
609 Buffer,
610 Length);
611 }
612
613
614 /* EOF */
615