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