ReactOS  0.4.15-dev-316-g938df97
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  {
2295  goto done;
2296  }
2297 
2298  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2299  if (EnumBuffer->Buffer == NULL)
2300  {
2302  goto done;
2303  }
2304 
2305  TRACE("Part 2\n");
2306 
2307  EnumIndex = *EnumerationContext;
2308  for (i = 0; i < EnumCount; i++, EnumIndex++)
2309  {
2310  NameLength = 64 * sizeof(WCHAR);
2311  DataLength = sizeof(ULONG);
2312  Status = SampRegEnumerateValue(NamesKeyHandle,
2313  EnumIndex,
2314  GroupName,
2315  &NameLength,
2316  NULL,
2317  &Rid,
2318  &DataLength);
2319  if (!NT_SUCCESS(Status))
2320  {
2323  break;
2324  }
2325 
2326  TRACE("EnumIndex: %lu\n", EnumIndex);
2327  TRACE("Group name: %S\n", GroupName);
2328  TRACE("Name length: %lu\n", NameLength);
2329  TRACE("RID: %lu\n", Rid);
2330 
2331  EnumBuffer->Buffer[i].RelativeId = Rid;
2332 
2333  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2334  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2335 
2336 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2337 #if 0
2338  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2339  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2340  {
2342  goto done;
2343  }
2344 
2345  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2346  GroupName,
2347  EnumBuffer->Buffer[i].Name.Length);
2348 #endif
2349  }
2350 
2351 done:
2352  if (NT_SUCCESS(Status))
2353  {
2354  *EnumerationContext += EnumCount;
2355  *Buffer = EnumBuffer;
2356  *CountReturned = EnumCount;
2357  }
2358  else
2359  {
2360  *EnumerationContext = 0;
2361  *Buffer = NULL;
2362  *CountReturned = 0;
2363 
2364  if (EnumBuffer != NULL)
2365  {
2366  if (EnumBuffer->Buffer != NULL)
2367  {
2368  if (EnumBuffer->EntriesRead != 0)
2369  {
2370  for (i = 0; i < EnumBuffer->EntriesRead; i++)
2371  {
2372  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2373  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2374  }
2375  }
2376 
2377  midl_user_free(EnumBuffer->Buffer);
2378  }
2379 
2380  midl_user_free(EnumBuffer);
2381  }
2382  }
2383 
2384  SampRegCloseKey(&NamesKeyHandle);
2385  SampRegCloseKey(&GroupsKeyHandle);
2386 
2387  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2389 
2391 
2392  return Status;
2393 }
2394 
2395 
2396 /* Function 12 */
2397 NTSTATUS
2398 NTAPI
2402  OUT SAMPR_HANDLE *UserHandle,
2403  OUT unsigned long *RelativeId)
2404 {
2405  SAM_DOMAIN_FIXED_DATA FixedDomainData;
2406  SAM_USER_FIXED_DATA FixedUserData;
2407  PSAM_DB_OBJECT DomainObject;
2408  PSAM_DB_OBJECT UserObject;
2409  GROUP_MEMBERSHIP GroupMembership;
2410  UCHAR LogonHours[23];
2411  ULONG ulSize;
2412  ULONG ulRid;
2413  WCHAR szRid[9];
2415  ULONG SdSize = 0;
2416  PSID UserSid = NULL;
2417  NTSTATUS Status;
2418 
2419  TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2420  DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2421 
2422  if (Name == NULL ||
2423  Name->Length == 0 ||
2424  Name->Buffer == NULL ||
2425  UserHandle == NULL ||
2426  RelativeId == NULL)
2427  return STATUS_INVALID_PARAMETER;
2428 
2429  /* Map generic access rights */
2431  &UserMapping);
2432 
2434  TRUE);
2435 
2436  /* Validate the domain handle */
2437  Status = SampValidateDbObject(DomainHandle,
2440  &DomainObject);
2441  if (!NT_SUCCESS(Status))
2442  {
2443  TRACE("failed with status 0x%08lx\n", Status);
2444  goto done;
2445  }
2446 
2447  /* Check the user account name */
2449  if (!NT_SUCCESS(Status))
2450  {
2451  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2452  goto done;
2453  }
2454 
2455  /* Check if the user name already exists in the domain */
2456  Status = SampCheckAccountNameInDomain(DomainObject,
2457  Name->Buffer);
2458  if (!NT_SUCCESS(Status))
2459  {
2460  TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2461  Name->Buffer, Status);
2462  goto done;
2463  }
2464 
2465  /* Get the fixed domain attributes */
2466  ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2467  Status = SampGetObjectAttribute(DomainObject,
2468  L"F",
2469  NULL,
2470  (PVOID)&FixedDomainData,
2471  &ulSize);
2472  if (!NT_SUCCESS(Status))
2473  {
2474  TRACE("failed with status 0x%08lx\n", Status);
2475  goto done;
2476  }
2477 
2478  /* Increment the NextRid attribute */
2479  ulRid = FixedDomainData.NextRid;
2480  FixedDomainData.NextRid++;
2481 
2482  TRACE("RID: %lx\n", ulRid);
2483 
2484  /* Create the user SID */
2485  Status = SampCreateAccountSid(DomainObject,
2486  ulRid,
2487  &UserSid);
2488  if (!NT_SUCCESS(Status))
2489  {
2490  TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
2491  goto done;
2492  }
2493 
2494  /* Create the security descriptor */
2495  Status = SampCreateUserSD(UserSid,
2496  &Sd,
2497  &SdSize);
2498  if (!NT_SUCCESS(Status))
2499  {
2500  TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
2501  goto done;
2502  }
2503 
2504  /* Store the fixed domain attributes */
2505  Status = SampSetObjectAttribute(DomainObject,
2506  L"F",
2507  REG_BINARY,
2508  &FixedDomainData,
2509  ulSize);
2510  if (!NT_SUCCESS(Status))
2511  {
2512  TRACE("failed with status 0x%08lx\n", Status);
2513  goto done;
2514  }
2515 
2516  /* Convert the RID into a string (hex) */
2517  swprintf(szRid, L"%08lX", ulRid);
2518 
2519  /* Create the user object */
2520  Status = SampCreateDbObject(DomainObject,
2521  L"Users",
2522  szRid,
2523  ulRid,
2525  DesiredAccess,
2526  &UserObject);
2527  if (!NT_SUCCESS(Status))
2528  {
2529  TRACE("failed with status 0x%08lx\n", Status);
2530  goto done;
2531  }
2532 
2533  /* Add the account name for the user object */
2534  Status = SampSetAccountNameInDomain(DomainObject,
2535  L"Users",
2536  Name->Buffer,
2537  ulRid);
2538  if (!NT_SUCCESS(Status))
2539  {
2540  TRACE("failed with status 0x%08lx\n", Status);
2541  goto done;
2542  }
2543 
2544  /* Initialize fixed user data */
2545  memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2546  FixedUserData.Version = 1;
2547  FixedUserData.Reserved = 0;
2548  FixedUserData.LastLogon.QuadPart = 0;
2549  FixedUserData.LastLogoff.QuadPart = 0;
2550  FixedUserData.PasswordLastSet.QuadPart = 0;
2551  FixedUserData.AccountExpires.QuadPart = MAXLONGLONG;
2552  FixedUserData.LastBadPasswordTime.QuadPart = 0;
2553  FixedUserData.UserId = ulRid;
2554  FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2555  FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2558  FixedUserData.CountryCode = 0;
2559  FixedUserData.CodePage = 0;
2560  FixedUserData.BadPasswordCount = 0;
2561  FixedUserData.LogonCount = 0;
2562  FixedUserData.AdminCount = 0;
2563  FixedUserData.OperatorCount = 0;
2564 
2565  /* Set fixed user data attribute */
2566  Status = SampSetObjectAttribute(UserObject,
2567  L"F",
2568  REG_BINARY,
2569  (LPVOID)&FixedUserData,
2570  sizeof(SAM_USER_FIXED_DATA));
2571  if (!NT_SUCCESS(Status))
2572  {
2573  TRACE("failed with status 0x%08lx\n", Status);
2574  goto done;
2575  }
2576 
2577  /* Set the Name attribute */
2578  Status = SampSetObjectAttributeString(UserObject,
2579  L"Name",
2580  Name);
2581  if (!NT_SUCCESS(Status))
2582  {
2583  TRACE("failed with status 0x%08lx\n", Status);
2584  goto done;
2585  }
2586 
2587  /* Set the FullName attribute */
2588  Status = SampSetObjectAttributeString(UserObject,
2589  L"FullName",
2590  NULL);
2591  if (!NT_SUCCESS(Status))
2592  {
2593  TRACE("failed with status 0x%08lx\n", Status);
2594  goto done;
2595  }
2596 
2597  /* Set the HomeDirectory attribute */
2598  Status = SampSetObjectAttributeString(UserObject,
2599  L"HomeDirectory",
2600  NULL);
2601  if (!NT_SUCCESS(Status))
2602  {
2603  TRACE("failed with status 0x%08lx\n", Status);
2604  goto done;
2605  }
2606 
2607  /* Set the HomeDirectoryDrive attribute */
2608  Status = SampSetObjectAttributeString(UserObject,
2609  L"HomeDirectoryDrive",
2610  NULL);
2611  if (!NT_SUCCESS(Status))
2612  {
2613  TRACE("failed with status 0x%08lx\n", Status);
2614  goto done;
2615  }
2616 
2617  /* Set the ScriptPath attribute */
2618  Status = SampSetObjectAttributeString(UserObject,
2619  L"ScriptPath",
2620  NULL);
2621  if (!NT_SUCCESS(Status))
2622  {
2623  TRACE("failed with status 0x%08lx\n", Status);
2624  goto done;
2625  }
2626 
2627  /* Set the ProfilePath attribute */
2628  Status = SampSetObjectAttributeString(UserObject,
2629  L"ProfilePath",
2630  NULL);
2631  if (!NT_SUCCESS(Status))
2632  {
2633  TRACE("failed with status 0x%08lx\n", Status);
2634  goto done;
2635  }
2636 
2637  /* Set the AdminComment attribute */
2638  Status = SampSetObjectAttributeString(UserObject,
2639  L"AdminComment",
2640  NULL);
2641  if (!NT_SUCCESS(Status))
2642  {
2643  TRACE("failed with status 0x%08lx\n", Status);
2644  goto done;
2645  }
2646 
2647  /* Set the UserComment attribute */
2648  Status = SampSetObjectAttributeString(UserObject,
2649  L"UserComment",
2650  NULL);
2651  if (!NT_SUCCESS(Status))
2652  {
2653  TRACE("failed with status 0x%08lx\n", Status);
2654  goto done;
2655  }
2656 
2657  /* Set the WorkStations attribute */
2658  Status = SampSetObjectAttributeString(UserObject,
2659  L"WorkStations",
2660  NULL);
2661  if (!NT_SUCCESS(Status))
2662  {
2663  TRACE("failed with status 0x%08lx\n", Status);
2664  goto done;
2665  }
2666 
2667  /* Set the Parameters attribute */
2668  Status = SampSetObjectAttributeString(UserObject,
2669  L"Parameters",
2670  NULL);
2671  if (!NT_SUCCESS(Status))
2672  {
2673  TRACE("failed with status 0x%08lx\n", Status);
2674  goto done;
2675  }
2676 
2677  /* Set LogonHours attribute*/
2678  *((PUSHORT)LogonHours) = 168;
2679  memset(&(LogonHours[2]), 0xff, 21);
2680 
2681  Status = SampSetObjectAttribute(UserObject,
2682  L"LogonHours",
2683  REG_BINARY,
2684  &LogonHours,
2685  sizeof(LogonHours));
2686  if (!NT_SUCCESS(Status))
2687  {
2688  TRACE("failed with status 0x%08lx\n", Status);
2689  goto done;
2690  }
2691 
2692  /* Set Groups attribute*/
2693  GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2694  GroupMembership.Attributes = SE_GROUP_MANDATORY |
2697 
2698  Status = SampSetObjectAttribute(UserObject,
2699  L"Groups",
2700  REG_BINARY,
2701  &GroupMembership,
2702  sizeof(GROUP_MEMBERSHIP));
2703  if (!NT_SUCCESS(Status))
2704  {
2705  TRACE("failed with status 0x%08lx\n", Status);
2706  goto done;
2707  }
2708 
2709  /* Set LMPwd attribute*/
2710  Status = SampSetObjectAttribute(UserObject,
2711  L"LMPwd",
2712  REG_BINARY,
2713  &EmptyLmHash,
2714  sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2715  if (!NT_SUCCESS(Status))
2716  {
2717  TRACE("failed with status 0x%08lx\n", Status);
2718  goto done;
2719  }
2720 
2721  /* Set NTPwd attribute*/
2722  Status = SampSetObjectAttribute(UserObject,
2723  L"NTPwd",
2724  REG_BINARY,
2725  &EmptyNtHash,
2726  sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2727  if (!NT_SUCCESS(Status))
2728  {
2729  TRACE("failed with status 0x%08lx\n", Status);
2730  goto done;
2731  }
2732 
2733  /* Set LMPwdHistory attribute*/
2734  Status = SampSetObjectAttribute(UserObject,
2735  L"LMPwdHistory",
2736  REG_BINARY,
2737  NULL,
2738  0);
2739  if (!NT_SUCCESS(Status))
2740  {
2741  TRACE("failed with status 0x%08lx\n", Status);
2742  goto done;
2743  }
2744 
2745  /* Set NTPwdHistory attribute*/
2746  Status = SampSetObjectAttribute(UserObject,
2747  L"NTPwdHistory",
2748  REG_BINARY,
2749  NULL,
2750  0);
2751  if (!NT_SUCCESS(Status))
2752  {
2753  TRACE("failed with status 0x%08lx\n", Status);
2754  goto done;
2755  }
2756 
2757  /* Set the PrivateData attribute */
2758  Status = SampSetObjectAttributeString(UserObject,
2759  L"PrivateData",
2760  NULL);
2761  if (!NT_SUCCESS(Status))
2762  {
2763  TRACE("failed with status 0x%08lx\n", Status);
2764  goto done;
2765  }
2766 
2767  /* Set the SecDesc attribute*/
2768  Status = SampSetObjectAttribute(UserObject,
2769  L"SecDesc",
2770  REG_BINARY,
2771  Sd,
2772  SdSize);
2773  if (!NT_SUCCESS(Status))
2774  {
2775  TRACE("failed with status 0x%08lx\n", Status);
2776  goto done;
2777  }
2778 
2779  if (NT_SUCCESS(Status))
2780  {
2781  *UserHandle = (SAMPR_HANDLE)UserObject;
2782  *RelativeId = ulRid;
2783  }
2784 
2785 done:
2786  if (Sd != NULL)
2787  RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2788 
2789  if (UserSid != NULL)
2790  RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2791 
2793 
2794  TRACE("returns with status 0x%08lx\n", Status);
2795 
2796  return Status;
2797 }
2798 
2799 
2800 /* Function 13 */
2801 NTSTATUS
2802 NTAPI
2804  IN OUT unsigned long *EnumerationContext,
2805  IN unsigned long UserAccountControl,
2807  IN unsigned long PreferedMaximumLength,
2808  OUT unsigned long *CountReturned)
2809 {
2810  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2811  PSAM_DB_OBJECT DomainObject;
2812  HANDLE UsersKeyHandle = NULL;
2813  HANDLE NamesKeyHandle = NULL;
2814  WCHAR UserName[64];
2815  ULONG EnumIndex;
2816  ULONG EnumCount = 0;
2817  ULONG RequiredLength = 0;
2818  ULONG NameLength;
2819  ULONG DataLength;
2820  ULONG Rid;
2821  ULONG i;
2822  BOOLEAN MoreEntries = FALSE;
2823  NTSTATUS Status;
2824 
2825  TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2826  DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2827  PreferedMaximumLength, CountReturned);
2828 
2830  TRUE);
2831 
2832  /* Validate the domain handle */
2833  Status = SampValidateDbObject(DomainHandle,
2836  &DomainObject);
2837  if (!NT_SUCCESS(Status))
2838  goto done;
2839 
2840  Status = SampRegOpenKey(DomainObject->KeyHandle,
2841  L"Users",
2842  KEY_READ,
2843  &UsersKeyHandle);
2844  if (!NT_SUCCESS(Status))
2845  goto done;
2846 
2847  Status = SampRegOpenKey(UsersKeyHandle,
2848  L"Names",
2849  KEY_READ,
2850  &NamesKeyHandle);
2851  if (!NT_SUCCESS(Status))
2852  goto done;
2853 
2854  TRACE("Part 1\n");
2855 
2856  EnumIndex = *EnumerationContext;
2857 
2858  while (TRUE)
2859  {
2860  NameLength = 64 * sizeof(WCHAR);
2861  Status = SampRegEnumerateValue(NamesKeyHandle,
2862  EnumIndex,
2863  UserName,
2864  &NameLength,
2865  NULL,
2866  NULL,
2867  NULL);
2868  if (!NT_SUCCESS(Status))
2869  {
2872  break;
2873  }
2874 
2875  TRACE("EnumIndex: %lu\n", EnumIndex);
2876  TRACE("User name: %S\n", UserName);
2877  TRACE("Name length: %lu\n", NameLength);
2878 
2879  if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2880  {
2881  MoreEntries = TRUE;
2882  break;
2883  }
2884 
2885  RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2886  EnumCount++;
2887 
2888  EnumIndex++;
2889  }
2890 
2891  TRACE("EnumCount: %lu\n", EnumCount);
2892  TRACE("RequiredLength: %lu\n", RequiredLength);
2893 
2894  if (!NT_SUCCESS(Status))
2895  goto done;
2896 
2897  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2898  if (EnumBuffer == NULL)
2899  {
2901  goto done;
2902  }
2903 
2904  EnumBuffer->EntriesRead = EnumCount;
2905  if (EnumCount == 0)
2906  {
2908  goto done;
2909  }
2910 
2911  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2912  if (EnumBuffer->Buffer == NULL)
2913  {
2915  goto done;
2916  }
2917 
2918  TRACE("Part 2\n");
2919 
2920  EnumIndex = *EnumerationContext;
2921  for (i = 0; i < EnumCount; i++, EnumIndex++)
2922  {
2923  NameLength = 64 * sizeof(WCHAR);
2924  DataLength = sizeof(ULONG);
2925  Status = SampRegEnumerateValue(NamesKeyHandle,
2926  EnumIndex,
2927  UserName,
2928  &NameLength,
2929  NULL,
2930  &Rid,
2931  &DataLength);
2932  if (!NT_SUCCESS(Status))
2933  {
2936  break;
2937  }
2938 
2939  TRACE("EnumIndex: %lu\n", EnumIndex);
2940  TRACE("User name: %S\n", UserName);
2941  TRACE("Name length: %lu\n", NameLength);
2942  TRACE("RID: %lu\n", Rid);
2943 
2944  EnumBuffer->Buffer[i].RelativeId = Rid;
2945 
2946  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2947  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2948 
2949 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2950 #if 0
2951  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2952  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2953  {
2955  goto done;
2956  }
2957 
2958  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2959  UserName,
2960  EnumBuffer->Buffer[i].Name.Length);
2961 #endif
2962  }
2963 
2964 done:
2965  if (NT_SUCCESS(Status))
2966  {
2967  *EnumerationContext += EnumCount;
2968  *Buffer = EnumBuffer;
2969  *CountReturned = EnumCount;
2970  }
2971  else
2972  {
2973  *EnumerationContext = 0;
2974  *Buffer = NULL;
2975  *CountReturned = 0;
2976 
2977  if (EnumBuffer != NULL)
2978  {
2979  if (EnumBuffer->Buffer != NULL)
2980  {
2981  if (EnumBuffer->EntriesRead != 0)
2982  {
2983  for (i = 0; i < EnumBuffer->EntriesRead; i++)
2984  {
2985  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2986  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2987  }
2988  }
2989 
2990  midl_user_free(EnumBuffer->Buffer);
2991  }
2992 
2993  midl_user_free(EnumBuffer);
2994  }
2995  }
2996 
2997  SampRegCloseKey(&NamesKeyHandle);
2998  SampRegCloseKey(&UsersKeyHandle);
2999 
3000  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3002 
3004 
3005  return Status;
3006 }
3007 
3008 
3009 /* Function 14 */
3010 NTSTATUS
3011 NTAPI
3013  IN PRPC_UNICODE_STRING AccountName,
3015  OUT SAMPR_HANDLE *AliasHandle,
3016  OUT unsigned long *RelativeId)
3017 {
3018  SAM_DOMAIN_FIXED_DATA FixedDomainData;
3019  PSAM_DB_OBJECT DomainObject;
3020  PSAM_DB_OBJECT AliasObject;
3022  ULONG SdSize = 0;
3023  ULONG ulSize;
3024  ULONG ulRid;
3025  WCHAR szRid[9];
3026  NTSTATUS Status;
3027 
3028  TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
3029  DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
3030 
3031  /* Map generic access rights */
3033  &AliasMapping);
3034 
3036  TRUE);
3037 
3038  /* Validate the domain handle */
3039  Status = SampValidateDbObject(DomainHandle,
3042  &DomainObject);
3043  if (!NT_SUCCESS(Status))
3044  {
3045  TRACE("failed with status 0x%08lx\n", Status);
3046  goto done;
3047  }
3048 
3049  /* Check the alias account name */
3050  Status = SampCheckAccountName(AccountName, 256);
3051  if (!NT_SUCCESS(Status))
3052  {
3053  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
3054  goto done;
3055  }
3056 
3057  /* Check if the alias name already exists in the domain */
3058  Status = SampCheckAccountNameInDomain(DomainObject,
3059  AccountName->Buffer);
3060  if (!NT_SUCCESS(Status))
3061  {
3062  TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
3063  AccountName->Buffer, Status);
3064  goto done;
3065  }
3066 
3067  /* Create the security descriptor */
3068  Status = SampCreateAliasSD(&Sd,
3069  &SdSize);
3070  if (!NT_SUCCESS(Status))
3071  {
3072  TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
3073  goto done;
3074  }
3075 
3076  /* Get the fixed domain attributes */
3077  ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
3078  Status = SampGetObjectAttribute(DomainObject,
3079  L"F",
3080  NULL,
3081  (PVOID)&FixedDomainData,
3082  &ulSize);
3083  if (!NT_SUCCESS(Status))
3084  {
3085  TRACE("failed with status 0x%08lx\n", Status);
3086  goto done;
3087  }
3088 
3089  /* Increment the NextRid attribute */
3090  ulRid = FixedDomainData.NextRid;
3091  FixedDomainData.NextRid++;
3092 
3093  /* Store the fixed domain attributes */
3094  Status = SampSetObjectAttribute(DomainObject,
3095  L"F",
3096  REG_BINARY,
3097  &FixedDomainData,
3098  ulSize);
3099  if (!NT_SUCCESS(Status))
3100  {
3101  TRACE("failed with status 0x%08lx\n", Status);
3102  goto done;
3103  }
3104 
3105  TRACE("RID: %lx\n", ulRid);
3106 
3107  /* Convert the RID into a string (hex) */
3108  swprintf(szRid, L"%08lX", ulRid);
3109 
3110  /* Create the alias object */
3111  Status = SampCreateDbObject(DomainObject,
3112  L"Aliases",
3113  szRid,
3114  ulRid,
3116  DesiredAccess,
3117  &AliasObject);
3118  if (!NT_SUCCESS(Status))
3119  {
3120  TRACE("failed with status 0x%08lx\n", Status);
3121  goto done;
3122  }
3123 
3124  /* Add the account name for the alias object */
3125  Status = SampSetAccountNameInDomain(DomainObject,
3126  L"Aliases",
3127  AccountName->Buffer,
3128  ulRid);
3129  if (!NT_SUCCESS(Status))
3130  {
3131  TRACE("failed with status 0x%08lx\n", Status);
3132  goto done;
3133  }
3134 
3135  /* Set the Name attribute */
3136  Status = SampSetObjectAttributeString(AliasObject,
3137  L"Name",
3138  AccountName);
3139  if (!NT_SUCCESS(Status))
3140  {
3141  TRACE("failed with status 0x%08lx\n", Status);
3142  goto done;
3143  }
3144 
3145  /* Set the Description attribute */
3146  Status = SampSetObjectAttributeString(AliasObject,
3147  L"Description",
3148  NULL);
3149  if (!NT_SUCCESS(Status))
3150  {
3151  TRACE("failed with status 0x%08lx\n", Status);
3152  goto done;
3153  }
3154 
3155  /* Set the SecDesc attribute*/
3156  Status = SampSetObjectAttribute(AliasObject,
3157  L"SecDesc",
3158  REG_BINARY,
3159  Sd,
3160  SdSize);
3161  if (!NT_SUCCESS(Status))
3162  {
3163  TRACE("failed with status 0x%08lx\n", Status);
3164  goto done;
3165  }
3166 
3167  if (NT_SUCCESS(Status))
3168  {
3169  *AliasHandle = (SAMPR_HANDLE)AliasObject;
3170  *RelativeId = ulRid;
3171  }
3172 
3173 done:
3174  if (Sd != NULL)
3175  RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
3176 
3178 
3179  TRACE("returns with status 0x%08lx\n", Status);
3180 
3181  return Status;
3182 }
3183 
3184 
3185 /* Function 15 */
3186 NTSTATUS
3187 NTAPI
3189  IN OUT unsigned long *EnumerationContext,
3191  IN unsigned long PreferedMaximumLength,
3192  OUT unsigned long *CountReturned)
3193 {
3194  PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
3195  PSAM_DB_OBJECT DomainObject;
3196  HANDLE AliasesKeyHandle = NULL;
3197  HANDLE NamesKeyHandle = NULL;
3198  WCHAR AliasName[64];
3199  ULONG EnumIndex;
3200  ULONG EnumCount = 0;
3201  ULONG RequiredLength = 0;
3202  ULONG NameLength;
3203  ULONG DataLength;
3204  ULONG Rid;
3205  ULONG i;
3206  BOOLEAN MoreEntries = FALSE;
3207  NTSTATUS Status;
3208 
3209  TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
3210  DomainHandle, EnumerationContext, Buffer,
3211  PreferedMaximumLength, CountReturned);
3212 
3214  TRUE);
3215 
3216  /* Validate the domain handle */
3217  Status = SampValidateDbObject(DomainHandle,
3220  &DomainObject);
3221  if (!NT_SUCCESS(Status))
3222  goto done;
3223 
3224  Status = SampRegOpenKey(DomainObject->KeyHandle,
3225  L"Aliases",
3226  KEY_READ,
3227  &AliasesKeyHandle);
3228  if (!NT_SUCCESS(Status))
3229  goto done;
3230 
3231  Status = SampRegOpenKey(AliasesKeyHandle,
3232  L"Names",
3233  KEY_READ,
3234  &NamesKeyHandle);
3235  if (!NT_SUCCESS(Status))
3236  goto done;
3237 
3238  TRACE("Part 1\n");
3239 
3240  EnumIndex = *EnumerationContext;
3241 
3242  while (TRUE)
3243  {
3244  NameLength = 64 * sizeof(WCHAR);
3245  Status = SampRegEnumerateValue(NamesKeyHandle,
3246  EnumIndex,
3247  AliasName,
3248  &NameLength,
3249  NULL,
3250  NULL,
3251  NULL);
3252  if (!NT_SUCCESS(Status))
3253  {
3256  break;
3257  }
3258 
3259  TRACE("EnumIndex: %lu\n", EnumIndex);
3260  TRACE("Alias name: %S\n", AliasName);
3261  TRACE("Name length: %lu\n", NameLength);
3262 
3263  if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3264  {
3265  MoreEntries = TRUE;
3266  break;
3267  }
3268 
3269  RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3270  EnumCount++;
3271 
3272  EnumIndex++;
3273  }
3274 
3275  TRACE("EnumCount: %lu\n", EnumCount);
3276  TRACE("RequiredLength: %lu\n", RequiredLength);
3277 
3278  if (!NT_SUCCESS(Status))
3279  goto done;
3280 
3281  EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3282  if (EnumBuffer == NULL)
3283  {
3285  goto done;
3286  }
3287 
3288  EnumBuffer->EntriesRead = EnumCount;
3289  if (EnumCount == 0)
3290  {
3292  goto done;
3293  }
3294 
3295  EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3296  if (EnumBuffer->Buffer == NULL)
3297  {
3299  goto done;
3300  }
3301 
3302  TRACE("Part 2\n");
3303 
3304  EnumIndex = *EnumerationContext;
3305  for (i = 0; i < EnumCount; i++, EnumIndex++)
3306  {
3307  NameLength = 64 * sizeof(WCHAR);
3308  DataLength = sizeof(ULONG);
3309  Status = SampRegEnumerateValue(NamesKeyHandle,
3310  EnumIndex,
3311  AliasName,
3312  &NameLength,
3313  NULL,
3314  &Rid,
3315  &DataLength);
3316  if (!NT_SUCCESS(Status))
3317  {
3320  break;
3321  }
3322 
3323  TRACE("EnumIndex: %lu\n", EnumIndex);
3324  TRACE("Alias name: %S\n", AliasName);
3325  TRACE("Name length: %lu\n", NameLength);
3326  TRACE("RID: %lu\n", Rid);
3327 
3328  EnumBuffer->Buffer[i].RelativeId = Rid;
3329 
3330  EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3331  EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
3332 
3333 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3334 #if 0
3335  EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3336  if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3337  {
3339  goto done;
3340  }
3341 
3342  memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3343  AliasName,
3344  EnumBuffer->Buffer[i].Name.Length);
3345 #endif
3346  }
3347 
3348 done:
3349  if (NT_SUCCESS(Status))
3350  {
3351  *EnumerationContext += EnumCount;
3352  *Buffer = EnumBuffer;
3353  *CountReturned = EnumCount;
3354  }
3355  else
3356  {
3357  *EnumerationContext = 0;
3358  *Buffer = NULL;
3359  *CountReturned = 0;
3360 
3361  if (EnumBuffer != NULL)
3362  {
3363  if (EnumBuffer->Buffer != NULL)
3364  {
3365  if (EnumBuffer->EntriesRead != 0)
3366  {
3367  for (i = 0; i < EnumBuffer->EntriesRead; i++)
3368  {
3369  if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3370  midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3371  }
3372  }
3373 
3374  midl_user_free(EnumBuffer->Buffer);
3375  }
3376 
3377  midl_user_free(EnumBuffer);
3378  }
3379  }
3380 
3381  SampRegCloseKey(&NamesKeyHandle);
3382  SampRegCloseKey(&AliasesKeyHandle);
3383 
3384  if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3386 
3388 
3389  return Status;
3390 }
3391 
3392 
3393 /* Function 16 */
3394 NTSTATUS
3395 NTAPI
3397  IN PSAMPR_PSID_ARRAY SidArray,
3398  OUT PSAMPR_ULONG_ARRAY Membership)
3399 {
3400  PSAM_DB_OBJECT DomainObject;
3401  HANDLE AliasesKeyHandle = NULL;
3402  HANDLE MembersKeyHandle = NULL;
3403  HANDLE MemberKeyHandle = NULL;
3404  LPWSTR MemberSidString = NULL;
3405  PULONG RidArray = NULL;
3406  ULONG MaxSidCount = 0;
3407  ULONG ValueCount;
3408  ULONG DataLength;
3409  ULONG i, j;
3410  ULONG RidIndex;
3411  NTSTATUS Status;
3412  WCHAR NameBuffer[9];
3413 
3414  TRACE("SamrGetAliasMembership(%p %p %p)\n",
3415  DomainHandle, SidArray, Membership);
3416 
3418  TRUE);
3419 
3420  /* Validate the domain handle */
3421  Status = SampValidateDbObject(DomainHandle,
3424  &DomainObject);
3425  if (!NT_SUCCESS(Status))
3426  goto done;
3427 
3428  Status = SampRegOpenKey(DomainObject->KeyHandle,
3429  L"Aliases",
3430  KEY_READ,
3431  &AliasesKeyHandle);
3432  TRACE("SampRegOpenKey returned %08lX\n", Status);
3433  if (!NT_SUCCESS(Status))
3434  goto done;
3435 
3436  Status = SampRegOpenKey(AliasesKeyHandle,
3437  L"Members",
3438  KEY_READ,
3439  &MembersKeyHandle);
3440  TRACE("SampRegOpenKey returned %08lX\n", Status);
3441 
3443  {
3445  goto done;
3446  }
3447 
3448  if (!NT_SUCCESS(Status))
3449  goto done;
3450 
3451  for (i = 0; i < SidArray->Count; i++)
3452  {
3453  ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3454 TRACE("Open %S\n", MemberSidString);
3455 
3456  Status = SampRegOpenKey(MembersKeyHandle,
3457  MemberSidString,
3458  KEY_READ,
3459  &MemberKeyHandle);
3460  TRACE("SampRegOpenKey returned %08lX\n", Status);
3461  if (NT_SUCCESS(Status))
3462  {
3463  Status = SampRegQueryKeyInfo(MemberKeyHandle,
3464  NULL,
3465  &ValueCount);
3466  if (NT_SUCCESS(Status))
3467  {
3468  TRACE("Found %lu values\n", ValueCount);
3469  MaxSidCount += ValueCount;
3470  }
3471 
3472  SampRegCloseKey(&MemberKeyHandle);
3473  }
3474 
3477 
3478  LocalFree(MemberSidString);
3479  }
3480 
3481  if (MaxSidCount == 0)
3482  {
3484  goto done;
3485  }
3486 
3487  TRACE("Maximum sid count: %lu\n", MaxSidCount);
3488  RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3489  if (RidArray == NULL)
3490  {
3492  goto done;
3493  }
3494 
3495  RidIndex = 0;
3496  for (i = 0; i < SidArray->Count; i++)
3497  {
3498  ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3499 TRACE("Open %S\n", MemberSidString);
3500 
3501  Status = SampRegOpenKey(MembersKeyHandle,
3502  MemberSidString,
3503  KEY_READ,
3504  &MemberKeyHandle);
3505  TRACE("SampRegOpenKey returned %08lX\n", Status);
3506  if (NT_SUCCESS(Status))
3507  {
3508  Status = SampRegQueryKeyInfo(MemberKeyHandle,
3509  NULL,
3510  &ValueCount);
3511  if (NT_SUCCESS(Status))
3512  {
3513  TRACE("Found %lu values\n", ValueCount);
3514 
3515  for (j = 0; j < ValueCount; j++)
3516  {
3517  DataLength = 9 * sizeof(WCHAR);
3518  Status = SampRegEnumerateValue(MemberKeyHandle,
3519  j,
3520  NameBuffer,
3521  &DataLength,
3522  NULL,
3523  NULL,
3524  NULL);
3525  if (NT_SUCCESS(Status))
3526  {
3527  /* FIXME: Do not return each RID more than once. */
3528  RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
3529  RidIndex++;
3530  }
3531  }
3532  }
3533 
3534  SampRegCloseKey(&MemberKeyHandle);
3535  }
3536 
3539 
3540  LocalFree(MemberSidString);
3541  }
3542 
3543 done:
3544  SampRegCloseKey(&MembersKeyHandle);
3545  SampRegCloseKey(&AliasesKeyHandle);
3546 
3547  if (NT_SUCCESS(Status))
3548  {
3549  Membership->Count = MaxSidCount;
3550  Membership->Element = RidArray;
3551  }
3552  else
3553  {
3554  if (RidArray != NULL)
3555  midl_user_free(RidArray);
3556  }
3557 
3559 
3560  return Status;
3561 }
3562 
3563 
3564 /* Function 17 */
3565 NTSTATUS
3566 NTAPI
3568  IN ULONG Count,
3570  OUT PSAMPR_ULONG_ARRAY RelativeIds,
3571  OUT PSAMPR_ULONG_ARRAY Use)
3572 {
3573  PSAM_DB_OBJECT DomainObject;
3574  HANDLE AccountsKeyHandle = NULL;
3575  HANDLE NamesKeyHandle = NULL;
3576  ULONG MappedCount = 0;
3577  ULONG DataLength;
3578  ULONG i;
3579  ULONG RelativeId;
3580  NTSTATUS Status;
3581 
3582  TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3583  DomainHandle, Count, Names, RelativeIds, Use);
3584 
3586  TRUE);
3587 
3588  /* Validate the domain handle */
3589  Status = SampValidateDbObject(DomainHandle,
3591  DOMAIN_LOOKUP,
3592  &DomainObject);
3593  if (!NT_SUCCESS(Status))
3594  {
3595  TRACE("failed with status 0x%08lx\n", Status);
3596  goto done;
3597  }
3598 
3599  RelativeIds->Count = 0;
3600  Use->Count = 0;
3601 
3602  if (Count == 0)
3603  {
3605  goto done;
3606  }
3607 
3608  /* Allocate the relative IDs array */
3609  RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3610  if (RelativeIds->Element == NULL)
3611  {
3613  goto done;
3614  }
3615 
3616  /* Allocate the use array */
3617  Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3618  if (Use->Element == NULL)
3619  {
3621  goto done;
3622  }
3623 
3624  RelativeIds->Count = Count;
3625  Use->Count = Count;
3626 
3627  for (i = 0; i < Count; i++)
3628  {
3629  TRACE("Name: %S\n", Names[i].Buffer);
3630 
3631  RelativeId = 0;
3632 
3633  /* Lookup aliases */
3634  Status = SampRegOpenKey(DomainObject->KeyHandle,
3635  L"Aliases",
3636  KEY_READ,
3637  &AccountsKeyHandle);
3638  if (NT_SUCCESS(Status))
3639  {
3640  Status = SampRegOpenKey(AccountsKeyHandle,
3641  L"Names",
3642  KEY_READ,
3643  &NamesKeyHandle);
3644  if (NT_SUCCESS(Status))
3645  {
3646  DataLength = sizeof(ULONG);
3647  Status = SampRegQueryValue(NamesKeyHandle,
3648  Names[i].Buffer,
3649  NULL,
3650  &RelativeId,
3651  &DataLength);
3652 
3653  SampRegCloseKey(&NamesKeyHandle);
3654  }
3655 
3656  SampRegCloseKey(&AccountsKeyHandle);
3657  }
3658 
3660  break;
3661 
3662  /* Return alias account */
3663  if (NT_SUCCESS(Status) && RelativeId != 0)
3664  {
3665  TRACE("Rid: %lu\n", RelativeId);
3666  RelativeIds->Element[i] = RelativeId;
3667  Use->Element[i] = SidTypeAlias;
3668  MappedCount++;
3669  continue;
3670  }
3671 
3672  /* Lookup groups */
3673  Status = SampRegOpenKey(DomainObject->KeyHandle,
3674  L"Groups",
3675  KEY_READ,
3676  &AccountsKeyHandle);
3677  if (NT_SUCCESS(Status))
3678  {
3679  Status = SampRegOpenKey(AccountsKeyHandle,
3680  L"Names",
3681  KEY_READ,
3682  &NamesKeyHandle);
3683  if (NT_SUCCESS(Status))
3684  {
3685  DataLength = sizeof(ULONG);
3686  Status = SampRegQueryValue(NamesKeyHandle,
3687  Names[i].Buffer,
3688  NULL,
3689  &RelativeId,
3690  &DataLength);
3691 
3692  SampRegCloseKey(&NamesKeyHandle);
3693  }
3694 
3695  SampRegCloseKey(&AccountsKeyHandle);
3696  }
3697 
3699  break;
3700 
3701  /* Return group account */
3702  if (NT_SUCCESS(Status) && RelativeId != 0)
3703  {
3704  TRACE("Rid: %lu\n", RelativeId);
3705  RelativeIds->Element[i] = RelativeId;
3706  Use->Element[i] = SidTypeGroup;
3707  MappedCount++;
3708  continue;
3709  }
3710 
3711  /* Lookup users */
3712  Status = SampRegOpenKey(DomainObject->KeyHandle,
3713  L"Users",
3714  KEY_READ,
3715  &AccountsKeyHandle);
3716  if (NT_SUCCESS(Status))
3717  {
3718  Status = SampRegOpenKey(AccountsKeyHandle,
3719  L"Names",
3720  KEY_READ,
3721  &NamesKeyHandle);
3722  if (NT_SUCCESS(Status))
3723  {
3724  DataLength = sizeof(ULONG);
3725  Status = SampRegQueryValue(NamesKeyHandle,
3726  Names[i].Buffer,
3727  NULL,
3728  &RelativeId,
3729  &DataLength);
3730 
3731  SampRegCloseKey(&NamesKeyHandle);
3732  }
3733 
3734  SampRegCloseKey(&AccountsKeyHandle);
3735  }
3736 
3738  break;
3739 
3740  /* Return user account */
3741  if (NT_SUCCESS(Status) && RelativeId != 0)
3742  {
3743  TRACE("Rid: %lu\n", RelativeId);
3744  RelativeIds->Element[i] = RelativeId;
3745  Use->Element[i] = SidTypeUser;
3746  MappedCount++;
3747  continue;
3748  }
3749 
3750  /* Return unknown account */
3751  RelativeIds->Element[i] = 0;
3752  Use->Element[i] = SidTypeUnknown;
3753  }
3754 
3755 done:
3758 
3759  if (NT_SUCCESS(Status))
3760  {
3761  if (MappedCount == 0)
3763  else if (MappedCount < Count)
3765  }
3766  else
3767  {
3768  if (RelativeIds->Element != NULL)
3769  {
3770  midl_user_free(RelativeIds->Element);
3771  RelativeIds->Element = NULL;
3772  }
3773 
3774  RelativeIds->Count = 0;
3775 
3776  if (Use->Element != NULL)
3777  {
3778  midl_user_free(Use->Element);
3779  Use->Element = NULL;
3780  }
3781 
3782  Use->Count = 0;
3783  }
3784 
3786 
3787  TRACE("Returned Status %lx\n", Status);
3788 
3789  return Status;
3790 }
3791 
3792 
3793 /* Function 18 */
3794 NTSTATUS
3795 NTAPI
3797  IN ULONG Count,
3798  IN ULONG *RelativeIds,
3800  OUT PSAMPR_ULONG_ARRAY Use)
3801 {
3802  PSAM_DB_OBJECT DomainObject;
3803  WCHAR RidString[9];
3804  HANDLE AccountsKeyHandle = NULL;
3805  HANDLE AccountKeyHandle = NULL;
3806  ULONG MappedCount = 0;
3807  ULONG DataLength;
3808  ULONG i;
3809  NTSTATUS Status;
3810 
3811  TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3812  DomainHandle, Count, RelativeIds, Names, Use);
3813 
3815  TRUE);
3816 
3817  /* Validate the domain handle */
3818  Status = SampValidateDbObject(DomainHandle,
3820  DOMAIN_LOOKUP,
3821  &DomainObject);
3822  if (!NT_SUCCESS(Status))
3823  {
3824  TRACE("failed with status 0x%08lx\n", Status);
3825  goto done;
3826  }
3827 
3828  Names->Count = 0;
3829  Use->Count = 0;
3830 
3831  if (Count == 0)
3832  {
3834  goto done;
3835  }
3836 
3837  /* Allocate the names array */
3838  Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
3839  if (Names->Element == NULL)
3840  {
3842  goto done;
3843  }
3844 
3845  /* Allocate the use array */
3846  Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
3847  if (Use->Element == NULL)
3848  {
3850  goto done;
3851  }
3852 
3853  Names->Count = Count;
3854  Use->Count = Count;
3855 
3856  for (i = 0; i < Count; i++)
3857  {
3858  TRACE("RID: %lu\n", RelativeIds[i]);
3859 
3860  swprintf(RidString, L"%08lx", RelativeIds[i]);
3861 
3862  /* Lookup aliases */
3863  Status = SampRegOpenKey(DomainObject->KeyHandle,
3864  L"Aliases",
3865  KEY_READ,
3866  &AccountsKeyHandle);
3867  if (NT_SUCCESS(Status))
3868  {
3869  Status = SampRegOpenKey(AccountsKeyHandle,
3870  RidString,
3871  KEY_READ,
3872  &AccountKeyHandle);
3873  if (NT_SUCCESS(Status))
3874  {
3875  DataLength = 0;
3876  Status = SampRegQueryValue(AccountKeyHandle,
3877  L"Name",
3878  NULL,
3879  NULL,
3880  &DataLength);
3881  if (NT_SUCCESS(Status))
3882  {
3883  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3884  if (Names->Element[i].Buffer == NULL)
3886 
3887  if (NT_SUCCESS(Status))
3888  {
3889  Names->Element[i].MaximumLength = (USHORT)DataLength;
3890  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3891 
3892  Status = SampRegQueryValue(AccountKeyHandle,
3893  L"Name",
3894  NULL,
3895  Names->Element[i].Buffer,
3896  &DataLength);
3897  }
3898  }
3899 
3900  SampRegCloseKey(&AccountKeyHandle);
3901  }
3902 
3903  SampRegCloseKey(&AccountsKeyHandle);
3904  }
3905 
3907  break;
3908 
3909  /* Return alias account */
3910  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3911  {
3912  TRACE("Name: %S\n", Names->Element[i].Buffer);
3913  Use->Element[i] = SidTypeAlias;
3914  MappedCount++;
3915  continue;
3916  }
3917 
3918  /* Lookup groups */
3919  Status = SampRegOpenKey(DomainObject->KeyHandle,
3920  L"Groups",
3921  KEY_READ,
3922  &AccountsKeyHandle);
3923  if (NT_SUCCESS(Status))
3924  {
3925  Status = SampRegOpenKey(AccountsKeyHandle,
3926  RidString,
3927  KEY_READ,
3928  &AccountKeyHandle);
3929  if (NT_SUCCESS(Status))
3930  {
3931  DataLength = 0;
3932  Status = SampRegQueryValue(AccountKeyHandle,
3933  L"Name",
3934  NULL,
3935  NULL,
3936  &DataLength);
3937  if (NT_SUCCESS(Status))
3938  {
3939  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3940  if (Names->Element[i].Buffer == NULL)
3942 
3943  if (NT_SUCCESS(Status))
3944  {
3945  Names->Element[i].MaximumLength = (USHORT)DataLength;
3946  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3947 
3948  Status = SampRegQueryValue(AccountKeyHandle,
3949  L"Name",
3950  NULL,
3951  Names->Element[i].Buffer,
3952  &DataLength);
3953  }
3954  }
3955 
3956  SampRegCloseKey(&AccountKeyHandle);
3957  }
3958 
3959  SampRegCloseKey(&AccountsKeyHandle);
3960  }
3961 
3963  break;
3964 
3965  /* Return group account */
3966  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3967  {
3968  TRACE("Name: %S\n", Names->Element[i].Buffer);
3969  Use->Element[i] = SidTypeGroup;
3970  MappedCount++;
3971  continue;
3972  }
3973 
3974  /* Lookup users */
3975  Status = SampRegOpenKey(DomainObject->KeyHandle,
3976  L"Users",
3977  KEY_READ,
3978  &AccountsKeyHandle);
3979  if (NT_SUCCESS(Status))
3980  {
3981  Status = SampRegOpenKey(AccountsKeyHandle,
3982  RidString,
3983  KEY_READ,
3984  &AccountKeyHandle);
3985  if (NT_SUCCESS(Status))
3986  {
3987  DataLength = 0;
3988  Status = SampRegQueryValue(AccountKeyHandle,
3989  L"Name",
3990  NULL,
3991  NULL,
3992  &DataLength);
3993  if (NT_SUCCESS(Status))
3994  {
3995  TRACE("DataLength: %lu\n", DataLength);
3996 
3997  Names->Element[i].Buffer = midl_user_allocate(DataLength);
3998  if (Names->Element[i].Buffer == NULL)
4000 
4001  if (NT_SUCCESS(Status))
4002  {
4003  Names->Element[i].MaximumLength = (USHORT)DataLength;
4004  Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
4005 
4006  Status = SampRegQueryValue(AccountKeyHandle,
4007  L"Name",
4008  NULL,
4009  Names->Element[i].Buffer,
4010  &DataLength);
4011  }
4012  }
4013 
4014  SampRegCloseKey(&AccountKeyHandle);
4015  }
4016 
4017  SampRegCloseKey(&AccountsKeyHandle);
4018  }
4019 
4021  break;
4022 
4023  /* Return user account */
4024  if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
4025  {
4026  TRACE("Name: %S\n", Names->Element[i].Buffer);
4027  Use->Element[i] = SidTypeUser;
4028  MappedCount++;
4029  continue;
4030  }
4031 
4032  /* Return unknown account */
4033  Use->Element[i] = SidTypeUnknown;
4034  }
4035 
4036 done:
4039 
4040  if (NT_SUCCESS(Status))
4041  {
4042  if (MappedCount == 0)
4044  else if (MappedCount < Count)
4046  }
4047  else
4048  {
4049  if (Names->Element != NULL)
4050  {
4051  for (i = 0; i < Count; i++)
4052  {
4053  if (Names->Element[i].Buffer != NULL)
4054  midl_user_free(Names->Element[i].Buffer);
4055  }
4056 
4057  midl_user_free(Names->Element);
4058  Names->Element = NULL;
4059  }
4060 
4061  Names->Count = 0;
4062 
4063  if (Use->Element != NULL)
4064  {
4065  midl_user_free(Use->Element);
4066  Use->Element = NULL;
4067  }
4068 
4069  Use->Count = 0;
4070  }
4071 
4073 
4074  return Status;
4075 }
4076 
4077 
4078 /* Function 19 */
4079 NTSTATUS
4080 NTAPI
4083  IN unsigned long GroupId,
4084  OUT SAMPR_HANDLE *GroupHandle)
4085 {
4086  PSAM_DB_OBJECT DomainObject;
4087  PSAM_DB_OBJECT GroupObject;
4088  WCHAR szRid[9];
4089  NTSTATUS Status;
4090 
4091  TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
4092  DomainHandle, DesiredAccess, GroupId, GroupHandle);
4093 
4094  /* Map generic access rights */
4096  &GroupMapping);
4097 
4099  TRUE);
4100 
4101  /* Validate the domain handle */
4102  Status = SampValidateDbObject(DomainHandle,
4104  DOMAIN_LOOKUP,
4105  &DomainObject);
4106  if (!NT_SUCCESS(Status))
4107  {
4108  TRACE("failed with status 0x%08lx\n", Status);
4109  goto done;
4110  }
4111 
4112  /* Convert the RID into a string (hex) */
4113  swprintf(szRid, L"%08lX", GroupId);
4114 
4115  /* Create the group object */
4116  Status = SampOpenDbObject(DomainObject,
4117  L"Groups",
4118  szRid,
4119  GroupId,
4121  DesiredAccess,
4122  &GroupObject);
4123  if (!NT_SUCCESS(Status))
4124  {
4125  TRACE("failed with status 0x%08lx\n", Status);
4126  goto done;
4127  }
4128 
4129  *GroupHandle = (SAMPR_HANDLE)GroupObject;
4130 
4131 done:
4133 
4134  return Status;
4135 }
4136 
4137 
4138 static NTSTATUS
4141 {
4142  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4143  SAM_GROUP_FIXED_DATA FixedData;
4144  ULONG MembersLength = 0;
4145  ULONG Length = 0;
4146  NTSTATUS Status;
4147 
4148  *Buffer = NULL;
4149 
4150  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4151  if (InfoBuffer == NULL)
4153 
4154  Status = SampGetObjectAttributeString(GroupObject,
4155  L"Name",
4156  &InfoBuffer->General.Name);
4157  if (!NT_SUCCESS(Status))
4158  {
4159  TRACE("Status 0x%08lx\n", Status);
4160  goto done;
4161  }
4162 
4163  Status = SampGetObjectAttributeString(GroupObject,
4164  L"AdminComment",
4165  &InfoBuffer->General.AdminComment);
4166  if (!NT_SUCCESS(Status))
4167  {
4168  TRACE("Status 0x%08lx\n", Status);
4169  goto done;
4170  }
4171 
4172  Length = sizeof(SAM_GROUP_FIXED_DATA);
4173  Status = SampGetObjectAttribute(GroupObject,
4174  L"F",
4175  NULL,
4176  (PVOID)&FixedData,
4177  &Length);
4178  if (!NT_SUCCESS(Status))
4179  {
4180  TRACE("Status 0x%08lx\n", Status);
4181  goto done;
4182  }
4183 
4184  InfoBuffer->General.Attributes = FixedData.Attributes;
4185 
4186  Status = SampGetObjectAttribute(GroupObject,
4187  L"Members",
4188  NULL,
4189  NULL,
4190  &MembersLength);
4192  {
4193  TRACE("Status 0x%08lx\n", Status);
4194  goto done;
4195  }
4196 
4198  {
4199  InfoBuffer->General.MemberCount = 0;
4201  }
4202  else
4203  {
4204  InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4205  }
4206 
4207  *Buffer = InfoBuffer;
4208 
4209 done:
4210  if (!NT_SUCCESS(Status))
4211  {
4212  if (InfoBuffer != NULL)
4213  {
4214  if (InfoBuffer->General.Name.Buffer != NULL)
4215  midl_user_free(InfoBuffer->General.Name.Buffer);
4216 
4217  if (InfoBuffer->General.AdminComment.Buffer != NULL)
4219 
4220  midl_user_free(InfoBuffer);
4221  }
4222  }
4223 
4224  return Status;
4225 }
4226 
4227 
4228 static NTSTATUS
4231 {
4232  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4233  NTSTATUS Status;
4234 
4235  *Buffer = NULL;
4236 
4237  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4238  if (InfoBuffer == NULL)
4240 
4241  Status = SampGetObjectAttributeString(GroupObject,
4242  L"Name",
4243  &InfoBuffer->Name.Name);
4244  if (!NT_SUCCESS(Status))
4245  {
4246  TRACE("Status 0x%08lx\n", Status);
4247  goto done;
4248  }
4249 
4250  *Buffer = InfoBuffer;
4251 
4252 done:
4253  if (!NT_SUCCESS(Status))
4254  {
4255  if (InfoBuffer != NULL)
4256  {
4257  if (InfoBuffer->Name.Name.Buffer != NULL)
4258  midl_user_free(InfoBuffer->Name.Name.Buffer);
4259 
4260  midl_user_free(InfoBuffer);
4261  }
4262  }
4263 
4264  return Status;
4265 }
4266 
4267 
4268 static NTSTATUS
4271 {
4272  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4273  SAM_GROUP_FIXED_DATA FixedData;
4274  ULONG Length = 0;
4275  NTSTATUS Status;
4276 
4277  *Buffer = NULL;
4278 
4279  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4280  if (InfoBuffer == NULL)
4282 
4283  Length = sizeof(SAM_GROUP_FIXED_DATA);
4284  Status = SampGetObjectAttribute(GroupObject,
4285  L"F",
4286  NULL,
4287  (PVOID)&FixedData,
4288  &Length);
4289  if (!NT_SUCCESS(Status))
4290  {
4291  TRACE("Status 0x%08lx\n", Status);
4292  goto done;
4293  }
4294 
4295  InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4296 
4297  *Buffer = InfoBuffer;
4298 
4299 done:
4300  if (!NT_SUCCESS(Status))
4301  {
4302  if (InfoBuffer != NULL)
4303  {
4304  midl_user_free(InfoBuffer);
4305  }
4306  }
4307 
4308  return Status;
4309 }
4310 
4311 
4312 static NTSTATUS
4315 {
4316  PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4317  NTSTATUS Status;
4318 
4319  *Buffer = NULL;
4320 
4321  InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4322  if (InfoBuffer == NULL)
4324 
4325  Status = SampGetObjectAttributeString(GroupObject,
4326  L"AdminComment",
4327  &InfoBuffer->AdminComment.AdminComment);
4328  if (!NT_SUCCESS(Status))
4329  {
4330  TRACE("Status 0x%08lx\n", Status);
4331  goto done;
4332  }
4333 
4334  *Buffer = InfoBuffer;
4335 
4336 done:
4337  if (!NT_SUCCESS(Status))
4338  {
4339  if (InfoBuffer != NULL)
4340  {
4341  if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4343 
4344  midl_user_free(InfoBuffer);
4345  }
4346  }
4347 
4348  return Status;
4349 }
4350 
4351 
4352 /* Function 20 */
4353 NTSTATUS
4354 NTAPI
4356  IN GROUP_INFORMATION_CLASS GroupInformationClass,
4358 {
4359  PSAM_DB_OBJECT GroupObject;
4360  NTSTATUS Status;
4361 
4362  TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4363  GroupHandle, GroupInformationClass, Buffer);
4364 
4366  TRUE);
4367 
4368  /* Validate the group handle */
4369  Status = SampValidateDbObject(GroupHandle,
4372  &GroupObject);
4373  if (!NT_SUCCESS(Status))
4374  goto done;
4375 
4376  switch (GroupInformationClass)
4377  {
4379  Status = SampQueryGroupGeneral(GroupObject,
4380  Buffer);
4381  break;
4382 
4383  case GroupNameInformation:
4384  Status = SampQueryGroupName(GroupObject,
4385  Buffer);
4386  break;
4387 
4389  Status = SampQueryGroupAttribute(GroupObject,
4390  Buffer);
4391  break;
4392 
4394  Status = SampQueryGroupAdminComment(GroupObject,
4395  Buffer);
4396  break;
4397 
4398  default:
4400  break;
4401  }
4402 
4403 done:
4405 
4406  return Status;
4407 }
4408 
4409 
4410 static NTSTATUS
4413 {
4414  UNICODE_STRING OldGroupName = {0, 0, NULL};
4415  UNICODE_STRING NewGroupName;
4416  NTSTATUS Status;
4417 
4418  Status = SampGetObjectAttributeString(GroupObject,
4419  L"Name",
4420  (PRPC_UNICODE_STRING)&OldGroupName);
4421  if (!NT_SUCCESS(Status))
4422  {
4423  TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4424  goto done;
4425  }
4426 
4427  /* Check the new account name */
4428  Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4429  if (!NT_SUCCESS(Status))
4430  {
4431  TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4432  return Status;
4433  }
4434 
4435  NewGroupName.Length = Buffer->Name.Name.Length;
4436  NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4437  NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4438 
4439  if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4440  {
4442  NewGroupName.Buffer);
4443  if (!NT_SUCCESS(Status))
4444  {
4445  TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4446  NewGroupName.Buffer, Status);
4447  goto done;
4448  }
4449  }
4450 
4452  L"Groups",
4453  NewGroupName.Buffer,
4454  GroupObject->RelativeId);
4455  if (!NT_SUCCESS(Status))
4456  {
4457  TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4458  goto done;
4459  }
4460 
4462  L"Groups",
4463  OldGroupName.Buffer);
4464  if (!NT_SUCCESS(Status))
4465  {
4466  TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4467  goto done;
4468  }
4469 
4470  Status = SampSetObjectAttributeString(GroupObject,
4471  L"Name",
4472  (PRPC_UNICODE_STRING)&NewGroupName);
4473  if (!NT_SUCCESS(Status))
4474  {
4475  TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4476  }
4477 
4478 done:
4479  if (OldGroupName.Buffer != NULL)
4480  midl_user_free(OldGroupName.Buffer);
4481 
4482  return Status;
4483 }
4484 
4485 
4486 static NTSTATUS
4489 {
4490  SAM_GROUP_FIXED_DATA FixedData;
4491  ULONG Length = 0;
4492  NTSTATUS Status;
4493 
4494  Length = sizeof(SAM_GROUP_FIXED_DATA);
4495  Status = SampGetObjectAttribute(GroupObject,
4496  L"F",
4497  NULL,
4498  (PVOID)&FixedData,
4499  &Length);
4500  if (!NT_SUCCESS(Status))
4501  goto done;
4502 
4503  FixedData.Attributes = Buffer->Attribute.Attributes;
4504 
4505  Status = SampSetObjectAttribute(GroupObject,
4506  L"F",
4507  REG_BINARY,
4508  &FixedData,
4509  Length);
4510 
4511 done:
4512  return Status;
4513 }
4514 
4515 
4516 /* Function 21 */
4517 NTSTATUS
4518 NTAPI
4520  IN GROUP_INFORMATION_CLASS GroupInformationClass,
4522 {
4523  PSAM_DB_OBJECT GroupObject;
4524  NTSTATUS Status;
4525 
4526  TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4527  GroupHandle, GroupInformationClass, Buffer);
4528 
4530  TRUE);
4531 
4532  /* Validate the group handle */
4533  Status = SampValidateDbObject(GroupHandle,
4536  &GroupObject);
4537  if (!NT_SUCCESS(Status))
4538  goto done;
4539 
4540  switch (GroupInformationClass)
4541  {
4542  case GroupNameInformation:
4543  Status = SampSetGroupName(GroupObject,
4544  Buffer);
4545  break;
4546 
4548  Status = SampSetGroupAttribute(GroupObject,
4549  Buffer);
4550  break;
4551 
4553  Status = SampSetObjectAttributeString(GroupObject,
4554  L"AdminComment",
4555  &Buffer->AdminComment.AdminComment);
4556  break;
4557 
4558  default:
4560  break;
4561  }
4562 
4563 done:
4565 
4566  return Status;
4567 }
4568 
4569 
4570 /* Function 22 */
4571 NTSTATUS
4572 NTAPI
4574  IN unsigned long MemberId,
4575  IN unsigned long Attributes)
4576 {
4577  PSAM_DB_OBJECT GroupObject;
4578  PSAM_DB_OBJECT UserObject = NULL;
4579  NTSTATUS Status;
4580 
4581  TRACE("SamrAddMemberToGroup(%p %lu %lx)\n",
4582  GroupHandle, MemberId, Attributes);
4583 
4585  TRUE);
4586 
4587  /* Validate the group handle */
4588  Status = SampValidateDbObject(GroupHandle,
4591  &GroupObject);
4592  if (!NT_SUCCESS(Status))
4593  goto done;
4594 
4595  /* Open the user object in the same domain */
4596  Status = SampOpenUserObject(GroupObject->ParentObject,
4597  MemberId,
4598  0,
4599  &UserObject);
4600  if (!NT_SUCCESS(Status))
4601  {
4602  TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4603  goto done;
4604  }
4605 
4606  /* Add group membership to the user object */
4607  Status = SampAddGroupMembershipToUser(UserObject,
4608  GroupObject->RelativeId,
4609  Attributes);
4610  if (!NT_SUCCESS(Status))
4611  {
4612  TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4613  goto done;
4614  }
4615 
4616  /* Add the member to the group object */
4617  Status = SampAddMemberToGroup(GroupObject,
4618  MemberId);
4619  if (!NT_SUCCESS(Status))
4620  {
4621  TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4622  }
4623 
4624 done:
4625  if (UserObject)
4626  SampCloseDbObject(UserObject);
4627 
4629 
4630  return Status;
4631 }
4632 
4633 
4634 /* Function 23 */
4635 NTSTATUS
4636 NTAPI
4638 {
4639  PSAM_DB_OBJECT GroupObject;
4640  ULONG Length = 0;
4641  NTSTATUS Status;
4642 
4643  TRACE("SamrDeleteGroup(%p)\n", GroupHandle);
4644 
4646  TRUE);
4647 
4648  /* Validate the group handle */
4649  Status = SampValidateDbObject(*GroupHandle,
4651  DELETE,
4652  &GroupObject);
4653  if (!NT_SUCCESS(Status))
4654  {
4655  TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4656  goto done;
4657  }
4658 
4659  /* Fail, if the group is built-in */
4660  if (GroupObject->RelativeId < 1000)
4661  {
4662  TRACE("You can not delete a special account!\n");
4664  goto done;
4665  }
4666 
4667  /* Get the length of the Members attribute */
4668  SampGetObjectAttribute(GroupObject,
4669  L"Members",
4670  NULL,
4671  NULL,
4672  &Length);
4673 
4674  /* Fail, if the group has members */
4675  if (Length != 0)
4676  {
4677  TRACE("There are still members in the group!\n");
4679  goto done;
4680  }
4681 
4682  /* FIXME: Remove the group from all aliases */
4683 
4684  /* Delete the group from the database */
4685  Status = SampDeleteAccountDbObject(GroupObject);
4686  if (!NT_SUCCESS(Status))
4687  {
4688  TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4689  goto done;
4690  }
4691 
4692  /* Invalidate the handle */
4693  *GroupHandle = NULL;
4694 
4695 done:
4697 
4698  return Status;
4699 }
4700 
4701 
4702 /* Function 24 */
4703 NTSTATUS
4704 NTAPI
4706  IN unsigned long MemberId)
4707 {
4708  PSAM_DB_OBJECT GroupObject;
4709  PSAM_DB_OBJECT UserObject = NULL;
4710  NTSTATUS Status;
4711 
4712  TRACE("SamrRemoveMemberFromGroup(%p %lu)\n",
4713  GroupHandle, MemberId);
4714 
4716  TRUE);
4717 
4718  /* Validate the group handle */
4719  Status = SampValidateDbObject(GroupHandle,
4722  &GroupObject);
4723  if (!NT_SUCCESS(Status))
4724  goto done;
4725 
4726  /* Open the user object in the same domain */
4727  Status = SampOpenUserObject(GroupObject->ParentObject,
4728  MemberId,
4729  0,
4730  &UserObject);
4731  if (!NT_SUCCESS(Status))
4732  {
4733  ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4734  goto done;
4735  }
4736 
4737  /* Remove group membership from the user object */
4739  GroupObject->RelativeId);
4740  if (!NT_SUCCESS(Status))
4741  {
4742  ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4743  goto done;
4744  }
4745 
4746  /* Remove the member from the group object */
4747  Status = SampRemoveMemberFromGroup(GroupObject,
4748  MemberId);
4749  if (!NT_SUCCESS(Status))
4750  {
4751  ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4752  }
4753 
4754 done:
4755  if (UserObject)
4756  SampCloseDbObject(UserObject);
4757 
4759 
4760  return Status;
4761 }
4762 
4763 
4764 /* Function 25 */
4765 NTSTATUS
4766 NTAPI
4768  OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4769 {
4770  PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4771  PSAM_DB_OBJECT GroupObject;
4772  ULONG Length = 0;
4773  ULONG i;
4774  NTSTATUS Status;
4775 
4776  TRACE("SamrGetMembersInGroup(%p %p)\n",
4777  GroupHandle, Members);
4778 
4780  TRUE);
4781 
4782  /* Validate the group handle */
4783  Status = SampValidateDbObject(GroupHandle,
4786  &GroupObject);
4787  if (!NT_SUCCESS(Status))
4788  goto done;
4789 
4790  MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4791  if (MembersBuffer == NULL)
4792  {
4794  goto done;
4795  }
4796 
4797  SampGetObjectAttribute(GroupObject,
4798  L"Members",
4799  NULL,
4800  NULL,
4801  &Length);
4802 
4803  if (Length == 0)
4804  {
4805  MembersBuffer->MemberCount = 0;
4806  MembersBuffer->Members = NULL;
4807  MembersBuffer->Attributes = NULL;
4808 
4809  *Members = MembersBuffer;
4810 
4812  goto done;
4813  }
4814 
4815  MembersBuffer->Members = midl_user_allocate(Length);
4816  if (MembersBuffer->Members == NULL)
4817  {
4819  goto done;
4820  }
4821 
4822  MembersBuffer->Attributes = midl_user_allocate(Length);
4823  if (MembersBuffer->Attributes == NULL)
4824  {
4826  goto done;
4827  }
4828 
4829  Status = SampGetObjectAttribute(GroupObject,
4830  L"Members",
4831  NULL,
4832  MembersBuffer->Members,
4833  &Length);
4834  if (!NT_SUCCESS(Status))
4835  {
4836  TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4837  goto done;
4838  }
4839 
4840  MembersBuffer->MemberCount = Length / sizeof(ULONG);
4841 
4842  for (i = 0; i < MembersBuffer->MemberCount; i++)
4843  {
4845  MembersBuffer->Members[i],
4846  GroupObject->RelativeId,
4847  &(MembersBuffer->Attributes[i]));
4848  if (!NT_SUCCESS(Status))
4849  {
4850  TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4851  goto done;
4852  }
4853  }
4854 
4855  *Members = MembersBuffer;
4856 
4857 done:
4858  if (!NT_SUCCESS(Status))
4859  {
4860  if (MembersBuffer != NULL)
4861  {
4862  if (MembersBuffer->Members != NULL)
4863  midl_user_free(MembersBuffer->Members);
4864 
4865  if (MembersBuffer->Attributes != NULL)
4866  midl_user_free(MembersBuffer->Attributes);
4867 
4868  midl_user_free(MembersBuffer);
4869  }
4870  }
4871 
4873 
4874  return Status;
4875 }
4876 
4877 
4878 /* Function 26 */
4879 NTSTATUS
4880 NTAPI
4882  IN unsigned long MemberId,
4883  IN unsigned long Attributes)
4884 {
4885  PSAM_DB_OBJECT GroupObject;
4886  NTSTATUS Status;
4887 
4888  TRACE("SamrSetMemberAttributesOfGroup(%p %lu %lx)\n",
4889  GroupHandle, MemberId, Attributes);
4890 
4892  TRUE);
4893 
4894  /* Validate the group handle */
4895  Status = SampValidateDbObject(GroupHandle,
4898  &GroupObject);
4899  if (!NT_SUCCESS(Status))
4900  {
4901  TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4902  goto done;
4903  }
4904 
4905  Status =