ReactOS  0.4.14-dev-608-gd495a4f
samrpc.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: Security Account Manager (SAM) Server
4  * FILE: reactos/dll/win32/samsrv/samrpc.c
5  * PURPOSE: RPC interface functions
6  *
7  * PROGRAMMERS: Eric Kohl
8  */
9 
10 #include "samsrv.h"
11 
12 /* GLOBALS *******************************************************************/
13 
15 
17 {
22 };
23 
25 {
30 };
31 
33 {
34  ALIAS_READ,
38 };
39 
41 {
42  GROUP_READ,
46 };
47 
49 {
50  USER_READ,
51  USER_WRITE,
54 };
55 
57 
58 
59 /* FUNCTIONS *****************************************************************/
60 
61 static
64  IN LARGE_INTEGER RelativeTime)
65 {
66  LARGE_INTEGER NewTime;
67 
68  NewTime.QuadPart = AbsoluteTime.QuadPart - RelativeTime.QuadPart;
69 
70  if (NewTime.QuadPart < 0)
71  NewTime.QuadPart = 0;
72 
73  return NewTime;
74 }
75 
76 
77 VOID
79 {
81 
82  TRACE("SampStartRpcServer() called\n");
83 
84  Status = RpcServerUseProtseqEpW(L"ncacn_np",
86  L"\\pipe\\samr",
87  NULL);
88  if (Status != RPC_S_OK)
89  {
90  WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
91  return;
92  }
93 
94  Status = RpcServerRegisterIf(samr_v1_0_s_ifspec,
95  NULL,
96  NULL);
97  if (Status != RPC_S_OK)
98  {
99  WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
100  return;
101  }
102 
103  Status = RpcServerListen(1, 20, TRUE);
104  if (Status != RPC_S_OK)
105  {
106  WARN("RpcServerListen() failed (Status %lx)\n", Status);
107  return;
108  }
109 
110  TRACE("SampStartRpcServer() done\n");
111 }
112 
113 
115 {
117 }
118 
119 
121 {
122  HeapFree(GetProcessHeap(), 0, ptr);
123 }
124 
125 
127 {
128 }
129 
130 
131 /* Function 0 */
132 NTSTATUS
133 NTAPI
135  OUT SAMPR_HANDLE *ServerHandle,
137 {
138  SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
139  ULONG OutVersion;
140 
141  TRACE("SamrConnect(%p %p %lx)\n",
142  ServerName, ServerHandle, DesiredAccess);
143 
144  InRevisionInfo.V1.Revision = 0;
145  InRevisionInfo.V1.SupportedFeatures = 0;
146 
147  return SamrConnect5(ServerName,
149  1,
150  &InRevisionInfo,
151  &OutVersion,
152  &OutRevisionInfo,
153  ServerHandle);
154 }
155 
156 
157 /* Function 1 */
158 NTSTATUS
159 NTAPI
161 {
162  PSAM_DB_OBJECT DbObject;
164 
165  TRACE("SamrCloseHandle(%p)\n", SamHandle);
166 
168  TRUE);
169 
170  Status = SampValidateDbObject(*SamHandle,
172  0,
173  &DbObject);
174  if (Status == STATUS_SUCCESS)
175  {
176  Status = SampCloseDbObject(DbObject);
177  *SamHandle = NULL;
178  }
179 
181 
182  TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
183 
184  return Status;
185 }
186 
187 
188 /* Function 2 */
189 NTSTATUS
190 NTAPI
194 {
195  PSAM_DB_OBJECT DbObject = NULL;
197  PSECURITY_DESCRIPTOR RelativeSd = NULL;
198  ULONG RelativeSdSize = 0;
202 
203  TRACE("SamrSetSecurityObject(%p %lx %p)\n",
204  ObjectHandle, SecurityInformation, SecurityDescriptor);
205 
206  if ((SecurityDescriptor == NULL) ||
207  (SecurityDescriptor->SecurityDescriptor == NULL) ||
210 
211  if (SecurityInformation == 0 ||
215 
218 
221 
224 
228 
232 
233  /* Validate the server handle */
234  Status = SampValidateDbObject(ObjectHandle,
237  &DbObject);
238  if (!NT_SUCCESS(Status))
239  goto done;
240 
241  /* Get the mapping for the object type */
242  switch (DbObject->ObjectType)
243  {
244  case SamDbServerObject:
246  break;
247 
248  case SamDbDomainObject:
250  break;
251 
252  case SamDbAliasObject:
254  break;
255 
256  case SamDbGroupObject:
258  break;
259 
260  case SamDbUserObject:
261  Mapping = &UserMapping;
262  break;
263 
264  default:
265  return STATUS_INVALID_HANDLE;
266  }
267 
268  /* Get the size of the SD */
269  Status = SampGetObjectAttribute(DbObject,
270  L"SecDesc",
271  NULL,
272  NULL,
273  &RelativeSdSize);
274  if (!NT_SUCCESS(Status))
275  return Status;
276 
277  /* Allocate a buffer for the SD */
278  RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), 0, RelativeSdSize);
279  if (RelativeSd == NULL)
281 
282  /* Get the SD */
283  Status = SampGetObjectAttribute(DbObject,
284  L"SecDesc",
285  NULL,
286  RelativeSd,
287  &RelativeSdSize);
288  if (!NT_SUCCESS(Status))
289  goto done;
290 
291  /* Build the new security descriptor */
293  (PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor,
294  &RelativeSd,
295  Mapping,
296  TokenHandle);
297  if (!NT_SUCCESS(Status))
298  {
299  ERR("RtlSetSecurityObject failed (Status 0x%08lx)\n", Status);
300  goto done;
301  }
302 
303  /* Set the modified SD */
304  Status = SampSetObjectAttribute(DbObject,
305  L"SecDesc",
306  REG_BINARY,
307  RelativeSd,
308  RtlLengthSecurityDescriptor(RelativeSd));
309  if (!NT_SUCCESS(Status))
310  {
311  ERR("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
312  }
313 
314 done:
315  if (TokenHandle != NULL)
317 
318  if (RelativeSd != NULL)
319  RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
320 
321  return Status;
322 }
323 
324 
325 /* Function 3 */
326 NTSTATUS
327 NTAPI
331 {
332  PSAM_DB_OBJECT SamObject;
334  PSECURITY_DESCRIPTOR RelativeSd = NULL;
335  PSECURITY_DESCRIPTOR ResultSd = NULL;
337  ULONG RelativeSdSize = 0;
338  ULONG ResultSdSize = 0;
340 
341  TRACE("SamrQuerySecurityObject(%p %lx %p)\n",
342  ObjectHandle, SecurityInformation, SecurityDescriptor);
343 
345 
347  TRUE);
348 
353 
356 
357  /* Validate the server handle */
358  Status = SampValidateDbObject(ObjectHandle,
361  &SamObject);
362  if (!NT_SUCCESS(Status))
363  goto done;
364 
365  /* Get the size of the SD */
366  Status = SampGetObjectAttribute(SamObject,
367  L"SecDesc",
368  NULL,
369  NULL,
370  &RelativeSdSize);
372  {
373  TRACE("Status 0x%08lx\n", Status);
374  goto done;
375  }
376 
377  /* Allocate a buffer for the SD */
378  RelativeSd = midl_user_allocate(RelativeSdSize);
379  if (RelativeSd == NULL)
380  {
382  goto done;
383  }
384 
385  /* Get the SD */
386  Status = SampGetObjectAttribute(SamObject,
387  L"SecDesc",
388  NULL,
389  RelativeSd,
390  &RelativeSdSize);
391  if (!NT_SUCCESS(Status))
392  {
393  TRACE("Status 0x%08lx\n", Status);
394  goto done;
395  }
396 
397  /* Invalidate the SD information that was not requested */
399  ((PISECURITY_DESCRIPTOR)RelativeSd)->Owner = NULL;
400 
402  ((PISECURITY_DESCRIPTOR)RelativeSd)->Group = NULL;
403 
405  ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_DACL_PRESENT;
406 
408  ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_SACL_PRESENT;
409 
410  /* Calculate the required SD size */
411  Status = RtlMakeSelfRelativeSD(RelativeSd,
412  NULL,
413  &ResultSdSize);
415  goto done;
416 
417  /* Allocate a buffer for the new SD */
418  ResultSd = MIDL_user_allocate(ResultSdSize);
419  if (ResultSd == NULL)
420  {
422  goto done;
423  }
424 
425  /* Build the new SD */
426  Status = RtlMakeSelfRelativeSD(RelativeSd,
427  ResultSd,
428  &ResultSdSize);
429  if (!NT_SUCCESS(Status))
430  goto done;
431 
432  /* Allocate the SD data buffer */
434  if (SdData == NULL)
435  {
437  goto done;
438  }
439 
440  /* Fill the SD data buffer and return it to the caller */
441  SdData->Length = RelativeSdSize;
442  SdData->SecurityDescriptor = (PBYTE)ResultSd;
443 
444  *SecurityDescriptor = SdData;
445 
446 done:
448 
449  if (!NT_SUCCESS(Status))
450  {
451  if (ResultSd != NULL)
452  MIDL_user_free(ResultSd);
453  }
454 
455  if (RelativeSd != NULL)
456  MIDL_user_free(RelativeSd);
457 
458  return Status;
459 }
460 
461 
462 /* Function 4 */
463 NTSTATUS
464 NTAPI
466 {
467  PSAM_DB_OBJECT ServerObject;
469 
470  TRACE("SamrShutdownSamServer(%p)\n",
471  ServerHandle);
472 
474  TRUE);
475 
476  /* Validate the server handle */
477  Status = SampValidateDbObject(ServerHandle,
480  &ServerObject);
481 
483 
484  if (!NT_SUCCESS(Status))
485  return Status;
486 
487  /* Shut the server down */
489 
490  return STATUS_SUCCESS;
491 }
492 
493 
494 /* Function 5 */
495 NTSTATUS
496 NTAPI
499  OUT PRPC_SID *DomainId)
500 {
501  PSAM_DB_OBJECT ServerObject;
502  HANDLE DomainsKeyHandle = NULL;
503  HANDLE DomainKeyHandle = NULL;
504  WCHAR DomainKeyName[64];
505  ULONG Index;
506  WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
507  UNICODE_STRING DomainName;
508  ULONG Length;
509  BOOL Found = FALSE;
511 
512  TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
513  ServerHandle, Name, DomainId);
514 
516  TRUE);
517 
518  /* Validate the server handle */
519  Status = SampValidateDbObject(ServerHandle,
522  &ServerObject);
523  if (!NT_SUCCESS(Status))
524  goto done;
525 
526  *DomainId = NULL;
527 
528  Status = SampRegOpenKey(ServerObject->KeyHandle,
529  L"Domains",
530  KEY_READ,
531  &DomainsKeyHandle);
532  if (!NT_SUCCESS(Status))
533  goto done;
534 
535  Index = 0;
536  while (Found == FALSE)
537  {
538  Status = SampRegEnumerateSubKey(DomainsKeyHandle,
539  Index,
540  64,
541  DomainKeyName);
542  if (!NT_SUCCESS(Status))
543  {
546  break;
547  }
548 
549  TRACE("Domain key name: %S\n", DomainKeyName);
550 
551  Status = SampRegOpenKey(DomainsKeyHandle,
552  DomainKeyName,
553  KEY_READ,
554  &DomainKeyHandle);
555  if (NT_SUCCESS(Status))
556  {
557  Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
558  Status = SampRegQueryValue(DomainKeyHandle,
559  L"Name",
560  NULL,
561  (PVOID)&DomainNameString,
562  &Length);
563  if (NT_SUCCESS(Status))
564  {
565  TRACE("Domain name: %S\n", DomainNameString);
566 
567  RtlInitUnicodeString(&DomainName,
568  DomainNameString);
569  if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
570  {
571  TRACE("Found it!\n");
572  Found = TRUE;
573 
574  Status = SampRegQueryValue(DomainKeyHandle,
575  L"SID",
576  NULL,
577  NULL,
578  &Length);
579  if (NT_SUCCESS(Status))
580  {
581  *DomainId = midl_user_allocate(Length);
582 
583  SampRegQueryValue(DomainKeyHandle,
584  L"SID",
585  NULL,
586  (PVOID)*DomainId,
587  &Length);
588 
590  break;
591  }
592  }
593  }
594 
595  SampRegCloseKey(&DomainKeyHandle);
596  }
597 
598  Index++;
599  }
600 
601 done:
602  SampRegCloseKey(&DomainKeyHandle);
603  SampRegCloseKey(&DomainsKeyHandle);
604 
606 
607  return Status;
608 }
609 
610 
611 /* Function 6 */
612 NTSTATUS
613 NTAPI
615  IN OUT unsigned long *EnumerationContext,
617  IN ULONG PreferedMaximumLength,
618  OUT PULONG CountReturned)
619 {
620  PSAM_DB_OBJECT ServerObject;
621  WCHAR DomainKeyName[64];
622  HANDLE DomainsKeyHandle = NULL;
623  HANDLE DomainKeyHandle = NULL;
624  ULONG EnumIndex;
625  ULONG EnumCount;
628  ULONG i;
629  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
631 
632  TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
633  ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
634  CountReturned);
635 
637  TRUE);
638 
639  /* Validate the server handle */
640  Status = SampValidateDbObject(ServerHandle,
643  &ServerObject);
644  if (!NT_SUCCESS(Status))
645  goto done;
646 
647  Status = SampRegOpenKey(ServerObject->KeyHandle,
648  L"Domains",
649  KEY_READ,
650  &DomainsKeyHandle);
651  if (!NT_SUCCESS(Status))
652  goto done;
653 
654  EnumIndex = *EnumerationContext;
655  EnumCount = 0;
656  RequiredLength = 0;
657 
658  while (TRUE)
659  {
660  Status = SampRegEnumerateSubKey(DomainsKeyHandle,
661  EnumIndex,
662  64 * sizeof(WCHAR),
663  DomainKeyName);
664  if (!NT_SUCCESS(Status))
665  break;
666 
667  TRACE("EnumIndex: %lu\n", EnumIndex);
668  TRACE("Domain key name: %S\n", DomainKeyName);
669 
670  Status = SampRegOpenKey(DomainsKeyHandle,
671  DomainKeyName,
672  KEY_READ,
673  &DomainKeyHandle);
674  TRACE("SampRegOpenKey returned %08lX\n", Status);
675  if (NT_SUCCESS(Status))
676  {
677  DataLength = 0;
678  Status = SampRegQueryValue(DomainKeyHandle,
679  L"Name",
680  NULL,
681  NULL,
682  &DataLength);
683  TRACE("SampRegQueryValue returned %08lX\n", Status);
684  if (NT_SUCCESS(Status))
685  {
686  TRACE("Data length: %lu\n", DataLength);
687 
688  if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
689  break;
690 
692  EnumCount++;
693  }
694 
695  SampRegCloseKey(&DomainKeyHandle);
696  }
697 
698  EnumIndex++;
699  }
700 
701  TRACE("EnumCount: %lu\n", EnumCount);
702  TRACE("RequiredLength: %lu\n", RequiredLength);
703 
704  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
705  if (EnumBuffer == NULL)
706  {
708  goto done;
709  }
710 
711  EnumBuffer->EntriesRead = EnumCount;
712  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
713  if (EnumBuffer->Buffer == NULL)
714  {
716  goto done;
717  }
718 
719  EnumIndex = *EnumerationContext;
720  for (i = 0; i < EnumCount; i++, EnumIndex++)
721  {
722  Status = SampRegEnumerateSubKey(DomainsKeyHandle,
723  EnumIndex,
724  64 * sizeof(WCHAR),
725  DomainKeyName);
726  if (!NT_SUCCESS(Status))
727  break;
728 
729  TRACE("EnumIndex: %lu\n", EnumIndex);
730  TRACE("Domain key name: %S\n", DomainKeyName);
731 
732  Status = SampRegOpenKey(DomainsKeyHandle,
733  DomainKeyName,
734  KEY_READ,
735  &DomainKeyHandle);
736  TRACE("SampRegOpenKey returned %08lX\n", Status);
737  if (NT_SUCCESS(Status))
738  {
739  DataLength = 0;
740  Status = SampRegQueryValue(DomainKeyHandle,
741  L"Name",
742  NULL,
743  NULL,
744  &DataLength);
745  TRACE("SampRegQueryValue returned %08lX\n", Status);
746  if (NT_SUCCESS(Status))
747  {
748  EnumBuffer->Buffer[i].RelativeId = 0;
749  EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
750  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
752  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
753  {
754  SampRegCloseKey(&DomainKeyHandle);
756  goto done;
757  }
758 
759  Status = SampRegQueryValue(DomainKeyHandle,
760  L"Name",
761  NULL,
762  EnumBuffer->Buffer[i].Name.Buffer,
763  &DataLength);
764  TRACE("SampRegQueryValue returned %08lX\n", Status);
765  if (NT_SUCCESS(Status))
766  {
767  TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
768  }
769  }
770 
771  SampRegCloseKey(&DomainKeyHandle);
772 
773  if (!NT_SUCCESS(Status))
774  goto done;
775  }
776  }
777 
778  if (NT_SUCCESS(Status))
779  {
780  *EnumerationContext += EnumCount;
781  *Buffer = EnumBuffer;
782  *CountReturned = EnumCount;
783  }
784 
785 done:
786  SampRegCloseKey(&DomainKeyHandle);
787  SampRegCloseKey(&DomainsKeyHandle);
788 
789  if (!NT_SUCCESS(Status))
790  {
791  *EnumerationContext = 0;
792  *Buffer = NULL;
793  *CountReturned = 0;
794 
795  if (EnumBuffer != NULL)
796  {
797  if (EnumBuffer->Buffer != NULL)
798  {
799  if (EnumBuffer->EntriesRead != 0)
800  {
801  for (i = 0; i < EnumBuffer->EntriesRead; i++)
802  {
803  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
804  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
805  }
806  }
807 
808  midl_user_free(EnumBuffer->Buffer);
809  }
810 
811  midl_user_free(EnumBuffer);
812  }
813  }
814 
816 
817  return Status;
818 }
819 
820 
821 /* Function 7 */
822 NTSTATUS
823 NTAPI
826  IN PRPC_SID DomainId,
827  OUT SAMPR_HANDLE *DomainHandle)
828 {
829  PSAM_DB_OBJECT ServerObject;
830  PSAM_DB_OBJECT DomainObject;
832 
833  TRACE("SamrOpenDomain(%p %lx %p %p)\n",
834  ServerHandle, DesiredAccess, DomainId, DomainHandle);
835 
836  /* Map generic access rights */
838  &DomainMapping);
839 
841  TRUE);
842 
843  /* Validate the server handle */
844  Status = SampValidateDbObject(ServerHandle,
847  &ServerObject);
848  if (!NT_SUCCESS(Status))
849  return Status;
850 
851  /* Validate the Domain SID */
852  if ((DomainId->Revision != SID_REVISION) ||
853  (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
854  (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
856 
857  /* Open the domain object */
858  if ((DomainId->SubAuthorityCount == 1) &&
859  (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
860  {
861  /* Builtin domain object */
862  TRACE("Opening the builtin domain object.\n");
863 
864  Status = SampOpenDbObject(ServerObject,
865  L"Domains",
866  L"Builtin",
867  0,
870  &DomainObject);
871  }
872  else if ((DomainId->SubAuthorityCount == 4) &&
873  (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
874  {
875  /* Account domain object */
876  TRACE("Opening the account domain object.\n");
877 
878  /* FIXME: Check the account domain sub authorities!!! */
879 
880  Status = SampOpenDbObject(ServerObject,
881  L"Domains",
882  L"Account",
883  0,
886  &DomainObject);
887  }
888  else
889  {
890  /* No valid domain SID */
892  }
893 
894  if (NT_SUCCESS(Status))
895  *DomainHandle = (SAMPR_HANDLE)DomainObject;
896 
898 
899  TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
900 
901  return Status;
902 }
903 
904 
905 static NTSTATUS
908 {
909  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
910  SAM_DOMAIN_FIXED_DATA FixedData;
911  ULONG Length = 0;
913 
914  *Buffer = NULL;
915 
916  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
917  if (InfoBuffer == NULL)
919 
920  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
921  Status = SampGetObjectAttribute(DomainObject,
922  L"F",
923  NULL,
924  (PVOID)&FixedData,
925  &Length);
926  if (!NT_SUCCESS(Status))
927  goto done;
928 
929  InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
930  InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
931  InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
932  InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
933  InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
934  InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
935  InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
936 
937  *Buffer = InfoBuffer;
938 
939 done:
940  if (!NT_SUCCESS(Status))
941  {
942  if (InfoBuffer != NULL)
943  {
944  midl_user_free(InfoBuffer);
945  }
946  }
947 
948  return Status;
949 }
950 
951 
952 static NTSTATUS
954  LPCWSTR AccountType,
955  PULONG Count)
956 {
957  HANDLE AccountKeyHandle = NULL;
958  HANDLE NamesKeyHandle = NULL;
960 
961  *Count = 0;
962 
963  Status = SampRegOpenKey(DomainObject->KeyHandle,
964  AccountType,
965  KEY_READ,
966  &AccountKeyHandle);
967  if (!NT_SUCCESS(Status))
968  return Status;
969 
970  Status = SampRegOpenKey(AccountKeyHandle,
971  L"Names",
972  KEY_READ,
973  &NamesKeyHandle);
974  if (!NT_SUCCESS(Status))
975  goto done;
976 
977  Status = SampRegQueryKeyInfo(NamesKeyHandle,
978  NULL,
979  Count);
980 
981 done:
982  SampRegCloseKey(&NamesKeyHandle);
983  SampRegCloseKey(&AccountKeyHandle);
984 
985  return Status;
986 }
987 
988 
989 static NTSTATUS
992 {
993  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
994  SAM_DOMAIN_FIXED_DATA FixedData;
995  ULONG Length = 0;
997 
998  *Buffer = NULL;
999 
1000  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1001  if (InfoBuffer == NULL)
1003 
1004  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1005  Status = SampGetObjectAttribute(DomainObject,
1006  L"F",
1007  NULL,
1008  (PVOID)&FixedData,
1009  &Length);
1010  if (!NT_SUCCESS(Status))
1011  goto done;
1012 
1013  InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1014  InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1015  InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1016  InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1017  InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
1018  InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
1019  InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1020 
1021  /* Get the OemInformation string */
1022  Status = SampGetObjectAttributeString(DomainObject,
1023  L"OemInformation",
1024  &InfoBuffer->General.OemInformation);
1025  if (!NT_SUCCESS(Status))
1026  {
1027  TRACE("Status 0x%08lx\n", Status);
1028  goto done;
1029  }
1030 
1031  /* Get the Name string */
1032  Status = SampGetObjectAttributeString(DomainObject,
1033  L"Name",
1034  &InfoBuffer->General.DomainName);
1035  if (!NT_SUCCESS(Status))
1036  {
1037  TRACE("Status 0x%08lx\n", Status);
1038  goto done;
1039  }
1040 
1041  /* Get the ReplicaSourceNodeName string */
1042  Status = SampGetObjectAttributeString(DomainObject,
1043  L"ReplicaSourceNodeName",
1044  &InfoBuffer->General.ReplicaSourceNodeName);
1045  if (!NT_SUCCESS(Status))
1046  {
1047  TRACE("Status 0x%08lx\n", Status);
1048  goto done;
1049  }
1050 
1051  /* Get the number of Users in the Domain */
1052  Status = SampGetNumberOfAccounts(DomainObject,
1053  L"Users",
1054  &InfoBuffer->General.UserCount);
1055  if (!NT_SUCCESS(Status))
1056  {
1057  TRACE("Status 0x%08lx\n", Status);
1058  goto done;
1059  }
1060 
1061  /* Get the number of Groups in the Domain */
1062  Status = SampGetNumberOfAccounts(DomainObject,
1063  L"Groups",
1064  &InfoBuffer->General.GroupCount);
1065  if (!NT_SUCCESS(Status))
1066  {
1067  TRACE("Status 0x%08lx\n", Status);
1068  goto done;
1069  }
1070 
1071  /* Get the number of Aliases in the Domain */
1072  Status = SampGetNumberOfAccounts(DomainObject,
1073  L"Aliases",
1074  &InfoBuffer->General.AliasCount);
1075  if (!NT_SUCCESS(Status))
1076  {
1077  TRACE("Status 0x%08lx\n", Status);
1078  goto done;
1079  }
1080 
1081  *Buffer = InfoBuffer;
1082 
1083 done:
1084  if (!NT_SUCCESS(Status))
1085  {
1086  if (InfoBuffer != NULL)
1087  {
1088  if (InfoBuffer->General.OemInformation.Buffer != NULL)
1090 
1091  if (InfoBuffer->General.DomainName.Buffer != NULL)
1092  midl_user_free(InfoBuffer->General.DomainName.Buffer);
1093 
1094  if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
1096 
1097  midl_user_free(InfoBuffer);
1098  }
1099  }
1100 
1101  return Status;
1102 }
1103 
1104 
1105 static NTSTATUS
1108 {
1109  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1110  SAM_DOMAIN_FIXED_DATA FixedData;
1111  ULONG Length = 0;
1112  NTSTATUS Status;
1113 
1114  *Buffer = NULL;
1115 
1116  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1117  if (InfoBuffer == NULL)
1119 
1120  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1121  Status = SampGetObjectAttribute(DomainObject,
1122  L"F",
1123  NULL,
1124  (PVOID)&FixedData,
1125  &Length);
1126  if (!NT_SUCCESS(Status))
1127  goto done;
1128 
1129  InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1130  InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1131 
1132  *Buffer = InfoBuffer;
1133 
1134 done:
1135  if (!NT_SUCCESS(Status))
1136  {
1137  if (InfoBuffer != NULL)
1138  {
1139  midl_user_free(InfoBuffer);
1140  }
1141  }
1142 
1143  return Status;
1144 }
1145 
1146 
1147 static NTSTATUS
1150 {
1151  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1152  NTSTATUS Status;
1153 
1154  *Buffer = NULL;
1155 
1156  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1157  if (InfoBuffer == NULL)
1159 
1160  /* Get the OemInformation string */
1161  Status = SampGetObjectAttributeString(DomainObject,
1162  L"OemInformation",
1163  &InfoBuffer->Oem.OemInformation);
1164  if (!NT_SUCCESS(Status))
1165  {
1166  TRACE("Status 0x%08lx\n", Status);
1167  goto done;
1168  }
1169 
1170  *Buffer = InfoBuffer;
1171 
1172 done:
1173  if (!NT_SUCCESS(Status))
1174  {
1175  if (InfoBuffer != NULL)
1176  {
1177  if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
1178  midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
1179 
1180  midl_user_free(InfoBuffer);
1181  }
1182  }
1183 
1184  return Status;
1185 }
1186 
1187 
1188 static NTSTATUS
1191 {
1192  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1193  NTSTATUS Status;
1194 
1195  *Buffer = NULL;
1196 
1197  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1198  if (InfoBuffer == NULL)
1200 
1201  /* Get the Name string */
1202  Status = SampGetObjectAttributeString(DomainObject,
1203  L"Name",
1204  &InfoBuffer->Name.DomainName);
1205  if (!NT_SUCCESS(Status))
1206  {
1207  TRACE("Status 0x%08lx\n", Status);
1208  goto done;
1209  }
1210 
1211  *Buffer = InfoBuffer;
1212 
1213 done:
1214  if (!NT_SUCCESS(Status))
1215  {
1216  if (InfoBuffer != NULL)
1217  {
1218  if (InfoBuffer->Name.DomainName.Buffer != NULL)
1219  midl_user_free(InfoBuffer->Name.DomainName.Buffer);
1220 
1221  midl_user_free(InfoBuffer);
1222  }
1223  }
1224 
1225  return Status;
1226 }
1227 
1228 
1229 static NTSTATUS
1232 {
1233  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1234  NTSTATUS Status;
1235 
1236  *Buffer = NULL;
1237 
1238  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1239  if (InfoBuffer == NULL)
1241 
1242  /* Get the ReplicaSourceNodeName string */
1243  Status = SampGetObjectAttributeString(DomainObject,
1244  L"ReplicaSourceNodeName",
1245  &InfoBuffer->Replication.ReplicaSourceNodeName);
1246  if (!NT_SUCCESS(Status))
1247  {
1248  TRACE("Status 0x%08lx\n", Status);
1249  goto done;
1250  }
1251 
1252  *Buffer = InfoBuffer;
1253 
1254 done:
1255  if (!NT_SUCCESS(Status))
1256  {
1257  if (InfoBuffer != NULL)
1258  {
1259  if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
1261 
1262  midl_user_free(InfoBuffer);
1263  }
1264  }
1265 
1266  return Status;
1267 }
1268 
1269 
1270 static NTSTATUS
1273 {
1274  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1275  SAM_DOMAIN_FIXED_DATA FixedData;
1276  ULONG Length = 0;
1277  NTSTATUS Status;
1278 
1279  *Buffer = NULL;
1280 
1281  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1282  if (InfoBuffer == NULL)
1284 
1285  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1286  Status = SampGetObjectAttribute(DomainObject,
1287  L"F",
1288  NULL,
1289  (PVOID)&FixedData,
1290  &Length);
1291  if (!NT_SUCCESS(Status))
1292  goto done;
1293 
1294  InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
1295 
1296  *Buffer = InfoBuffer;
1297 
1298 done:
1299  if (!NT_SUCCESS(Status))
1300  {
1301  if (InfoBuffer != NULL)
1302  {
1303  midl_user_free(InfoBuffer);
1304  }
1305  }
1306 
1307  return Status;
1308 }
1309 
1310 
1311 static NTSTATUS
1314 {
1315  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1316  SAM_DOMAIN_FIXED_DATA FixedData;
1317  ULONG Length = 0;
1318  NTSTATUS Status;
1319 
1320  *Buffer = NULL;
1321 
1322  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1323  if (InfoBuffer == NULL)
1325 
1326  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1327  Status = SampGetObjectAttribute(DomainObject,
1328  L"F",
1329  NULL,
1330  (PVOID)&FixedData,
1331  &Length);
1332  if (!NT_SUCCESS(Status))
1333  goto done;
1334 
1335  InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1336  InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1337  InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1338  InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1339 
1340  *Buffer = InfoBuffer;
1341 
1342 done:
1343  if (!NT_SUCCESS(Status))
1344  {
1345  if (InfoBuffer != NULL)
1346  {
1347  midl_user_free(InfoBuffer);
1348  }
1349  }
1350 
1351  return Status;
1352 }
1353 
1354 
1355 static NTSTATUS
1358 {
1359  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1360  SAM_DOMAIN_FIXED_DATA FixedData;
1361  ULONG Length = 0;
1362  NTSTATUS Status;
1363 
1364  *Buffer = NULL;
1365 
1366  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1367  if (InfoBuffer == NULL)
1369 
1370  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1371  Status = SampGetObjectAttribute(DomainObject,
1372  L"F",
1373  NULL,
1374  (PVOID)&FixedData,
1375  &Length);
1376  if (!NT_SUCCESS(Status))
1377  goto done;
1378 
1379  InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1380 
1381  *Buffer = InfoBuffer;
1382 
1383 done:
1384  if (!NT_SUCCESS(Status))
1385  {
1386  if (InfoBuffer != NULL)
1387  {
1388  midl_user_free(InfoBuffer);
1389  }
1390  }
1391 
1392  return Status;
1393 }
1394 
1395 
1396 static NTSTATUS
1399 {
1400  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1401  SAM_DOMAIN_FIXED_DATA FixedData;
1402  ULONG Length = 0;
1403  NTSTATUS Status;
1404 
1405  *Buffer = NULL;
1406 
1407  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1408  if (InfoBuffer == NULL)
1410 
1411  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1412  Status = SampGetObjectAttribute(DomainObject,
1413  L"F",
1414  NULL,
1415  (PVOID)&FixedData,
1416  &Length);
1417  if (!NT_SUCCESS(Status))
1418  goto done;
1419 
1420  InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1421  InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1422  InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1423  InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1424  InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1425  InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1426  InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1427 
1428  InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1429  InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1430  InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1431 
1432  /* Get the OemInformation string */
1433  Status = SampGetObjectAttributeString(DomainObject,
1434  L"OemInformation",
1435  &InfoBuffer->General2.I1.OemInformation);
1436  if (!NT_SUCCESS(Status))
1437  {
1438  TRACE("Status 0x%08lx\n", Status);
1439  goto done;
1440  }
1441 
1442  /* Get the Name string */
1443  Status = SampGetObjectAttributeString(DomainObject,
1444  L"Name",
1445  &InfoBuffer->General2.I1.DomainName);
1446  if (!NT_SUCCESS(Status))
1447  {
1448  TRACE("Status 0x%08lx\n", Status);
1449  goto done;
1450  }
1451 
1452  /* Get the ReplicaSourceNodeName string */
1453  Status = SampGetObjectAttributeString(DomainObject,
1454  L"ReplicaSourceNodeName",
1455  &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1456  if (!NT_SUCCESS(Status))
1457  {
1458  TRACE("Status 0x%08lx\n", Status);
1459  goto done;
1460  }
1461 
1462  /* Get the number of Users in the Domain */
1463  Status = SampGetNumberOfAccounts(DomainObject,
1464  L"Users",
1465  &InfoBuffer->General2.I1.UserCount);
1466  if (!NT_SUCCESS(Status))
1467  {
1468  TRACE("Status 0x%08lx\n", Status);
1469  goto done;
1470  }
1471 
1472  /* Get the number of Groups in the Domain */
1473  Status = SampGetNumberOfAccounts(DomainObject,
1474  L"Groups",
1475  &InfoBuffer->General2.I1.GroupCount);
1476  if (!NT_SUCCESS(Status))
1477  {
1478  TRACE("Status 0x%08lx\n", Status);
1479  goto done;
1480  }
1481 
1482  /* Get the number of Aliases in the Domain */
1483  Status = SampGetNumberOfAccounts(DomainObject,
1484  L"Aliases",
1485  &InfoBuffer->General2.I1.AliasCount);
1486  if (!NT_SUCCESS(Status))
1487  {
1488  TRACE("Status 0x%08lx\n", Status);
1489  goto done;
1490  }
1491 
1492  *Buffer = InfoBuffer;
1493 
1494 done:
1495  if (!NT_SUCCESS(Status))
1496  {
1497  if (InfoBuffer != NULL)
1498  {
1499  if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1501 
1502  if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1504 
1505  if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1507 
1508  midl_user_free(InfoBuffer);
1509  }
1510  }
1511 
1512  return Status;
1513 }
1514 
1515 
1516 static NTSTATUS
1519 {
1520  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1521  SAM_DOMAIN_FIXED_DATA FixedData;
1522  ULONG Length = 0;
1523  NTSTATUS Status;
1524 
1525  *Buffer = NULL;
1526 
1527  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1528  if (InfoBuffer == NULL)
1530 
1531  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1532  Status = SampGetObjectAttribute(DomainObject,
1533  L"F",
1534  NULL,
1535  (PVOID)&FixedData,
1536  &Length);
1537  if (!NT_SUCCESS(Status))
1538  goto done;
1539 
1540  InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1541  InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1542  InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1543 
1544  *Buffer = InfoBuffer;
1545 
1546 done:
1547  if (!NT_SUCCESS(Status))
1548  {
1549  if (InfoBuffer != NULL)
1550  {
1551  midl_user_free(InfoBuffer);
1552  }
1553  }
1554 
1555  return Status;
1556 }
1557 
1558 
1559 static NTSTATUS
1562 {
1563  PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1564  SAM_DOMAIN_FIXED_DATA FixedData;
1565  ULONG Length = 0;
1566  NTSTATUS Status;
1567 
1568  *Buffer = NULL;
1569 
1570  InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1571  if (InfoBuffer == NULL)
1573 
1574  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1575  Status = SampGetObjectAttribute(DomainObject,
1576  L"F",
1577  NULL,
1578  (PVOID)&FixedData,
1579  &Length);
1580  if (!NT_SUCCESS(Status))
1581  goto done;
1582 
1583  InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1584  InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1585  InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1586  InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1587  InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1588  InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1589 
1590  *Buffer = InfoBuffer;
1591 
1592 done:
1593  if (!NT_SUCCESS(Status))
1594  {
1595  if (InfoBuffer != NULL)
1596  {
1597  midl_user_free(InfoBuffer);
1598  }
1599  }
1600 
1601  return Status;
1602 }
1603 
1604 
1605 /* Function 8 */
1606 NTSTATUS
1607 NTAPI
1609  IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1611 {
1612  PSAM_DB_OBJECT DomainObject;
1614  NTSTATUS Status;
1615 
1616  TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1617  DomainHandle, DomainInformationClass, Buffer);
1618 
1619  switch (DomainInformationClass)
1620  {
1624  break;
1625 
1628  case DomainOemInformation:
1629  case DomainNameInformation:
1636  break;
1637 
1641  break;
1642 
1643  default:
1645  }
1646 
1648  TRUE);
1649 
1650  /* Validate the server handle */
1651  Status = SampValidateDbObject(DomainHandle,
1653  DesiredAccess,
1654  &DomainObject);
1655  if (!NT_SUCCESS(Status))
1656  goto done;
1657 
1658  switch (DomainInformationClass)
1659  {
1661  Status = SampQueryDomainPassword(DomainObject,
1662  Buffer);
1663  break;
1664 
1666  Status = SampQueryDomainGeneral(DomainObject,
1667  Buffer);
1668  break;
1669 
1671  Status = SampQueryDomainLogoff(DomainObject,
1672  Buffer);
1673  break;
1674 
1675  case DomainOemInformation:
1676  Status = SampQueryDomainOem(DomainObject,
1677  Buffer);
1678  break;
1679 
1680  case DomainNameInformation:
1681  Status = SampQueryDomainName(DomainObject,
1682  Buffer);
1683  break;
1684 
1686  Status = SampQueryDomainReplication(DomainObject,
1687  Buffer);
1688  break;
1689 
1691  Status = SampQueryDomainServerRole(DomainObject,
1692  Buffer);
1693  break;
1694 
1696  Status = SampQueryDomainModified(DomainObject,
1697  Buffer);
1698  break;
1699 
1701  Status = SampQueryDomainState(DomainObject,
1702  Buffer);
1703  break;
1704 
1706  Status = SampQueryDomainGeneral2(DomainObject,
1707  Buffer);
1708  break;
1709 
1711  Status = SampQueryDomainLockout(DomainObject,
1712  Buffer);
1713  break;
1714 
1716  Status = SampQueryDomainModified2(DomainObject,
1717  Buffer);
1718  break;
1719 
1720  default:
1722  }
1723 
1724 done:
1726 
1727  return Status;
1728 }
1729 
1730 
1731 static NTSTATUS
1734 {
1735  SAM_DOMAIN_FIXED_DATA FixedData;
1736  ULONG Length = 0;
1737  NTSTATUS Status;
1738 
1739  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1740  Status = SampGetObjectAttribute(DomainObject,
1741  L"F",
1742  NULL,
1743  (PVOID)&FixedData,
1744  &Length);
1745  if (!NT_SUCCESS(Status))
1746  goto done;
1747 
1748  FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1749  FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1750  FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1751  FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1752  FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1753  FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1754  FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1755 
1756  Status = SampSetObjectAttribute(DomainObject,
1757  L"F",
1758  REG_BINARY,
1759  &FixedData,
1760  Length);
1761 
1762 done:
1763  return Status;
1764 }
1765 
1766 
1767 static NTSTATUS
1770 {
1771  SAM_DOMAIN_FIXED_DATA FixedData;
1772  ULONG Length = 0;
1773  NTSTATUS Status;
1774 
1775  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1776  Status = SampGetObjectAttribute(DomainObject,
1777  L"F",
1778  NULL,
1779  (PVOID)&FixedData,
1780  &Length);
1781  if (!NT_SUCCESS(Status))
1782  goto done;
1783 
1784  FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1785  FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1786 
1787  Status = SampSetObjectAttribute(DomainObject,
1788  L"F",
1789  REG_BINARY,
1790  &FixedData,
1791  Length);
1792 
1793 done:
1794  return Status;
1795 }
1796 
1797 
1798 static NTSTATUS
1801 {
1802  SAM_DOMAIN_FIXED_DATA FixedData;
1803  ULONG Length = 0;
1804  NTSTATUS Status;
1805 
1806  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1807  Status = SampGetObjectAttribute(DomainObject,
1808  L"F",
1809  NULL,
1810  (PVOID)&FixedData,
1811  &Length);
1812  if (!NT_SUCCESS(Status))
1813  goto done;
1814 
1815  FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1816 
1817  Status = SampSetObjectAttribute(DomainObject,
1818  L"F",
1819  REG_BINARY,
1820  &FixedData,
1821  Length);
1822 
1823 done:
1824  return Status;
1825 }
1826 
1827 
1828 static NTSTATUS
1831 {
1832  SAM_DOMAIN_FIXED_DATA FixedData;
1833  ULONG Length = 0;
1834  NTSTATUS Status;
1835 
1836  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1837  Status = SampGetObjectAttribute(DomainObject,
1838  L"F",
1839  NULL,
1840  (PVOID)&FixedData,
1841  &Length);
1842  if (!NT_SUCCESS(Status))
1843  goto done;
1844 
1845  FixedData.DomainServerState = Buffer->State.DomainServerState;
1846 
1847  Status = SampSetObjectAttribute(DomainObject,
1848  L"F",
1849  REG_BINARY,
1850  &FixedData,
1851  Length);
1852 
1853 done:
1854  return Status;
1855 }
1856 
1857 
1858 static NTSTATUS
1861 {
1862  SAM_DOMAIN_FIXED_DATA FixedData;
1863  ULONG Length = 0;
1864  NTSTATUS Status;
1865 
1866  Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1867  Status = SampGetObjectAttribute(DomainObject,
1868  L"F",
1869  NULL,
1870  (PVOID)&FixedData,
1871  &Length);
1872  if (!NT_SUCCESS(Status))
1873  goto done;
1874 
1875  FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1876  FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1877  FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1878 
1879  Status = SampSetObjectAttribute(DomainObject,
1880  L"F",
1881  REG_BINARY,
1882  &FixedData,
1883  Length);
1884 
1885 done:
1886  return Status;
1887 }
1888 
1889 
1890 /* Function 9 */
1891 NTSTATUS
1892 NTAPI
1894  IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1895  IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1896 {
1897  PSAM_DB_OBJECT DomainObject;
1899  NTSTATUS Status;
1900 
1901  TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1902  DomainHandle, DomainInformationClass, DomainInformation);
1903 
1904  switch (DomainInformationClass)
1905  {
1909  break;
1910 
1912  case DomainOemInformation:
1913  case DomainNameInformation:
1915  break;
1916 
1921  break;
1922 
1923  default:
1925  }
1926 
1928  TRUE);
1929 
1930  /* Validate the server handle */
1931  Status = SampValidateDbObject(DomainHandle,
1933  DesiredAccess,
1934  &DomainObject);
1935  if (!NT_SUCCESS(Status))
1936  goto done;
1937 
1938  switch (DomainInformationClass)
1939  {
1941  Status = SampSetDomainPassword(DomainObject,
1942  DomainInformation);
1943  break;
1944 
1946  Status = SampSetDomainLogoff(DomainObject,
1947  DomainInformation);
1948  break;
1949 
1950  case DomainOemInformation:
1951  Status = SampSetObjectAttributeString(DomainObject,
1952  L"OemInformation",
1953  &DomainInformation->Oem.OemInformation);
1954  break;
1955 
1956  case DomainNameInformation:
1957  Status = SampSetObjectAttributeString(DomainObject,
1958  L"Name",
1959  &DomainInformation->Name.DomainName);
1960  break;
1961 
1963  Status = SampSetObjectAttributeString(DomainObject,
1964  L"ReplicaSourceNodeName",
1965  &DomainInformation->Replication.ReplicaSourceNodeName);
1966  break;
1967 
1969  Status = SampSetDomainServerRole(DomainObject,
1970  DomainInformation);
1971  break;
1972 
1974  Status = SampSetDomainState(DomainObject,
1975  DomainInformation);
1976  break;
1977 
1979  Status = SampSetDomainLockout(DomainObject,
1980  DomainInformation);
1981  break;
1982 
1983  default:
1985  }
1986 
1987 done:
1989 
1990  return Status;
1991 }
1992 
1993 
1994 /* Function 10 */
1995 NTSTATUS
1996 NTAPI
2000  OUT SAMPR_HANDLE *GroupHandle,
2001  OUT unsigned long *RelativeId)
2002 {
2003  SAM_DOMAIN_FIXED_DATA FixedDomainData;
2004  SAM_GROUP_FIXED_DATA FixedGroupData;
2005  PSAM_DB_OBJECT DomainObject;
2006  PSAM_DB_OBJECT GroupObject;
2008  ULONG SdSize = 0;
2009  ULONG ulSize;
2010  ULONG ulRid;
2011  WCHAR szRid[9];
2012  NTSTATUS Status;
2013 
2014  TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
2015  DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
2016 
2017  /* Map generic access rights */
2019  &GroupMapping);
2020 
2022  TRUE);
2023 
2024  /* Validate the domain handle */
2025  Status = SampValidateDbObject(DomainHandle,
2028  &DomainObject);
2029  if (!NT_SUCCESS(Status))
2030  {
2031  TRACE("failed with status 0x%08lx\n", Status);
2032  goto done;
2033  }
2034 
2035  /* Check the group account name */
2037  if (!NT_SUCCESS(Status))
2038  {
2039  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2040  goto done;
2041  }
2042 
2043  /* Check if the group name already exists in the domain */
2044  Status = SampCheckAccountNameInDomain(DomainObject,
2045  Name->Buffer);
2046  if (!NT_SUCCESS(Status))
2047  {
2048  TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
2049  Name->Buffer, Status);
2050  goto done;
2051  }
2052 
2053  /* Create the security descriptor */
2054  Status = SampCreateGroupSD(&Sd,
2055  &SdSize);
2056  if (!NT_SUCCESS(Status))
2057  {
2058  TRACE("SampCreateGroupSD failed (Status 0x%08lx)\n", Status);
2059  goto done;
2060  }
2061 
2062  /* Get the fixed domain attributes */
2063  ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2064  Status = SampGetObjectAttribute(DomainObject,
2065  L"F",
2066  NULL,
2067  (PVOID)&FixedDomainData,
2068  &ulSize);
2069  if (!NT_SUCCESS(Status))
2070  {
2071  TRACE("failed with status 0x%08lx\n", Status);
2072  goto done;
2073  }
2074 
2075  /* Increment the NextRid attribute */
2076  ulRid = FixedDomainData.NextRid;
2077  FixedDomainData.NextRid++;
2078 
2079  /* Store the fixed domain attributes */
2080  Status = SampSetObjectAttribute(DomainObject,
2081  L"F",
2082  REG_BINARY,
2083  &FixedDomainData,
2084  ulSize);
2085  if (!NT_SUCCESS(Status))
2086  {
2087  TRACE("failed with status 0x%08lx\n", Status);
2088  goto done;
2089  }
2090 
2091  TRACE("RID: %lx\n", ulRid);
2092 
2093  /* Convert the RID into a string (hex) */
2094  swprintf(szRid, L"%08lX", ulRid);
2095 
2096  /* Create the group object */
2097  Status = SampCreateDbObject(DomainObject,
2098  L"Groups",
2099  szRid,
2100  ulRid,
2102  DesiredAccess,
2103  &GroupObject);
2104  if (!NT_SUCCESS(Status))
2105  {
2106  TRACE("failed with status 0x%08lx\n", Status);
2107  goto done;
2108  }
2109 
2110  /* Add the account name of the user object */
2111  Status = SampSetAccountNameInDomain(DomainObject,
2112  L"Groups",
2113  Name->Buffer,
2114  ulRid);
2115  if (!NT_SUCCESS(Status))
2116  {
2117  TRACE("failed with status 0x%08lx\n", Status);
2118  goto done;
2119  }
2120 
2121  /* Initialize fixed user data */
2122  memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
2123  FixedGroupData.Version = 1;
2124  FixedGroupData.GroupId = ulRid;
2125 
2126  /* Set fixed user data attribute */
2127  Status = SampSetObjectAttribute(GroupObject,
2128  L"F",
2129  REG_BINARY,
2130  (LPVOID)&FixedGroupData,
2131  sizeof(SAM_GROUP_FIXED_DATA));
2132  if (!NT_SUCCESS(Status))
2133  {
2134  TRACE("failed with status 0x%08lx\n", Status);
2135  goto done;
2136  }
2137 
2138  /* Set the Name attribute */
2139  Status = SampSetObjectAttributeString(GroupObject,
2140  L"Name",
2141  Name);
2142  if (!NT_SUCCESS(Status))
2143  {
2144  TRACE("failed with status 0x%08lx\n", Status);
2145  goto done;
2146  }
2147 
2148  /* Set the AdminComment attribute */
2149  Status = SampSetObjectAttributeString(GroupObject,
2150  L"AdminComment",
2151  NULL);
2152  if (!NT_SUCCESS(Status))
2153  {
2154  TRACE("failed with status 0x%08lx\n", Status);
2155  goto done;
2156  }
2157 
2158  /* Set the SecDesc attribute*/
2159  Status = SampSetObjectAttribute(GroupObject,
2160  L"SecDesc",
2161  REG_BINARY,
2162  Sd,
2163  SdSize);
2164  if (!NT_SUCCESS(Status))
2165  {
2166  TRACE("failed with status 0x%08lx\n", Status);
2167  goto done;
2168  }
2169 
2170  if (NT_SUCCESS(Status))
2171  {
2172  *GroupHandle = (SAMPR_HANDLE)GroupObject;
2173  *RelativeId = ulRid;
2174  }
2175 
2176 done:
2177  if (Sd != NULL)
2178  RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2179 
2181 
2182  TRACE("returns with status 0x%08lx\n", Status);
2183 
2184  return Status;
2185 }
2186 
2187 
2188 /* Function 11 */
2189 NTSTATUS
2190 NTAPI
2192  IN OUT unsigned long *EnumerationContext,
2194  IN unsigned long PreferedMaximumLength,
2195  OUT unsigned long *CountReturned)
2196 {
2197  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2198  PSAM_DB_OBJECT DomainObject;
2199  HANDLE GroupsKeyHandle = NULL;
2200  HANDLE NamesKeyHandle = NULL;
2201  WCHAR GroupName[64];
2202  ULONG EnumIndex;
2203  ULONG EnumCount = 0;
2204  ULONG RequiredLength = 0;
2205  ULONG NameLength;
2206  ULONG DataLength;
2207  ULONG Rid;
2208  ULONG i;
2209  BOOLEAN MoreEntries = FALSE;
2210  NTSTATUS Status;
2211 
2212  TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
2213  DomainHandle, EnumerationContext, Buffer,
2214  PreferedMaximumLength, CountReturned);
2215 
2217  TRUE);
2218 
2219  /* Validate the domain handle */
2220  Status = SampValidateDbObject(DomainHandle,
2223  &DomainObject);
2224  if (!NT_SUCCESS(Status))
2225  goto done;
2226 
2227  Status = SampRegOpenKey(DomainObject->KeyHandle,
2228  L"Groups",
2229  KEY_READ,
2230  &GroupsKeyHandle);
2231  if (!NT_SUCCESS(Status))
2232  goto done;
2233 
2234  Status = SampRegOpenKey(GroupsKeyHandle,
2235  L"Names",
2236  KEY_READ,
2237  &NamesKeyHandle);
2238  if (!NT_SUCCESS(Status))
2239  goto done;
2240 
2241  TRACE("Part 1\n");
2242 
2243  EnumIndex = *EnumerationContext;
2244 
2245  while (TRUE)
2246  {
2247  NameLength = 64 * sizeof(WCHAR);
2248  Status = SampRegEnumerateValue(NamesKeyHandle,
2249  EnumIndex,
2250  GroupName,
2251  &NameLength,
2252  NULL,
2253  NULL,
2254  NULL);
2255  if (!NT_SUCCESS(Status))
2256  {
2259  break;
2260  }
2261 
2262  TRACE("EnumIndex: %lu\n", EnumIndex);
2263  TRACE("Group name: %S\n", GroupName);
2264  TRACE("Name length: %lu\n", NameLength);
2265 
2266  if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2267  {
2268  MoreEntries = TRUE;
2269  break;
2270  }
2271 
2272  RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2273  EnumCount++;
2274 
2275  EnumIndex++;
2276  }
2277 
2278  TRACE("EnumCount: %lu\n", EnumCount);
2279  TRACE("RequiredLength: %lu\n", RequiredLength);
2280 
2281  if (!NT_SUCCESS(Status))
2282  goto done;
2283 
2284  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2285  if (EnumBuffer == NULL)
2286  {
2288  goto done;
2289  }
2290 
2291  EnumBuffer->EntriesRead = EnumCount;
2292  if (EnumCount == 0)
2293  goto done;
2294 
2295  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2296  if (EnumBuffer->Buffer == NULL)
2297  {
2299  goto done;
2300  }
2301 
2302  TRACE("Part 2\n");
2303 
2304  EnumIndex = *EnumerationContext;
2305  for (i = 0; i < EnumCount; i++, EnumIndex++)
2306  {
2307  NameLength = 64 * sizeof(WCHAR);
2308  DataLength = sizeof(ULONG);
2309  Status = SampRegEnumerateValue(NamesKeyHandle,
2310  EnumIndex,
2311  GroupName,
2312  &NameLength,
2313  NULL,
2314  &Rid,
2315  &DataLength);
2316  if (!NT_SUCCESS(Status))
2317  {
2320  break;
2321  }
2322 
2323  TRACE("EnumIndex: %lu\n", EnumIndex);
2324  TRACE("Group name: %S\n", GroupName);
2325  TRACE("Name length: %lu\n", NameLength);
2326  TRACE("RID: %lu\n", Rid);
2327 
2328  EnumBuffer->Buffer[i].RelativeId = Rid;
2329 
2330  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2331  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2332 
2333 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2334 #if 0
2335  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2336  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2337  {
2339  goto done;
2340  }
2341 
2342  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2343  GroupName,
2344  EnumBuffer->Buffer[i].Name.Length);
2345 #endif
2346  }
2347 
2348 done:
2349  if (NT_SUCCESS(Status))
2350  {
2351  *EnumerationContext += EnumCount;
2352  *Buffer = EnumBuffer;
2353  *CountReturned = EnumCount;
2354  }
2355  else
2356  {
2357  *EnumerationContext = 0;
2358  *Buffer = NULL;
2359  *CountReturned = 0;
2360 
2361  if (EnumBuffer != NULL)
2362  {
2363  if (EnumBuffer->Buffer != NULL)
2364  {
2365  if (EnumBuffer->EntriesRead != 0)
2366  {
2367  for (i = 0; i < EnumBuffer->EntriesRead; i++)
2368  {
2369  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2370  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2371  }
2372  }
2373 
2374  midl_user_free(EnumBuffer->Buffer);
2375  }
2376 
2377  midl_user_free(EnumBuffer);
2378  }
2379  }
2380 
2381  SampRegCloseKey(&NamesKeyHandle);
2382  SampRegCloseKey(&GroupsKeyHandle);
2383 
2384  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2386 
2388 
2389  return Status;
2390 }
2391 
2392 
2393 /* Function 12 */
2394 NTSTATUS
2395 NTAPI
2399  OUT SAMPR_HANDLE *UserHandle,
2400  OUT unsigned long *RelativeId)
2401 {
2402  SAM_DOMAIN_FIXED_DATA FixedDomainData;
2403  SAM_USER_FIXED_DATA FixedUserData;
2404  PSAM_DB_OBJECT DomainObject;
2405  PSAM_DB_OBJECT UserObject;
2406  GROUP_MEMBERSHIP GroupMembership;
2407  UCHAR LogonHours[23];
2408  ULONG ulSize;
2409  ULONG ulRid;
2410  WCHAR szRid[9];
2412  ULONG SdSize = 0;
2413  PSID UserSid = NULL;
2414  NTSTATUS Status;
2415 
2416  TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2417  DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2418 
2419  if (Name == NULL ||
2420  Name->Length == 0 ||
2421  Name->Buffer == NULL ||
2422  UserHandle == NULL ||
2423  RelativeId == NULL)
2424  return STATUS_INVALID_PARAMETER;
2425 
2426  /* Map generic access rights */
2428  &UserMapping);
2429 
2431  TRUE);
2432 
2433  /* Validate the domain handle */
2434  Status = SampValidateDbObject(DomainHandle,
2437  &DomainObject);
2438  if (!NT_SUCCESS(Status))
2439  {
2440  TRACE("failed with status 0x%08lx\n", Status);
2441  goto done;
2442  }
2443 
2444  /* Check the user account name */
2446  if (!NT_SUCCESS(Status))
2447  {
2448  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2449  goto done;
2450  }
2451 
2452  /* Check if the user name already exists in the domain */
2453  Status = SampCheckAccountNameInDomain(DomainObject,
2454  Name->Buffer);
2455  if (!NT_SUCCESS(Status))
2456  {
2457  TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2458  Name->Buffer, Status);
2459  goto done;
2460  }
2461 
2462  /* Get the fixed domain attributes */
2463  ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2464  Status = SampGetObjectAttribute(DomainObject,
2465  L"F",
2466  NULL,
2467  (PVOID)&FixedDomainData,
2468  &ulSize);
2469  if (!NT_SUCCESS(Status))
2470  {
2471  TRACE("failed with status 0x%08lx\n", Status);
2472  goto done;
2473  }
2474 
2475  /* Increment the NextRid attribute */
2476  ulRid = FixedDomainData.NextRid;
2477  FixedDomainData.NextRid++;
2478 
2479  TRACE("RID: %lx\n", ulRid);
2480 
2481  /* Create the user SID */
2482  Status = SampCreateAccountSid(DomainObject,
2483  ulRid,
2484  &UserSid);
2485  if (!NT_SUCCESS(Status))
2486  {
2487  TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
2488  goto done;
2489  }
2490 
2491  /* Create the security descriptor */
2492  Status = SampCreateUserSD(UserSid,
2493  &Sd,
2494  &SdSize);
2495  if (!NT_SUCCESS(Status))
2496  {
2497  TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
2498  goto done;
2499  }
2500 
2501  /* Store the fixed domain attributes */
2502  Status = SampSetObjectAttribute(DomainObject,
2503  L"F",
2504  REG_BINARY,
2505  &FixedDomainData,
2506  ulSize);
2507  if (!NT_SUCCESS(Status))
2508  {
2509  TRACE("failed with status 0x%08lx\n", Status);
2510  goto done;
2511  }
2512 
2513  /* Convert the RID into a string (hex) */
2514  swprintf(szRid, L"%08lX", ulRid);
2515 
2516  /* Create the user object */
2517  Status = SampCreateDbObject(DomainObject,
2518  L"Users",
2519  szRid,
2520  ulRid,
2522  DesiredAccess,
2523  &UserObject);
2524  if (!NT_SUCCESS(Status))
2525  {
2526  TRACE("failed with status 0x%08lx\n", Status);
2527  goto done;
2528  }
2529 
2530  /* Add the account name for the user object */
2531  Status = SampSetAccountNameInDomain(DomainObject,
2532  L"Users",
2533  Name->Buffer,
2534  ulRid);
2535  if (!NT_SUCCESS(Status))
2536  {
2537  TRACE("failed with status 0x%08lx\n", Status);
2538  goto done;
2539  }
2540 
2541  /* Initialize fixed user data */
2542  memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2543  FixedUserData.Version = 1;
2544  FixedUserData.Reserved = 0;
2545  FixedUserData.LastLogon.QuadPart = 0;
2546  FixedUserData.LastLogoff.QuadPart = 0;
2547  FixedUserData.PasswordLastSet.QuadPart = 0;
2548  FixedUserData.AccountExpires.QuadPart = MAXLONGLONG;
2549  FixedUserData.LastBadPasswordTime.QuadPart = 0;
2550  FixedUserData.UserId = ulRid;
2551  FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2552  FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2555  FixedUserData.CountryCode = 0;
2556  FixedUserData.CodePage = 0;
2557  FixedUserData.BadPasswordCount = 0;
2558  FixedUserData.LogonCount = 0;
2559  FixedUserData.AdminCount = 0;
2560  FixedUserData.OperatorCount = 0;
2561 
2562  /* Set fixed user data attribute */
2563  Status = SampSetObjectAttribute(UserObject,
2564  L"F",
2565  REG_BINARY,
2566  (LPVOID)&FixedUserData,
2567  sizeof(SAM_USER_FIXED_DATA));
2568  if (!NT_SUCCESS(Status))
2569  {
2570  TRACE("failed with status 0x%08lx\n", Status);
2571  goto done;
2572  }
2573 
2574  /* Set the Name attribute */
2575  Status = SampSetObjectAttributeString(UserObject,
2576  L"Name",
2577  Name);
2578  if (!NT_SUCCESS(Status))
2579  {
2580  TRACE("failed with status 0x%08lx\n", Status);
2581  goto done;
2582  }
2583 
2584  /* Set the FullName attribute */
2585  Status = SampSetObjectAttributeString(UserObject,
2586  L"FullName",
2587  NULL);
2588  if (!NT_SUCCESS(Status))
2589  {
2590  TRACE("failed with status 0x%08lx\n", Status);
2591  goto done;
2592  }
2593 
2594  /* Set the HomeDirectory attribute */
2595  Status = SampSetObjectAttributeString(UserObject,
2596  L"HomeDirectory",
2597  NULL);
2598  if (!NT_SUCCESS(Status))
2599  {
2600  TRACE("failed with status 0x%08lx\n", Status);
2601  goto done;
2602  }
2603 
2604  /* Set the HomeDirectoryDrive attribute */
2605  Status = SampSetObjectAttributeString(UserObject,
2606  L"HomeDirectoryDrive",
2607  NULL);
2608  if (!NT_SUCCESS(Status))
2609  {
2610  TRACE("failed with status 0x%08lx\n", Status);
2611  goto done;
2612  }
2613 
2614  /* Set the ScriptPath attribute */
2615  Status = SampSetObjectAttributeString(UserObject,
2616  L"ScriptPath",
2617  NULL);
2618  if (!NT_SUCCESS(Status))
2619  {
2620  TRACE("failed with status 0x%08lx\n", Status);
2621  goto done;
2622  }
2623 
2624  /* Set the ProfilePath attribute */
2625  Status = SampSetObjectAttributeString(UserObject,
2626  L"ProfilePath",
2627  NULL);
2628  if (!NT_SUCCESS(Status))
2629  {
2630  TRACE("failed with status 0x%08lx\n", Status);
2631  goto done;
2632  }
2633 
2634  /* Set the AdminComment attribute */
2635  Status = SampSetObjectAttributeString(UserObject,
2636  L"AdminComment",
2637  NULL);
2638  if (!NT_SUCCESS(Status))
2639  {
2640  TRACE("failed with status 0x%08lx\n", Status);
2641  goto done;
2642  }
2643 
2644  /* Set the UserComment attribute */
2645  Status = SampSetObjectAttributeString(UserObject,
2646  L"UserComment",
2647  NULL);
2648  if (!NT_SUCCESS(Status))
2649  {
2650  TRACE("failed with status 0x%08lx\n", Status);
2651  goto done;
2652  }
2653 
2654  /* Set the WorkStations attribute */
2655  Status = SampSetObjectAttributeString(UserObject,
2656  L"WorkStations",
2657  NULL);
2658  if (!NT_SUCCESS(Status))
2659  {
2660  TRACE("failed with status 0x%08lx\n", Status);
2661  goto done;
2662  }
2663 
2664  /* Set the Parameters attribute */
2665  Status = SampSetObjectAttributeString(UserObject,
2666  L"Parameters",
2667  NULL);
2668  if (!NT_SUCCESS(Status))
2669  {
2670  TRACE("failed with status 0x%08lx\n", Status);
2671  goto done;
2672  }
2673 
2674  /* Set LogonHours attribute*/
2675  *((PUSHORT)LogonHours) = 168;
2676  memset(&(LogonHours[2]), 0xff, 21);
2677 
2678  Status = SampSetObjectAttribute(UserObject,
2679  L"LogonHours",
2680  REG_BINARY,
2681  &LogonHours,
2682  sizeof(LogonHours));
2683  if (!NT_SUCCESS(Status))
2684  {
2685  TRACE("failed with status 0x%08lx\n", Status);
2686  goto done;
2687  }
2688 
2689  /* Set Groups attribute*/
2690  GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2691  GroupMembership.Attributes = SE_GROUP_MANDATORY |
2694 
2695  Status = SampSetObjectAttribute(UserObject,
2696  L"Groups",
2697  REG_BINARY,
2698  &GroupMembership,
2699  sizeof(GROUP_MEMBERSHIP));
2700  if (!NT_SUCCESS(Status))
2701  {
2702  TRACE("failed with status 0x%08lx\n", Status);
2703  goto done;
2704  }
2705 
2706  /* Set LMPwd attribute*/
2707  Status = SampSetObjectAttribute(UserObject,
2708  L"LMPwd",
2709  REG_BINARY,
2710  &EmptyLmHash,
2711  sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2712  if (!NT_SUCCESS(Status))
2713  {
2714  TRACE("failed with status 0x%08lx\n", Status);
2715  goto done;
2716  }
2717 
2718  /* Set NTPwd attribute*/
2719  Status = SampSetObjectAttribute(UserObject,
2720  L"NTPwd",
2721  REG_BINARY,
2722  &EmptyNtHash,
2723  sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2724  if (!NT_SUCCESS(Status))
2725  {
2726  TRACE("failed with status 0x%08lx\n", Status);
2727  goto done;
2728  }
2729 
2730  /* Set LMPwdHistory attribute*/
2731  Status = SampSetObjectAttribute(UserObject,
2732  L"LMPwdHistory",
2733  REG_BINARY,
2734  NULL,
2735  0);
2736  if (!NT_SUCCESS(Status))
2737  {
2738  TRACE("failed with status 0x%08lx\n", Status);
2739  goto done;
2740  }
2741 
2742  /* Set NTPwdHistory attribute*/
2743  Status = SampSetObjectAttribute(UserObject,
2744  L"NTPwdHistory",
2745  REG_BINARY,
2746  NULL,
2747  0);
2748  if (!NT_SUCCESS(Status))
2749  {
2750  TRACE("failed with status 0x%08lx\n", Status);
2751  goto done;
2752  }
2753 
2754  /* Set the PrivateData attribute */
2755  Status = SampSetObjectAttributeString(UserObject,
2756  L"PrivateData",
2757  NULL);
2758  if (!NT_SUCCESS(Status))
2759  {
2760  TRACE("failed with status 0x%08lx\n", Status);
2761  goto done;
2762  }
2763 
2764  /* Set the SecDesc attribute*/
2765  Status = SampSetObjectAttribute(UserObject,
2766  L"SecDesc",
2767  REG_BINARY,
2768  Sd,
2769  SdSize);
2770  if (!NT_SUCCESS(Status))
2771  {
2772  TRACE("failed with status 0x%08lx\n", Status);
2773  goto done;
2774  }
2775 
2776  if (NT_SUCCESS(Status))
2777  {
2778  *UserHandle = (SAMPR_HANDLE)UserObject;
2779  *RelativeId = ulRid;
2780  }
2781 
2782 done:
2783  if (Sd != NULL)
2784  RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2785 
2786  if (UserSid != NULL)
2787  RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2788 
2790 
2791  TRACE("returns with status 0x%08lx\n", Status);
2792 
2793  return Status;
2794 }
2795 
2796 
2797 /* Function 13 */
2798 NTSTATUS
2799 NTAPI
2801  IN OUT unsigned long *EnumerationContext,
2802  IN unsigned long UserAccountControl,
2804  IN unsigned long PreferedMaximumLength,
2805  OUT unsigned long *CountReturned)
2806 {
2807  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2808  PSAM_DB_OBJECT DomainObject;
2809  HANDLE UsersKeyHandle = NULL;
2810  HANDLE NamesKeyHandle = NULL;
2811  WCHAR UserName[64];
2812  ULONG EnumIndex;
2813  ULONG EnumCount = 0;
2814  ULONG RequiredLength = 0;
2815  ULONG NameLength;
2816  ULONG DataLength;
2817  ULONG Rid;
2818  ULONG i;
2819  BOOLEAN MoreEntries = FALSE;
2820  NTSTATUS Status;
2821 
2822  TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2823  DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2824  PreferedMaximumLength, CountReturned);
2825 
2827  TRUE);
2828 
2829  /* Validate the domain handle */
2830  Status = SampValidateDbObject(DomainHandle,
2833  &DomainObject);
2834  if (!NT_SUCCESS(Status))
2835  goto done;
2836 
2837  Status = SampRegOpenKey(DomainObject->KeyHandle,
2838  L"Users",
2839  KEY_READ,
2840  &UsersKeyHandle);
2841  if (!NT_SUCCESS(Status))
2842  goto done;
2843 
2844  Status = SampRegOpenKey(UsersKeyHandle,
2845  L"Names",
2846  KEY_READ,
2847  &NamesKeyHandle);
2848  if (!NT_SUCCESS(Status))
2849  goto done;
2850 
2851  TRACE("Part 1\n");
2852 
2853  EnumIndex = *EnumerationContext;
2854 
2855  while (TRUE)
2856  {
2857  NameLength = 64 * sizeof(WCHAR);
2858  Status = SampRegEnumerateValue(NamesKeyHandle,
2859  EnumIndex,
2860  UserName,
2861  &NameLength,
2862  NULL,
2863  NULL,
2864  NULL);
2865  if (!NT_SUCCESS(Status))
2866  {
2869  break;
2870  }
2871 
2872  TRACE("EnumIndex: %lu\n", EnumIndex);
2873  TRACE("User name: %S\n", UserName);
2874  TRACE("Name length: %lu\n", NameLength);
2875 
2876  if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2877  {
2878  MoreEntries = TRUE;
2879  break;
2880  }
2881 
2882  RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2883  EnumCount++;
2884 
2885  EnumIndex++;
2886  }
2887 
2888  TRACE("EnumCount: %lu\n", EnumCount);
2889  TRACE("RequiredLength: %lu\n", RequiredLength);
2890 
2891  if (!NT_SUCCESS(Status))
2892  goto done;
2893 
2894  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2895  if (EnumBuffer == NULL)
2896  {
2898  goto done;
2899  }
2900 
2901  EnumBuffer->EntriesRead = EnumCount;
2902  if (EnumCount == 0)
2903  goto done;
2904 
2905  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2906  if (EnumBuffer->Buffer == NULL)
2907  {
2909  goto done;
2910  }
2911 
2912  TRACE("Part 2\n");
2913 
2914  EnumIndex = *EnumerationContext;
2915  for (i = 0; i < EnumCount; i++, EnumIndex++)
2916  {
2917  NameLength = 64 * sizeof(WCHAR);
2918  DataLength = sizeof(ULONG);
2919  Status = SampRegEnumerateValue(NamesKeyHandle,
2920  EnumIndex,
2921  UserName,
2922  &NameLength,
2923  NULL,
2924  &Rid,
2925  &DataLength);
2926  if (!NT_SUCCESS(Status))
2927  {
2930  break;
2931  }
2932 
2933  TRACE("EnumIndex: %lu\n", EnumIndex);
2934  TRACE("User name: %S\n", UserName);
2935  TRACE("Name length: %lu\n", NameLength);
2936  TRACE("RID: %lu\n", Rid);
2937 
2938  EnumBuffer->Buffer[i].RelativeId = Rid;
2939 
2940  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2941  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2942 
2943 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2944 #if 0
2945  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2946  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2947  {
2949  goto done;
2950  }
2951 
2952  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2953  UserName,
2954  EnumBuffer->Buffer[i].Name.Length);
2955 #endif
2956  }
2957 
2958 done:
2959  if (NT_SUCCESS(Status))
2960  {
2961  *EnumerationContext += EnumCount;
2962  *Buffer = EnumBuffer;
2963  *CountReturned = EnumCount;
2964  }
2965  else
2966  {
2967  *EnumerationContext = 0;
2968  *Buffer = NULL;
2969  *CountReturned = 0;
2970 
2971  if (EnumBuffer != NULL)
2972  {
2973  if (EnumBuffer->Buffer != NULL)
2974  {
2975  if (EnumBuffer->EntriesRead != 0)
2976  {
2977  for (i = 0; i < EnumBuffer->EntriesRead; i++)
2978  {
2979  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2980  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2981  }
2982  }
2983 
2984  midl_user_free(EnumBuffer->Buffer);
2985  }
2986 
2987  midl_user_free(EnumBuffer);
2988  }
2989  }
2990 
2991  SampRegCloseKey(&NamesKeyHandle);
2992  SampRegCloseKey(&UsersKeyHandle);
2993 
2994  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2996 
2998 
2999  return Status;
3000 }
3001 
3002 
3003 /* Function 14 */
3004 NTSTATUS
3005 NTAPI
3007  IN PRPC_UNICODE_STRING AccountName,
3009  OUT SAMPR_HANDLE *AliasHandle,
3010  OUT unsigned long *RelativeId)
3011 {
3012  SAM_DOMAIN_FIXED_DATA FixedDomainData;
3013  PSAM_DB_OBJECT DomainObject;
3014  PSAM_DB_OBJECT AliasObject;
3016  ULONG SdSize = 0;
3017  ULONG ulSize;
3018  ULONG ulRid;
3019  WCHAR szRid[9];
3020  NTSTATUS Status;
3021 
3022  TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
3023  DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
3024 
3025  /* Map generic access rights */
3027  &AliasMapping);
3028 
3030  TRUE);
3031 
3032  /* Validate the domain handle */
3033  Status = SampValidateDbObject(DomainHandle,
3036  &DomainObject);
3037  if (!NT_SUCCESS(Status))
3038  {
3039  TRACE("failed with status 0x%08lx\n", Status);
3040  goto done;
3041  }
3042 
3043  /* Check the alias account name */
3044  Status = SampCheckAccountName(AccountName, 256);
3045  if (!NT_SUCCESS(Status))
3046  {
3047  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
3048  goto done;
3049  }
3050 
3051  /* Check if the alias name already exists in the domain */
3052  Status = SampCheckAccountNameInDomain(DomainObject,
3053  AccountName->Buffer);
3054  if (!NT_SUCCESS(Status))
3055  {
3056  TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
3057  AccountName->Buffer, Status);
3058  goto done;
3059  }
3060 
3061  /* Create the security descriptor */
3062  Status = SampCreateAliasSD(&Sd,
3063  &SdSize);
3064  if (!NT_SUCCESS(Status))
3065  {
3066  TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
3067  goto done;
3068  }
3069 
3070  /* Get the fixed domain attributes */
3071  ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
3072  Status = SampGetObjectAttribute(DomainObject,
3073  L"F",
3074  NULL,
3075  (PVOID)&FixedDomainData,
3076  &ulSize);
3077  if (!NT_SUCCESS(Status))
3078  {
3079  TRACE("failed with status 0x%08lx\n", Status);
3080  goto done;
3081  }
3082 
3083  /* Increment the NextRid attribute */
3084  ulRid = FixedDomainData.NextRid;
3085  FixedDomainData.NextRid++;
3086 
3087  /* Store the fixed domain attributes */
3088  Status = SampSetObjectAttribute(DomainObject,
3089  L"F",
3090  REG_BINARY,
3091  &FixedDomainData,
3092  ulSize);
3093  if (!NT_SUCCESS(Status))
3094  {
3095  TRACE("failed with status 0x%08lx\n", Status);
3096  goto done;
3097  }
3098 
3099  TRACE("RID: %lx\n", ulRid);
3100 
3101  /* Convert the RID into a string (hex) */
3102  swprintf(szRid, L"%08lX", ulRid);
3103 
3104  /* Create the alias object */
3105  Status = SampCreateDbObject(DomainObject,
3106  L"Aliases",
3107  szRid,
3108  ulRid,
3110  DesiredAccess,
3111  &AliasObject);
3112  if (!NT_SUCCESS(Status))
3113  {
3114  TRACE("failed with status 0x%08lx\n", Status);
3115  goto done;
3116  }
3117 
3118  /* Add the account name for the alias object */
3119  Status = SampSetAccountNameInDomain(DomainObject,
3120  L"Aliases",
3121  AccountName->Buffer,
3122  ulRid);
3123  if (!NT_SUCCESS(Status))
3124  {
3125  TRACE("failed with status 0x%08lx\n", Status);
3126  goto done;
3127  }
3128 
3129  /* Set the Name attribute */
3130  Status = SampSetObjectAttributeString(AliasObject,
3131  L"Name",
3132  AccountName);
3133  if (!NT_SUCCESS(Status))
3134  {
3135  TRACE("failed with status 0x%08lx\n", Status);
3136  goto done;
3137  }
3138 
3139  /* Set the Description attribute */
3140  Status = SampSetObjectAttributeString(AliasObject,
3141  L"Description",
3142  NULL);
3143  if (!NT_SUCCESS(Status))
3144  {
3145  TRACE("failed with status 0x%08lx\n", Status);
3146  goto done;
3147  }
3148 
3149  /* Set the SecDesc attribute*/
3150  Status = SampSetObjectAttribute(AliasObject,
3151  L"SecDesc",
3152  REG_BINARY,
3153  Sd,
3154  SdSize);
3155  if (!NT_SUCCESS(Status))
3156  {
3157  TRACE("failed with status 0x%08lx\n", Status);
3158  goto done;
3159  }
3160 
3161  if (NT_SUCCESS(Status))
3162  {
3163  *AliasHandle = (SAMPR_HANDLE)AliasObject;
3164  *RelativeId = ulRid;
3165  }
3166 
3167 done:
3168  if (Sd != NULL)
3169  RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
3170 
3172 
3173  TRACE("returns with status 0x%08lx\n", Status);
3174 
3175  return Status;
3176 }
3177 
3178 
3179 /* Function 15 */
3180 NTSTATUS
3181 NTAPI
3183  IN OUT unsigned long *EnumerationContext,
3185  IN unsigned long PreferedMaximumLength,
3186  OUT unsigned long *CountReturned)
3187 {
3188  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
3189  PSAM_DB_OBJECT DomainObject;
3190  HANDLE AliasesKeyHandle = NULL;
3191  HANDLE NamesKeyHandle = NULL;
3192  WCHAR AliasName[64];
3193  ULONG EnumIndex;
3194  ULONG EnumCount = 0;
3195  ULONG RequiredLength = 0;
3196  ULONG NameLength;
3197  ULONG DataLength;
3198  ULONG Rid;
3199  ULONG i;
3200  BOOLEAN MoreEntries = FALSE;
3201  NTSTATUS Status;
3202 
3203  TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
3204  DomainHandle, EnumerationContext, Buffer,
3205  PreferedMaximumLength, CountReturned);
3206 
3208  TRUE);
3209 
3210  /* Validate the domain handle */
3211  Status = SampValidateDbObject(DomainHandle,
3214  &DomainObject);
3215  if (!NT_SUCCESS(Status))
3216  goto done;
3217 
3218  Status = SampRegOpenKey(DomainObject->KeyHandle,
3219  L"Aliases",
3220  KEY_READ,
3221  &AliasesKeyHandle);
3222  if (!NT_SUCCESS(Status))
3223  goto done;
3224 
3225  Status = SampRegOpenKey(AliasesKeyHandle,
3226  L"Names",
3227  KEY_READ,
3228  &NamesKeyHandle);
3229  if (!NT_SUCCESS(Status))
3230  goto done;
3231 
3232  TRACE("Part 1\n");
3233 
3234  EnumIndex = *EnumerationContext;
3235 
3236  while (TRUE)
3237  {
3238  NameLength = 64 * sizeof(WCHAR);
3239  Status = SampRegEnumerateValue(NamesKeyHandle,
3240  EnumIndex,
3241  AliasName,
3242  &NameLength,
3243  NULL,
3244  NULL,
3245  NULL);
3246  if (!NT_SUCCESS(Status))
3247  {
3250  break;
3251  }
3252 
3253  TRACE("EnumIndex: %lu\n", EnumIndex);
3254  TRACE("Alias name: %S\n", AliasName);
3255  TRACE("Name length: %lu\n", NameLength);
3256 
3257  if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3258  {
3259  MoreEntries = TRUE;
3260  break;
3261  }
3262 
3263  RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3264  EnumCount++;
3265 
3266  EnumIndex++;
3267  }
3268 
3269  TRACE("EnumCount: %lu\n", EnumCount);
3270  TRACE("RequiredLength: %lu\n", RequiredLength);
3271 
3272  if (!NT_SUCCESS(Status))
3273  goto done;
3274 
3275  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3276  if (EnumBuffer == NULL)
3277  {
3279  goto done;
3280  }
3281 
3282  EnumBuffer->EntriesRead = EnumCount;
3283  if (EnumCount == 0)
3284  goto done;
3285 
3286  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3287  if (EnumBuffer->Buffer == NULL)
3288  {
3290  goto done;
3291  }
3292 
3293  TRACE("Part 2\n");
3294 
3295  EnumIndex = *EnumerationContext;
3296  for (i = 0; i < EnumCount; i++, EnumIndex++)
3297  {
3298  NameLength = 64 * sizeof(WCHAR);
3299  DataLength = sizeof(ULONG);
3300  Status = SampRegEnumerateValue(NamesKeyHandle,
3301  EnumIndex,
3302  AliasName,
3303  &NameLength,
3304  NULL,
3305  &Rid,
3306  &DataLength);
3307  if (!NT_SUCCESS(Status))
3308  {
3311  break;
3312  }
3313 
3314  TRACE("EnumIndex: %lu\n", EnumIndex);
3315  TRACE("Alias name: %S\n", AliasName);
3316  TRACE("Name length: %lu\n", NameLength);
3317  TRACE("RID: %lu\n", Rid);
3318 
3319  EnumBuffer->Buffer[i].RelativeId = Rid;
3320 
3321  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3322  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
3323 
3324 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3325 #if 0
3326  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3327  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3328  {
3330  goto done;
3331  }
3332 
3333  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3334  AliasName,
3335  EnumBuffer->Buffer[i].Name.Length);
3336 #endif
3337  }
3338 
3339 done:
3340  if (NT_SUCCESS(Status))
3341  {
3342  *EnumerationContext += EnumCount;
3343  *Buffer = EnumBuffer;
3344  *CountReturned = EnumCount;
3345  }
3346  else
3347  {
3348  *EnumerationContext = 0;
3349  *Buffer = NULL;
3350  *CountReturned = 0;
3351 
3352  if (EnumBuffer != NULL)
3353  {
3354  if (EnumBuffer->Buffer != NULL)
3355  {
3356  if (EnumBuffer->EntriesRead != 0)
3357  {
3358  for (i = 0; i < EnumBuffer->EntriesRead; i++)
3359  {
3360  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3361  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3362  }
3363  }
3364 
3365  midl_user_free(EnumBuffer->Buffer);
3366  }
3367 
3368  midl_user_free(EnumBuffer);
3369  }
3370  }
3371 
3372  SampRegCloseKey(&NamesKeyHandle);
3373  SampRegCloseKey(&AliasesKeyHandle);
3374 
3375  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3377 
3379 
3380  return Status;
3381 }
3382 
3383 
3384 /* Function 16 */
3385 NTSTATUS
3386 NTAPI
3388  IN PSAMPR_PSID_ARRAY SidArray,
3389  OUT PSAMPR_ULONG_ARRAY Membership)
3390 {
3391  PSAM_DB_OBJECT DomainObject;
3392  HANDLE AliasesKeyHandle = NULL;
3393  HANDLE MembersKeyHandle = NULL;
3394  HANDLE MemberKeyHandle = NULL;
3395  LPWSTR MemberSidString = NULL;
3396  PULONG RidArray = NULL;
3397  ULONG MaxSidCount = 0;
3398  ULONG ValueCount;
3399  ULONG DataLength;
3400  ULONG i, j;
3401  ULONG RidIndex;
3402  NTSTATUS Status;
3403  WCHAR NameBuffer[9];
3404 
3405  TRACE("SamrGetAliasMembership(%p %p %p)\n",
3406  DomainHandle, SidArray, Membership);
3407 
3409  TRUE);
3410 
3411  /* Validate the domain handle */
3412  Status = SampValidateDbObject(DomainHandle,
3415  &DomainObject);
3416  if (!NT_SUCCESS(Status))
3417  goto done;
3418 
3419  Status = SampRegOpenKey(DomainObject->KeyHandle,
3420  L"Aliases",
3421  KEY_READ,
3422  &AliasesKeyHandle);
3423  TRACE("SampRegOpenKey returned %08lX\n", Status);
3424  if (!NT_SUCCESS(Status))
3425  goto done;
3426 
3427  Status = SampRegOpenKey(AliasesKeyHandle,
3428  L"Members",
3429  KEY_READ,
3430  &MembersKeyHandle);
3431  TRACE("SampRegOpenKey returned %08lX\n", Status);
3432 
3434  {
3436  goto done;
3437  }
3438 
3439  if (!NT_SUCCESS(Status))
3440  goto done;
3441 
3442  for (i = 0; i < SidArray->Count; i++)
3443  {
3444  ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3445 TRACE("Open %S\n", MemberSidString);
3446 
3447  Status = SampRegOpenKey(MembersKeyHandle,
3448  MemberSidString,
3449  KEY_READ,
3450  &MemberKeyHandle);
3451  TRACE("SampRegOpenKey returned %08lX\n", Status);
3452  if (NT_SUCCESS(Status))
3453  {
3454  Status = SampRegQueryKeyInfo(MemberKeyHandle,
3455  NULL,
3456  &ValueCount);
3457  if (NT_SUCCESS(Status))
3458  {
3459  TRACE("Found %lu values\n", ValueCount);
3460  MaxSidCount += ValueCount;
3461  }
3462 
3463  SampRegCloseKey(&MemberKeyHandle);
3464  }
3465 
3468 
3469  LocalFree(MemberSidString);
3470  }
3471 
3472  if (MaxSidCount == 0)
3473  {
3475  goto done;
3476  }
3477 
3478  TRACE("Maximum sid count: %lu\n", MaxSidCount);
3479  RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3480  if (RidArray == NULL)
3481  {
3483  goto done;
3484  }
3485 
3486  RidIndex = 0;
3487  for (i = 0; i < SidArray->Count; i++)
3488  {
3489  ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3490 TRACE("Open %S\n", MemberSidString);
3491 
3492  Status = SampRegOpenKey(MembersKeyHandle,
3493  MemberSidString,
3494  KEY_READ,
3495  &MemberKeyHandle);
3496  TRACE("SampRegOpenKey returned %08lX\n", Status);
3497  if (NT_SUCCESS(Status))
3498  {
3499  Status = SampRegQueryKeyInfo(MemberKeyHandle,
3500  NULL,
3501  &ValueCount);
3502  if (NT_SUCCESS(Status))
3503  {
3504  TRACE("Found %lu values\n", ValueCount);
3505 
3506  for (j = 0; j < ValueCount; j++)
3507  {
3508  DataLength = 9 * sizeof(WCHAR);
3509  Status = SampRegEnumerateValue(MemberKeyHandle,
3510  j,
3511  NameBuffer,
3512  &DataLength,
3513  NULL,
3514  NULL,
3515  NULL);
3516  if (NT_SUCCESS(Status))
3517  {
3518  /* FIXME: Do not return each RID more than once. */
3519  RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
3520  RidIndex++;
3521  }
3522  }
3523  }
3524 
3525  SampRegCloseKey(&MemberKeyHandle);
3526  }
3527 
3530 
3531  LocalFree(MemberSidString);
3532  }
3533 
3534 done:
3535  SampRegCloseKey(&MembersKeyHandle);
3536  SampRegCloseKey(&AliasesKeyHandle);
3537 
3538  if (NT_SUCCESS(Status))
3539  {
3540  Membership->Count = MaxSidCount;
3541  Membership->Element = RidArray;
3542  }
3543  else
3544  {
3545  if (RidArray != NULL)
3546  midl_user_free(RidArray);
3547  }
3548 
3550 
3551  return Status;
3552 }
3553 
3554 
3555 /* Function 17 */
3556 NTSTATUS
3557 NTAPI
3559  IN ULONG Count,
3561  OUT PSAMPR_ULONG_ARRAY RelativeIds,
3562  OUT PSAMPR_ULONG_ARRAY Use)
3563 {
3564  PSAM_DB_OBJECT DomainObject;
3565  HANDLE AccountsKeyHandle = NULL;
3566  HANDLE NamesKeyHandle = NULL;
3567  ULONG MappedCount = 0;
3568  ULONG DataLength;
3569  ULONG i;
3570  ULONG RelativeId;
3571  NTSTATUS Status;
3572 
3573  TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3574  DomainHandle, Count, Names, RelativeIds, Use);
3575 
3577  TRUE);
3578 
3579  /* Validate the domain handle */
3580  Status = SampValidateDbObject(DomainHandle,
3582  DOMAIN_LOOKUP,
3583  &DomainObject);
3584  if (!NT_SUCCESS(Status))
3585  {
3586  TRACE("failed with status 0x%08lx\n", Status);
3587  goto done;
3588  }
3589 
3590  RelativeIds->Count = 0;
3591  Use->Count = 0;
3592 
3593  if (Count == 0)
3594  {
3596  goto done;
3597  }
3598 
3599  /* Allocate the relative IDs array */
3600  RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3601  if (RelativeIds->Element == NULL)
3602  {
3604  goto done;
3605  }
3606 
3607  /* Allocate the use array */
3608  Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3609  if (Use->Element == NULL)
3610  {
3612  goto done;
3613  }
3614 
3615  RelativeIds->Count = Count;
3616  Use->Count = Count;
3617 
3618  for (i = 0; i < Count; i++)
3619  {
3620  TRACE("Name: %S\n", Names[i].Buffer);
3621 
3622  RelativeId = 0;
3623 
3624  /* Lookup aliases */
3625  Status = SampRegOpenKey(DomainObject->KeyHandle,
3626  L"Aliases",
3627  KEY_READ,
3628  &AccountsKeyHandle);
3629  if (NT_SUCCESS(Status))
3630  {
3631  Status = SampRegOpenKey(AccountsKeyHandle,
3632  L"Names",
3633  KEY_READ,
3634  &NamesKeyHandle);
3635  if (NT_SUCCESS(Status))
3636  {
3637  DataLength = sizeof(ULONG);
3638  Status = SampRegQueryValue(NamesKeyHandle,
3639  Names[i].Buffer,
3640  NULL,
3641  &RelativeId,
3642  &DataLength);
3643 
3644  SampRegCloseKey(&NamesKeyHandle);
3645  }
3646 
3647  SampRegCloseKey(&AccountsKeyHandle);
3648  }
3649 
3651  break;
3652 
3653  /* Return alias account */
3654  if (NT_SUCCESS(Status) && RelativeId != 0)
3655  {
3656  TRACE("Rid: %lu\n", RelativeId);
3657  RelativeIds->Element[i] = RelativeId;
3658  Use->Element[i] = SidTypeAlias;
3659  MappedCount++;
3660  continue;
3661  }
3662 
3663  /* Lookup groups */
3664  Status = SampRegOpenKey(DomainObject->KeyHandle,
3665  L"Groups",
3666  KEY_READ,
3667  &AccountsKeyHandle);
3668  if (NT_SUCCESS(Status))
3669  {
3670  Status = SampRegOpenKey(AccountsKeyHandle,
3671  L"Names",
3672  KEY_READ,
3673  &NamesKeyHandle);
3674  if (NT_SUCCESS(Status))
3675  {
3676  DataLength = sizeof(ULONG);
3677  Status = SampRegQueryValue(NamesKeyHandle,
3678  Names[i].Buffer,
3679  NULL,
3680  &RelativeId,
3681  &DataLength);
3682 
3683  SampRegCloseKey(&NamesKeyHandle);
3684  }
3685 
3686  SampRegCloseKey(&AccountsKeyHandle);
3687  }
3688 
3690  break;
3691 
3692  /* Return group account */
3693  if (NT_SUCCESS(Status) && RelativeId != 0)
3694  {
3695  TRACE("Rid: %lu\n", RelativeId);
3696  RelativeIds->Element[i] = RelativeId;
3697  Use->Element[i] = SidTypeGroup;
3698  MappedCount++;
3699  continue;
3700  }
3701 
3702  /* Lookup users */
3703  Status = SampRegOpenKey(DomainObject->KeyHandle,
3704  L"Users",
3705  KEY_READ,
3706  &AccountsKeyHandle);
3707  if (NT_SUCCESS(Status))
3708  {
3709  Status = SampRegOpenKey(AccountsKeyHandle,
3710  L"Names",
3711  KEY_READ,
3712  &NamesKeyHandle);
3713  if (NT_SUCCESS(Status))
3714  {
3715  DataLength = sizeof(ULONG);
3716  Status = SampRegQueryValue(NamesKeyHandle,
3717  Names[i].Buffer,
3718  NULL,
3719  &RelativeId,
3720  &DataLength);
3721 
3722  SampRegCloseKey(&NamesKeyHandle);
3723  }
3724 
3725  SampRegCloseKey(&AccountsKeyHandle);
3726  }
3727 
3729  break;
3730 
3731  /* Return user account */
3732  if (NT_SUCCESS(Status) && RelativeId != 0)
3733  {
3734  TRACE("Rid: %lu\n", RelativeId);
3735  RelativeIds->Element[i] = RelativeId;
3736  Use->Element[i] = SidTypeUser;
3737  MappedCount++;
3738  continue;
3739  }
3740 
3741  /* Return unknown account */
3742  RelativeIds->Element[i] = 0;
3743  Use->Element[i] = SidTypeUnknown;
3744  }
3745 
3746 done:
3749 
3750  if (NT_SUCCESS(Status))
3751  {
3752  if (MappedCount == 0)
3754  else if (MappedCount < Count)
3756  }
3757  else
3758  {
3759  if (RelativeIds->Element != NULL)
3760  {
3761  midl_user_free(RelativeIds->Element);
3762  RelativeIds->Element = NULL;
3763  }
3764 
3765  RelativeIds->Count = 0;
3766 
3767  if (Use->Element != NULL)
3768  {
3769  midl_user_free(Use->Element);
3770  Use->Element = NULL;
3771  }
3772 
3773  Use->Count = 0;
3774  }
3775 
3777 
3778  TRACE("Returned Status %lx\n", Status);
3779 
3780  return Status;
3781 }
3782 
3783 
3784 /* Function 18 */
3785 NTSTATUS
3786 NTAPI
3788  IN ULONG Count,
3789  IN ULONG *RelativeIds,
3791  OUT PSAMPR_ULONG_ARRAY Use)
3792 {
3793  PSAM_DB_OBJECT DomainObject;
3794  WCHAR RidString[9];
3795  HANDLE AccountsKeyHandle = NULL;
3796  HANDLE AccountKeyHandle = NULL;
3797  ULONG MappedCount = 0;
3798  ULONG DataLength;
3799  ULONG i;
3800  NTSTATUS Status;
3801 
3802  TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3803  DomainHandle, Count, RelativeIds, Names, Use);
3804 
3806  TRUE);
3807 
3808  /* Validate the domain handle */
3809  Status = SampValidateDbObject(DomainHandle,
3811  DOMAIN_LOOKUP,
3812  &DomainObject);
3813  if (!NT_SUCCESS(Status))
3814  {
3815  TRACE("failed with status 0x%08lx\n", Status);
3816  goto done;
3817  }
3818 
3819  Names->Count = 0;
3820  Use->Count = 0;
3821 
3822  if (Count == 0)
3823  {
3825  goto done;
3826  }
3827 
3828  /* Allocate the names array */
3829  Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
3830  if (Names->Element == NULL)
3831  {
3833  goto done;
3834  }
3835 
3836  /* Allocate the use array */
3837  Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
3838  if (Use->Element == NULL)
3839  {
3841  goto done;
3842  }
3843 
3844  Names->Count = Count;
3845  Use->Count = Count;
3846 
3847  for (i = 0; i < Count; i++)
3848  {
3849  TRACE("RID: %lu\n", RelativeIds[i]);
3850 
3851  swprintf(RidString, L"%08lx", RelativeIds[i]);
3852 
3853  /* Lookup aliases */
3854  Status = SampRegOpenKey(DomainObject->KeyHandle,
3855  L"Aliases",
3856  KEY_READ,
3857  &AccountsKeyHandle);
3858  if (NT_SUCCESS(Status))
3859  {
3860  Status = SampRegOpenKey(AccountsKeyHandle,
3861  RidString,
3862  KEY_READ,
3863  &AccountKeyHandle);
3864  if (NT_SUCCESS(Status))
3865  {
3866  DataLength = 0;
3867  Status = SampRegQueryValue(AccountKeyHandle,
3868  L"Name",
3869  NULL,
3870  NULL,
3871  &DataLength);
3872  if (NT_SUCCESS(Status))
3873  {
3874  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3875  if (Names->Element[i].Buffer == NULL)
3877 
3878  if (NT_SUCCESS(Status))
3879  {
3880  Names->Element[i].MaximumLength = (USHORT)DataLength;
3881  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3882 
3883  Status = SampRegQueryValue(AccountKeyHandle,
3884  L"Name",
3885  NULL,
3886  Names->Element[i].Buffer,
3887  &DataLength);
3888  }
3889  }
3890 
3891  SampRegCloseKey(&AccountKeyHandle);
3892  }
3893 
3894  SampRegCloseKey(&AccountsKeyHandle);
3895  }
3896 
3898  break;
3899 
3900  /* Return alias account */
3901  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3902  {
3903  TRACE("Name: %S\n", Names->Element[i].Buffer);
3904  Use->Element[i] = SidTypeAlias;
3905  MappedCount++;
3906  continue;
3907  }
3908 
3909  /* Lookup groups */
3910  Status = SampRegOpenKey(DomainObject->KeyHandle,
3911  L"Groups",
3912  KEY_READ,
3913  &AccountsKeyHandle);
3914  if (NT_SUCCESS(Status))
3915  {
3916  Status = SampRegOpenKey(AccountsKeyHandle,
3917  RidString,
3918  KEY_READ,
3919  &AccountKeyHandle);
3920  if (NT_SUCCESS(Status))
3921  {
3922  DataLength = 0;
3923  Status = SampRegQueryValue(AccountKeyHandle,
3924  L"Name",
3925  NULL,
3926  NULL,
3927  &DataLength);
3928  if (NT_SUCCESS(Status))
3929  {
3930  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3931  if (Names->Element[i].Buffer == NULL)
3933 
3934  if (NT_SUCCESS(Status))
3935  {
3936  Names->Element[i].MaximumLength = (USHORT)DataLength;
3937  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3938 
3939  Status = SampRegQueryValue(AccountKeyHandle,
3940  L"Name",
3941  NULL,
3942  Names->Element[i].Buffer,
3943  &DataLength);
3944  }
3945  }
3946 
3947  SampRegCloseKey(&AccountKeyHandle);
3948  }
3949 
3950  SampRegCloseKey(&AccountsKeyHandle);
3951  }
3952 
3954  break;
3955 
3956  /* Return group account */
3957  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3958  {
3959  TRACE("Name: %S\n", Names->Element[i].Buffer);
3960  Use->Element[i] = SidTypeGroup;
3961  MappedCount++;
3962  continue;
3963  }
3964 
3965  /* Lookup users */
3966  Status = SampRegOpenKey(DomainObject->KeyHandle,
3967  L"Users",
3968  KEY_READ,
3969  &AccountsKeyHandle);
3970  if (NT_SUCCESS(Status))
3971  {
3972  Status = SampRegOpenKey(AccountsKeyHandle,
3973  RidString,
3974  KEY_READ,
3975  &AccountKeyHandle);
3976  if (NT_SUCCESS(Status))
3977  {
3978  DataLength = 0;
3979  Status = SampRegQueryValue(AccountKeyHandle,
3980  L"Name",
3981  NULL,
3982  NULL,
3983  &DataLength);
3984  if (NT_SUCCESS(Status))
3985  {
3986  TRACE("DataLength: %lu\n", DataLength);
3987 
3988  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3989  if (Names->Element[i].Buffer == NULL)
3991 
3992  if (NT_SUCCESS(Status))
3993  {
3994  Names->Element[i].MaximumLength = (USHORT)DataLength;
3995  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3996 
3997  Status = SampRegQueryValue(AccountKeyHandle,
3998  L"Name",
3999  NULL,
4000  Names->Element[i].Buffer,
4001  &DataLength);
4002  }
4003  }
4004 
4005  SampRegCloseKey(&AccountKeyHandle);
4006  }
4007 
4008  SampRegCloseKey(&AccountsKeyHandle);
4009  }
4010 
4012  break;
4013 
4014  /* Return user account */
4015  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
4016  {
4017  TRACE("Name: %S\n", Names->Element[i].Buffer);
4018  Use->Element[i] = SidTypeUser;
4019  MappedCount++;
4020  continue;
4021  }
4022 
4023  /* Return unknown account */
4024  Use->Element[i] = SidTypeUnknown;
4025  }
4026 
4027 done:
4030 
4031  if (NT_SUCCESS(Status))
4032  {
4033  if (MappedCount == 0)
4035  else if (MappedCount < Count)
4037  }
4038  else
4039  {
4040  if (Names->Element != NULL)
4041  {
4042  for (i = 0; i < Count; i++)
4043  {
4044  if (Names->Element[i].Buffer != NULL)
4045  midl_user_free(Names->Element[i].Buffer);
4046  }
4047 
4048  midl_user_free(Names->Element);
4049  Names->Element = NULL;
4050  }
4051 
4052  Names->Count = 0;
4053 
4054  if (Use->Element != NULL)
4055  {
4056  midl_user_free(Use->Element);
4057  Use->Element = NULL;
4058  }
4059 
4060  Use->Count = 0;
4061  }
4062 
4064 
4065  return Status;
4066 }
4067 
4068 
4069 /* Function 19 */
4070 NTSTATUS
4071 NTAPI
4074  IN unsigned long GroupId,
4075  OUT SAMPR_HANDLE *GroupHandle)
4076 {
4077  PSAM_DB_OBJECT DomainObject;
4078  PSAM_DB_OBJECT GroupObject;
4079  WCHAR szRid[9];
4080  NTSTATUS Status;
4081 
4082  TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
4083  DomainHandle, DesiredAccess, GroupId, GroupHandle);
4084 
4085  /* Map generic access rights */
4087  &GroupMapping);
4088 
4090  TRUE);
4091 
4092  /* Validate the domain handle */
4093  Status = SampValidateDbObject(DomainHandle,
4095  DOMAIN_LOOKUP,
4096  &DomainObject);
4097  if (!NT_SUCCESS(Status))
4098  {
4099  TRACE("failed with status 0x%08lx\n", Status);
4100  goto done;
4101  }
4102 
4103  /* Convert the RID into a string (hex) */
4104  swprintf(szRid, L"%08lX", GroupId);
4105 
4106  /* Create the group object */
4107  Status = SampOpenDbObject(DomainObject,
4108  L"Groups",
4109  szRid,
4110  GroupId,
4112  DesiredAccess,
4113  &GroupObject);
4114  if (!NT_SUCCESS(Status))
4115  {
4116  TRACE("failed with status 0x%08lx\n", Status);
4117  goto done;
4118  }
4119 
4120  *GroupHandle = (SAMPR_HANDLE)GroupObject;
4121 
4122 done:
4124 
4125  return Status;
4126 }
4127 
4128 
4129 static NTSTATUS
4132 {
4133  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4134  SAM_GROUP_FIXED_DATA FixedData;
4135  ULONG MembersLength = 0;
4136  ULONG Length = 0;
4137  NTSTATUS Status;
4138 
4139  *Buffer = NULL;
4140 
4141  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4142  if (InfoBuffer == NULL)
4144 
4145  Status = SampGetObjectAttributeString(GroupObject,
4146  L"Name",
4147  &InfoBuffer->General.Name);
4148  if (!NT_SUCCESS(Status))
4149  {
4150  TRACE("Status 0x%08lx\n", Status);
4151  goto done;
4152  }
4153 
4154  Status = SampGetObjectAttributeString(GroupObject,
4155  L"AdminComment",
4156  &InfoBuffer->General.AdminComment);
4157  if (!NT_SUCCESS(Status))
4158  {
4159  TRACE("Status 0x%08lx\n", Status);
4160  goto done;
4161  }
4162 
4163  Length = sizeof(SAM_GROUP_FIXED_DATA);
4164  Status = SampGetObjectAttribute(GroupObject,
4165  L"F",
4166  NULL,
4167  (PVOID)&FixedData,
4168  &Length);
4169  if (!NT_SUCCESS(Status))
4170  {
4171  TRACE("Status 0x%08lx\n", Status);
4172  goto done;
4173  }
4174 
4175  InfoBuffer->General.Attributes = FixedData.Attributes;
4176 
4177  Status = SampGetObjectAttribute(GroupObject,
4178  L"Members",
4179  NULL,
4180  NULL,
4181  &MembersLength);
4183  {
4184  TRACE("Status 0x%08lx\n", Status);
4185  goto done;
4186  }
4187 
4189  {
4190  InfoBuffer->General.MemberCount = 0;
4192  }
4193  else
4194  {
4195  InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4196  }
4197 
4198  *Buffer = InfoBuffer;
4199 
4200 done:
4201  if (!NT_SUCCESS(Status))
4202  {
4203  if (InfoBuffer != NULL)
4204  {
4205  if (InfoBuffer->General.Name.Buffer != NULL)
4206  midl_user_free(InfoBuffer->General.Name.Buffer);
4207 
4208  if (InfoBuffer->General.AdminComment.Buffer != NULL)
4210 
4211  midl_user_free(InfoBuffer);
4212  }
4213  }
4214 
4215  return Status;
4216 }
4217 
4218 
4219 static NTSTATUS
4222 {
4223  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4224  NTSTATUS Status;
4225 
4226  *Buffer = NULL;
4227 
4228  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4229  if (InfoBuffer == NULL)
4231 
4232  Status = SampGetObjectAttributeString(GroupObject,
4233  L"Name",
4234  &InfoBuffer->Name.Name);
4235  if (!NT_SUCCESS(Status))
4236  {
4237  TRACE("Status 0x%08lx\n", Status);
4238  goto done;
4239  }
4240 
4241  *Buffer = InfoBuffer;
4242 
4243 done:
4244  if (!NT_SUCCESS(Status))
4245  {
4246  if (InfoBuffer != NULL)
4247  {
4248  if (InfoBuffer->Name.Name.Buffer != NULL)
4249  midl_user_free(InfoBuffer->Name.Name.Buffer);
4250 
4251  midl_user_free(InfoBuffer);
4252  }
4253  }
4254 
4255  return Status;
4256 }
4257 
4258 
4259 static NTSTATUS
4262 {
4263  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4264  SAM_GROUP_FIXED_DATA FixedData;
4265  ULONG Length = 0;
4266  NTSTATUS Status;
4267 
4268  *Buffer = NULL;
4269 
4270  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4271  if (InfoBuffer == NULL)
4273 
4274  Length = sizeof(SAM_GROUP_FIXED_DATA);
4275  Status = SampGetObjectAttribute(GroupObject,
4276  L"F",
4277  NULL,
4278  (PVOID)&FixedData,
4279  &Length);
4280  if (!NT_SUCCESS(Status))
4281  {
4282  TRACE("Status 0x%08lx\n", Status);
4283  goto done;
4284  }
4285 
4286  InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4287 
4288  *Buffer = InfoBuffer;
4289 
4290 done:
4291  if (!NT_SUCCESS(Status))
4292  {
4293  if (InfoBuffer != NULL)
4294  {
4295  midl_user_free(InfoBuffer);
4296  }
4297  }
4298 
4299  return Status;
4300 }
4301 
4302 
4303 static NTSTATUS
4306 {
4307  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4308  NTSTATUS Status;
4309 
4310  *Buffer = NULL;
4311 
4312  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4313  if (InfoBuffer == NULL)
4315 
4316  Status = SampGetObjectAttributeString(GroupObject,
4317  L"AdminComment",
4318  &InfoBuffer->AdminComment.AdminComment);
4319  if (!NT_SUCCESS(Status))
4320  {
4321  TRACE("Status 0x%08lx\n", Status);
4322  goto done;
4323  }
4324 
4325  *Buffer = InfoBuffer;
4326 
4327 done:
4328  if (!NT_SUCCESS(Status))
4329  {
4330  if (InfoBuffer != NULL)
4331  {
4332  if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4334 
4335  midl_user_free(InfoBuffer);
4336  }
4337  }
4338 
4339  return Status;
4340 }
4341 
4342 
4343 /* Function 20 */
4344 NTSTATUS
4345 NTAPI
4347  IN GROUP_INFORMATION_CLASS GroupInformationClass,
4349 {
4350  PSAM_DB_OBJECT GroupObject;
4351  NTSTATUS Status;
4352 
4353  TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4354  GroupHandle, GroupInformationClass, Buffer);
4355 
4357  TRUE);
4358 
4359  /* Validate the group handle */
4360  Status = SampValidateDbObject(GroupHandle,
4363  &GroupObject);
4364  if (!NT_SUCCESS(Status))
4365  goto done;
4366 
4367  switch (GroupInformationClass)
4368  {
4370  Status = SampQueryGroupGeneral(GroupObject,
4371  Buffer);
4372  break;
4373 
4374  case GroupNameInformation:
4375  Status = SampQueryGroupName(GroupObject,
4376  Buffer);
4377  break;
4378 
4380  Status = SampQueryGroupAttribute(GroupObject,
4381  Buffer);
4382  break;
4383 
4385  Status = SampQueryGroupAdminComment(GroupObject,
4386  Buffer);
4387  break;
4388 
4389  default:
4391  break;
4392  }
4393 
4394 done:
4396 
4397  return Status;
4398 }
4399 
4400 
4401 static NTSTATUS
4404 {
4405  UNICODE_STRING OldGroupName = {0, 0, NULL};
4406  UNICODE_STRING NewGroupName;
4407  NTSTATUS Status;
4408 
4409  Status = SampGetObjectAttributeString(GroupObject,
4410  L"Name",
4411  (PRPC_UNICODE_STRING)&OldGroupName);
4412  if (!NT_SUCCESS(Status))
4413  {
4414  TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4415  goto done;
4416  }
4417 
4418  /* Check the new account name */
4419  Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4420  if (!NT_SUCCESS(Status))
4421  {
4422  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4423  return Status;
4424  }
4425 
4426  NewGroupName.Length = Buffer->Name.Name.Length;
4427  NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4428  NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4429 
4430  if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4431  {
4433  NewGroupName.Buffer);
4434  if (!NT_SUCCESS(Status))
4435  {
4436  TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4437  NewGroupName.Buffer, Status);
4438  goto done;
4439  }
4440  }
4441 
4443  L"Groups",
4444  NewGroupName.Buffer,
4445  GroupObject->RelativeId);
4446  if (!NT_SUCCESS(Status))
4447  {
4448  TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4449  goto done;
4450  }
4451 
4453  L"Groups",
4454  OldGroupName.Buffer);
4455  if (!NT_SUCCESS(Status))
4456  {
4457  TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4458  goto done;
4459  }
4460 
4461  Status = SampSetObjectAttributeString(GroupObject,
4462  L"Name",
4463  (PRPC_UNICODE_STRING)&NewGroupName);
4464  if (!NT_SUCCESS(Status))
4465  {
4466  TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4467  }
4468 
4469 done:
4470  if (OldGroupName.Buffer != NULL)
4471  midl_user_free(OldGroupName.Buffer);
4472 
4473  return Status;
4474 }
4475 
4476 
4477 static NTSTATUS
4480 {
4481  SAM_GROUP_FIXED_DATA FixedData;
4482  ULONG Length = 0;
4483  NTSTATUS Status;
4484 
4485  Length = sizeof(SAM_GROUP_FIXED_DATA);
4486  Status = SampGetObjectAttribute(GroupObject,
4487  L"F",
4488  NULL,
4489  (PVOID)&FixedData,
4490  &Length);
4491  if (!NT_SUCCESS(Status))
4492  goto done;
4493 
4494  FixedData.Attributes = Buffer->Attribute.Attributes;
4495 
4496  Status = SampSetObjectAttribute(GroupObject,
4497  L"F",
4498  REG_BINARY,
4499  &FixedData,
4500  Length);
4501 
4502 done:
4503  return Status;
4504 }
4505 
4506 
4507 /* Function 21 */
4508 NTSTATUS
4509 NTAPI
4511  IN GROUP_INFORMATION_CLASS GroupInformationClass,
4513 {
4514  PSAM_DB_OBJECT GroupObject;
4515  NTSTATUS Status;
4516 
4517  TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4518  GroupHandle, GroupInformationClass, Buffer);
4519 
4521  TRUE);
4522 
4523  /* Validate the group handle */
4524  Status = SampValidateDbObject(GroupHandle,
4527  &GroupObject);
4528  if (!NT_SUCCESS(Status))
4529  goto done;
4530 
4531  switch (GroupInformationClass)
4532  {
4533  case GroupNameInformation:
4534  Status = SampSetGroupName(GroupObject,
4535  Buffer);
4536  break;
4537 
4539  Status = SampSetGroupAttribute(GroupObject,
4540  Buffer);
4541  break;
4542 
4544  Status = SampSetObjectAttributeString(GroupObject,
4545  L"AdminComment",
4546  &Buffer->AdminComment.AdminComment);
4547  break;
4548 
4549  default:
4551  break;
4552  }
4553 
4554 done:
4556 
4557  return Status;
4558 }
4559 
4560 
4561 /* Function 22 */
4562 NTSTATUS
4563 NTAPI
4565  IN unsigned long MemberId,
4566  IN unsigned long Attributes)
4567 {
4568  PSAM_DB_OBJECT GroupObject;
4569  PSAM_DB_OBJECT UserObject = NULL;
4570  NTSTATUS Status;
4571 
4572  TRACE("SamrAddMemberToGroup(%p %lu %lx)\n",
4573  GroupHandle, MemberId, Attributes);
4574 
4576  TRUE);
4577 
4578  /* Validate the group handle */
4579  Status = SampValidateDbObject(GroupHandle,
4582  &GroupObject);
4583  if (!NT_SUCCESS(Status))
4584  goto done;
4585 
4586  /* Open the user object in the same domain */
4587  Status = SampOpenUserObject(GroupObject->ParentObject,
4588  MemberId,
4589  0,
4590  &UserObject);
4591  if (!NT_SUCCESS(Status))
4592  {
4593  TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4594  goto done;
4595  }
4596 
4597  /* Add group membership to the user object */
4598  Status = SampAddGroupMembershipToUser(UserObject,
4599  GroupObject->RelativeId,
4600  Attributes);
4601  if (!NT_SUCCESS(Status))
4602  {
4603  TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4604  goto done;
4605  }
4606 
4607  /* Add the member to the group object */
4608  Status = SampAddMemberToGroup(GroupObject,
4609  MemberId);
4610  if (!NT_SUCCESS(Status))
4611  {
4612  TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4613  }
4614 
4615 done:
4616  if (UserObject)
4617  SampCloseDbObject(UserObject);
4618 
4620 
4621  return Status;
4622 }
4623 
4624 
4625 /* Function 23 */
4626 NTSTATUS
4627 NTAPI
4629 {
4630  PSAM_DB_OBJECT GroupObject;
4631  ULONG Length = 0;
4632  NTSTATUS Status;
4633 
4634  TRACE("SamrDeleteGroup(%p)\n", GroupHandle);
4635 
4637  TRUE);
4638 
4639  /* Validate the group handle */
4640  Status = SampValidateDbObject(*GroupHandle,
4642  DELETE,
4643  &GroupObject);
4644  if (!NT_SUCCESS(Status))
4645  {
4646  TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4647  goto done;
4648  }
4649 
4650  /* Fail, if the group is built-in */
4651  if (GroupObject->RelativeId < 1000)
4652  {
4653  TRACE("You can not delete a special account!\n");
4655  goto done;
4656  }
4657 
4658  /* Get the length of the Members attribute */
4659  SampGetObjectAttribute(GroupObject,
4660  L"Members",
4661  NULL,
4662  NULL,
4663  &Length);
4664 
4665  /* Fail, if the group has members */
4666  if (Length != 0)
4667  {
4668  TRACE("There are still members in the group!\n");
4670  goto done;
4671  }
4672 
4673  /* FIXME: Remove the group from all aliases */
4674 
4675  /* Delete the group from the database */
4676  Status = SampDeleteAccountDbObject(GroupObject);
4677  if (!NT_SUCCESS(Status))
4678  {
4679  TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4680  goto done;
4681  }
4682 
4683  /* Invalidate the handle */
4684  *GroupHandle = NULL;
4685 
4686 done:
4688 
4689  return Status;
4690 }
4691 
4692 
4693 /* Function 24 */
4694 NTSTATUS
4695 NTAPI
4697  IN unsigned long MemberId)
4698 {
4699  PSAM_DB_OBJECT GroupObject;
4700  PSAM_DB_OBJECT UserObject = NULL;
4701  NTSTATUS Status;
4702 
4703  TRACE("SamrRemoveMemberFromGroup(%p %lu)\n",
4704  GroupHandle, MemberId);
4705 
4707  TRUE);
4708 
4709  /* Validate the group handle */
4710  Status = SampValidateDbObject(GroupHandle,
4713  &GroupObject);
4714  if (!NT_SUCCESS(Status))
4715  goto done;
4716 
4717  /* Open the user object in the same domain */
4718  Status = SampOpenUserObject(GroupObject->ParentObject,
4719  MemberId,
4720  0,
4721  &UserObject);
4722  if (!NT_SUCCESS(Status))
4723  {
4724  ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4725  goto done;
4726  }
4727 
4728  /* Remove group membership from the user object */
4730  GroupObject->RelativeId);
4731  if (!NT_SUCCESS(Status))
4732  {
4733  ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4734  goto done;
4735  }
4736 
4737  /* Remove the member from the group object */
4738  Status = SampRemoveMemberFromGroup(GroupObject,
4739  MemberId);
4740  if (!NT_SUCCESS(Status))
4741  {
4742  ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4743  }
4744 
4745 done:
4746  if (UserObject)
4747  SampCloseDbObject(UserObject);
4748 
4750 
4751  return Status;
4752 }
4753 
4754 
4755 /* Function 25 */
4756 NTSTATUS
4757 NTAPI
4759  OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4760 {
4761  PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4762  PSAM_DB_OBJECT GroupObject;
4763  ULONG Length = 0;
4764  ULONG i;
4765  NTSTATUS Status;
4766 
4767  TRACE("SamrGetMembersInGroup(%p %p)\n",
4768  GroupHandle, Members);
4769 
4771  TRUE);
4772 
4773  /* Validate the group handle */
4774  Status = SampValidateDbObject(GroupHandle,
4777  &GroupObject);
4778  if (!NT_SUCCESS(Status))
4779  goto done;
4780 
4781  MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4782  if (MembersBuffer == NULL)
4783  {
4785  goto done;
4786  }
4787 
4788  SampGetObjectAttribute(GroupObject,
4789  L"Members",
4790  NULL,
4791  NULL,
4792  &Length);
4793 
4794  if (Length == 0)
4795  {
4796  MembersBuffer->MemberCount = 0;
4797  MembersBuffer->Members = NULL;
4798  MembersBuffer->Attributes = NULL;
4799 
4800  *Members = MembersBuffer;
4801 
4803  goto done;
4804  }
4805 
4806  MembersBuffer->Members = midl_user_allocate(Length);
4807  if (MembersBuffer->Members == NULL)
4808  {
4810  goto done;
4811  }
4812 
4813  MembersBuffer->Attributes = midl_user_allocate(Length);
4814  if (MembersBuffer->Attributes == NULL)
4815  {
4817  goto done;
4818  }
4819 
4820  Status = SampGetObjectAttribute(GroupObject,
4821  L"Members",
4822  NULL,
4823  MembersBuffer->Members,
4824  &Length);
4825  if (!NT_SUCCESS(Status))
4826  {
4827  TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4828  goto done;
4829  }
4830 
4831  MembersBuffer->MemberCount = Length / sizeof(ULONG);
4832 
4833  for (i = 0; i < MembersBuffer->MemberCount; i++)
4834  {
4836  MembersBuffer->Members[i],
4837  GroupObject->RelativeId,
4838  &(MembersBuffer->Attributes[i]));
4839  if (!NT_SUCCESS(Status))
4840  {
4841  TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4842  goto done;
4843  }
4844  }
4845 
4846  *Members = MembersBuffer;
4847 
4848 done:
4849  if (!NT_SUCCESS(Status))
4850  {
4851  if (MembersBuffer != NULL)
4852  {
4853  if (MembersBuffer->Members != NULL)
4854  midl_user_free(MembersBuffer->Members);
4855 
4856  if (MembersBuffer->Attributes != NULL)
4857  midl_user_free(MembersBuffer->Attributes);
4858 
4859  midl_user_free(MembersBuffer);
4860  }
4861  }
4862 
4864 
4865  return Status;
4866 }
4867 
4868 
4869 /* Function 26 */
4870 NTSTATUS
4871 NTAPI
4873  IN unsigned long MemberId,
4874  IN unsigned long Attributes)
4875 {
4876  PSAM_DB_OBJECT GroupObject;
4877  NTSTATUS Status;
4878 
4879  TRACE("SamrSetMemberAttributesOfGroup(%p %lu %lx)\n",
4880  GroupHandle, MemberId, Attributes);
4881 
4883  TRUE);
4884 
4885  /* Validate the group handle */
4886  Status = SampValidateDbObject(GroupHandle,
4889  &GroupObject);
4890  if (!NT_SUCCESS(Status))
4891  {
4892  TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4893  goto done;
4894  }
4895 
4897  MemberId,
4898  GroupObject->RelativeId,
4899  Attributes);
4900  if (!NT_SUCCESS(Status))
4901  {
4902  TRACE(<