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