ReactOS  0.4.15-dev-3295-gaa8fc87
database.c
Go to the documentation of this file.
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 
16 
17 
18 /* FUNCTIONS ***************************************************************/
19 
22 {
24 
25  TRACE("SampInitDatabase()\n");
26 
28  L"\\Registry\\Machine\\SAM",
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 
45  IN LPWSTR ContainerName,
47  IN ULONG RelativeId,
50  OUT PSAM_DB_OBJECT *DbObject)
51 {
53  HANDLE ParentKeyHandle;
54  HANDLE ContainerKeyHandle = NULL;
55  HANDLE ObjectKeyHandle = NULL;
56  HANDLE MembersKeyHandle = NULL;
58 
59  if (DbObject == NULL)
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,
75  &ContainerKeyHandle);
76  if (!NT_SUCCESS(Status))
77  {
78  goto done;
79  }
80 
81  /* Create the object key */
82  Status = SampRegCreateKey(ContainerKeyHandle,
83  ObjectName,
85  &ObjectKeyHandle);
86  if (!NT_SUCCESS(Status))
87  {
88  goto done;
89  }
90 
92  {
93  /* Create the object key */
94  Status = SampRegCreateKey(ContainerKeyHandle,
95  L"Members",
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,
110  &ObjectKeyHandle);
111  if (!NT_SUCCESS(Status))
112  {
113  goto done;
114  }
115  }
116 
117  NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
119  sizeof(SAM_DB_OBJECT));
120  if (NewObject == NULL)
121  {
123  goto done;
124  }
125 
126  NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
127  0,
128  (wcslen(ObjectName) + 1) * sizeof(WCHAR));
129  if (NewObject->Name == NULL)
130  {
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
174  IN LPWSTR ContainerName,
176  IN ULONG RelativeId,
179  OUT PSAM_DB_OBJECT *DbObject)
180 {
182  HANDLE ParentKeyHandle;
183  HANDLE ContainerKeyHandle = NULL;
184  HANDLE ObjectKeyHandle = NULL;
185  HANDLE MembersKeyHandle = NULL;
187 
188  if (DbObject == NULL)
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,
204  &ContainerKeyHandle);
205  if (!NT_SUCCESS(Status))
206  {
207  goto done;
208  }
209 
210  /* Open the object key */
211  Status = SampRegOpenKey(ContainerKeyHandle,
212  ObjectName,
214  &ObjectKeyHandle);
215  if (!NT_SUCCESS(Status))
216  {
217  goto done;
218  }
219 
221  {
222  /* Open the object key */
223  Status = SampRegOpenKey(ContainerKeyHandle,
224  L"Members",
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,
239  &ObjectKeyHandle);
240  if (!NT_SUCCESS(Status))
241  {
242  goto done;
243  }
244  }
245 
246  NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
248  sizeof(SAM_DB_OBJECT));
249  if (NewObject == NULL)
250  {
252  goto done;
253  }
254 
255  NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
256  0,
257  (wcslen(ObjectName) + 1) * sizeof(WCHAR));
258  if (NewObject->Name == NULL)
259  {
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
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  }
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
347 {
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
369 {
370  LPCWSTR ContainerName;
371  LPWSTR AccountName = NULL;
372  HANDLE ContainerKey = NULL;
373  HANDLE NamesKey = NULL;
374  ULONG Length = 0;
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:
396  }
397 
398  /* Get the account name */
399  Status = SampGetObjectAttribute(DbObject,
400  L"Name",
401  NULL,
402  NULL,
403  &Length);
405  {
406  TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status);
407  goto done;
408  }
409 
410  AccountName = RtlAllocateHeap(RtlGetProcessHeap(),
412  Length);
413  if (AccountName == NULL)
414  {
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,
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",
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 
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
502  LPWSTR AttributeName,
503  ULONG AttributeType,
505  ULONG AttributeSize)
506 {
507  return SampRegSetValue(DbObject->KeyHandle,
508  AttributeName,
509  AttributeType,
511  AttributeSize);
512 }
513 
514 
515 NTSTATUS
517  LPWSTR AttributeName,
518  PULONG AttributeType,
520  PULONG AttributeSize)
521 {
522  return SampRegQueryValue(DbObject->KeyHandle,
523  AttributeName,
524  AttributeType,
526  AttributeSize);
527 }
528 
529 
530 NTSTATUS
532  LPWSTR AttributeName,
534 {
535  ULONG Length = 0;
537 
538  Status = SampGetObjectAttribute(DbObject,
539  AttributeName,
540  NULL,
541  NULL,
542  &Length);
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 
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  {
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
596  LPWSTR AttributeName,
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 
ULONG Signature
Definition: samsrv.h:47
ObjectType
Definition: metafile.c:80
enum _SAM_DB_OBJECT_TYPE SAM_DB_OBJECT_TYPE
#define IN
Definition: typedefs.h:39
#define midl_user_free
Definition: rpc.h:45
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2654
NTSTATUS SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject, IN LPWSTR ContainerName, IN LPWSTR ObjectName, IN ULONG RelativeId, IN SAM_DB_OBJECT_TYPE ObjectType, IN ACCESS_MASK DesiredAccess, OUT PSAM_DB_OBJECT *DbObject)
Definition: database.c:44
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define KEY_SET_VALUE
Definition: nt_native.h:1017
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
SAM_DB_OBJECT_TYPE ObjectType
Definition: samsrv.h:48
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
#define midl_user_allocate
Definition: rpc.h:44
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
NTSTATUS SampSetObjectAttribute(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, ULONG AttributeType, LPVOID AttributeData, ULONG AttributeSize)
Definition: database.c:501
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
NTSTATUS SampRegDeleteValue(IN HANDLE KeyHandle, IN LPCWSTR ValueName)
Definition: registry.c:212
uint16_t * PWCHAR
Definition: typedefs.h:56
_In_ PVOID _Out_opt_ PULONG_PTR _Outptr_opt_ PCUNICODE_STRING * ObjectName
Definition: cmfuncs.h:62
NTSTATUS SampDeleteAccountDbObject(PSAM_DB_OBJECT DbObject)
Definition: database.c:368
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:245
_SEH2_TRY
Definition: create.c:4226
NTSTATUS SampRegCloseKey(IN OUT PHANDLE KeyHandle)
Definition: registry.c:26
HANDLE MembersKeyHandle
Definition: samsrv.h:53
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2430
#define FALSE
Definition: types.h:117
struct _SAM_DB_OBJECT * PSAM_DB_OBJECT
unsigned char BOOLEAN
static HANDLE SamKeyHandle
Definition: database.c:15
ULONG RefCount
Definition: samsrv.h:49
Definition: bufpool.h:45
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
Status
Definition: gdiplustypes.h:24
LPWSTR Name
Definition: samsrv.h:51
#define TRACE(s)
Definition: solgame.cpp:4
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
NTSTATUS SampGetObjectAttributeString(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, PRPC_UNICODE_STRING String)
Definition: database.c:531
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
NTSTATUS SampValidateDbObject(SAMPR_HANDLE Handle, SAM_DB_OBJECT_TYPE ObjectType, ACCESS_MASK DesiredAccess, PSAM_DB_OBJECT *DbObject)
Definition: database.c:301
NTSTATUS SampCloseDbObject(PSAM_DB_OBJECT DbObject)
Definition: database.c:346
NTSTATUS SampGetObjectAttribute(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, PULONG AttributeType, LPVOID AttributeData, PULONG AttributeSize)
Definition: database.c:516
NTSTATUS SampRegDeleteKey(IN HANDLE ParentKeyHandle, IN LPCWSTR KeyName)
Definition: registry.c:71
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
NTSTATUS SampRegQueryValue(IN HANDLE KeyHandle, IN LPCWSTR ValueName, OUT PULONG Type OPTIONAL, OUT PVOID Data OPTIONAL, IN OUT PULONG DataLength OPTIONAL)
Definition: registry.c:332
static const WCHAR L[]
Definition: oid.c:1250
ACCESS_MASK Access
Definition: samsrv.h:50
NTSTATUS SampInitDatabase(VOID)
Definition: database.c:21
HANDLE KeyHandle
Definition: samsrv.h:52
#define ERR(fmt,...)
Definition: debug.h:110
_SEH2_END
Definition: create.c:4400
struct _SAM_DB_OBJECT * ParentObject
Definition: samsrv.h:56
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
NTSTATUS SampRegOpenKey(IN HANDLE ParentKeyHandle, IN LPCWSTR KeyName, IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle)
Definition: registry.c:158
unsigned short USHORT
Definition: pedump.c:61
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
NTSTATUS SampRegSetValue(HANDLE KeyHandle, LPCWSTR ValueName, ULONG Type, LPVOID Data, ULONG DataLength)
Definition: registry.c:402
_In_ HANDLE Handle
Definition: extypes.h:390
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
NTSTATUS SampSetObjectAttributeString(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, PRPC_UNICODE_STRING String)
Definition: database.c:595
#define SAMP_DB_SIGNATURE
Definition: samsrv.h:59
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
NTSTATUS SampRegCreateKey(IN HANDLE ParentKeyHandle, IN LPCWSTR KeyName, IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle)
Definition: registry.c:42
WCHAR * LPWSTR
Definition: xmlstorage.h:184
_Inout_opt_ PACCESS_STATE _In_opt_ ACCESS_MASK _In_ ULONG _Out_opt_ PVOID * NewObject
Definition: obfuncs.h:71
#define KEY_CREATE_SUB_KEY
Definition: nt_native.h:1018
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define DELETE
Definition: nt_native.h:57
NTSTATUS SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject, IN LPWSTR ContainerName, IN LPWSTR ObjectName, IN ULONG RelativeId, IN SAM_DB_OBJECT_TYPE ObjectType, IN ACCESS_MASK DesiredAccess, OUT PSAM_DB_OBJECT *DbObject)
Definition: database.c:173
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019
#define REG_SZ
Definition: layer.c:22