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