xref: /reactos/dll/win32/samsrv/samrpc.c (revision 3435c3b5)
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 
14 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
15 
16 static GENERIC_MAPPING ServerMapping =
17 {
18     SAM_SERVER_READ,
19     SAM_SERVER_WRITE,
20     SAM_SERVER_EXECUTE,
21     SAM_SERVER_ALL_ACCESS
22 };
23 
24 static GENERIC_MAPPING DomainMapping =
25 {
26     DOMAIN_READ,
27     DOMAIN_WRITE,
28     DOMAIN_EXECUTE,
29     DOMAIN_ALL_ACCESS
30 };
31 
32 static GENERIC_MAPPING AliasMapping =
33 {
34     ALIAS_READ,
35     ALIAS_WRITE,
36     ALIAS_EXECUTE,
37     ALIAS_ALL_ACCESS
38 };
39 
40 static GENERIC_MAPPING GroupMapping =
41 {
42     GROUP_READ,
43     GROUP_WRITE,
44     GROUP_EXECUTE,
45     GROUP_ALL_ACCESS
46 };
47 
48 static GENERIC_MAPPING UserMapping =
49 {
50     USER_READ,
51     USER_WRITE,
52     USER_EXECUTE,
53     USER_ALL_ACCESS
54 };
55 
56 PGENERIC_MAPPING pServerMapping = &ServerMapping;
57 
58 
59 /* FUNCTIONS *****************************************************************/
60 
61 static
62 LARGE_INTEGER
63 SampAddRelativeTimeToTime(IN LARGE_INTEGER AbsoluteTime,
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
78 SampStartRpcServer(VOID)
79 {
80     RPC_STATUS Status;
81 
82     TRACE("SampStartRpcServer() called\n");
83 
84     Status = RpcServerUseProtseqEpW(L"ncacn_np",
85                                     RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
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 
114 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
115 {
116     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
117 }
118 
119 
120 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
121 {
122     HeapFree(GetProcessHeap(), 0, ptr);
123 }
124 
125 
126 void __RPC_USER SAMPR_HANDLE_rundown(SAMPR_HANDLE hHandle)
127 {
128 }
129 
130 
131 /* Function 0 */
132 NTSTATUS
133 NTAPI
134 SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
135             OUT SAMPR_HANDLE *ServerHandle,
136             IN ACCESS_MASK DesiredAccess)
137 {
138     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
139     ULONG OutVersion;
140 
141     TRACE("SamrConnect(%p %p %lx)\n",
142           ServerName, ServerHandle, DesiredAccess);
143 
144     InRevisionInfo.V1.Revision = 0;
145     InRevisionInfo.V1.SupportedFeatures = 0;
146 
147     return SamrConnect5(ServerName,
148                         DesiredAccess,
149                         1,
150                         &InRevisionInfo,
151                         &OutVersion,
152                         &OutRevisionInfo,
153                         ServerHandle);
154 }
155 
156 
157 /* Function 1 */
158 NTSTATUS
159 NTAPI
160 SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle)
161 {
162     PSAM_DB_OBJECT DbObject;
163     NTSTATUS Status = STATUS_SUCCESS;
164 
165     TRACE("SamrCloseHandle(%p)\n", SamHandle);
166 
167     RtlAcquireResourceShared(&SampResource,
168                              TRUE);
169 
170     Status = SampValidateDbObject(*SamHandle,
171                                   SamDbIgnoreObject,
172                                   0,
173                                   &DbObject);
174     if (Status == STATUS_SUCCESS)
175     {
176         Status = SampCloseDbObject(DbObject);
177         *SamHandle = NULL;
178     }
179 
180     RtlReleaseResource(&SampResource);
181 
182     TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
183 
184     return Status;
185 }
186 
187 
188 /* Function 2 */
189 NTSTATUS
190 NTAPI
191 SamrSetSecurityObject(IN SAMPR_HANDLE ObjectHandle,
192                       IN SECURITY_INFORMATION SecurityInformation,
193                       IN PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
194 {
195     PSAM_DB_OBJECT DbObject = NULL;
196     ACCESS_MASK DesiredAccess = 0;
197     PSECURITY_DESCRIPTOR RelativeSd = NULL;
198     ULONG RelativeSdSize = 0;
199     HANDLE TokenHandle = NULL;
200     PGENERIC_MAPPING Mapping;
201     NTSTATUS Status;
202 
203     TRACE("SamrSetSecurityObject(%p %lx %p)\n",
204           ObjectHandle, SecurityInformation, SecurityDescriptor);
205 
206     if ((SecurityDescriptor == NULL) ||
207         (SecurityDescriptor->SecurityDescriptor == NULL) ||
208         !RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor))
209         return ERROR_INVALID_PARAMETER;
210 
211     if (SecurityInformation == 0 ||
212         SecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
213         | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
214         return ERROR_INVALID_PARAMETER;
215 
216     if (SecurityInformation & SACL_SECURITY_INFORMATION)
217         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
218 
219     if (SecurityInformation & DACL_SECURITY_INFORMATION)
220         DesiredAccess |= WRITE_DAC;
221 
222     if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
223         DesiredAccess |= WRITE_OWNER;
224 
225     if ((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
226         (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Owner == NULL))
227         return ERROR_INVALID_PARAMETER;
228 
229     if ((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
230         (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Group == NULL))
231         return ERROR_INVALID_PARAMETER;
232 
233     /* Validate the server handle */
234     Status = SampValidateDbObject(ObjectHandle,
235                                   SamDbIgnoreObject,
236                                   DesiredAccess,
237                                   &DbObject);
238     if (!NT_SUCCESS(Status))
239         goto done;
240 
241     /* Get the mapping for the object type */
242     switch (DbObject->ObjectType)
243     {
244         case SamDbServerObject:
245             Mapping = &ServerMapping;
246             break;
247 
248         case SamDbDomainObject:
249             Mapping = &DomainMapping;
250             break;
251 
252         case SamDbAliasObject:
253             Mapping = &AliasMapping;
254             break;
255 
256         case SamDbGroupObject:
257             Mapping = &GroupMapping;
258             break;
259 
260         case SamDbUserObject:
261             Mapping = &UserMapping;
262             break;
263 
264         default:
265             return STATUS_INVALID_HANDLE;
266     }
267 
268     /* Get the size of the SD */
269     Status = SampGetObjectAttribute(DbObject,
270                                     L"SecDesc",
271                                     NULL,
272                                     NULL,
273                                     &RelativeSdSize);
274     if (!NT_SUCCESS(Status))
275         return Status;
276 
277     /* Allocate a buffer for the SD */
278     RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), 0, RelativeSdSize);
279     if (RelativeSd == NULL)
280         return STATUS_INSUFFICIENT_RESOURCES;
281 
282     /* Get the SD */
283     Status = SampGetObjectAttribute(DbObject,
284                                     L"SecDesc",
285                                     NULL,
286                                     RelativeSd,
287                                     &RelativeSdSize);
288     if (!NT_SUCCESS(Status))
289         goto done;
290 
291     /* Build the new security descriptor */
292     Status = RtlSetSecurityObject(SecurityInformation,
293                                   (PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor,
294                                   &RelativeSd,
295                                   Mapping,
296                                   TokenHandle);
297     if (!NT_SUCCESS(Status))
298     {
299         ERR("RtlSetSecurityObject failed (Status 0x%08lx)\n", Status);
300         goto done;
301     }
302 
303     /* Set the modified SD */
304     Status = SampSetObjectAttribute(DbObject,
305                                     L"SecDesc",
306                                     REG_BINARY,
307                                     RelativeSd,
308                                     RtlLengthSecurityDescriptor(RelativeSd));
309     if (!NT_SUCCESS(Status))
310     {
311         ERR("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
312     }
313 
314 done:
315     if (TokenHandle != NULL)
316         NtClose(TokenHandle);
317 
318     if (RelativeSd != NULL)
319         RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
320 
321     return Status;
322 }
323 
324 
325 /* Function 3 */
326 NTSTATUS
327 NTAPI
328 SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
329                         IN SECURITY_INFORMATION SecurityInformation,
330                         OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
331 {
332     PSAM_DB_OBJECT SamObject;
333     PSAMPR_SR_SECURITY_DESCRIPTOR SdData = NULL;
334     PSECURITY_DESCRIPTOR RelativeSd = NULL;
335     PSECURITY_DESCRIPTOR ResultSd = NULL;
336     ACCESS_MASK DesiredAccess = 0;
337     ULONG RelativeSdSize = 0;
338     ULONG ResultSdSize = 0;
339     NTSTATUS Status;
340 
341     TRACE("SamrQuerySecurityObject(%p %lx %p)\n",
342           ObjectHandle, SecurityInformation, SecurityDescriptor);
343 
344     *SecurityDescriptor = NULL;
345 
346     RtlAcquireResourceShared(&SampResource,
347                              TRUE);
348 
349     if (SecurityInformation & (DACL_SECURITY_INFORMATION |
350                                OWNER_SECURITY_INFORMATION |
351                                GROUP_SECURITY_INFORMATION))
352         DesiredAccess |= READ_CONTROL;
353 
354     if (SecurityInformation & SACL_SECURITY_INFORMATION)
355         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
356 
357     /* Validate the server handle */
358     Status = SampValidateDbObject(ObjectHandle,
359                                   SamDbIgnoreObject,
360                                   DesiredAccess,
361                                   &SamObject);
362     if (!NT_SUCCESS(Status))
363         goto done;
364 
365     /* Get the size of the SD */
366     Status = SampGetObjectAttribute(SamObject,
367                                     L"SecDesc",
368                                     NULL,
369                                     NULL,
370                                     &RelativeSdSize);
371     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
372     {
373         TRACE("Status 0x%08lx\n", Status);
374         goto done;
375     }
376 
377     /* Allocate a buffer for the SD */
378     RelativeSd = midl_user_allocate(RelativeSdSize);
379     if (RelativeSd == NULL)
380     {
381         Status = STATUS_INSUFFICIENT_RESOURCES;
382         goto done;
383     }
384 
385     /* Get the SD */
386     Status = SampGetObjectAttribute(SamObject,
387                                     L"SecDesc",
388                                     NULL,
389                                     RelativeSd,
390                                     &RelativeSdSize);
391     if (!NT_SUCCESS(Status))
392     {
393         TRACE("Status 0x%08lx\n", Status);
394         goto done;
395     }
396 
397     /* Invalidate the SD information that was not requested */
398     if (!(SecurityInformation & OWNER_SECURITY_INFORMATION))
399         ((PISECURITY_DESCRIPTOR)RelativeSd)->Owner = NULL;
400 
401     if (!(SecurityInformation & GROUP_SECURITY_INFORMATION))
402         ((PISECURITY_DESCRIPTOR)RelativeSd)->Group = NULL;
403 
404     if (!(SecurityInformation & DACL_SECURITY_INFORMATION))
405         ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_DACL_PRESENT;
406 
407     if (!(SecurityInformation & SACL_SECURITY_INFORMATION))
408         ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_SACL_PRESENT;
409 
410     /* Calculate the required SD size */
411     Status = RtlMakeSelfRelativeSD(RelativeSd,
412                                    NULL,
413                                    &ResultSdSize);
414     if (Status != STATUS_BUFFER_TOO_SMALL)
415         goto done;
416 
417     /* Allocate a buffer for the new SD */
418     ResultSd = MIDL_user_allocate(ResultSdSize);
419     if (ResultSd == NULL)
420     {
421         Status = STATUS_INSUFFICIENT_RESOURCES;
422         goto done;
423     }
424 
425     /* Build the new SD */
426     Status = RtlMakeSelfRelativeSD(RelativeSd,
427                                    ResultSd,
428                                    &ResultSdSize);
429     if (!NT_SUCCESS(Status))
430         goto done;
431 
432     /* Allocate the SD data buffer */
433     SdData = midl_user_allocate(sizeof(SAMPR_SR_SECURITY_DESCRIPTOR));
434     if (SdData == NULL)
435     {
436         Status = STATUS_INSUFFICIENT_RESOURCES;
437         goto done;
438     }
439 
440     /* Fill the SD data buffer and return it to the caller */
441     SdData->Length = RelativeSdSize;
442     SdData->SecurityDescriptor = (PBYTE)ResultSd;
443 
444     *SecurityDescriptor = SdData;
445 
446 done:
447     RtlReleaseResource(&SampResource);
448 
449     if (!NT_SUCCESS(Status))
450     {
451         if (ResultSd != NULL)
452             MIDL_user_free(ResultSd);
453     }
454 
455     if (RelativeSd != NULL)
456         MIDL_user_free(RelativeSd);
457 
458     return Status;
459 }
460 
461 
462 /* Function 4 */
463 NTSTATUS
464 NTAPI
465 SamrShutdownSamServer(IN SAMPR_HANDLE ServerHandle)
466 {
467     PSAM_DB_OBJECT ServerObject;
468     NTSTATUS Status;
469 
470     TRACE("SamrShutdownSamServer(%p)\n",
471           ServerHandle);
472 
473     RtlAcquireResourceShared(&SampResource,
474                              TRUE);
475 
476     /* Validate the server handle */
477     Status = SampValidateDbObject(ServerHandle,
478                                   SamDbServerObject,
479                                   SAM_SERVER_SHUTDOWN,
480                                   &ServerObject);
481 
482     RtlReleaseResource(&SampResource);
483 
484     if (!NT_SUCCESS(Status))
485         return Status;
486 
487     /* Shut the server down */
488     RpcMgmtStopServerListening(0);
489 
490     return STATUS_SUCCESS;
491 }
492 
493 
494 /* Function 5 */
495 NTSTATUS
496 NTAPI
497 SamrLookupDomainInSamServer(IN SAMPR_HANDLE ServerHandle,
498                             IN PRPC_UNICODE_STRING Name,
499                             OUT PRPC_SID *DomainId)
500 {
501     PSAM_DB_OBJECT ServerObject;
502     HANDLE DomainsKeyHandle = NULL;
503     HANDLE DomainKeyHandle = NULL;
504     WCHAR DomainKeyName[64];
505     ULONG Index;
506     WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
507     UNICODE_STRING DomainName;
508     ULONG Length;
509     BOOL Found = FALSE;
510     NTSTATUS Status;
511 
512     TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
513           ServerHandle, Name, DomainId);
514 
515     RtlAcquireResourceShared(&SampResource,
516                              TRUE);
517 
518     /* Validate the server handle */
519     Status = SampValidateDbObject(ServerHandle,
520                                   SamDbServerObject,
521                                   SAM_SERVER_LOOKUP_DOMAIN,
522                                   &ServerObject);
523     if (!NT_SUCCESS(Status))
524         goto done;
525 
526     *DomainId = NULL;
527 
528     Status = SampRegOpenKey(ServerObject->KeyHandle,
529                             L"Domains",
530                             KEY_READ,
531                             &DomainsKeyHandle);
532     if (!NT_SUCCESS(Status))
533         goto done;
534 
535     Index = 0;
536     while (Found == FALSE)
537     {
538         Status = SampRegEnumerateSubKey(DomainsKeyHandle,
539                                         Index,
540                                         64,
541                                         DomainKeyName);
542         if (!NT_SUCCESS(Status))
543         {
544             if (Status == STATUS_NO_MORE_ENTRIES)
545                 Status = STATUS_NO_SUCH_DOMAIN;
546             break;
547         }
548 
549         TRACE("Domain key name: %S\n", DomainKeyName);
550 
551         Status = SampRegOpenKey(DomainsKeyHandle,
552                                 DomainKeyName,
553                                 KEY_READ,
554                                 &DomainKeyHandle);
555         if (NT_SUCCESS(Status))
556         {
557             Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
558             Status = SampRegQueryValue(DomainKeyHandle,
559                                        L"Name",
560                                        NULL,
561                                        (PVOID)&DomainNameString,
562                                        &Length);
563             if (NT_SUCCESS(Status))
564             {
565                 TRACE("Domain name: %S\n", DomainNameString);
566 
567                 RtlInitUnicodeString(&DomainName,
568                                      DomainNameString);
569                 if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
570                 {
571                    TRACE("Found it!\n");
572                    Found = TRUE;
573 
574                    Status = SampRegQueryValue(DomainKeyHandle,
575                                               L"SID",
576                                               NULL,
577                                               NULL,
578                                               &Length);
579                    if (NT_SUCCESS(Status))
580                    {
581                        *DomainId = midl_user_allocate(Length);
582 
583                        SampRegQueryValue(DomainKeyHandle,
584                                          L"SID",
585                                          NULL,
586                                          (PVOID)*DomainId,
587                                          &Length);
588 
589                        Status = STATUS_SUCCESS;
590                        break;
591                    }
592                 }
593             }
594 
595             SampRegCloseKey(&DomainKeyHandle);
596         }
597 
598         Index++;
599     }
600 
601 done:
602     SampRegCloseKey(&DomainKeyHandle);
603     SampRegCloseKey(&DomainsKeyHandle);
604 
605     RtlReleaseResource(&SampResource);
606 
607     return Status;
608 }
609 
610 
611 /* Function 6 */
612 NTSTATUS
613 NTAPI
614 SamrEnumerateDomainsInSamServer(IN SAMPR_HANDLE ServerHandle,
615                                 IN OUT unsigned long *EnumerationContext,
616                                 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
617                                 IN ULONG PreferedMaximumLength,
618                                 OUT PULONG CountReturned)
619 {
620     PSAM_DB_OBJECT ServerObject;
621     WCHAR DomainKeyName[64];
622     HANDLE DomainsKeyHandle = NULL;
623     HANDLE DomainKeyHandle = NULL;
624     ULONG EnumIndex;
625     ULONG EnumCount;
626     ULONG RequiredLength;
627     ULONG DataLength;
628     ULONG i;
629     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
630     NTSTATUS Status;
631 
632     TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
633           ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
634           CountReturned);
635 
636     RtlAcquireResourceShared(&SampResource,
637                              TRUE);
638 
639     /* Validate the server handle */
640     Status = SampValidateDbObject(ServerHandle,
641                                   SamDbServerObject,
642                                   SAM_SERVER_ENUMERATE_DOMAINS,
643                                   &ServerObject);
644     if (!NT_SUCCESS(Status))
645         goto done;
646 
647     Status = SampRegOpenKey(ServerObject->KeyHandle,
648                             L"Domains",
649                             KEY_READ,
650                             &DomainsKeyHandle);
651     if (!NT_SUCCESS(Status))
652         goto done;
653 
654     EnumIndex = *EnumerationContext;
655     EnumCount = 0;
656     RequiredLength = 0;
657 
658     while (TRUE)
659     {
660         Status = SampRegEnumerateSubKey(DomainsKeyHandle,
661                                         EnumIndex,
662                                         64 * sizeof(WCHAR),
663                                         DomainKeyName);
664         if (!NT_SUCCESS(Status))
665             break;
666 
667         TRACE("EnumIndex: %lu\n", EnumIndex);
668         TRACE("Domain key name: %S\n", DomainKeyName);
669 
670         Status = SampRegOpenKey(DomainsKeyHandle,
671                                 DomainKeyName,
672                                 KEY_READ,
673                                 &DomainKeyHandle);
674         TRACE("SampRegOpenKey returned %08lX\n", Status);
675         if (NT_SUCCESS(Status))
676         {
677             DataLength = 0;
678             Status = SampRegQueryValue(DomainKeyHandle,
679                                        L"Name",
680                                        NULL,
681                                        NULL,
682                                        &DataLength);
683             TRACE("SampRegQueryValue returned %08lX\n", Status);
684             if (NT_SUCCESS(Status))
685             {
686                 TRACE("Data length: %lu\n", DataLength);
687 
688                 if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
689                     break;
690 
691                 RequiredLength += (DataLength + sizeof(UNICODE_STRING));
692                 EnumCount++;
693             }
694 
695             SampRegCloseKey(&DomainKeyHandle);
696         }
697 
698         EnumIndex++;
699     }
700 
701     TRACE("EnumCount: %lu\n", EnumCount);
702     TRACE("RequiredLength: %lu\n", RequiredLength);
703 
704     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
705     if (EnumBuffer == NULL)
706     {
707         Status = STATUS_INSUFFICIENT_RESOURCES;
708         goto done;
709     }
710 
711     EnumBuffer->EntriesRead = EnumCount;
712     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
713     if (EnumBuffer->Buffer == NULL)
714     {
715         Status = STATUS_INSUFFICIENT_RESOURCES;
716         goto done;
717     }
718 
719     EnumIndex = *EnumerationContext;
720     for (i = 0; i < EnumCount; i++, EnumIndex++)
721     {
722         Status = SampRegEnumerateSubKey(DomainsKeyHandle,
723                                         EnumIndex,
724                                         64 * sizeof(WCHAR),
725                                         DomainKeyName);
726         if (!NT_SUCCESS(Status))
727             break;
728 
729         TRACE("EnumIndex: %lu\n", EnumIndex);
730         TRACE("Domain key name: %S\n", DomainKeyName);
731 
732         Status = SampRegOpenKey(DomainsKeyHandle,
733                                 DomainKeyName,
734                                 KEY_READ,
735                                 &DomainKeyHandle);
736         TRACE("SampRegOpenKey returned %08lX\n", Status);
737         if (NT_SUCCESS(Status))
738         {
739             DataLength = 0;
740             Status = SampRegQueryValue(DomainKeyHandle,
741                                        L"Name",
742                                        NULL,
743                                        NULL,
744                                        &DataLength);
745             TRACE("SampRegQueryValue returned %08lX\n", Status);
746             if (NT_SUCCESS(Status))
747             {
748                 EnumBuffer->Buffer[i].RelativeId = 0;
749                 EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
750                 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
751                 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
752                 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
753                 {
754                     SampRegCloseKey(&DomainKeyHandle);
755                     Status = STATUS_INSUFFICIENT_RESOURCES;
756                     goto done;
757                 }
758 
759                 Status = SampRegQueryValue(DomainKeyHandle,
760                                            L"Name",
761                                            NULL,
762                                            EnumBuffer->Buffer[i].Name.Buffer,
763                                            &DataLength);
764                 TRACE("SampRegQueryValue returned %08lX\n", Status);
765                 if (NT_SUCCESS(Status))
766                 {
767                     TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
768                 }
769             }
770 
771             SampRegCloseKey(&DomainKeyHandle);
772 
773             if (!NT_SUCCESS(Status))
774                 goto done;
775         }
776     }
777 
778     if (NT_SUCCESS(Status))
779     {
780         *EnumerationContext += EnumCount;
781         *Buffer = EnumBuffer;
782         *CountReturned = EnumCount;
783     }
784 
785 done:
786     SampRegCloseKey(&DomainKeyHandle);
787     SampRegCloseKey(&DomainsKeyHandle);
788 
789     if (!NT_SUCCESS(Status))
790     {
791         *EnumerationContext = 0;
792         *Buffer = NULL;
793         *CountReturned = 0;
794 
795         if (EnumBuffer != NULL)
796         {
797             if (EnumBuffer->Buffer != NULL)
798             {
799                 if (EnumBuffer->EntriesRead != 0)
800                 {
801                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
802                     {
803                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
804                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
805                     }
806                 }
807 
808                 midl_user_free(EnumBuffer->Buffer);
809             }
810 
811             midl_user_free(EnumBuffer);
812         }
813     }
814 
815     RtlReleaseResource(&SampResource);
816 
817     return Status;
818 }
819 
820 
821 /* Function 7 */
822 NTSTATUS
823 NTAPI
824 SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
825                IN ACCESS_MASK DesiredAccess,
826                IN PRPC_SID DomainId,
827                OUT SAMPR_HANDLE *DomainHandle)
828 {
829     PSAM_DB_OBJECT ServerObject;
830     PSAM_DB_OBJECT DomainObject;
831     NTSTATUS Status;
832 
833     TRACE("SamrOpenDomain(%p %lx %p %p)\n",
834           ServerHandle, DesiredAccess, DomainId, DomainHandle);
835 
836     /* Map generic access rights */
837     RtlMapGenericMask(&DesiredAccess,
838                       &DomainMapping);
839 
840     RtlAcquireResourceShared(&SampResource,
841                              TRUE);
842 
843     /* Validate the server handle */
844     Status = SampValidateDbObject(ServerHandle,
845                                   SamDbServerObject,
846                                   SAM_SERVER_LOOKUP_DOMAIN,
847                                   &ServerObject);
848     if (!NT_SUCCESS(Status))
849         return Status;
850 
851     /* Validate the Domain SID */
852     if ((DomainId->Revision != SID_REVISION) ||
853         (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
854         (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
855         return STATUS_INVALID_PARAMETER;
856 
857     /* Open the domain object */
858     if ((DomainId->SubAuthorityCount == 1) &&
859         (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
860     {
861         /* Builtin domain object */
862         TRACE("Opening the builtin domain object.\n");
863 
864         Status = SampOpenDbObject(ServerObject,
865                                   L"Domains",
866                                   L"Builtin",
867                                   0,
868                                   SamDbDomainObject,
869                                   DesiredAccess,
870                                   &DomainObject);
871     }
872     else if ((DomainId->SubAuthorityCount == 4) &&
873              (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
874     {
875         /* Account domain object */
876         TRACE("Opening the account domain object.\n");
877 
878         /* FIXME: Check the account domain sub authorities!!! */
879 
880         Status = SampOpenDbObject(ServerObject,
881                                   L"Domains",
882                                   L"Account",
883                                   0,
884                                   SamDbDomainObject,
885                                   DesiredAccess,
886                                   &DomainObject);
887     }
888     else
889     {
890         /* No valid domain SID */
891         Status = STATUS_INVALID_PARAMETER;
892     }
893 
894     if (NT_SUCCESS(Status))
895         *DomainHandle = (SAMPR_HANDLE)DomainObject;
896 
897     RtlReleaseResource(&SampResource);
898 
899     TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
900 
901     return Status;
902 }
903 
904 
905 static NTSTATUS
906 SampQueryDomainPassword(PSAM_DB_OBJECT DomainObject,
907                         PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
908 {
909     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
910     SAM_DOMAIN_FIXED_DATA FixedData;
911     ULONG Length = 0;
912     NTSTATUS Status;
913 
914     *Buffer = NULL;
915 
916     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
917     if (InfoBuffer == NULL)
918         return STATUS_INSUFFICIENT_RESOURCES;
919 
920     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
921     Status = SampGetObjectAttribute(DomainObject,
922                                     L"F",
923                                     NULL,
924                                     (PVOID)&FixedData,
925                                     &Length);
926     if (!NT_SUCCESS(Status))
927         goto done;
928 
929     InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
930     InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
931     InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
932     InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
933     InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
934     InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
935     InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
936 
937     *Buffer = InfoBuffer;
938 
939 done:
940     if (!NT_SUCCESS(Status))
941     {
942         if (InfoBuffer != NULL)
943         {
944             midl_user_free(InfoBuffer);
945         }
946     }
947 
948     return Status;
949 }
950 
951 
952 static NTSTATUS
953 SampGetNumberOfAccounts(PSAM_DB_OBJECT DomainObject,
954                         LPCWSTR AccountType,
955                         PULONG Count)
956 {
957     HANDLE AccountKeyHandle = NULL;
958     HANDLE NamesKeyHandle = NULL;
959     NTSTATUS Status;
960 
961     *Count = 0;
962 
963     Status = SampRegOpenKey(DomainObject->KeyHandle,
964                             AccountType,
965                             KEY_READ,
966                             &AccountKeyHandle);
967     if (!NT_SUCCESS(Status))
968         return Status;
969 
970     Status = SampRegOpenKey(AccountKeyHandle,
971                             L"Names",
972                             KEY_READ,
973                             &NamesKeyHandle);
974     if (!NT_SUCCESS(Status))
975         goto done;
976 
977     Status = SampRegQueryKeyInfo(NamesKeyHandle,
978                                  NULL,
979                                  Count);
980 
981 done:
982     SampRegCloseKey(&NamesKeyHandle);
983     SampRegCloseKey(&AccountKeyHandle);
984 
985     return Status;
986 }
987 
988 
989 static NTSTATUS
990 SampQueryDomainGeneral(PSAM_DB_OBJECT DomainObject,
991                        PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
992 {
993     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
994     SAM_DOMAIN_FIXED_DATA FixedData;
995     ULONG Length = 0;
996     NTSTATUS Status;
997 
998     *Buffer = NULL;
999 
1000     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1001     if (InfoBuffer == NULL)
1002         return STATUS_INSUFFICIENT_RESOURCES;
1003 
1004     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1005     Status = SampGetObjectAttribute(DomainObject,
1006                                     L"F",
1007                                     NULL,
1008                                     (PVOID)&FixedData,
1009                                     &Length);
1010     if (!NT_SUCCESS(Status))
1011         goto done;
1012 
1013     InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1014     InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1015     InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1016     InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1017     InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
1018     InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
1019     InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1020 
1021     /* Get the OemInformation string */
1022     Status = SampGetObjectAttributeString(DomainObject,
1023                                           L"OemInformation",
1024                                           &InfoBuffer->General.OemInformation);
1025     if (!NT_SUCCESS(Status))
1026     {
1027         TRACE("Status 0x%08lx\n", Status);
1028         goto done;
1029     }
1030 
1031     /* Get the Name string */
1032     Status = SampGetObjectAttributeString(DomainObject,
1033                                           L"Name",
1034                                           &InfoBuffer->General.DomainName);
1035     if (!NT_SUCCESS(Status))
1036     {
1037         TRACE("Status 0x%08lx\n", Status);
1038         goto done;
1039     }
1040 
1041     /* Get the ReplicaSourceNodeName string */
1042     Status = SampGetObjectAttributeString(DomainObject,
1043                                           L"ReplicaSourceNodeName",
1044                                           &InfoBuffer->General.ReplicaSourceNodeName);
1045     if (!NT_SUCCESS(Status))
1046     {
1047         TRACE("Status 0x%08lx\n", Status);
1048         goto done;
1049     }
1050 
1051     /* Get the number of Users in the Domain */
1052     Status = SampGetNumberOfAccounts(DomainObject,
1053                                      L"Users",
1054                                      &InfoBuffer->General.UserCount);
1055     if (!NT_SUCCESS(Status))
1056     {
1057         TRACE("Status 0x%08lx\n", Status);
1058         goto done;
1059     }
1060 
1061     /* Get the number of Groups in the Domain */
1062     Status = SampGetNumberOfAccounts(DomainObject,
1063                                      L"Groups",
1064                                      &InfoBuffer->General.GroupCount);
1065     if (!NT_SUCCESS(Status))
1066     {
1067         TRACE("Status 0x%08lx\n", Status);
1068         goto done;
1069     }
1070 
1071     /* Get the number of Aliases in the Domain */
1072     Status = SampGetNumberOfAccounts(DomainObject,
1073                                      L"Aliases",
1074                                      &InfoBuffer->General.AliasCount);
1075     if (!NT_SUCCESS(Status))
1076     {
1077         TRACE("Status 0x%08lx\n", Status);
1078         goto done;
1079     }
1080 
1081     *Buffer = InfoBuffer;
1082 
1083 done:
1084     if (!NT_SUCCESS(Status))
1085     {
1086         if (InfoBuffer != NULL)
1087         {
1088             if (InfoBuffer->General.OemInformation.Buffer != NULL)
1089                 midl_user_free(InfoBuffer->General.OemInformation.Buffer);
1090 
1091             if (InfoBuffer->General.DomainName.Buffer != NULL)
1092                 midl_user_free(InfoBuffer->General.DomainName.Buffer);
1093 
1094             if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
1095                 midl_user_free(InfoBuffer->General.ReplicaSourceNodeName.Buffer);
1096 
1097             midl_user_free(InfoBuffer);
1098         }
1099     }
1100 
1101     return Status;
1102 }
1103 
1104 
1105 static NTSTATUS
1106 SampQueryDomainLogoff(PSAM_DB_OBJECT DomainObject,
1107                       PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1108 {
1109     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1110     SAM_DOMAIN_FIXED_DATA FixedData;
1111     ULONG Length = 0;
1112     NTSTATUS Status;
1113 
1114     *Buffer = NULL;
1115 
1116     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1117     if (InfoBuffer == NULL)
1118         return STATUS_INSUFFICIENT_RESOURCES;
1119 
1120     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1121     Status = SampGetObjectAttribute(DomainObject,
1122                                     L"F",
1123                                     NULL,
1124                                     (PVOID)&FixedData,
1125                                     &Length);
1126     if (!NT_SUCCESS(Status))
1127         goto done;
1128 
1129     InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1130     InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1131 
1132     *Buffer = InfoBuffer;
1133 
1134 done:
1135     if (!NT_SUCCESS(Status))
1136     {
1137         if (InfoBuffer != NULL)
1138         {
1139             midl_user_free(InfoBuffer);
1140         }
1141     }
1142 
1143     return Status;
1144 }
1145 
1146 
1147 static NTSTATUS
1148 SampQueryDomainOem(PSAM_DB_OBJECT DomainObject,
1149                    PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1150 {
1151     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1152     NTSTATUS Status;
1153 
1154     *Buffer = NULL;
1155 
1156     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1157     if (InfoBuffer == NULL)
1158         return STATUS_INSUFFICIENT_RESOURCES;
1159 
1160     /* Get the OemInformation string */
1161     Status = SampGetObjectAttributeString(DomainObject,
1162                                           L"OemInformation",
1163                                           &InfoBuffer->Oem.OemInformation);
1164     if (!NT_SUCCESS(Status))
1165     {
1166         TRACE("Status 0x%08lx\n", Status);
1167         goto done;
1168     }
1169 
1170     *Buffer = InfoBuffer;
1171 
1172 done:
1173     if (!NT_SUCCESS(Status))
1174     {
1175         if (InfoBuffer != NULL)
1176         {
1177             if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
1178                 midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
1179 
1180             midl_user_free(InfoBuffer);
1181         }
1182     }
1183 
1184     return Status;
1185 }
1186 
1187 
1188 static NTSTATUS
1189 SampQueryDomainName(PSAM_DB_OBJECT DomainObject,
1190                     PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1191 {
1192     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1193     NTSTATUS Status;
1194 
1195     *Buffer = NULL;
1196 
1197     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1198     if (InfoBuffer == NULL)
1199         return STATUS_INSUFFICIENT_RESOURCES;
1200 
1201     /* Get the Name string */
1202     Status = SampGetObjectAttributeString(DomainObject,
1203                                           L"Name",
1204                                           &InfoBuffer->Name.DomainName);
1205     if (!NT_SUCCESS(Status))
1206     {
1207         TRACE("Status 0x%08lx\n", Status);
1208         goto done;
1209     }
1210 
1211     *Buffer = InfoBuffer;
1212 
1213 done:
1214     if (!NT_SUCCESS(Status))
1215     {
1216         if (InfoBuffer != NULL)
1217         {
1218             if (InfoBuffer->Name.DomainName.Buffer != NULL)
1219                 midl_user_free(InfoBuffer->Name.DomainName.Buffer);
1220 
1221             midl_user_free(InfoBuffer);
1222         }
1223     }
1224 
1225     return Status;
1226 }
1227 
1228 
1229 static NTSTATUS
1230 SampQueryDomainReplication(PSAM_DB_OBJECT DomainObject,
1231                            PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1232 {
1233     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1234     NTSTATUS Status;
1235 
1236     *Buffer = NULL;
1237 
1238     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1239     if (InfoBuffer == NULL)
1240         return STATUS_INSUFFICIENT_RESOURCES;
1241 
1242     /* Get the ReplicaSourceNodeName string */
1243     Status = SampGetObjectAttributeString(DomainObject,
1244                                           L"ReplicaSourceNodeName",
1245                                           &InfoBuffer->Replication.ReplicaSourceNodeName);
1246     if (!NT_SUCCESS(Status))
1247     {
1248         TRACE("Status 0x%08lx\n", Status);
1249         goto done;
1250     }
1251 
1252     *Buffer = InfoBuffer;
1253 
1254 done:
1255     if (!NT_SUCCESS(Status))
1256     {
1257         if (InfoBuffer != NULL)
1258         {
1259             if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
1260                 midl_user_free(InfoBuffer->Replication.ReplicaSourceNodeName.Buffer);
1261 
1262             midl_user_free(InfoBuffer);
1263         }
1264     }
1265 
1266     return Status;
1267 }
1268 
1269 
1270 static NTSTATUS
1271 SampQueryDomainServerRole(PSAM_DB_OBJECT DomainObject,
1272                           PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1273 {
1274     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1275     SAM_DOMAIN_FIXED_DATA FixedData;
1276     ULONG Length = 0;
1277     NTSTATUS Status;
1278 
1279     *Buffer = NULL;
1280 
1281     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1282     if (InfoBuffer == NULL)
1283         return STATUS_INSUFFICIENT_RESOURCES;
1284 
1285     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1286     Status = SampGetObjectAttribute(DomainObject,
1287                                     L"F",
1288                                     NULL,
1289                                     (PVOID)&FixedData,
1290                                     &Length);
1291     if (!NT_SUCCESS(Status))
1292         goto done;
1293 
1294     InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
1295 
1296     *Buffer = InfoBuffer;
1297 
1298 done:
1299     if (!NT_SUCCESS(Status))
1300     {
1301         if (InfoBuffer != NULL)
1302         {
1303             midl_user_free(InfoBuffer);
1304         }
1305     }
1306 
1307     return Status;
1308 }
1309 
1310 
1311 static NTSTATUS
1312 SampQueryDomainModified(PSAM_DB_OBJECT DomainObject,
1313                         PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1314 {
1315     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1316     SAM_DOMAIN_FIXED_DATA FixedData;
1317     ULONG Length = 0;
1318     NTSTATUS Status;
1319 
1320     *Buffer = NULL;
1321 
1322     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1323     if (InfoBuffer == NULL)
1324         return STATUS_INSUFFICIENT_RESOURCES;
1325 
1326     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1327     Status = SampGetObjectAttribute(DomainObject,
1328                                     L"F",
1329                                     NULL,
1330                                     (PVOID)&FixedData,
1331                                     &Length);
1332     if (!NT_SUCCESS(Status))
1333         goto done;
1334 
1335     InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1336     InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1337     InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1338     InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1339 
1340     *Buffer = InfoBuffer;
1341 
1342 done:
1343     if (!NT_SUCCESS(Status))
1344     {
1345         if (InfoBuffer != NULL)
1346         {
1347             midl_user_free(InfoBuffer);
1348         }
1349     }
1350 
1351     return Status;
1352 }
1353 
1354 
1355 static NTSTATUS
1356 SampQueryDomainState(PSAM_DB_OBJECT DomainObject,
1357                      PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1358 {
1359     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1360     SAM_DOMAIN_FIXED_DATA FixedData;
1361     ULONG Length = 0;
1362     NTSTATUS Status;
1363 
1364     *Buffer = NULL;
1365 
1366     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1367     if (InfoBuffer == NULL)
1368         return STATUS_INSUFFICIENT_RESOURCES;
1369 
1370     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1371     Status = SampGetObjectAttribute(DomainObject,
1372                                     L"F",
1373                                     NULL,
1374                                     (PVOID)&FixedData,
1375                                     &Length);
1376     if (!NT_SUCCESS(Status))
1377         goto done;
1378 
1379     InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1380 
1381     *Buffer = InfoBuffer;
1382 
1383 done:
1384     if (!NT_SUCCESS(Status))
1385     {
1386         if (InfoBuffer != NULL)
1387         {
1388             midl_user_free(InfoBuffer);
1389         }
1390     }
1391 
1392     return Status;
1393 }
1394 
1395 
1396 static NTSTATUS
1397 SampQueryDomainGeneral2(PSAM_DB_OBJECT DomainObject,
1398                         PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1399 {
1400     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1401     SAM_DOMAIN_FIXED_DATA FixedData;
1402     ULONG Length = 0;
1403     NTSTATUS Status;
1404 
1405     *Buffer = NULL;
1406 
1407     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1408     if (InfoBuffer == NULL)
1409         return STATUS_INSUFFICIENT_RESOURCES;
1410 
1411     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1412     Status = SampGetObjectAttribute(DomainObject,
1413                                     L"F",
1414                                     NULL,
1415                                     (PVOID)&FixedData,
1416                                     &Length);
1417     if (!NT_SUCCESS(Status))
1418         goto done;
1419 
1420     InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1421     InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1422     InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1423     InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1424     InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1425     InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1426     InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1427 
1428     InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1429     InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1430     InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1431 
1432     /* Get the OemInformation string */
1433     Status = SampGetObjectAttributeString(DomainObject,
1434                                           L"OemInformation",
1435                                           &InfoBuffer->General2.I1.OemInformation);
1436     if (!NT_SUCCESS(Status))
1437     {
1438         TRACE("Status 0x%08lx\n", Status);
1439         goto done;
1440     }
1441 
1442     /* Get the Name string */
1443     Status = SampGetObjectAttributeString(DomainObject,
1444                                           L"Name",
1445                                           &InfoBuffer->General2.I1.DomainName);
1446     if (!NT_SUCCESS(Status))
1447     {
1448         TRACE("Status 0x%08lx\n", Status);
1449         goto done;
1450     }
1451 
1452     /* Get the ReplicaSourceNodeName string */
1453     Status = SampGetObjectAttributeString(DomainObject,
1454                                           L"ReplicaSourceNodeName",
1455                                           &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1456     if (!NT_SUCCESS(Status))
1457     {
1458         TRACE("Status 0x%08lx\n", Status);
1459         goto done;
1460     }
1461 
1462     /* Get the number of Users in the Domain */
1463     Status = SampGetNumberOfAccounts(DomainObject,
1464                                      L"Users",
1465                                      &InfoBuffer->General2.I1.UserCount);
1466     if (!NT_SUCCESS(Status))
1467     {
1468         TRACE("Status 0x%08lx\n", Status);
1469         goto done;
1470     }
1471 
1472     /* Get the number of Groups in the Domain */
1473     Status = SampGetNumberOfAccounts(DomainObject,
1474                                      L"Groups",
1475                                      &InfoBuffer->General2.I1.GroupCount);
1476     if (!NT_SUCCESS(Status))
1477     {
1478         TRACE("Status 0x%08lx\n", Status);
1479         goto done;
1480     }
1481 
1482     /* Get the number of Aliases in the Domain */
1483     Status = SampGetNumberOfAccounts(DomainObject,
1484                                      L"Aliases",
1485                                      &InfoBuffer->General2.I1.AliasCount);
1486     if (!NT_SUCCESS(Status))
1487     {
1488         TRACE("Status 0x%08lx\n", Status);
1489         goto done;
1490     }
1491 
1492     *Buffer = InfoBuffer;
1493 
1494 done:
1495     if (!NT_SUCCESS(Status))
1496     {
1497         if (InfoBuffer != NULL)
1498         {
1499             if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1500                 midl_user_free(InfoBuffer->General2.I1.OemInformation.Buffer);
1501 
1502             if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1503                 midl_user_free(InfoBuffer->General2.I1.DomainName.Buffer);
1504 
1505             if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1506                 midl_user_free(InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer);
1507 
1508             midl_user_free(InfoBuffer);
1509         }
1510     }
1511 
1512     return Status;
1513 }
1514 
1515 
1516 static NTSTATUS
1517 SampQueryDomainLockout(PSAM_DB_OBJECT DomainObject,
1518                        PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1519 {
1520     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1521     SAM_DOMAIN_FIXED_DATA FixedData;
1522     ULONG Length = 0;
1523     NTSTATUS Status;
1524 
1525     *Buffer = NULL;
1526 
1527     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1528     if (InfoBuffer == NULL)
1529         return STATUS_INSUFFICIENT_RESOURCES;
1530 
1531     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1532     Status = SampGetObjectAttribute(DomainObject,
1533                                     L"F",
1534                                     NULL,
1535                                     (PVOID)&FixedData,
1536                                     &Length);
1537     if (!NT_SUCCESS(Status))
1538         goto done;
1539 
1540     InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1541     InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1542     InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1543 
1544     *Buffer = InfoBuffer;
1545 
1546 done:
1547     if (!NT_SUCCESS(Status))
1548     {
1549         if (InfoBuffer != NULL)
1550         {
1551             midl_user_free(InfoBuffer);
1552         }
1553     }
1554 
1555     return Status;
1556 }
1557 
1558 
1559 static NTSTATUS
1560 SampQueryDomainModified2(PSAM_DB_OBJECT DomainObject,
1561                         PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1562 {
1563     PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1564     SAM_DOMAIN_FIXED_DATA FixedData;
1565     ULONG Length = 0;
1566     NTSTATUS Status;
1567 
1568     *Buffer = NULL;
1569 
1570     InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1571     if (InfoBuffer == NULL)
1572         return STATUS_INSUFFICIENT_RESOURCES;
1573 
1574     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1575     Status = SampGetObjectAttribute(DomainObject,
1576                                     L"F",
1577                                     NULL,
1578                                     (PVOID)&FixedData,
1579                                     &Length);
1580     if (!NT_SUCCESS(Status))
1581         goto done;
1582 
1583     InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1584     InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1585     InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1586     InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1587     InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1588     InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1589 
1590     *Buffer = InfoBuffer;
1591 
1592 done:
1593     if (!NT_SUCCESS(Status))
1594     {
1595         if (InfoBuffer != NULL)
1596         {
1597             midl_user_free(InfoBuffer);
1598         }
1599     }
1600 
1601     return Status;
1602 }
1603 
1604 
1605 /* Function 8 */
1606 NTSTATUS
1607 NTAPI
1608 SamrQueryInformationDomain(IN SAMPR_HANDLE DomainHandle,
1609                            IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1610                            OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1611 {
1612     PSAM_DB_OBJECT DomainObject;
1613     ACCESS_MASK DesiredAccess;
1614     NTSTATUS Status;
1615 
1616     TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1617           DomainHandle, DomainInformationClass, Buffer);
1618 
1619     switch (DomainInformationClass)
1620     {
1621         case DomainPasswordInformation:
1622         case DomainLockoutInformation:
1623             DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
1624             break;
1625 
1626         case DomainGeneralInformation:
1627         case DomainLogoffInformation:
1628         case DomainOemInformation:
1629         case DomainNameInformation:
1630         case DomainReplicationInformation:
1631         case DomainServerRoleInformation:
1632         case DomainModifiedInformation:
1633         case DomainStateInformation:
1634         case DomainModifiedInformation2:
1635             DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
1636             break;
1637 
1638         case DomainGeneralInformation2:
1639             DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS |
1640                             DOMAIN_READ_OTHER_PARAMETERS;
1641             break;
1642 
1643         default:
1644             return STATUS_INVALID_INFO_CLASS;
1645     }
1646 
1647     RtlAcquireResourceShared(&SampResource,
1648                              TRUE);
1649 
1650     /* Validate the server handle */
1651     Status = SampValidateDbObject(DomainHandle,
1652                                   SamDbDomainObject,
1653                                   DesiredAccess,
1654                                   &DomainObject);
1655     if (!NT_SUCCESS(Status))
1656         goto done;
1657 
1658     switch (DomainInformationClass)
1659     {
1660         case DomainPasswordInformation:
1661             Status = SampQueryDomainPassword(DomainObject,
1662                                              Buffer);
1663             break;
1664 
1665         case DomainGeneralInformation:
1666             Status = SampQueryDomainGeneral(DomainObject,
1667                                             Buffer);
1668             break;
1669 
1670         case DomainLogoffInformation:
1671             Status = SampQueryDomainLogoff(DomainObject,
1672                                            Buffer);
1673             break;
1674 
1675         case DomainOemInformation:
1676             Status = SampQueryDomainOem(DomainObject,
1677                                         Buffer);
1678             break;
1679 
1680         case DomainNameInformation:
1681             Status = SampQueryDomainName(DomainObject,
1682                                          Buffer);
1683             break;
1684 
1685         case DomainReplicationInformation:
1686             Status = SampQueryDomainReplication(DomainObject,
1687                                                 Buffer);
1688             break;
1689 
1690         case DomainServerRoleInformation:
1691             Status = SampQueryDomainServerRole(DomainObject,
1692                                                Buffer);
1693             break;
1694 
1695         case DomainModifiedInformation:
1696             Status = SampQueryDomainModified(DomainObject,
1697                                              Buffer);
1698             break;
1699 
1700         case DomainStateInformation:
1701             Status = SampQueryDomainState(DomainObject,
1702                                           Buffer);
1703             break;
1704 
1705         case DomainGeneralInformation2:
1706             Status = SampQueryDomainGeneral2(DomainObject,
1707                                              Buffer);
1708             break;
1709 
1710         case DomainLockoutInformation:
1711             Status = SampQueryDomainLockout(DomainObject,
1712                                             Buffer);
1713             break;
1714 
1715         case DomainModifiedInformation2:
1716             Status = SampQueryDomainModified2(DomainObject,
1717                                               Buffer);
1718             break;
1719 
1720         default:
1721             Status = STATUS_NOT_IMPLEMENTED;
1722     }
1723 
1724 done:
1725     RtlReleaseResource(&SampResource);
1726 
1727     return Status;
1728 }
1729 
1730 
1731 static NTSTATUS
1732 SampSetDomainPassword(PSAM_DB_OBJECT DomainObject,
1733                       PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1734 {
1735     SAM_DOMAIN_FIXED_DATA FixedData;
1736     ULONG Length = 0;
1737     NTSTATUS Status;
1738 
1739     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1740     Status = SampGetObjectAttribute(DomainObject,
1741                                     L"F",
1742                                     NULL,
1743                                     (PVOID)&FixedData,
1744                                     &Length);
1745     if (!NT_SUCCESS(Status))
1746         goto done;
1747 
1748     FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1749     FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1750     FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1751     FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1752     FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1753     FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1754     FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1755 
1756     Status = SampSetObjectAttribute(DomainObject,
1757                                     L"F",
1758                                     REG_BINARY,
1759                                     &FixedData,
1760                                     Length);
1761 
1762 done:
1763     return Status;
1764 }
1765 
1766 
1767 static NTSTATUS
1768 SampSetDomainLogoff(PSAM_DB_OBJECT DomainObject,
1769                     PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1770 {
1771     SAM_DOMAIN_FIXED_DATA FixedData;
1772     ULONG Length = 0;
1773     NTSTATUS Status;
1774 
1775     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1776     Status = SampGetObjectAttribute(DomainObject,
1777                                     L"F",
1778                                     NULL,
1779                                     (PVOID)&FixedData,
1780                                     &Length);
1781     if (!NT_SUCCESS(Status))
1782         goto done;
1783 
1784     FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1785     FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1786 
1787     Status = SampSetObjectAttribute(DomainObject,
1788                                     L"F",
1789                                     REG_BINARY,
1790                                     &FixedData,
1791                                     Length);
1792 
1793 done:
1794     return Status;
1795 }
1796 
1797 
1798 static NTSTATUS
1799 SampSetDomainServerRole(PSAM_DB_OBJECT DomainObject,
1800                         PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1801 {
1802     SAM_DOMAIN_FIXED_DATA FixedData;
1803     ULONG Length = 0;
1804     NTSTATUS Status;
1805 
1806     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1807     Status = SampGetObjectAttribute(DomainObject,
1808                                     L"F",
1809                                     NULL,
1810                                     (PVOID)&FixedData,
1811                                     &Length);
1812     if (!NT_SUCCESS(Status))
1813         goto done;
1814 
1815     FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1816 
1817     Status = SampSetObjectAttribute(DomainObject,
1818                                     L"F",
1819                                     REG_BINARY,
1820                                     &FixedData,
1821                                     Length);
1822 
1823 done:
1824     return Status;
1825 }
1826 
1827 
1828 static NTSTATUS
1829 SampSetDomainState(PSAM_DB_OBJECT DomainObject,
1830                    PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1831 {
1832     SAM_DOMAIN_FIXED_DATA FixedData;
1833     ULONG Length = 0;
1834     NTSTATUS Status;
1835 
1836     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1837     Status = SampGetObjectAttribute(DomainObject,
1838                                     L"F",
1839                                     NULL,
1840                                     (PVOID)&FixedData,
1841                                     &Length);
1842     if (!NT_SUCCESS(Status))
1843         goto done;
1844 
1845     FixedData.DomainServerState = Buffer->State.DomainServerState;
1846 
1847     Status = SampSetObjectAttribute(DomainObject,
1848                                     L"F",
1849                                     REG_BINARY,
1850                                     &FixedData,
1851                                     Length);
1852 
1853 done:
1854     return Status;
1855 }
1856 
1857 
1858 static NTSTATUS
1859 SampSetDomainLockout(PSAM_DB_OBJECT DomainObject,
1860                      PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1861 {
1862     SAM_DOMAIN_FIXED_DATA FixedData;
1863     ULONG Length = 0;
1864     NTSTATUS Status;
1865 
1866     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1867     Status = SampGetObjectAttribute(DomainObject,
1868                                     L"F",
1869                                     NULL,
1870                                     (PVOID)&FixedData,
1871                                     &Length);
1872     if (!NT_SUCCESS(Status))
1873         goto done;
1874 
1875     FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1876     FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1877     FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1878 
1879     Status = SampSetObjectAttribute(DomainObject,
1880                                     L"F",
1881                                     REG_BINARY,
1882                                     &FixedData,
1883                                     Length);
1884 
1885 done:
1886     return Status;
1887 }
1888 
1889 
1890 /* Function 9 */
1891 NTSTATUS
1892 NTAPI
1893 SamrSetInformationDomain(IN SAMPR_HANDLE DomainHandle,
1894                          IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1895                          IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1896 {
1897     PSAM_DB_OBJECT DomainObject;
1898     ACCESS_MASK DesiredAccess;
1899     NTSTATUS Status;
1900 
1901     TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1902           DomainHandle, DomainInformationClass, DomainInformation);
1903 
1904     switch (DomainInformationClass)
1905     {
1906         case DomainPasswordInformation:
1907         case DomainLockoutInformation:
1908             DesiredAccess = DOMAIN_WRITE_PASSWORD_PARAMS;
1909             break;
1910 
1911         case DomainLogoffInformation:
1912         case DomainOemInformation:
1913         case DomainNameInformation:
1914             DesiredAccess = DOMAIN_WRITE_OTHER_PARAMETERS;
1915             break;
1916 
1917         case DomainReplicationInformation:
1918         case DomainServerRoleInformation:
1919         case DomainStateInformation:
1920             DesiredAccess = DOMAIN_ADMINISTER_SERVER;
1921             break;
1922 
1923         default:
1924             return STATUS_INVALID_INFO_CLASS;
1925     }
1926 
1927     RtlAcquireResourceExclusive(&SampResource,
1928                                 TRUE);
1929 
1930     /* Validate the server handle */
1931     Status = SampValidateDbObject(DomainHandle,
1932                                   SamDbDomainObject,
1933                                   DesiredAccess,
1934                                   &DomainObject);
1935     if (!NT_SUCCESS(Status))
1936         goto done;
1937 
1938     switch (DomainInformationClass)
1939     {
1940         case DomainPasswordInformation:
1941             Status = SampSetDomainPassword(DomainObject,
1942                                            DomainInformation);
1943             break;
1944 
1945         case DomainLogoffInformation:
1946             Status = SampSetDomainLogoff(DomainObject,
1947                                          DomainInformation);
1948             break;
1949 
1950         case DomainOemInformation:
1951             Status = SampSetObjectAttributeString(DomainObject,
1952                                                   L"OemInformation",
1953                                                   &DomainInformation->Oem.OemInformation);
1954             break;
1955 
1956         case DomainNameInformation:
1957             Status = SampSetObjectAttributeString(DomainObject,
1958                                                   L"Name",
1959                                                   &DomainInformation->Name.DomainName);
1960             break;
1961 
1962         case DomainReplicationInformation:
1963             Status = SampSetObjectAttributeString(DomainObject,
1964                                                   L"ReplicaSourceNodeName",
1965                                                   &DomainInformation->Replication.ReplicaSourceNodeName);
1966             break;
1967 
1968         case DomainServerRoleInformation:
1969             Status = SampSetDomainServerRole(DomainObject,
1970                                              DomainInformation);
1971             break;
1972 
1973         case DomainStateInformation:
1974             Status = SampSetDomainState(DomainObject,
1975                                         DomainInformation);
1976             break;
1977 
1978         case DomainLockoutInformation:
1979             Status = SampSetDomainLockout(DomainObject,
1980                                           DomainInformation);
1981             break;
1982 
1983         default:
1984             Status = STATUS_NOT_IMPLEMENTED;
1985     }
1986 
1987 done:
1988     RtlReleaseResource(&SampResource);
1989 
1990     return Status;
1991 }
1992 
1993 
1994 /* Function 10 */
1995 NTSTATUS
1996 NTAPI
1997 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1998                         IN PRPC_UNICODE_STRING Name,
1999                         IN ACCESS_MASK DesiredAccess,
2000                         OUT SAMPR_HANDLE *GroupHandle,
2001                         OUT unsigned long *RelativeId)
2002 {
2003     SAM_DOMAIN_FIXED_DATA FixedDomainData;
2004     SAM_GROUP_FIXED_DATA FixedGroupData;
2005     PSAM_DB_OBJECT DomainObject;
2006     PSAM_DB_OBJECT GroupObject;
2007     PSECURITY_DESCRIPTOR Sd = NULL;
2008     ULONG SdSize = 0;
2009     ULONG ulSize;
2010     ULONG ulRid;
2011     WCHAR szRid[9];
2012     NTSTATUS Status;
2013 
2014     TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
2015           DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
2016 
2017     /* Map generic access rights */
2018     RtlMapGenericMask(&DesiredAccess,
2019                       &GroupMapping);
2020 
2021     RtlAcquireResourceExclusive(&SampResource,
2022                                 TRUE);
2023 
2024     /* Validate the domain handle */
2025     Status = SampValidateDbObject(DomainHandle,
2026                                   SamDbDomainObject,
2027                                   DOMAIN_CREATE_GROUP,
2028                                   &DomainObject);
2029     if (!NT_SUCCESS(Status))
2030     {
2031         TRACE("failed with status 0x%08lx\n", Status);
2032         goto done;
2033     }
2034 
2035     /* Check the group account name */
2036     Status = SampCheckAccountName(Name, 256);
2037     if (!NT_SUCCESS(Status))
2038     {
2039         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2040         goto done;
2041     }
2042 
2043     /* Check if the group name already exists in the domain */
2044     Status = SampCheckAccountNameInDomain(DomainObject,
2045                                           Name->Buffer);
2046     if (!NT_SUCCESS(Status))
2047     {
2048         TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
2049               Name->Buffer, Status);
2050         goto done;
2051     }
2052 
2053     /* Create the security descriptor */
2054     Status = SampCreateGroupSD(&Sd,
2055                                &SdSize);
2056     if (!NT_SUCCESS(Status))
2057     {
2058         TRACE("SampCreateGroupSD failed (Status 0x%08lx)\n", Status);
2059         goto done;
2060     }
2061 
2062     /* Get the fixed domain attributes */
2063     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2064     Status = SampGetObjectAttribute(DomainObject,
2065                                     L"F",
2066                                     NULL,
2067                                     (PVOID)&FixedDomainData,
2068                                     &ulSize);
2069     if (!NT_SUCCESS(Status))
2070     {
2071         TRACE("failed with status 0x%08lx\n", Status);
2072         goto done;
2073     }
2074 
2075     /* Increment the NextRid attribute */
2076     ulRid = FixedDomainData.NextRid;
2077     FixedDomainData.NextRid++;
2078 
2079     /* Store the fixed domain attributes */
2080     Status = SampSetObjectAttribute(DomainObject,
2081                                     L"F",
2082                                     REG_BINARY,
2083                                     &FixedDomainData,
2084                                     ulSize);
2085     if (!NT_SUCCESS(Status))
2086     {
2087         TRACE("failed with status 0x%08lx\n", Status);
2088         goto done;
2089     }
2090 
2091     TRACE("RID: %lx\n", ulRid);
2092 
2093     /* Convert the RID into a string (hex) */
2094     swprintf(szRid, L"%08lX", ulRid);
2095 
2096     /* Create the group object */
2097     Status = SampCreateDbObject(DomainObject,
2098                                 L"Groups",
2099                                 szRid,
2100                                 ulRid,
2101                                 SamDbGroupObject,
2102                                 DesiredAccess,
2103                                 &GroupObject);
2104     if (!NT_SUCCESS(Status))
2105     {
2106         TRACE("failed with status 0x%08lx\n", Status);
2107         goto done;
2108     }
2109 
2110     /* Add the account name of the user object */
2111     Status = SampSetAccountNameInDomain(DomainObject,
2112                                         L"Groups",
2113                                         Name->Buffer,
2114                                         ulRid);
2115     if (!NT_SUCCESS(Status))
2116     {
2117         TRACE("failed with status 0x%08lx\n", Status);
2118         goto done;
2119     }
2120 
2121     /* Initialize fixed user data */
2122     memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
2123     FixedGroupData.Version = 1;
2124     FixedGroupData.GroupId = ulRid;
2125 
2126     /* Set fixed user data attribute */
2127     Status = SampSetObjectAttribute(GroupObject,
2128                                     L"F",
2129                                     REG_BINARY,
2130                                     (LPVOID)&FixedGroupData,
2131                                     sizeof(SAM_GROUP_FIXED_DATA));
2132     if (!NT_SUCCESS(Status))
2133     {
2134         TRACE("failed with status 0x%08lx\n", Status);
2135         goto done;
2136     }
2137 
2138     /* Set the Name attribute */
2139     Status = SampSetObjectAttributeString(GroupObject,
2140                                           L"Name",
2141                                           Name);
2142     if (!NT_SUCCESS(Status))
2143     {
2144         TRACE("failed with status 0x%08lx\n", Status);
2145         goto done;
2146     }
2147 
2148     /* Set the AdminComment attribute */
2149     Status = SampSetObjectAttributeString(GroupObject,
2150                                           L"AdminComment",
2151                                           NULL);
2152     if (!NT_SUCCESS(Status))
2153     {
2154         TRACE("failed with status 0x%08lx\n", Status);
2155         goto done;
2156     }
2157 
2158     /* Set the SecDesc attribute*/
2159     Status = SampSetObjectAttribute(GroupObject,
2160                                     L"SecDesc",
2161                                     REG_BINARY,
2162                                     Sd,
2163                                     SdSize);
2164     if (!NT_SUCCESS(Status))
2165     {
2166         TRACE("failed with status 0x%08lx\n", Status);
2167         goto done;
2168     }
2169 
2170     if (NT_SUCCESS(Status))
2171     {
2172         *GroupHandle = (SAMPR_HANDLE)GroupObject;
2173         *RelativeId = ulRid;
2174     }
2175 
2176 done:
2177     if (Sd != NULL)
2178         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2179 
2180     RtlReleaseResource(&SampResource);
2181 
2182     TRACE("returns with status 0x%08lx\n", Status);
2183 
2184     return Status;
2185 }
2186 
2187 
2188 /* Function 11 */
2189 NTSTATUS
2190 NTAPI
2191 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
2192                             IN OUT unsigned long *EnumerationContext,
2193                             OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2194                             IN unsigned long PreferedMaximumLength,
2195                             OUT unsigned long *CountReturned)
2196 {
2197     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2198     PSAM_DB_OBJECT DomainObject;
2199     HANDLE GroupsKeyHandle = NULL;
2200     HANDLE NamesKeyHandle = NULL;
2201     WCHAR GroupName[64];
2202     ULONG EnumIndex;
2203     ULONG EnumCount = 0;
2204     ULONG RequiredLength = 0;
2205     ULONG NameLength;
2206     ULONG DataLength;
2207     ULONG Rid;
2208     ULONG i;
2209     BOOLEAN MoreEntries = FALSE;
2210     NTSTATUS Status;
2211 
2212     TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
2213           DomainHandle, EnumerationContext, Buffer,
2214           PreferedMaximumLength, CountReturned);
2215 
2216     RtlAcquireResourceShared(&SampResource,
2217                              TRUE);
2218 
2219     /* Validate the domain handle */
2220     Status = SampValidateDbObject(DomainHandle,
2221                                   SamDbDomainObject,
2222                                   DOMAIN_LIST_ACCOUNTS,
2223                                   &DomainObject);
2224     if (!NT_SUCCESS(Status))
2225         goto done;
2226 
2227     Status = SampRegOpenKey(DomainObject->KeyHandle,
2228                             L"Groups",
2229                             KEY_READ,
2230                             &GroupsKeyHandle);
2231     if (!NT_SUCCESS(Status))
2232         goto done;
2233 
2234     Status = SampRegOpenKey(GroupsKeyHandle,
2235                             L"Names",
2236                             KEY_READ,
2237                             &NamesKeyHandle);
2238     if (!NT_SUCCESS(Status))
2239         goto done;
2240 
2241     TRACE("Part 1\n");
2242 
2243     EnumIndex = *EnumerationContext;
2244 
2245     while (TRUE)
2246     {
2247         NameLength = 64 * sizeof(WCHAR);
2248         Status = SampRegEnumerateValue(NamesKeyHandle,
2249                                        EnumIndex,
2250                                        GroupName,
2251                                        &NameLength,
2252                                        NULL,
2253                                        NULL,
2254                                        NULL);
2255         if (!NT_SUCCESS(Status))
2256         {
2257             if (Status == STATUS_NO_MORE_ENTRIES)
2258                 Status = STATUS_SUCCESS;
2259             break;
2260         }
2261 
2262         TRACE("EnumIndex: %lu\n", EnumIndex);
2263         TRACE("Group name: %S\n", GroupName);
2264         TRACE("Name length: %lu\n", NameLength);
2265 
2266         if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2267         {
2268             MoreEntries = TRUE;
2269             break;
2270         }
2271 
2272         RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2273         EnumCount++;
2274 
2275         EnumIndex++;
2276     }
2277 
2278     TRACE("EnumCount: %lu\n", EnumCount);
2279     TRACE("RequiredLength: %lu\n", RequiredLength);
2280 
2281     if (!NT_SUCCESS(Status))
2282         goto done;
2283 
2284     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2285     if (EnumBuffer == NULL)
2286     {
2287         Status = STATUS_INSUFFICIENT_RESOURCES;
2288         goto done;
2289     }
2290 
2291     EnumBuffer->EntriesRead = EnumCount;
2292     if (EnumCount == 0)
2293     {
2294         Status = STATUS_NO_MORE_ENTRIES;
2295         goto done;
2296     }
2297 
2298     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2299     if (EnumBuffer->Buffer == NULL)
2300     {
2301         Status = STATUS_INSUFFICIENT_RESOURCES;
2302         goto done;
2303     }
2304 
2305     TRACE("Part 2\n");
2306 
2307     EnumIndex = *EnumerationContext;
2308     for (i = 0; i < EnumCount; i++, EnumIndex++)
2309     {
2310         NameLength = 64 * sizeof(WCHAR);
2311         DataLength = sizeof(ULONG);
2312         Status = SampRegEnumerateValue(NamesKeyHandle,
2313                                        EnumIndex,
2314                                        GroupName,
2315                                        &NameLength,
2316                                        NULL,
2317                                        &Rid,
2318                                        &DataLength);
2319         if (!NT_SUCCESS(Status))
2320         {
2321             if (Status == STATUS_NO_MORE_ENTRIES)
2322                 Status = STATUS_SUCCESS;
2323             break;
2324         }
2325 
2326         TRACE("EnumIndex: %lu\n", EnumIndex);
2327         TRACE("Group name: %S\n", GroupName);
2328         TRACE("Name length: %lu\n", NameLength);
2329         TRACE("RID: %lu\n", Rid);
2330 
2331         EnumBuffer->Buffer[i].RelativeId = Rid;
2332 
2333         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2334         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2335 
2336 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2337 #if 0
2338         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2339         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2340         {
2341             Status = STATUS_INSUFFICIENT_RESOURCES;
2342             goto done;
2343         }
2344 
2345         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2346                GroupName,
2347                EnumBuffer->Buffer[i].Name.Length);
2348 #endif
2349     }
2350 
2351 done:
2352     if (NT_SUCCESS(Status))
2353     {
2354         *EnumerationContext += EnumCount;
2355         *Buffer = EnumBuffer;
2356         *CountReturned = EnumCount;
2357     }
2358     else
2359     {
2360         *EnumerationContext = 0;
2361         *Buffer = NULL;
2362         *CountReturned = 0;
2363 
2364         if (EnumBuffer != NULL)
2365         {
2366             if (EnumBuffer->Buffer != NULL)
2367             {
2368                 if (EnumBuffer->EntriesRead != 0)
2369                 {
2370                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
2371                     {
2372                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2373                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2374                     }
2375                 }
2376 
2377                 midl_user_free(EnumBuffer->Buffer);
2378             }
2379 
2380             midl_user_free(EnumBuffer);
2381         }
2382     }
2383 
2384     SampRegCloseKey(&NamesKeyHandle);
2385     SampRegCloseKey(&GroupsKeyHandle);
2386 
2387     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2388         Status = STATUS_MORE_ENTRIES;
2389 
2390     RtlReleaseResource(&SampResource);
2391 
2392     return Status;
2393 }
2394 
2395 
2396 /* Function 12 */
2397 NTSTATUS
2398 NTAPI
2399 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2400                        IN PRPC_UNICODE_STRING Name,
2401                        IN ACCESS_MASK DesiredAccess,
2402                        OUT SAMPR_HANDLE *UserHandle,
2403                        OUT unsigned long *RelativeId)
2404 {
2405     SAM_DOMAIN_FIXED_DATA FixedDomainData;
2406     SAM_USER_FIXED_DATA FixedUserData;
2407     PSAM_DB_OBJECT DomainObject;
2408     PSAM_DB_OBJECT UserObject;
2409     GROUP_MEMBERSHIP GroupMembership;
2410     UCHAR LogonHours[23];
2411     ULONG ulSize;
2412     ULONG ulRid;
2413     WCHAR szRid[9];
2414     PSECURITY_DESCRIPTOR Sd = NULL;
2415     ULONG SdSize = 0;
2416     PSID UserSid = NULL;
2417     NTSTATUS Status;
2418 
2419     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2420           DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2421 
2422     if (Name == NULL ||
2423         Name->Length == 0 ||
2424         Name->Buffer == NULL ||
2425         UserHandle == NULL ||
2426         RelativeId == NULL)
2427         return STATUS_INVALID_PARAMETER;
2428 
2429     /* Map generic access rights */
2430     RtlMapGenericMask(&DesiredAccess,
2431                       &UserMapping);
2432 
2433     RtlAcquireResourceExclusive(&SampResource,
2434                                 TRUE);
2435 
2436     /* Validate the domain handle */
2437     Status = SampValidateDbObject(DomainHandle,
2438                                   SamDbDomainObject,
2439                                   DOMAIN_CREATE_USER,
2440                                   &DomainObject);
2441     if (!NT_SUCCESS(Status))
2442     {
2443         TRACE("failed with status 0x%08lx\n", Status);
2444         goto done;
2445     }
2446 
2447     /* Check the user account name */
2448     Status = SampCheckAccountName(Name, 20);
2449     if (!NT_SUCCESS(Status))
2450     {
2451         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2452         goto done;
2453     }
2454 
2455     /* Check if the user name already exists in the domain */
2456     Status = SampCheckAccountNameInDomain(DomainObject,
2457                                           Name->Buffer);
2458     if (!NT_SUCCESS(Status))
2459     {
2460         TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2461               Name->Buffer, Status);
2462         goto done;
2463     }
2464 
2465     /* Get the fixed domain attributes */
2466     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2467     Status = SampGetObjectAttribute(DomainObject,
2468                                     L"F",
2469                                     NULL,
2470                                     (PVOID)&FixedDomainData,
2471                                     &ulSize);
2472     if (!NT_SUCCESS(Status))
2473     {
2474         TRACE("failed with status 0x%08lx\n", Status);
2475         goto done;
2476     }
2477 
2478     /* Increment the NextRid attribute */
2479     ulRid = FixedDomainData.NextRid;
2480     FixedDomainData.NextRid++;
2481 
2482     TRACE("RID: %lx\n", ulRid);
2483 
2484     /* Create the user SID */
2485     Status = SampCreateAccountSid(DomainObject,
2486                                   ulRid,
2487                                   &UserSid);
2488     if (!NT_SUCCESS(Status))
2489     {
2490         TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
2491         goto done;
2492     }
2493 
2494     /* Create the security descriptor */
2495     Status = SampCreateUserSD(UserSid,
2496                               &Sd,
2497                               &SdSize);
2498     if (!NT_SUCCESS(Status))
2499     {
2500         TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
2501         goto done;
2502     }
2503 
2504     /* Store the fixed domain attributes */
2505     Status = SampSetObjectAttribute(DomainObject,
2506                                     L"F",
2507                                     REG_BINARY,
2508                                     &FixedDomainData,
2509                                     ulSize);
2510     if (!NT_SUCCESS(Status))
2511     {
2512         TRACE("failed with status 0x%08lx\n", Status);
2513         goto done;
2514     }
2515 
2516     /* Convert the RID into a string (hex) */
2517     swprintf(szRid, L"%08lX", ulRid);
2518 
2519     /* Create the user object */
2520     Status = SampCreateDbObject(DomainObject,
2521                                 L"Users",
2522                                 szRid,
2523                                 ulRid,
2524                                 SamDbUserObject,
2525                                 DesiredAccess,
2526                                 &UserObject);
2527     if (!NT_SUCCESS(Status))
2528     {
2529         TRACE("failed with status 0x%08lx\n", Status);
2530         goto done;
2531     }
2532 
2533     /* Add the account name for the user object */
2534     Status = SampSetAccountNameInDomain(DomainObject,
2535                                         L"Users",
2536                                         Name->Buffer,
2537                                         ulRid);
2538     if (!NT_SUCCESS(Status))
2539     {
2540         TRACE("failed with status 0x%08lx\n", Status);
2541         goto done;
2542     }
2543 
2544     /* Initialize fixed user data */
2545     memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2546     FixedUserData.Version = 1;
2547     FixedUserData.Reserved = 0;
2548     FixedUserData.LastLogon.QuadPart = 0;
2549     FixedUserData.LastLogoff.QuadPart = 0;
2550     FixedUserData.PasswordLastSet.QuadPart = 0;
2551     FixedUserData.AccountExpires.QuadPart = MAXLONGLONG;
2552     FixedUserData.LastBadPasswordTime.QuadPart = 0;
2553     FixedUserData.UserId = ulRid;
2554     FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2555     FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2556                                        USER_PASSWORD_NOT_REQUIRED |
2557                                        USER_NORMAL_ACCOUNT;
2558     FixedUserData.CountryCode = 0;
2559     FixedUserData.CodePage = 0;
2560     FixedUserData.BadPasswordCount = 0;
2561     FixedUserData.LogonCount = 0;
2562     FixedUserData.AdminCount = 0;
2563     FixedUserData.OperatorCount = 0;
2564 
2565     /* Set fixed user data attribute */
2566     Status = SampSetObjectAttribute(UserObject,
2567                                     L"F",
2568                                     REG_BINARY,
2569                                     (LPVOID)&FixedUserData,
2570                                     sizeof(SAM_USER_FIXED_DATA));
2571     if (!NT_SUCCESS(Status))
2572     {
2573         TRACE("failed with status 0x%08lx\n", Status);
2574         goto done;
2575     }
2576 
2577     /* Set the Name attribute */
2578     Status = SampSetObjectAttributeString(UserObject,
2579                                           L"Name",
2580                                           Name);
2581     if (!NT_SUCCESS(Status))
2582     {
2583         TRACE("failed with status 0x%08lx\n", Status);
2584         goto done;
2585     }
2586 
2587     /* Set the FullName attribute */
2588     Status = SampSetObjectAttributeString(UserObject,
2589                                           L"FullName",
2590                                           NULL);
2591     if (!NT_SUCCESS(Status))
2592     {
2593         TRACE("failed with status 0x%08lx\n", Status);
2594         goto done;
2595     }
2596 
2597     /* Set the HomeDirectory attribute */
2598     Status = SampSetObjectAttributeString(UserObject,
2599                                           L"HomeDirectory",
2600                                           NULL);
2601     if (!NT_SUCCESS(Status))
2602     {
2603         TRACE("failed with status 0x%08lx\n", Status);
2604         goto done;
2605     }
2606 
2607     /* Set the HomeDirectoryDrive attribute */
2608     Status = SampSetObjectAttributeString(UserObject,
2609                                           L"HomeDirectoryDrive",
2610                                           NULL);
2611     if (!NT_SUCCESS(Status))
2612     {
2613         TRACE("failed with status 0x%08lx\n", Status);
2614         goto done;
2615     }
2616 
2617     /* Set the ScriptPath attribute */
2618     Status = SampSetObjectAttributeString(UserObject,
2619                                           L"ScriptPath",
2620                                           NULL);
2621     if (!NT_SUCCESS(Status))
2622     {
2623         TRACE("failed with status 0x%08lx\n", Status);
2624         goto done;
2625     }
2626 
2627     /* Set the ProfilePath attribute */
2628     Status = SampSetObjectAttributeString(UserObject,
2629                                           L"ProfilePath",
2630                                           NULL);
2631     if (!NT_SUCCESS(Status))
2632     {
2633         TRACE("failed with status 0x%08lx\n", Status);
2634         goto done;
2635     }
2636 
2637     /* Set the AdminComment attribute */
2638     Status = SampSetObjectAttributeString(UserObject,
2639                                           L"AdminComment",
2640                                           NULL);
2641     if (!NT_SUCCESS(Status))
2642     {
2643         TRACE("failed with status 0x%08lx\n", Status);
2644         goto done;
2645     }
2646 
2647     /* Set the UserComment attribute */
2648     Status = SampSetObjectAttributeString(UserObject,
2649                                           L"UserComment",
2650                                           NULL);
2651     if (!NT_SUCCESS(Status))
2652     {
2653         TRACE("failed with status 0x%08lx\n", Status);
2654         goto done;
2655     }
2656 
2657     /* Set the WorkStations attribute */
2658     Status = SampSetObjectAttributeString(UserObject,
2659                                           L"WorkStations",
2660                                           NULL);
2661     if (!NT_SUCCESS(Status))
2662     {
2663         TRACE("failed with status 0x%08lx\n", Status);
2664         goto done;
2665     }
2666 
2667     /* Set the Parameters attribute */
2668     Status = SampSetObjectAttributeString(UserObject,
2669                                           L"Parameters",
2670                                           NULL);
2671     if (!NT_SUCCESS(Status))
2672     {
2673         TRACE("failed with status 0x%08lx\n", Status);
2674         goto done;
2675     }
2676 
2677     /* Set LogonHours attribute*/
2678     *((PUSHORT)LogonHours) = 168;
2679     memset(&(LogonHours[2]), 0xff, 21);
2680 
2681     Status = SampSetObjectAttribute(UserObject,
2682                                     L"LogonHours",
2683                                     REG_BINARY,
2684                                     &LogonHours,
2685                                     sizeof(LogonHours));
2686     if (!NT_SUCCESS(Status))
2687     {
2688         TRACE("failed with status 0x%08lx\n", Status);
2689         goto done;
2690     }
2691 
2692     /* Set Groups attribute*/
2693     GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2694     GroupMembership.Attributes = SE_GROUP_MANDATORY |
2695                                  SE_GROUP_ENABLED |
2696                                  SE_GROUP_ENABLED_BY_DEFAULT;
2697 
2698     Status = SampSetObjectAttribute(UserObject,
2699                                     L"Groups",
2700                                     REG_BINARY,
2701                                     &GroupMembership,
2702                                     sizeof(GROUP_MEMBERSHIP));
2703     if (!NT_SUCCESS(Status))
2704     {
2705         TRACE("failed with status 0x%08lx\n", Status);
2706         goto done;
2707     }
2708 
2709     /* Set LMPwd attribute*/
2710     Status = SampSetObjectAttribute(UserObject,
2711                                     L"LMPwd",
2712                                     REG_BINARY,
2713                                     &EmptyLmHash,
2714                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2715     if (!NT_SUCCESS(Status))
2716     {
2717         TRACE("failed with status 0x%08lx\n", Status);
2718         goto done;
2719     }
2720 
2721     /* Set NTPwd attribute*/
2722     Status = SampSetObjectAttribute(UserObject,
2723                                     L"NTPwd",
2724                                     REG_BINARY,
2725                                     &EmptyNtHash,
2726                                     sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2727     if (!NT_SUCCESS(Status))
2728     {
2729         TRACE("failed with status 0x%08lx\n", Status);
2730         goto done;
2731     }
2732 
2733     /* Set LMPwdHistory attribute*/
2734     Status = SampSetObjectAttribute(UserObject,
2735                                     L"LMPwdHistory",
2736                                     REG_BINARY,
2737                                     NULL,
2738                                     0);
2739     if (!NT_SUCCESS(Status))
2740     {
2741         TRACE("failed with status 0x%08lx\n", Status);
2742         goto done;
2743     }
2744 
2745     /* Set NTPwdHistory attribute*/
2746     Status = SampSetObjectAttribute(UserObject,
2747                                     L"NTPwdHistory",
2748                                     REG_BINARY,
2749                                     NULL,
2750                                     0);
2751     if (!NT_SUCCESS(Status))
2752     {
2753         TRACE("failed with status 0x%08lx\n", Status);
2754         goto done;
2755     }
2756 
2757     /* Set the PrivateData attribute */
2758     Status = SampSetObjectAttributeString(UserObject,
2759                                           L"PrivateData",
2760                                           NULL);
2761     if (!NT_SUCCESS(Status))
2762     {
2763         TRACE("failed with status 0x%08lx\n", Status);
2764         goto done;
2765     }
2766 
2767     /* Set the SecDesc attribute*/
2768     Status = SampSetObjectAttribute(UserObject,
2769                                     L"SecDesc",
2770                                     REG_BINARY,
2771                                     Sd,
2772                                     SdSize);
2773     if (!NT_SUCCESS(Status))
2774     {
2775         TRACE("failed with status 0x%08lx\n", Status);
2776         goto done;
2777     }
2778 
2779     if (NT_SUCCESS(Status))
2780     {
2781         *UserHandle = (SAMPR_HANDLE)UserObject;
2782         *RelativeId = ulRid;
2783     }
2784 
2785 done:
2786     if (Sd != NULL)
2787         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2788 
2789     if (UserSid != NULL)
2790         RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2791 
2792     RtlReleaseResource(&SampResource);
2793 
2794     TRACE("returns with status 0x%08lx\n", Status);
2795 
2796     return Status;
2797 }
2798 
2799 
2800 /* Function 13 */
2801 NTSTATUS
2802 NTAPI
2803 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2804                            IN OUT unsigned long *EnumerationContext,
2805                            IN unsigned long UserAccountControl,
2806                            OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2807                            IN unsigned long PreferedMaximumLength,
2808                            OUT unsigned long *CountReturned)
2809 {
2810     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2811     PSAM_DB_OBJECT DomainObject;
2812     HANDLE UsersKeyHandle = NULL;
2813     HANDLE NamesKeyHandle = NULL;
2814     WCHAR UserName[64];
2815     ULONG EnumIndex;
2816     ULONG EnumCount = 0;
2817     ULONG RequiredLength = 0;
2818     ULONG NameLength;
2819     ULONG DataLength;
2820     ULONG Rid;
2821     ULONG i;
2822     BOOLEAN MoreEntries = FALSE;
2823     NTSTATUS Status;
2824 
2825     TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2826           DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2827           PreferedMaximumLength, CountReturned);
2828 
2829     RtlAcquireResourceShared(&SampResource,
2830                              TRUE);
2831 
2832     /* Validate the domain handle */
2833     Status = SampValidateDbObject(DomainHandle,
2834                                   SamDbDomainObject,
2835                                   DOMAIN_LIST_ACCOUNTS,
2836                                   &DomainObject);
2837     if (!NT_SUCCESS(Status))
2838         goto done;
2839 
2840     Status = SampRegOpenKey(DomainObject->KeyHandle,
2841                             L"Users",
2842                             KEY_READ,
2843                             &UsersKeyHandle);
2844     if (!NT_SUCCESS(Status))
2845         goto done;
2846 
2847     Status = SampRegOpenKey(UsersKeyHandle,
2848                             L"Names",
2849                             KEY_READ,
2850                             &NamesKeyHandle);
2851     if (!NT_SUCCESS(Status))
2852         goto done;
2853 
2854     TRACE("Part 1\n");
2855 
2856     EnumIndex = *EnumerationContext;
2857 
2858     while (TRUE)
2859     {
2860         NameLength = 64 * sizeof(WCHAR);
2861         Status = SampRegEnumerateValue(NamesKeyHandle,
2862                                        EnumIndex,
2863                                        UserName,
2864                                        &NameLength,
2865                                        NULL,
2866                                        NULL,
2867                                        NULL);
2868         if (!NT_SUCCESS(Status))
2869         {
2870             if (Status == STATUS_NO_MORE_ENTRIES)
2871                 Status = STATUS_SUCCESS;
2872             break;
2873         }
2874 
2875         TRACE("EnumIndex: %lu\n", EnumIndex);
2876         TRACE("User name: %S\n", UserName);
2877         TRACE("Name length: %lu\n", NameLength);
2878 
2879         if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2880         {
2881             MoreEntries = TRUE;
2882             break;
2883         }
2884 
2885         RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2886         EnumCount++;
2887 
2888         EnumIndex++;
2889     }
2890 
2891     TRACE("EnumCount: %lu\n", EnumCount);
2892     TRACE("RequiredLength: %lu\n", RequiredLength);
2893 
2894     if (!NT_SUCCESS(Status))
2895         goto done;
2896 
2897     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2898     if (EnumBuffer == NULL)
2899     {
2900         Status = STATUS_INSUFFICIENT_RESOURCES;
2901         goto done;
2902     }
2903 
2904     EnumBuffer->EntriesRead = EnumCount;
2905     if (EnumCount == 0)
2906     {
2907         Status = STATUS_NO_MORE_ENTRIES;
2908         goto done;
2909     }
2910 
2911     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2912     if (EnumBuffer->Buffer == NULL)
2913     {
2914         Status = STATUS_INSUFFICIENT_RESOURCES;
2915         goto done;
2916     }
2917 
2918     TRACE("Part 2\n");
2919 
2920     EnumIndex = *EnumerationContext;
2921     for (i = 0; i < EnumCount; i++, EnumIndex++)
2922     {
2923         NameLength = 64 * sizeof(WCHAR);
2924         DataLength = sizeof(ULONG);
2925         Status = SampRegEnumerateValue(NamesKeyHandle,
2926                                        EnumIndex,
2927                                        UserName,
2928                                        &NameLength,
2929                                        NULL,
2930                                        &Rid,
2931                                        &DataLength);
2932         if (!NT_SUCCESS(Status))
2933         {
2934             if (Status == STATUS_NO_MORE_ENTRIES)
2935                 Status = STATUS_SUCCESS;
2936             break;
2937         }
2938 
2939         TRACE("EnumIndex: %lu\n", EnumIndex);
2940         TRACE("User name: %S\n", UserName);
2941         TRACE("Name length: %lu\n", NameLength);
2942         TRACE("RID: %lu\n", Rid);
2943 
2944         EnumBuffer->Buffer[i].RelativeId = Rid;
2945 
2946         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2947         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2948 
2949 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2950 #if 0
2951         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2952         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2953         {
2954             Status = STATUS_INSUFFICIENT_RESOURCES;
2955             goto done;
2956         }
2957 
2958         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2959                UserName,
2960                EnumBuffer->Buffer[i].Name.Length);
2961 #endif
2962     }
2963 
2964 done:
2965     if (NT_SUCCESS(Status))
2966     {
2967         *EnumerationContext += EnumCount;
2968         *Buffer = EnumBuffer;
2969         *CountReturned = EnumCount;
2970     }
2971     else
2972     {
2973         *EnumerationContext = 0;
2974         *Buffer = NULL;
2975         *CountReturned = 0;
2976 
2977         if (EnumBuffer != NULL)
2978         {
2979             if (EnumBuffer->Buffer != NULL)
2980             {
2981                 if (EnumBuffer->EntriesRead != 0)
2982                 {
2983                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
2984                     {
2985                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2986                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2987                     }
2988                 }
2989 
2990                 midl_user_free(EnumBuffer->Buffer);
2991             }
2992 
2993             midl_user_free(EnumBuffer);
2994         }
2995     }
2996 
2997     SampRegCloseKey(&NamesKeyHandle);
2998     SampRegCloseKey(&UsersKeyHandle);
2999 
3000     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3001         Status = STATUS_MORE_ENTRIES;
3002 
3003     RtlReleaseResource(&SampResource);
3004 
3005     return Status;
3006 }
3007 
3008 
3009 /* Function 14 */
3010 NTSTATUS
3011 NTAPI
3012 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
3013                         IN PRPC_UNICODE_STRING AccountName,
3014                         IN ACCESS_MASK DesiredAccess,
3015                         OUT SAMPR_HANDLE *AliasHandle,
3016                         OUT unsigned long *RelativeId)
3017 {
3018     SAM_DOMAIN_FIXED_DATA FixedDomainData;
3019     PSAM_DB_OBJECT DomainObject;
3020     PSAM_DB_OBJECT AliasObject;
3021     PSECURITY_DESCRIPTOR Sd = NULL;
3022     ULONG SdSize = 0;
3023     ULONG ulSize;
3024     ULONG ulRid;
3025     WCHAR szRid[9];
3026     NTSTATUS Status;
3027 
3028     TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
3029           DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
3030 
3031     /* Map generic access rights */
3032     RtlMapGenericMask(&DesiredAccess,
3033                       &AliasMapping);
3034 
3035     RtlAcquireResourceExclusive(&SampResource,
3036                                 TRUE);
3037 
3038     /* Validate the domain handle */
3039     Status = SampValidateDbObject(DomainHandle,
3040                                   SamDbDomainObject,
3041                                   DOMAIN_CREATE_ALIAS,
3042                                   &DomainObject);
3043     if (!NT_SUCCESS(Status))
3044     {
3045         TRACE("failed with status 0x%08lx\n", Status);
3046         goto done;
3047     }
3048 
3049     /* Check the alias account name */
3050     Status = SampCheckAccountName(AccountName, 256);
3051     if (!NT_SUCCESS(Status))
3052     {
3053         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
3054         goto done;
3055     }
3056 
3057     /* Check if the alias name already exists in the domain */
3058     Status = SampCheckAccountNameInDomain(DomainObject,
3059                                           AccountName->Buffer);
3060     if (!NT_SUCCESS(Status))
3061     {
3062         TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
3063               AccountName->Buffer, Status);
3064         goto done;
3065     }
3066 
3067     /* Create the security descriptor */
3068     Status = SampCreateAliasSD(&Sd,
3069                                &SdSize);
3070     if (!NT_SUCCESS(Status))
3071     {
3072         TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
3073         goto done;
3074     }
3075 
3076     /* Get the fixed domain attributes */
3077     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
3078     Status = SampGetObjectAttribute(DomainObject,
3079                                     L"F",
3080                                     NULL,
3081                                     (PVOID)&FixedDomainData,
3082                                     &ulSize);
3083     if (!NT_SUCCESS(Status))
3084     {
3085         TRACE("failed with status 0x%08lx\n", Status);
3086         goto done;
3087     }
3088 
3089     /* Increment the NextRid attribute */
3090     ulRid = FixedDomainData.NextRid;
3091     FixedDomainData.NextRid++;
3092 
3093     /* Store the fixed domain attributes */
3094     Status = SampSetObjectAttribute(DomainObject,
3095                            L"F",
3096                            REG_BINARY,
3097                            &FixedDomainData,
3098                            ulSize);
3099     if (!NT_SUCCESS(Status))
3100     {
3101         TRACE("failed with status 0x%08lx\n", Status);
3102         goto done;
3103     }
3104 
3105     TRACE("RID: %lx\n", ulRid);
3106 
3107     /* Convert the RID into a string (hex) */
3108     swprintf(szRid, L"%08lX", ulRid);
3109 
3110     /* Create the alias object */
3111     Status = SampCreateDbObject(DomainObject,
3112                                 L"Aliases",
3113                                 szRid,
3114                                 ulRid,
3115                                 SamDbAliasObject,
3116                                 DesiredAccess,
3117                                 &AliasObject);
3118     if (!NT_SUCCESS(Status))
3119     {
3120         TRACE("failed with status 0x%08lx\n", Status);
3121         goto done;
3122     }
3123 
3124     /* Add the account name for the alias object */
3125     Status = SampSetAccountNameInDomain(DomainObject,
3126                                         L"Aliases",
3127                                         AccountName->Buffer,
3128                                         ulRid);
3129     if (!NT_SUCCESS(Status))
3130     {
3131         TRACE("failed with status 0x%08lx\n", Status);
3132         goto done;
3133     }
3134 
3135     /* Set the Name attribute */
3136     Status = SampSetObjectAttributeString(AliasObject,
3137                                           L"Name",
3138                                           AccountName);
3139     if (!NT_SUCCESS(Status))
3140     {
3141         TRACE("failed with status 0x%08lx\n", Status);
3142         goto done;
3143     }
3144 
3145     /* Set the Description attribute */
3146     Status = SampSetObjectAttributeString(AliasObject,
3147                                           L"Description",
3148                                           NULL);
3149     if (!NT_SUCCESS(Status))
3150     {
3151         TRACE("failed with status 0x%08lx\n", Status);
3152         goto done;
3153     }
3154 
3155     /* Set the SecDesc attribute*/
3156     Status = SampSetObjectAttribute(AliasObject,
3157                                     L"SecDesc",
3158                                     REG_BINARY,
3159                                     Sd,
3160                                     SdSize);
3161     if (!NT_SUCCESS(Status))
3162     {
3163         TRACE("failed with status 0x%08lx\n", Status);
3164         goto done;
3165     }
3166 
3167     if (NT_SUCCESS(Status))
3168     {
3169         *AliasHandle = (SAMPR_HANDLE)AliasObject;
3170         *RelativeId = ulRid;
3171     }
3172 
3173 done:
3174     if (Sd != NULL)
3175         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
3176 
3177     RtlReleaseResource(&SampResource);
3178 
3179     TRACE("returns with status 0x%08lx\n", Status);
3180 
3181     return Status;
3182 }
3183 
3184 
3185 /* Function 15 */
3186 NTSTATUS
3187 NTAPI
3188 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
3189                              IN OUT unsigned long *EnumerationContext,
3190                              OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
3191                              IN unsigned long PreferedMaximumLength,
3192                              OUT unsigned long *CountReturned)
3193 {
3194     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
3195     PSAM_DB_OBJECT DomainObject;
3196     HANDLE AliasesKeyHandle = NULL;
3197     HANDLE NamesKeyHandle = NULL;
3198     WCHAR AliasName[64];
3199     ULONG EnumIndex;
3200     ULONG EnumCount = 0;
3201     ULONG RequiredLength = 0;
3202     ULONG NameLength;
3203     ULONG DataLength;
3204     ULONG Rid;
3205     ULONG i;
3206     BOOLEAN MoreEntries = FALSE;
3207     NTSTATUS Status;
3208 
3209     TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
3210           DomainHandle, EnumerationContext, Buffer,
3211           PreferedMaximumLength, CountReturned);
3212 
3213     RtlAcquireResourceShared(&SampResource,
3214                              TRUE);
3215 
3216     /* Validate the domain handle */
3217     Status = SampValidateDbObject(DomainHandle,
3218                                   SamDbDomainObject,
3219                                   DOMAIN_LIST_ACCOUNTS,
3220                                   &DomainObject);
3221     if (!NT_SUCCESS(Status))
3222         goto done;
3223 
3224     Status = SampRegOpenKey(DomainObject->KeyHandle,
3225                             L"Aliases",
3226                             KEY_READ,
3227                             &AliasesKeyHandle);
3228     if (!NT_SUCCESS(Status))
3229         goto done;
3230 
3231     Status = SampRegOpenKey(AliasesKeyHandle,
3232                             L"Names",
3233                             KEY_READ,
3234                             &NamesKeyHandle);
3235     if (!NT_SUCCESS(Status))
3236         goto done;
3237 
3238     TRACE("Part 1\n");
3239 
3240     EnumIndex = *EnumerationContext;
3241 
3242     while (TRUE)
3243     {
3244         NameLength = 64 * sizeof(WCHAR);
3245         Status = SampRegEnumerateValue(NamesKeyHandle,
3246                                        EnumIndex,
3247                                        AliasName,
3248                                        &NameLength,
3249                                        NULL,
3250                                        NULL,
3251                                        NULL);
3252         if (!NT_SUCCESS(Status))
3253         {
3254             if (Status == STATUS_NO_MORE_ENTRIES)
3255                 Status = STATUS_SUCCESS;
3256             break;
3257         }
3258 
3259         TRACE("EnumIndex: %lu\n", EnumIndex);
3260         TRACE("Alias name: %S\n", AliasName);
3261         TRACE("Name length: %lu\n", NameLength);
3262 
3263         if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3264         {
3265             MoreEntries = TRUE;
3266             break;
3267         }
3268 
3269         RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3270         EnumCount++;
3271 
3272         EnumIndex++;
3273     }
3274 
3275     TRACE("EnumCount: %lu\n", EnumCount);
3276     TRACE("RequiredLength: %lu\n", RequiredLength);
3277 
3278     if (!NT_SUCCESS(Status))
3279         goto done;
3280 
3281     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3282     if (EnumBuffer == NULL)
3283     {
3284         Status = STATUS_INSUFFICIENT_RESOURCES;
3285         goto done;
3286     }
3287 
3288     EnumBuffer->EntriesRead = EnumCount;
3289     if (EnumCount == 0)
3290     {
3291         Status = STATUS_NO_MORE_ENTRIES;
3292         goto done;
3293     }
3294 
3295     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3296     if (EnumBuffer->Buffer == NULL)
3297     {
3298         Status = STATUS_INSUFFICIENT_RESOURCES;
3299         goto done;
3300     }
3301 
3302     TRACE("Part 2\n");
3303 
3304     EnumIndex = *EnumerationContext;
3305     for (i = 0; i < EnumCount; i++, EnumIndex++)
3306     {
3307         NameLength = 64 * sizeof(WCHAR);
3308         DataLength = sizeof(ULONG);
3309         Status = SampRegEnumerateValue(NamesKeyHandle,
3310                                        EnumIndex,
3311                                        AliasName,
3312                                        &NameLength,
3313                                        NULL,
3314                                        &Rid,
3315                                        &DataLength);
3316         if (!NT_SUCCESS(Status))
3317         {
3318             if (Status == STATUS_NO_MORE_ENTRIES)
3319                 Status = STATUS_SUCCESS;
3320             break;
3321         }
3322 
3323         TRACE("EnumIndex: %lu\n", EnumIndex);
3324         TRACE("Alias name: %S\n", AliasName);
3325         TRACE("Name length: %lu\n", NameLength);
3326         TRACE("RID: %lu\n", Rid);
3327 
3328         EnumBuffer->Buffer[i].RelativeId = Rid;
3329 
3330         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3331         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
3332 
3333 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3334 #if 0
3335         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3336         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3337         {
3338             Status = STATUS_INSUFFICIENT_RESOURCES;
3339             goto done;
3340         }
3341 
3342         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3343                AliasName,
3344                EnumBuffer->Buffer[i].Name.Length);
3345 #endif
3346     }
3347 
3348 done:
3349     if (NT_SUCCESS(Status))
3350     {
3351         *EnumerationContext += EnumCount;
3352         *Buffer = EnumBuffer;
3353         *CountReturned = EnumCount;
3354     }
3355     else
3356     {
3357         *EnumerationContext = 0;
3358         *Buffer = NULL;
3359         *CountReturned = 0;
3360 
3361         if (EnumBuffer != NULL)
3362         {
3363             if (EnumBuffer->Buffer != NULL)
3364             {
3365                 if (EnumBuffer->EntriesRead != 0)
3366                 {
3367                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
3368                     {
3369                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3370                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3371                     }
3372                 }
3373 
3374                 midl_user_free(EnumBuffer->Buffer);
3375             }
3376 
3377             midl_user_free(EnumBuffer);
3378         }
3379     }
3380 
3381     SampRegCloseKey(&NamesKeyHandle);
3382     SampRegCloseKey(&AliasesKeyHandle);
3383 
3384     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3385         Status = STATUS_MORE_ENTRIES;
3386 
3387     RtlReleaseResource(&SampResource);
3388 
3389     return Status;
3390 }
3391 
3392 
3393 /* Function 16 */
3394 NTSTATUS
3395 NTAPI
3396 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3397                        IN PSAMPR_PSID_ARRAY SidArray,
3398                        OUT PSAMPR_ULONG_ARRAY Membership)
3399 {
3400     PSAM_DB_OBJECT DomainObject;
3401     HANDLE AliasesKeyHandle = NULL;
3402     HANDLE MembersKeyHandle = NULL;
3403     HANDLE MemberKeyHandle = NULL;
3404     LPWSTR MemberSidString = NULL;
3405     PULONG RidArray = NULL;
3406     ULONG MaxSidCount = 0;
3407     ULONG ValueCount;
3408     ULONG DataLength;
3409     ULONG i, j;
3410     ULONG RidIndex;
3411     NTSTATUS Status;
3412     WCHAR NameBuffer[9];
3413 
3414     TRACE("SamrGetAliasMembership(%p %p %p)\n",
3415           DomainHandle, SidArray, Membership);
3416 
3417     RtlAcquireResourceShared(&SampResource,
3418                              TRUE);
3419 
3420     /* Validate the domain handle */
3421     Status = SampValidateDbObject(DomainHandle,
3422                                   SamDbDomainObject,
3423                                   DOMAIN_GET_ALIAS_MEMBERSHIP,
3424                                   &DomainObject);
3425     if (!NT_SUCCESS(Status))
3426         goto done;
3427 
3428     Status = SampRegOpenKey(DomainObject->KeyHandle,
3429                             L"Aliases",
3430                             KEY_READ,
3431                             &AliasesKeyHandle);
3432     TRACE("SampRegOpenKey returned %08lX\n", Status);
3433     if (!NT_SUCCESS(Status))
3434         goto done;
3435 
3436     Status = SampRegOpenKey(AliasesKeyHandle,
3437                             L"Members",
3438                             KEY_READ,
3439                             &MembersKeyHandle);
3440     TRACE("SampRegOpenKey returned %08lX\n", Status);
3441 
3442     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3443     {
3444         Status = STATUS_SUCCESS;
3445         goto done;
3446     }
3447 
3448     if (!NT_SUCCESS(Status))
3449         goto done;
3450 
3451     for (i = 0; i < SidArray->Count; i++)
3452     {
3453         ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3454 TRACE("Open %S\n", MemberSidString);
3455 
3456         Status = SampRegOpenKey(MembersKeyHandle,
3457                                 MemberSidString,
3458                                 KEY_READ,
3459                                 &MemberKeyHandle);
3460         TRACE("SampRegOpenKey returned %08lX\n", Status);
3461         if (NT_SUCCESS(Status))
3462         {
3463             Status = SampRegQueryKeyInfo(MemberKeyHandle,
3464                                          NULL,
3465                                          &ValueCount);
3466             if (NT_SUCCESS(Status))
3467             {
3468                 TRACE("Found %lu values\n", ValueCount);
3469                 MaxSidCount += ValueCount;
3470             }
3471 
3472             SampRegCloseKey(&MemberKeyHandle);
3473         }
3474 
3475         if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3476             Status = STATUS_SUCCESS;
3477 
3478         LocalFree(MemberSidString);
3479     }
3480 
3481     if (MaxSidCount == 0)
3482     {
3483         Status = STATUS_SUCCESS;
3484         goto done;
3485     }
3486 
3487     TRACE("Maximum sid count: %lu\n", MaxSidCount);
3488     RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3489     if (RidArray == NULL)
3490     {
3491         Status = STATUS_INSUFFICIENT_RESOURCES;
3492         goto done;
3493     }
3494 
3495     RidIndex = 0;
3496     for (i = 0; i < SidArray->Count; i++)
3497     {
3498         ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3499 TRACE("Open %S\n", MemberSidString);
3500 
3501         Status = SampRegOpenKey(MembersKeyHandle,
3502                                 MemberSidString,
3503                                 KEY_READ,
3504                                 &MemberKeyHandle);
3505         TRACE("SampRegOpenKey returned %08lX\n", Status);
3506         if (NT_SUCCESS(Status))
3507         {
3508             Status = SampRegQueryKeyInfo(MemberKeyHandle,
3509                                          NULL,
3510                                          &ValueCount);
3511             if (NT_SUCCESS(Status))
3512             {
3513                 TRACE("Found %lu values\n", ValueCount);
3514 
3515                 for (j = 0; j < ValueCount; j++)
3516                 {
3517                     DataLength = 9 * sizeof(WCHAR);
3518                     Status = SampRegEnumerateValue(MemberKeyHandle,
3519                                                    j,
3520                                                    NameBuffer,
3521                                                    &DataLength,
3522                                                    NULL,
3523                                                    NULL,
3524                                                    NULL);
3525                     if (NT_SUCCESS(Status))
3526                     {
3527                         /* FIXME: Do not return each RID more than once. */
3528                         RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
3529                         RidIndex++;
3530                     }
3531                 }
3532             }
3533 
3534             SampRegCloseKey(&MemberKeyHandle);
3535         }
3536 
3537         if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3538             Status = STATUS_SUCCESS;
3539 
3540         LocalFree(MemberSidString);
3541     }
3542 
3543 done:
3544     SampRegCloseKey(&MembersKeyHandle);
3545     SampRegCloseKey(&AliasesKeyHandle);
3546 
3547     if (NT_SUCCESS(Status))
3548     {
3549         Membership->Count = MaxSidCount;
3550         Membership->Element = RidArray;
3551     }
3552     else
3553     {
3554         if (RidArray != NULL)
3555             midl_user_free(RidArray);
3556     }
3557 
3558     RtlReleaseResource(&SampResource);
3559 
3560     return Status;
3561 }
3562 
3563 
3564 /* Function 17 */
3565 NTSTATUS
3566 NTAPI
3567 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3568                         IN ULONG Count,
3569                         IN RPC_UNICODE_STRING Names[],
3570                         OUT PSAMPR_ULONG_ARRAY RelativeIds,
3571                         OUT PSAMPR_ULONG_ARRAY Use)
3572 {
3573     PSAM_DB_OBJECT DomainObject;
3574     HANDLE AccountsKeyHandle = NULL;
3575     HANDLE NamesKeyHandle = NULL;
3576     ULONG MappedCount = 0;
3577     ULONG DataLength;
3578     ULONG i;
3579     ULONG RelativeId;
3580     NTSTATUS Status;
3581 
3582     TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3583           DomainHandle, Count, Names, RelativeIds, Use);
3584 
3585     RtlAcquireResourceShared(&SampResource,
3586                              TRUE);
3587 
3588     /* Validate the domain handle */
3589     Status = SampValidateDbObject(DomainHandle,
3590                                   SamDbDomainObject,
3591                                   DOMAIN_LOOKUP,
3592                                   &DomainObject);
3593     if (!NT_SUCCESS(Status))
3594     {
3595         TRACE("failed with status 0x%08lx\n", Status);
3596         goto done;
3597     }
3598 
3599     RelativeIds->Count = 0;
3600     Use->Count = 0;
3601 
3602     if (Count == 0)
3603     {
3604         Status = STATUS_SUCCESS;
3605         goto done;
3606     }
3607 
3608     /* Allocate the relative IDs array */
3609     RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3610     if (RelativeIds->Element == NULL)
3611     {
3612         Status = STATUS_INSUFFICIENT_RESOURCES;
3613         goto done;
3614     }
3615 
3616     /* Allocate the use array */
3617     Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3618     if (Use->Element == NULL)
3619     {
3620         Status = STATUS_INSUFFICIENT_RESOURCES;
3621         goto done;
3622     }
3623 
3624     RelativeIds->Count = Count;
3625     Use->Count = Count;
3626 
3627     for (i = 0; i < Count; i++)
3628     {
3629         TRACE("Name: %S\n", Names[i].Buffer);
3630 
3631         RelativeId = 0;
3632 
3633         /* Lookup aliases */
3634         Status = SampRegOpenKey(DomainObject->KeyHandle,
3635                                 L"Aliases",
3636                                 KEY_READ,
3637                                 &AccountsKeyHandle);
3638         if (NT_SUCCESS(Status))
3639         {
3640             Status = SampRegOpenKey(AccountsKeyHandle,
3641                                     L"Names",
3642                                     KEY_READ,
3643                                     &NamesKeyHandle);
3644             if (NT_SUCCESS(Status))
3645             {
3646                 DataLength = sizeof(ULONG);
3647                 Status = SampRegQueryValue(NamesKeyHandle,
3648                                            Names[i].Buffer,
3649                                            NULL,
3650                                            &RelativeId,
3651                                            &DataLength);
3652 
3653                 SampRegCloseKey(&NamesKeyHandle);
3654             }
3655 
3656             SampRegCloseKey(&AccountsKeyHandle);
3657         }
3658 
3659         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3660             break;
3661 
3662         /* Return alias account */
3663         if (NT_SUCCESS(Status) && RelativeId != 0)
3664         {
3665             TRACE("Rid: %lu\n", RelativeId);
3666             RelativeIds->Element[i] = RelativeId;
3667             Use->Element[i] = SidTypeAlias;
3668             MappedCount++;
3669             continue;
3670         }
3671 
3672         /* Lookup groups */
3673         Status = SampRegOpenKey(DomainObject->KeyHandle,
3674                                 L"Groups",
3675                                 KEY_READ,
3676                                 &AccountsKeyHandle);
3677         if (NT_SUCCESS(Status))
3678         {
3679             Status = SampRegOpenKey(AccountsKeyHandle,
3680                                     L"Names",
3681                                     KEY_READ,
3682                                     &NamesKeyHandle);
3683             if (NT_SUCCESS(Status))
3684             {
3685                 DataLength = sizeof(ULONG);
3686                 Status = SampRegQueryValue(NamesKeyHandle,
3687                                            Names[i].Buffer,
3688                                            NULL,
3689                                            &RelativeId,
3690                                            &DataLength);
3691 
3692                 SampRegCloseKey(&NamesKeyHandle);
3693             }
3694 
3695             SampRegCloseKey(&AccountsKeyHandle);
3696         }
3697 
3698         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3699             break;
3700 
3701         /* Return group account */
3702         if (NT_SUCCESS(Status) && RelativeId != 0)
3703         {
3704             TRACE("Rid: %lu\n", RelativeId);
3705             RelativeIds->Element[i] = RelativeId;
3706             Use->Element[i] = SidTypeGroup;
3707             MappedCount++;
3708             continue;
3709         }
3710 
3711         /* Lookup users */
3712         Status = SampRegOpenKey(DomainObject->KeyHandle,
3713                                 L"Users",
3714                                 KEY_READ,
3715                                 &AccountsKeyHandle);
3716         if (NT_SUCCESS(Status))
3717         {
3718             Status = SampRegOpenKey(AccountsKeyHandle,
3719                                     L"Names",
3720                                     KEY_READ,
3721                                     &NamesKeyHandle);
3722             if (NT_SUCCESS(Status))
3723             {
3724                 DataLength = sizeof(ULONG);
3725                 Status = SampRegQueryValue(NamesKeyHandle,
3726                                            Names[i].Buffer,
3727                                            NULL,
3728                                            &RelativeId,
3729                                            &DataLength);
3730 
3731                 SampRegCloseKey(&NamesKeyHandle);
3732             }
3733 
3734             SampRegCloseKey(&AccountsKeyHandle);
3735         }
3736 
3737         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3738             break;
3739 
3740         /* Return user account */
3741         if (NT_SUCCESS(Status) && RelativeId != 0)
3742         {
3743             TRACE("Rid: %lu\n", RelativeId);
3744             RelativeIds->Element[i] = RelativeId;
3745             Use->Element[i] = SidTypeUser;
3746             MappedCount++;
3747             continue;
3748         }
3749 
3750         /* Return unknown account */
3751         RelativeIds->Element[i] = 0;
3752         Use->Element[i] = SidTypeUnknown;
3753     }
3754 
3755 done:
3756     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3757         Status = STATUS_SUCCESS;
3758 
3759     if (NT_SUCCESS(Status))
3760     {
3761         if (MappedCount == 0)
3762             Status = STATUS_NONE_MAPPED;
3763         else if (MappedCount < Count)
3764             Status = STATUS_SOME_NOT_MAPPED;
3765     }
3766     else
3767     {
3768         if (RelativeIds->Element != NULL)
3769         {
3770             midl_user_free(RelativeIds->Element);
3771             RelativeIds->Element = NULL;
3772         }
3773 
3774         RelativeIds->Count = 0;
3775 
3776         if (Use->Element != NULL)
3777         {
3778             midl_user_free(Use->Element);
3779             Use->Element = NULL;
3780         }
3781 
3782         Use->Count = 0;
3783     }
3784 
3785     RtlReleaseResource(&SampResource);
3786 
3787     TRACE("Returned Status %lx\n", Status);
3788 
3789     return Status;
3790 }
3791 
3792 
3793 /* Function 18 */
3794 NTSTATUS
3795 NTAPI
3796 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3797                       IN ULONG Count,
3798                       IN ULONG *RelativeIds,
3799                       OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3800                       OUT PSAMPR_ULONG_ARRAY Use)
3801 {
3802     PSAM_DB_OBJECT DomainObject;
3803     WCHAR RidString[9];
3804     HANDLE AccountsKeyHandle = NULL;
3805     HANDLE AccountKeyHandle = NULL;
3806     ULONG MappedCount = 0;
3807     ULONG DataLength;
3808     ULONG i;
3809     NTSTATUS Status;
3810 
3811     TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3812           DomainHandle, Count, RelativeIds, Names, Use);
3813 
3814     RtlAcquireResourceShared(&SampResource,
3815                              TRUE);
3816 
3817     /* Validate the domain handle */
3818     Status = SampValidateDbObject(DomainHandle,
3819                                   SamDbDomainObject,
3820                                   DOMAIN_LOOKUP,
3821                                   &DomainObject);
3822     if (!NT_SUCCESS(Status))
3823     {
3824         TRACE("failed with status 0x%08lx\n", Status);
3825         goto done;
3826     }
3827 
3828     Names->Count = 0;
3829     Use->Count = 0;
3830 
3831     if (Count == 0)
3832     {
3833         Status = STATUS_SUCCESS;
3834         goto done;
3835     }
3836 
3837     /* Allocate the names array */
3838     Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
3839     if (Names->Element == NULL)
3840     {
3841         Status = STATUS_INSUFFICIENT_RESOURCES;
3842         goto done;
3843     }
3844 
3845     /* Allocate the use array */
3846     Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
3847     if (Use->Element == NULL)
3848     {
3849         Status = STATUS_INSUFFICIENT_RESOURCES;
3850         goto done;
3851     }
3852 
3853     Names->Count = Count;
3854     Use->Count = Count;
3855 
3856     for (i = 0; i < Count; i++)
3857     {
3858         TRACE("RID: %lu\n", RelativeIds[i]);
3859 
3860         swprintf(RidString, L"%08lx", RelativeIds[i]);
3861 
3862         /* Lookup aliases */
3863         Status = SampRegOpenKey(DomainObject->KeyHandle,
3864                                 L"Aliases",
3865                                 KEY_READ,
3866                                 &AccountsKeyHandle);
3867         if (NT_SUCCESS(Status))
3868         {
3869             Status = SampRegOpenKey(AccountsKeyHandle,
3870                                     RidString,
3871                                     KEY_READ,
3872                                     &AccountKeyHandle);
3873             if (NT_SUCCESS(Status))
3874             {
3875                 DataLength = 0;
3876                 Status = SampRegQueryValue(AccountKeyHandle,
3877                                            L"Name",
3878                                            NULL,
3879                                            NULL,
3880                                            &DataLength);
3881                 if (NT_SUCCESS(Status))
3882                 {
3883                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3884                     if (Names->Element[i].Buffer == NULL)
3885                         Status = STATUS_INSUFFICIENT_RESOURCES;
3886 
3887                     if (NT_SUCCESS(Status))
3888                     {
3889                         Names->Element[i].MaximumLength = (USHORT)DataLength;
3890                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3891 
3892                         Status = SampRegQueryValue(AccountKeyHandle,
3893                                                    L"Name",
3894                                                    NULL,
3895                                                    Names->Element[i].Buffer,
3896                                                    &DataLength);
3897                     }
3898                 }
3899 
3900                 SampRegCloseKey(&AccountKeyHandle);
3901             }
3902 
3903             SampRegCloseKey(&AccountsKeyHandle);
3904         }
3905 
3906         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3907             break;
3908 
3909         /* Return alias account */
3910         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3911         {
3912             TRACE("Name: %S\n", Names->Element[i].Buffer);
3913             Use->Element[i] = SidTypeAlias;
3914             MappedCount++;
3915             continue;
3916         }
3917 
3918         /* Lookup groups */
3919         Status = SampRegOpenKey(DomainObject->KeyHandle,
3920                                 L"Groups",
3921                                 KEY_READ,
3922                                 &AccountsKeyHandle);
3923         if (NT_SUCCESS(Status))
3924         {
3925             Status = SampRegOpenKey(AccountsKeyHandle,
3926                                     RidString,
3927                                     KEY_READ,
3928                                     &AccountKeyHandle);
3929             if (NT_SUCCESS(Status))
3930             {
3931                 DataLength = 0;
3932                 Status = SampRegQueryValue(AccountKeyHandle,
3933                                            L"Name",
3934                                            NULL,
3935                                            NULL,
3936                                            &DataLength);
3937                 if (NT_SUCCESS(Status))
3938                 {
3939                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3940                     if (Names->Element[i].Buffer == NULL)
3941                         Status = STATUS_INSUFFICIENT_RESOURCES;
3942 
3943                     if (NT_SUCCESS(Status))
3944                     {
3945                         Names->Element[i].MaximumLength = (USHORT)DataLength;
3946                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3947 
3948                         Status = SampRegQueryValue(AccountKeyHandle,
3949                                                    L"Name",
3950                                                    NULL,
3951                                                    Names->Element[i].Buffer,
3952                                                    &DataLength);
3953                     }
3954                 }
3955 
3956                 SampRegCloseKey(&AccountKeyHandle);
3957             }
3958 
3959             SampRegCloseKey(&AccountsKeyHandle);
3960         }
3961 
3962         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3963             break;
3964 
3965         /* Return group account */
3966         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3967         {
3968             TRACE("Name: %S\n", Names->Element[i].Buffer);
3969             Use->Element[i] = SidTypeGroup;
3970             MappedCount++;
3971             continue;
3972         }
3973 
3974         /* Lookup users */
3975         Status = SampRegOpenKey(DomainObject->KeyHandle,
3976                                 L"Users",
3977                                 KEY_READ,
3978                                 &AccountsKeyHandle);
3979         if (NT_SUCCESS(Status))
3980         {
3981             Status = SampRegOpenKey(AccountsKeyHandle,
3982                                     RidString,
3983                                     KEY_READ,
3984                                     &AccountKeyHandle);
3985             if (NT_SUCCESS(Status))
3986             {
3987                 DataLength = 0;
3988                 Status = SampRegQueryValue(AccountKeyHandle,
3989                                            L"Name",
3990                                            NULL,
3991                                            NULL,
3992                                            &DataLength);
3993                 if (NT_SUCCESS(Status))
3994                 {
3995                     TRACE("DataLength: %lu\n", DataLength);
3996 
3997                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3998                     if (Names->Element[i].Buffer == NULL)
3999                         Status = STATUS_INSUFFICIENT_RESOURCES;
4000 
4001                     if (NT_SUCCESS(Status))
4002                     {
4003                         Names->Element[i].MaximumLength = (USHORT)DataLength;
4004                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
4005 
4006                         Status = SampRegQueryValue(AccountKeyHandle,
4007                                                    L"Name",
4008                                                    NULL,
4009                                                    Names->Element[i].Buffer,
4010                                                    &DataLength);
4011                     }
4012                 }
4013 
4014                 SampRegCloseKey(&AccountKeyHandle);
4015             }
4016 
4017             SampRegCloseKey(&AccountsKeyHandle);
4018         }
4019 
4020         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4021             break;
4022 
4023         /* Return user account */
4024         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
4025         {
4026             TRACE("Name: %S\n", Names->Element[i].Buffer);
4027             Use->Element[i] = SidTypeUser;
4028             MappedCount++;
4029             continue;
4030         }
4031 
4032         /* Return unknown account */
4033         Use->Element[i] = SidTypeUnknown;
4034     }
4035 
4036 done:
4037     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4038         Status = STATUS_SUCCESS;
4039 
4040     if (NT_SUCCESS(Status))
4041     {
4042         if (MappedCount == 0)
4043             Status = STATUS_NONE_MAPPED;
4044         else if (MappedCount < Count)
4045             Status = STATUS_SOME_NOT_MAPPED;
4046     }
4047     else
4048     {
4049         if (Names->Element != NULL)
4050         {
4051             for (i = 0; i < Count; i++)
4052             {
4053                 if (Names->Element[i].Buffer != NULL)
4054                     midl_user_free(Names->Element[i].Buffer);
4055             }
4056 
4057             midl_user_free(Names->Element);
4058             Names->Element = NULL;
4059         }
4060 
4061         Names->Count = 0;
4062 
4063         if (Use->Element != NULL)
4064         {
4065             midl_user_free(Use->Element);
4066             Use->Element = NULL;
4067         }
4068 
4069         Use->Count = 0;
4070     }
4071 
4072     RtlReleaseResource(&SampResource);
4073 
4074     return Status;
4075 }
4076 
4077 
4078 /* Function 19 */
4079 NTSTATUS
4080 NTAPI
4081 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
4082               IN ACCESS_MASK DesiredAccess,
4083               IN unsigned long GroupId,
4084               OUT SAMPR_HANDLE *GroupHandle)
4085 {
4086     PSAM_DB_OBJECT DomainObject;
4087     PSAM_DB_OBJECT GroupObject;
4088     WCHAR szRid[9];
4089     NTSTATUS Status;
4090 
4091     TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
4092           DomainHandle, DesiredAccess, GroupId, GroupHandle);
4093 
4094     /* Map generic access rights */
4095     RtlMapGenericMask(&DesiredAccess,
4096                       &GroupMapping);
4097 
4098     RtlAcquireResourceShared(&SampResource,
4099                              TRUE);
4100 
4101     /* Validate the domain handle */
4102     Status = SampValidateDbObject(DomainHandle,
4103                                   SamDbDomainObject,
4104                                   DOMAIN_LOOKUP,
4105                                   &DomainObject);
4106     if (!NT_SUCCESS(Status))
4107     {
4108         TRACE("failed with status 0x%08lx\n", Status);
4109         goto done;
4110     }
4111 
4112     /* Convert the RID into a string (hex) */
4113     swprintf(szRid, L"%08lX", GroupId);
4114 
4115     /* Create the group object */
4116     Status = SampOpenDbObject(DomainObject,
4117                               L"Groups",
4118                               szRid,
4119                               GroupId,
4120                               SamDbGroupObject,
4121                               DesiredAccess,
4122                               &GroupObject);
4123     if (!NT_SUCCESS(Status))
4124     {
4125         TRACE("failed with status 0x%08lx\n", Status);
4126         goto done;
4127     }
4128 
4129     *GroupHandle = (SAMPR_HANDLE)GroupObject;
4130 
4131 done:
4132     RtlReleaseResource(&SampResource);
4133 
4134     return Status;
4135 }
4136 
4137 
4138 static NTSTATUS
4139 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
4140                       PSAMPR_GROUP_INFO_BUFFER *Buffer)
4141 {
4142     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4143     SAM_GROUP_FIXED_DATA FixedData;
4144     ULONG MembersLength = 0;
4145     ULONG Length = 0;
4146     NTSTATUS Status;
4147 
4148     *Buffer = NULL;
4149 
4150     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4151     if (InfoBuffer == NULL)
4152         return STATUS_INSUFFICIENT_RESOURCES;
4153 
4154     Status = SampGetObjectAttributeString(GroupObject,
4155                                           L"Name",
4156                                           &InfoBuffer->General.Name);
4157     if (!NT_SUCCESS(Status))
4158     {
4159         TRACE("Status 0x%08lx\n", Status);
4160         goto done;
4161     }
4162 
4163     Status = SampGetObjectAttributeString(GroupObject,
4164                                           L"AdminComment",
4165                                           &InfoBuffer->General.AdminComment);
4166     if (!NT_SUCCESS(Status))
4167     {
4168         TRACE("Status 0x%08lx\n", Status);
4169         goto done;
4170     }
4171 
4172     Length = sizeof(SAM_GROUP_FIXED_DATA);
4173     Status = SampGetObjectAttribute(GroupObject,
4174                                     L"F",
4175                                     NULL,
4176                                     (PVOID)&FixedData,
4177                                     &Length);
4178     if (!NT_SUCCESS(Status))
4179     {
4180         TRACE("Status 0x%08lx\n", Status);
4181         goto done;
4182     }
4183 
4184     InfoBuffer->General.Attributes = FixedData.Attributes;
4185 
4186     Status = SampGetObjectAttribute(GroupObject,
4187                                     L"Members",
4188                                     NULL,
4189                                     NULL,
4190                                     &MembersLength);
4191     if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4192     {
4193         TRACE("Status 0x%08lx\n", Status);
4194         goto done;
4195     }
4196 
4197     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4198     {
4199         InfoBuffer->General.MemberCount = 0;
4200         Status = STATUS_SUCCESS;
4201     }
4202     else
4203     {
4204         InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4205     }
4206 
4207     *Buffer = InfoBuffer;
4208 
4209 done:
4210     if (!NT_SUCCESS(Status))
4211     {
4212         if (InfoBuffer != NULL)
4213         {
4214             if (InfoBuffer->General.Name.Buffer != NULL)
4215                 midl_user_free(InfoBuffer->General.Name.Buffer);
4216 
4217             if (InfoBuffer->General.AdminComment.Buffer != NULL)
4218                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4219 
4220             midl_user_free(InfoBuffer);
4221         }
4222     }
4223 
4224     return Status;
4225 }
4226 
4227 
4228 static NTSTATUS
4229 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
4230                    PSAMPR_GROUP_INFO_BUFFER *Buffer)
4231 {
4232     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4233     NTSTATUS Status;
4234 
4235     *Buffer = NULL;
4236 
4237     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4238     if (InfoBuffer == NULL)
4239         return STATUS_INSUFFICIENT_RESOURCES;
4240 
4241     Status = SampGetObjectAttributeString(GroupObject,
4242                                           L"Name",
4243                                           &InfoBuffer->Name.Name);
4244     if (!NT_SUCCESS(Status))
4245     {
4246         TRACE("Status 0x%08lx\n", Status);
4247         goto done;
4248     }
4249 
4250     *Buffer = InfoBuffer;
4251 
4252 done:
4253     if (!NT_SUCCESS(Status))
4254     {
4255         if (InfoBuffer != NULL)
4256         {
4257             if (InfoBuffer->Name.Name.Buffer != NULL)
4258                 midl_user_free(InfoBuffer->Name.Name.Buffer);
4259 
4260             midl_user_free(InfoBuffer);
4261         }
4262     }
4263 
4264     return Status;
4265 }
4266 
4267 
4268 static NTSTATUS
4269 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
4270                         PSAMPR_GROUP_INFO_BUFFER *Buffer)
4271 {
4272     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4273     SAM_GROUP_FIXED_DATA FixedData;
4274     ULONG Length = 0;
4275     NTSTATUS Status;
4276 
4277     *Buffer = NULL;
4278 
4279     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4280     if (InfoBuffer == NULL)
4281         return STATUS_INSUFFICIENT_RESOURCES;
4282 
4283     Length = sizeof(SAM_GROUP_FIXED_DATA);
4284     Status = SampGetObjectAttribute(GroupObject,
4285                                     L"F",
4286                                     NULL,
4287                                     (PVOID)&FixedData,
4288                                     &Length);
4289     if (!NT_SUCCESS(Status))
4290     {
4291         TRACE("Status 0x%08lx\n", Status);
4292         goto done;
4293     }
4294 
4295     InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4296 
4297     *Buffer = InfoBuffer;
4298 
4299 done:
4300     if (!NT_SUCCESS(Status))
4301     {
4302         if (InfoBuffer != NULL)
4303         {
4304             midl_user_free(InfoBuffer);
4305         }
4306     }
4307 
4308     return Status;
4309 }
4310 
4311 
4312 static NTSTATUS
4313 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
4314                            PSAMPR_GROUP_INFO_BUFFER *Buffer)
4315 {
4316     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4317     NTSTATUS Status;
4318 
4319     *Buffer = NULL;
4320 
4321     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4322     if (InfoBuffer == NULL)
4323         return STATUS_INSUFFICIENT_RESOURCES;
4324 
4325     Status = SampGetObjectAttributeString(GroupObject,
4326                                           L"AdminComment",
4327                                           &InfoBuffer->AdminComment.AdminComment);
4328     if (!NT_SUCCESS(Status))
4329     {
4330         TRACE("Status 0x%08lx\n", Status);
4331         goto done;
4332     }
4333 
4334     *Buffer = InfoBuffer;
4335 
4336 done:
4337     if (!NT_SUCCESS(Status))
4338     {
4339         if (InfoBuffer != NULL)
4340         {
4341             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4342                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4343 
4344             midl_user_free(InfoBuffer);
4345         }
4346     }
4347 
4348     return Status;
4349 }
4350 
4351 
4352 /* Function 20 */
4353 NTSTATUS
4354 NTAPI
4355 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
4356                           IN GROUP_INFORMATION_CLASS GroupInformationClass,
4357                           OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
4358 {
4359     PSAM_DB_OBJECT GroupObject;
4360     NTSTATUS Status;
4361 
4362     TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4363           GroupHandle, GroupInformationClass, Buffer);
4364 
4365     RtlAcquireResourceShared(&SampResource,
4366                              TRUE);
4367 
4368     /* Validate the group handle */
4369     Status = SampValidateDbObject(GroupHandle,
4370                                   SamDbGroupObject,
4371                                   GROUP_READ_INFORMATION,
4372                                   &GroupObject);
4373     if (!NT_SUCCESS(Status))
4374         goto done;
4375 
4376     switch (GroupInformationClass)
4377     {
4378         case GroupGeneralInformation:
4379             Status = SampQueryGroupGeneral(GroupObject,
4380                                            Buffer);
4381             break;
4382 
4383         case GroupNameInformation:
4384             Status = SampQueryGroupName(GroupObject,
4385                                         Buffer);
4386             break;
4387 
4388         case GroupAttributeInformation:
4389             Status = SampQueryGroupAttribute(GroupObject,
4390                                              Buffer);
4391             break;
4392 
4393         case GroupAdminCommentInformation:
4394             Status = SampQueryGroupAdminComment(GroupObject,
4395                                                 Buffer);
4396             break;
4397 
4398         default:
4399             Status = STATUS_INVALID_INFO_CLASS;
4400             break;
4401     }
4402 
4403 done:
4404     RtlReleaseResource(&SampResource);
4405 
4406     return Status;
4407 }
4408 
4409 
4410 static NTSTATUS
4411 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
4412                  PSAMPR_GROUP_INFO_BUFFER Buffer)
4413 {
4414     UNICODE_STRING OldGroupName = {0, 0, NULL};
4415     UNICODE_STRING NewGroupName;
4416     NTSTATUS Status;
4417 
4418     Status = SampGetObjectAttributeString(GroupObject,
4419                                           L"Name",
4420                                           (PRPC_UNICODE_STRING)&OldGroupName);
4421     if (!NT_SUCCESS(Status))
4422     {
4423         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4424         goto done;
4425     }
4426 
4427     /* Check the new account name */
4428     Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4429     if (!NT_SUCCESS(Status))
4430     {
4431         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4432         return Status;
4433     }
4434 
4435     NewGroupName.Length = Buffer->Name.Name.Length;
4436     NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4437     NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4438 
4439     if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4440     {
4441         Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
4442                                               NewGroupName.Buffer);
4443         if (!NT_SUCCESS(Status))
4444         {
4445             TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4446                   NewGroupName.Buffer, Status);
4447             goto done;
4448         }
4449     }
4450 
4451     Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
4452                                         L"Groups",
4453                                         NewGroupName.Buffer,
4454                                         GroupObject->RelativeId);
4455     if (!NT_SUCCESS(Status))
4456     {
4457         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4458         goto done;
4459     }
4460 
4461     Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4462                                              L"Groups",
4463                                              OldGroupName.Buffer);
4464     if (!NT_SUCCESS(Status))
4465     {
4466         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4467         goto done;
4468     }
4469 
4470     Status = SampSetObjectAttributeString(GroupObject,
4471                                           L"Name",
4472                                           (PRPC_UNICODE_STRING)&NewGroupName);
4473     if (!NT_SUCCESS(Status))
4474     {
4475         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4476     }
4477 
4478 done:
4479     if (OldGroupName.Buffer != NULL)
4480         midl_user_free(OldGroupName.Buffer);
4481 
4482     return Status;
4483 }
4484 
4485 
4486 static NTSTATUS
4487 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4488                       PSAMPR_GROUP_INFO_BUFFER Buffer)
4489 {
4490     SAM_GROUP_FIXED_DATA FixedData;
4491     ULONG Length = 0;
4492     NTSTATUS Status;
4493 
4494     Length = sizeof(SAM_GROUP_FIXED_DATA);
4495     Status = SampGetObjectAttribute(GroupObject,
4496                                     L"F",
4497                                     NULL,
4498                                     (PVOID)&FixedData,
4499                                     &Length);
4500     if (!NT_SUCCESS(Status))
4501         goto done;
4502 
4503     FixedData.Attributes = Buffer->Attribute.Attributes;
4504 
4505     Status = SampSetObjectAttribute(GroupObject,
4506                                     L"F",
4507                                     REG_BINARY,
4508                                     &FixedData,
4509                                     Length);
4510 
4511 done:
4512     return Status;
4513 }
4514 
4515 
4516 /* Function 21 */
4517 NTSTATUS
4518 NTAPI
4519 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4520                         IN GROUP_INFORMATION_CLASS GroupInformationClass,
4521                         IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4522 {
4523     PSAM_DB_OBJECT GroupObject;
4524     NTSTATUS Status;
4525 
4526     TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4527           GroupHandle, GroupInformationClass, Buffer);
4528 
4529     RtlAcquireResourceExclusive(&SampResource,
4530                                 TRUE);
4531 
4532     /* Validate the group handle */
4533     Status = SampValidateDbObject(GroupHandle,
4534                                   SamDbGroupObject,
4535                                   GROUP_WRITE_ACCOUNT,
4536                                   &GroupObject);
4537     if (!NT_SUCCESS(Status))
4538         goto done;
4539 
4540     switch (GroupInformationClass)
4541     {
4542         case GroupNameInformation:
4543             Status = SampSetGroupName(GroupObject,
4544                                       Buffer);
4545             break;
4546 
4547         case GroupAttributeInformation:
4548             Status = SampSetGroupAttribute(GroupObject,
4549                                            Buffer);
4550             break;
4551 
4552         case GroupAdminCommentInformation:
4553             Status = SampSetObjectAttributeString(GroupObject,
4554                                                   L"AdminComment",
4555                                                   &Buffer->AdminComment.AdminComment);
4556             break;
4557 
4558         default:
4559             Status = STATUS_INVALID_INFO_CLASS;
4560             break;
4561     }
4562 
4563 done:
4564     RtlReleaseResource(&SampResource);
4565 
4566     return Status;
4567 }
4568 
4569 
4570 /* Function 22 */
4571 NTSTATUS
4572 NTAPI
4573 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4574                      IN unsigned long MemberId,
4575                      IN unsigned long Attributes)
4576 {
4577     PSAM_DB_OBJECT GroupObject;
4578     PSAM_DB_OBJECT UserObject = NULL;
4579     NTSTATUS Status;
4580 
4581     TRACE("SamrAddMemberToGroup(%p %lu %lx)\n",
4582           GroupHandle, MemberId, Attributes);
4583 
4584     RtlAcquireResourceExclusive(&SampResource,
4585                                 TRUE);
4586 
4587     /* Validate the group handle */
4588     Status = SampValidateDbObject(GroupHandle,
4589                                   SamDbGroupObject,
4590                                   GROUP_ADD_MEMBER,
4591                                   &GroupObject);
4592     if (!NT_SUCCESS(Status))
4593         goto done;
4594 
4595     /* Open the user object in the same domain */
4596     Status = SampOpenUserObject(GroupObject->ParentObject,
4597                                 MemberId,
4598                                 0,
4599                                 &UserObject);
4600     if (!NT_SUCCESS(Status))
4601     {
4602         TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4603         goto done;
4604     }
4605 
4606     /* Add group membership to the user object */
4607     Status = SampAddGroupMembershipToUser(UserObject,
4608                                           GroupObject->RelativeId,
4609                                           Attributes);
4610     if (!NT_SUCCESS(Status))
4611     {
4612         TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4613         goto done;
4614     }
4615 
4616     /* Add the member to the group object */
4617     Status = SampAddMemberToGroup(GroupObject,
4618                                   MemberId);
4619     if (!NT_SUCCESS(Status))
4620     {
4621         TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4622     }
4623 
4624 done:
4625     if (UserObject)
4626         SampCloseDbObject(UserObject);
4627 
4628     RtlReleaseResource(&SampResource);
4629 
4630     return Status;
4631 }
4632 
4633 
4634 /* Function 23 */
4635 NTSTATUS
4636 NTAPI
4637 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4638 {
4639     PSAM_DB_OBJECT GroupObject;
4640     ULONG Length = 0;
4641     NTSTATUS Status;
4642 
4643     TRACE("SamrDeleteGroup(%p)\n", GroupHandle);
4644 
4645     RtlAcquireResourceExclusive(&SampResource,
4646                                 TRUE);
4647 
4648     /* Validate the group handle */
4649     Status = SampValidateDbObject(*GroupHandle,
4650                                   SamDbGroupObject,
4651                                   DELETE,
4652                                   &GroupObject);
4653     if (!NT_SUCCESS(Status))
4654     {
4655         TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4656         goto done;
4657     }
4658 
4659     /* Fail, if the group is built-in */
4660     if (GroupObject->RelativeId < 1000)
4661     {
4662         TRACE("You can not delete a special account!\n");
4663         Status = STATUS_SPECIAL_ACCOUNT;
4664         goto done;
4665     }
4666 
4667     /* Get the length of the Members attribute */
4668     SampGetObjectAttribute(GroupObject,
4669                            L"Members",
4670                            NULL,
4671                            NULL,
4672                            &Length);
4673 
4674     /* Fail, if the group has members */
4675     if (Length != 0)
4676     {
4677         TRACE("There are still members in the group!\n");
4678         Status = STATUS_MEMBER_IN_GROUP;
4679         goto done;
4680     }
4681 
4682     /* FIXME: Remove the group from all aliases */
4683 
4684     /* Delete the group from the database */
4685     Status = SampDeleteAccountDbObject(GroupObject);
4686     if (!NT_SUCCESS(Status))
4687     {
4688         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4689         goto done;
4690     }
4691 
4692     /* Invalidate the handle */
4693     *GroupHandle = NULL;
4694 
4695 done:
4696     RtlReleaseResource(&SampResource);
4697 
4698     return Status;
4699 }
4700 
4701 
4702 /* Function 24 */
4703 NTSTATUS
4704 NTAPI
4705 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4706                           IN unsigned long MemberId)
4707 {
4708     PSAM_DB_OBJECT GroupObject;
4709     PSAM_DB_OBJECT UserObject = NULL;
4710     NTSTATUS Status;
4711 
4712     TRACE("SamrRemoveMemberFromGroup(%p %lu)\n",
4713           GroupHandle, MemberId);
4714 
4715     RtlAcquireResourceExclusive(&SampResource,
4716                                 TRUE);
4717 
4718     /* Validate the group handle */
4719     Status = SampValidateDbObject(GroupHandle,
4720                                   SamDbGroupObject,
4721                                   GROUP_REMOVE_MEMBER,
4722                                   &GroupObject);
4723     if (!NT_SUCCESS(Status))
4724         goto done;
4725 
4726     /* Open the user object in the same domain */
4727     Status = SampOpenUserObject(GroupObject->ParentObject,
4728                                 MemberId,
4729                                 0,
4730                                 &UserObject);
4731     if (!NT_SUCCESS(Status))
4732     {
4733         ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4734         goto done;
4735     }
4736 
4737     /* Remove group membership from the user object */
4738     Status = SampRemoveGroupMembershipFromUser(UserObject,
4739                                                GroupObject->RelativeId);
4740     if (!NT_SUCCESS(Status))
4741     {
4742         ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4743         goto done;
4744     }
4745 
4746     /* Remove the member from the group object */
4747     Status = SampRemoveMemberFromGroup(GroupObject,
4748                                        MemberId);
4749     if (!NT_SUCCESS(Status))
4750     {
4751         ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4752     }
4753 
4754 done:
4755     if (UserObject)
4756         SampCloseDbObject(UserObject);
4757 
4758     RtlReleaseResource(&SampResource);
4759 
4760     return Status;
4761 }
4762 
4763 
4764 /* Function 25 */
4765 NTSTATUS
4766 NTAPI
4767 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4768                       OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4769 {
4770     PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4771     PSAM_DB_OBJECT GroupObject;
4772     ULONG Length = 0;
4773     ULONG i;
4774     NTSTATUS Status;
4775 
4776     TRACE("SamrGetMembersInGroup(%p %p)\n",
4777           GroupHandle, Members);
4778 
4779     RtlAcquireResourceShared(&SampResource,
4780                              TRUE);
4781 
4782     /* Validate the group handle */
4783     Status = SampValidateDbObject(GroupHandle,
4784                                   SamDbGroupObject,
4785                                   GROUP_LIST_MEMBERS,
4786                                   &GroupObject);
4787     if (!NT_SUCCESS(Status))
4788         goto done;
4789 
4790     MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4791     if (MembersBuffer == NULL)
4792     {
4793         Status = STATUS_INSUFFICIENT_RESOURCES;
4794         goto done;
4795     }
4796 
4797     SampGetObjectAttribute(GroupObject,
4798                            L"Members",
4799                            NULL,
4800                            NULL,
4801                            &Length);
4802 
4803     if (Length == 0)
4804     {
4805         MembersBuffer->MemberCount = 0;
4806         MembersBuffer->Members = NULL;
4807         MembersBuffer->Attributes = NULL;
4808 
4809         *Members = MembersBuffer;
4810 
4811         Status = STATUS_SUCCESS;
4812         goto done;
4813     }
4814 
4815     MembersBuffer->Members = midl_user_allocate(Length);
4816     if (MembersBuffer->Members == NULL)
4817     {
4818         Status = STATUS_INSUFFICIENT_RESOURCES;
4819         goto done;
4820     }
4821 
4822     MembersBuffer->Attributes = midl_user_allocate(Length);
4823     if (MembersBuffer->Attributes == NULL)
4824     {
4825         Status = STATUS_INSUFFICIENT_RESOURCES;
4826         goto done;
4827     }
4828 
4829     Status = SampGetObjectAttribute(GroupObject,
4830                                     L"Members",
4831                                     NULL,
4832                                     MembersBuffer->Members,
4833                                     &Length);
4834     if (!NT_SUCCESS(Status))
4835     {
4836         TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4837         goto done;
4838     }
4839 
4840     MembersBuffer->MemberCount = Length / sizeof(ULONG);
4841 
4842     for (i = 0; i < MembersBuffer->MemberCount; i++)
4843     {
4844         Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4845                                             MembersBuffer->Members[i],
4846                                             GroupObject->RelativeId,
4847                                             &(MembersBuffer->Attributes[i]));
4848         if (!NT_SUCCESS(Status))
4849         {
4850             TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4851             goto done;
4852         }
4853     }
4854 
4855     *Members = MembersBuffer;
4856 
4857 done:
4858     if (!NT_SUCCESS(Status))
4859     {
4860         if (MembersBuffer != NULL)
4861         {
4862             if (MembersBuffer->Members != NULL)
4863                 midl_user_free(MembersBuffer->Members);
4864 
4865             if (MembersBuffer->Attributes != NULL)
4866                 midl_user_free(MembersBuffer->Attributes);
4867 
4868             midl_user_free(MembersBuffer);
4869         }
4870     }
4871 
4872     RtlReleaseResource(&SampResource);
4873 
4874     return Status;
4875 }
4876 
4877 
4878 /* Function 26 */
4879 NTSTATUS
4880 NTAPI
4881 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4882                                IN unsigned long MemberId,
4883                                IN unsigned long Attributes)
4884 {
4885     PSAM_DB_OBJECT GroupObject;
4886     NTSTATUS Status;
4887 
4888     TRACE("SamrSetMemberAttributesOfGroup(%p %lu %lx)\n",
4889           GroupHandle, MemberId, Attributes);
4890 
4891     RtlAcquireResourceExclusive(&SampResource,
4892                                 TRUE);
4893 
4894     /* Validate the group handle */
4895     Status = SampValidateDbObject(GroupHandle,
4896                                   SamDbGroupObject,
4897                                   GROUP_ADD_MEMBER,
4898                                   &GroupObject);
4899     if (!NT_SUCCESS(Status))
4900     {
4901         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4902         goto done;
4903     }
4904 
4905     Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4906                                         MemberId,
4907                                         GroupObject->RelativeId,
4908                                         Attributes);
4909     if (!NT_SUCCESS(Status))
4910     {
4911         TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4912     }
4913 
4914 done:
4915     RtlReleaseResource(&SampResource);
4916 
4917     return Status;
4918 }
4919 
4920 
4921 /* Function 27 */
4922 NTSTATUS
4923 NTAPI
4924 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4925               IN ACCESS_MASK DesiredAccess,
4926               IN ULONG AliasId,
4927               OUT SAMPR_HANDLE *AliasHandle)
4928 {
4929     PSAM_DB_OBJECT DomainObject;
4930     PSAM_DB_OBJECT AliasObject;
4931     WCHAR szRid[9];
4932     NTSTATUS Status;
4933 
4934     TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4935           DomainHandle, DesiredAccess, AliasId, AliasHandle);
4936 
4937     /* Map generic access rights */
4938     RtlMapGenericMask(&DesiredAccess,
4939                       &AliasMapping);
4940 
4941     RtlAcquireResourceShared(&SampResource,
4942                              TRUE);
4943 
4944     /* Validate the domain handle */
4945     Status = SampValidateDbObject(DomainHandle,
4946                                   SamDbDomainObject,
4947                                   DOMAIN_LOOKUP,
4948                                   &DomainObject);
4949     if (!NT_SUCCESS(Status))
4950     {
4951         TRACE("failed with status 0x%08lx\n", Status);
4952         goto done;
4953     }
4954 
4955     /* Convert the RID into a string (hex) */
4956     swprintf(szRid, L"%08lX", AliasId);
4957 
4958     /* Create the alias object */
4959     Status = SampOpenDbObject(DomainObject,
4960                               L"Aliases",
4961                               szRid,
4962                               AliasId,
4963                               SamDbAliasObject,
4964                               DesiredAccess,
4965                               &AliasObject);
4966     if (!NT_SUCCESS(Status))
4967     {
4968         TRACE("failed with status 0x%08lx\n", Status);
4969         goto done;
4970     }
4971 
4972     *AliasHandle = (SAMPR_HANDLE)AliasObject;
4973 
4974 done:
4975     RtlReleaseResource(&SampResource);
4976 
4977     return Status;
4978 }
4979 
4980 
4981 static NTSTATUS
4982 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4983                       PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4984 {
4985     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4986     HANDLE MembersKeyHandle = NULL;
4987     NTSTATUS Status;
4988 
4989     *Buffer = NULL;
4990 
4991     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4992     if (InfoBuffer == NULL)
4993         return STATUS_INSUFFICIENT_RESOURCES;
4994 
4995     Status = SampGetObjectAttributeString(AliasObject,
4996                                           L"Name",
4997                                           &InfoBuffer->General.Name);
4998     if (!NT_SUCCESS(Status))
4999     {
5000         TRACE("Status 0x%08lx\n", Status);
5001         goto done;
5002     }
5003 
5004     Status = SampGetObjectAttributeString(AliasObject,
5005                                           L"Description",
5006                                           &InfoBuffer->General.AdminComment);
5007     if (!NT_SUCCESS(Status))
5008     {
5009         TRACE("Status 0x%08lx\n", Status);
5010         goto done;
5011     }
5012 
5013     /* Open the Members subkey */
5014     Status = SampRegOpenKey(AliasObject->KeyHandle,
5015                             L"Members",
5016                             KEY_READ,
5017                             &MembersKeyHandle);
5018     if (NT_SUCCESS(Status))
5019     {
5020         /* Retrieve the number of members of the alias */
5021         Status = SampRegQueryKeyInfo(MembersKeyHandle,
5022                                      NULL,
5023                                      &InfoBuffer->General.MemberCount);
5024         if (!NT_SUCCESS(Status))
5025         {
5026             TRACE("Status 0x%08lx\n", Status);
5027             goto done;
5028         }
5029     }
5030     else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
5031     {
5032         InfoBuffer->General.MemberCount = 0;
5033         Status = STATUS_SUCCESS;
5034     }
5035     else
5036     {
5037         TRACE("Status 0x%08lx\n", Status);
5038         goto done;
5039     }
5040 
5041     *Buffer = InfoBuffer;
5042 
5043 done:
5044     SampRegCloseKey(&MembersKeyHandle);
5045 
5046     if (!NT_SUCCESS(Status))
5047     {
5048         if (InfoBuffer != NULL)
5049         {
5050             if (InfoBuffer->General.Name.Buffer != NULL)
5051                 midl_user_free(InfoBuffer->General.Name.Buffer);
5052 
5053             if (InfoBuffer->General.AdminComment.Buffer != NULL)
5054                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5055 
5056             midl_user_free(InfoBuffer);
5057         }
5058     }
5059 
5060     return Status;
5061 }
5062 
5063 
5064 static NTSTATUS
5065 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
5066                    PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5067 {
5068     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5069     NTSTATUS Status;
5070 
5071     *Buffer = NULL;
5072 
5073     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5074     if (InfoBuffer == NULL)
5075         return STATUS_INSUFFICIENT_RESOURCES;
5076 
5077     Status = SampGetObjectAttributeString(AliasObject,
5078                                           L"Name",
5079                                           &InfoBuffer->Name.Name);
5080     if (!NT_SUCCESS(Status))
5081     {
5082         TRACE("Status 0x%08lx\n", Status);
5083         goto done;
5084     }
5085 
5086     *Buffer = InfoBuffer;
5087 
5088 done:
5089     if (!NT_SUCCESS(Status))
5090     {
5091         if (InfoBuffer != NULL)
5092         {
5093             if (InfoBuffer->Name.Name.Buffer != NULL)
5094                 midl_user_free(InfoBuffer->Name.Name.Buffer);
5095 
5096             midl_user_free(InfoBuffer);
5097         }
5098     }
5099 
5100     return Status;
5101 }
5102 
5103 
5104 static NTSTATUS
5105 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
5106                            PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5107 {
5108     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5109     NTSTATUS Status;
5110 
5111     *Buffer = NULL;
5112 
5113     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5114     if (InfoBuffer == NULL)
5115         return STATUS_INSUFFICIENT_RESOURCES;
5116 
5117     Status = SampGetObjectAttributeString(AliasObject,
5118                                           L"Description",
5119                                           &InfoBuffer->AdminComment.AdminComment);
5120     if (!NT_SUCCESS(Status))
5121     {
5122         TRACE("Status 0x%08lx\n", Status);
5123         goto done;
5124     }
5125 
5126     *Buffer = InfoBuffer;
5127 
5128 done:
5129     if (!NT_SUCCESS(Status))
5130     {
5131         if (InfoBuffer != NULL)
5132         {
5133             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
5134                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
5135 
5136             midl_user_free(InfoBuffer);
5137         }
5138     }
5139 
5140     return Status;
5141 }
5142 
5143 
5144 /* Function 28 */
5145 NTSTATUS
5146 NTAPI
5147 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
5148                           IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5149                           OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5150 {
5151     PSAM_DB_OBJECT AliasObject;
5152     NTSTATUS Status;
5153 
5154     TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
5155           AliasHandle, AliasInformationClass, Buffer);
5156 
5157     RtlAcquireResourceShared(&SampResource,
5158                              TRUE);
5159 
5160     /* Validate the alias handle */
5161     Status = SampValidateDbObject(AliasHandle,
5162                                   SamDbAliasObject,
5163                                   ALIAS_READ_INFORMATION,
5164                                   &AliasObject);
5165     if (!NT_SUCCESS(Status))
5166         goto done;
5167 
5168     switch (AliasInformationClass)
5169     {
5170         case AliasGeneralInformation:
5171             Status = SampQueryAliasGeneral(AliasObject,
5172                                            Buffer);
5173             break;
5174 
5175         case AliasNameInformation:
5176             Status = SampQueryAliasName(AliasObject,
5177                                         Buffer);
5178             break;
5179 
5180         case AliasAdminCommentInformation:
5181             Status = SampQueryAliasAdminComment(AliasObject,
5182                                                 Buffer);
5183             break;
5184 
5185         default:
5186             Status = STATUS_INVALID_INFO_CLASS;
5187             break;
5188     }
5189 
5190 done:
5191     RtlReleaseResource(&SampResource);
5192 
5193     return Status;
5194 }
5195 
5196 
5197 static NTSTATUS
5198 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
5199                  PSAMPR_ALIAS_INFO_BUFFER Buffer)
5200 {
5201     UNICODE_STRING OldAliasName = {0, 0, NULL};
5202     UNICODE_STRING NewAliasName;
5203     NTSTATUS Status;
5204 
5205     Status = SampGetObjectAttributeString(AliasObject,
5206                                           L"Name",
5207                                           (PRPC_UNICODE_STRING)&OldAliasName);
5208     if (!NT_SUCCESS(Status))
5209     {
5210         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
5211         goto done;
5212     }
5213 
5214     /* Check the new account name */
5215     Status = SampCheckAccountName(&Buffer->Name.Name, 256);
5216     if (!NT_SUCCESS(Status))
5217     {
5218         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
5219         return Status;
5220     }
5221 
5222     NewAliasName.Length = Buffer->Name.Name.Length;
5223     NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
5224     NewAliasName.Buffer = Buffer->Name.Name.Buffer;
5225 
5226     if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
5227     {
5228         Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
5229                                               NewAliasName.Buffer);
5230         if (!NT_SUCCESS(Status))
5231         {
5232             TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
5233                   NewAliasName.Buffer, Status);
5234             goto done;
5235         }
5236     }
5237 
5238     Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
5239                                         L"Aliases",
5240                                         NewAliasName.Buffer,
5241                                         AliasObject->RelativeId);
5242     if (!NT_SUCCESS(Status))
5243     {
5244         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
5245         goto done;
5246     }
5247 
5248     Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
5249                                              L"Aliases",
5250                                              OldAliasName.Buffer);
5251     if (!NT_SUCCESS(Status))
5252     {
5253         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
5254         goto done;
5255     }
5256 
5257     Status = SampSetObjectAttributeString(AliasObject,
5258                                           L"Name",
5259                                           (PRPC_UNICODE_STRING)&NewAliasName);
5260     if (!NT_SUCCESS(Status))
5261     {
5262         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
5263     }
5264 
5265 done:
5266     if (OldAliasName.Buffer != NULL)
5267         midl_user_free(OldAliasName.Buffer);
5268 
5269     return Status;
5270 }
5271 
5272 
5273 /* Function 29 */
5274 NTSTATUS
5275 NTAPI
5276 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
5277                         IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5278                         IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
5279 {
5280     PSAM_DB_OBJECT AliasObject;
5281     NTSTATUS Status;
5282 
5283     TRACE("SamrSetInformationAlias(%p %lu %p)\n",
5284           AliasHandle, AliasInformationClass, Buffer);
5285 
5286     RtlAcquireResourceExclusive(&SampResource,
5287                                 TRUE);
5288 
5289     /* Validate the alias handle */
5290     Status = SampValidateDbObject(AliasHandle,
5291                                   SamDbAliasObject,
5292                                   ALIAS_WRITE_ACCOUNT,
5293                                   &AliasObject);
5294     if (!NT_SUCCESS(Status))
5295         goto done;
5296 
5297     switch (AliasInformationClass)
5298     {
5299         case AliasNameInformation:
5300             Status = SampSetAliasName(AliasObject,
5301                                       Buffer);
5302             break;
5303 
5304         case AliasAdminCommentInformation:
5305             Status = SampSetObjectAttributeString(AliasObject,
5306                                                   L"Description",
5307                                                   &Buffer->AdminComment.AdminComment);
5308             break;
5309 
5310         default:
5311             Status = STATUS_INVALID_INFO_CLASS;
5312             break;
5313     }
5314 
5315 done:
5316     RtlReleaseResource(&SampResource);
5317 
5318     return Status;
5319 }
5320 
5321 
5322 /* Function 30 */
5323 NTSTATUS
5324 NTAPI
5325 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
5326 {
5327     PSAM_DB_OBJECT AliasObject;
5328     NTSTATUS Status;
5329 
5330     TRACE("SamrDeleteAlias(%p)\n", AliasHandle);
5331 
5332     RtlAcquireResourceExclusive(&SampResource,
5333                                 TRUE);
5334 
5335     /* Validate the alias handle */
5336     Status = SampValidateDbObject(*AliasHandle,
5337                                   SamDbAliasObject,
5338                                   DELETE,
5339                                   &AliasObject);
5340     if (!NT_SUCCESS(Status))
5341     {
5342         TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
5343         goto done;
5344     }
5345 
5346     /* Fail, if the alias is built-in */
5347     if (AliasObject->RelativeId < 1000)
5348     {
5349         TRACE("You can not delete a special account!\n");
5350         Status = STATUS_SPECIAL_ACCOUNT;
5351         goto done;
5352     }
5353 
5354     /* Remove all members from the alias */
5355     Status = SampRemoveAllMembersFromAlias(AliasObject);
5356     if (!NT_SUCCESS(Status))
5357     {
5358         TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
5359         goto done;
5360     }
5361 
5362     /* Delete the alias from the database */
5363     Status = SampDeleteAccountDbObject(AliasObject);
5364     if (!NT_SUCCESS(Status))
5365     {
5366         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5367         goto done;
5368     }
5369 
5370     /* Invalidate the handle */
5371     *AliasHandle = NULL;
5372 
5373 done:
5374     RtlReleaseResource(&SampResource);
5375 
5376     return Status;
5377 }
5378 
5379 
5380 /* Function 31 */
5381 NTSTATUS
5382 NTAPI
5383 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
5384                      IN PRPC_SID MemberId)
5385 {
5386     PSAM_DB_OBJECT AliasObject;
5387     NTSTATUS Status;
5388 
5389     TRACE("SamrAddMemberToAlias(%p %p)\n",
5390           AliasHandle, MemberId);
5391 
5392     RtlAcquireResourceExclusive(&SampResource,
5393                                 TRUE);
5394 
5395     /* Validate the alias handle */
5396     Status = SampValidateDbObject(AliasHandle,
5397                                   SamDbAliasObject,
5398                                   ALIAS_ADD_MEMBER,
5399                                   &AliasObject);
5400     if (!NT_SUCCESS(Status))
5401     {
5402         TRACE("failed with status 0x%08lx\n", Status);
5403         goto done;
5404     }
5405 
5406     Status = SampAddMemberToAlias(AliasObject,
5407                                   MemberId);
5408     if (!NT_SUCCESS(Status))
5409     {
5410         TRACE("failed with status 0x%08lx\n", Status);
5411     }
5412 
5413 done:
5414     RtlReleaseResource(&SampResource);
5415 
5416     return Status;
5417 }
5418 
5419 
5420 /* Function 32 */
5421 NTSTATUS
5422 NTAPI
5423 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
5424                           IN PRPC_SID MemberId)
5425 {
5426     PSAM_DB_OBJECT AliasObject;
5427     NTSTATUS Status;
5428 
5429     TRACE("SamrRemoveMemberFromAlias(%p %p)\n",
5430           AliasHandle, MemberId);
5431 
5432     RtlAcquireResourceExclusive(&SampResource,
5433                                 TRUE);
5434 
5435     /* Validate the alias handle */
5436     Status = SampValidateDbObject(AliasHandle,
5437                                   SamDbAliasObject,
5438                                   ALIAS_REMOVE_MEMBER,
5439                                   &AliasObject);
5440     if (!NT_SUCCESS(Status))
5441     {
5442         TRACE("failed with status 0x%08lx\n", Status);
5443         goto done;
5444     }
5445 
5446     Status = SampRemoveMemberFromAlias(AliasObject,
5447                                        MemberId);
5448     if (!NT_SUCCESS(Status))
5449     {
5450         TRACE("failed with status 0x%08lx\n", Status);
5451     }
5452 
5453 done:
5454     RtlReleaseResource(&SampResource);
5455 
5456     return Status;
5457 }
5458 
5459 
5460 /* Function 33 */
5461 NTSTATUS
5462 NTAPI
5463 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
5464                       OUT PSAMPR_PSID_ARRAY_OUT Members)
5465 {
5466     PSAM_DB_OBJECT AliasObject;
5467     PSAMPR_SID_INFORMATION MemberArray = NULL;
5468     ULONG MemberCount = 0;
5469     ULONG Index;
5470     NTSTATUS Status;
5471 
5472     TRACE("SamrGetMembersInAlias(%p %p %p)\n",
5473           AliasHandle, Members);
5474 
5475     RtlAcquireResourceShared(&SampResource,
5476                              TRUE);
5477 
5478     /* Validate the alias handle */
5479     Status = SampValidateDbObject(AliasHandle,
5480                                   SamDbAliasObject,
5481                                   ALIAS_LIST_MEMBERS,
5482                                   &AliasObject);
5483     if (!NT_SUCCESS(Status))
5484     {
5485         ERR("failed with status 0x%08lx\n", Status);
5486         goto done;
5487     }
5488 
5489     Status = SampGetMembersInAlias(AliasObject,
5490                                    &MemberCount,
5491                                    &MemberArray);
5492 
5493     /* Return the number of members and the member array */
5494     if (NT_SUCCESS(Status))
5495     {
5496         Members->Count = MemberCount;
5497         Members->Sids = MemberArray;
5498     }
5499 
5500 done:
5501     /* Clean up the members array and the SID buffers if something failed */
5502     if (!NT_SUCCESS(Status))
5503     {
5504         if (MemberArray != NULL)
5505         {
5506             for (Index = 0; Index < MemberCount; Index++)
5507             {
5508                 if (MemberArray[Index].SidPointer != NULL)
5509                     midl_user_free(MemberArray[Index].SidPointer);
5510             }
5511 
5512             midl_user_free(MemberArray);
5513         }
5514     }
5515 
5516     RtlReleaseResource(&SampResource);
5517 
5518     return Status;
5519 }
5520 
5521 
5522 /* Function 34 */
5523 NTSTATUS
5524 NTAPI
5525 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5526              IN ACCESS_MASK DesiredAccess,
5527              IN unsigned long UserId,
5528              OUT SAMPR_HANDLE *UserHandle)
5529 {
5530     PSAM_DB_OBJECT DomainObject;
5531     PSAM_DB_OBJECT UserObject;
5532     WCHAR szRid[9];
5533     NTSTATUS Status;
5534 
5535     TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5536           DomainHandle, DesiredAccess, UserId, UserHandle);
5537 
5538     /* Map generic access rights */
5539     RtlMapGenericMask(&DesiredAccess,
5540                       &UserMapping);
5541 
5542     RtlAcquireResourceShared(&SampResource,
5543                              TRUE);
5544 
5545     /* Validate the domain handle */
5546     Status = SampValidateDbObject(DomainHandle,
5547                                   SamDbDomainObject,
5548                                   DOMAIN_LOOKUP,
5549                                   &DomainObject);
5550     if (!NT_SUCCESS(Status))
5551     {
5552         TRACE("failed with status 0x%08lx\n", Status);
5553         goto done;
5554     }
5555 
5556     /* Convert the RID into a string (hex) */
5557     swprintf(szRid, L"%08lX", UserId);
5558 
5559     /* Create the user object */
5560     Status = SampOpenDbObject(DomainObject,
5561                               L"Users",
5562                               szRid,
5563                               UserId,
5564                               SamDbUserObject,
5565                               DesiredAccess,
5566                               &UserObject);
5567     if (!NT_SUCCESS(Status))
5568     {
5569         TRACE("failed with status 0x%08lx\n", Status);
5570         goto done;
5571     }
5572 
5573     *UserHandle = (SAMPR_HANDLE)UserObject;
5574 
5575 done:
5576     RtlReleaseResource(&SampResource);
5577 
5578     return Status;
5579 }
5580 
5581 
5582 /* Function 35 */
5583 NTSTATUS
5584 NTAPI
5585 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5586 {
5587     PSAM_DB_OBJECT UserObject;
5588     NTSTATUS Status;
5589 
5590     TRACE("SamrDeleteUser(%p)\n", UserHandle);
5591 
5592     RtlAcquireResourceExclusive(&SampResource,
5593                                 TRUE);
5594 
5595     /* Validate the user handle */
5596     Status = SampValidateDbObject(*UserHandle,
5597                                   SamDbUserObject,
5598                                   DELETE,
5599                                   &UserObject);
5600     if (!NT_SUCCESS(Status))
5601     {
5602         TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5603         goto done;
5604     }
5605 
5606     /* Fail, if the user is built-in */
5607     if (UserObject->RelativeId < 1000)
5608     {
5609         TRACE("You can not delete a special account!\n");
5610         Status = STATUS_SPECIAL_ACCOUNT;
5611         goto done;
5612     }
5613 
5614     /* Remove the user from all groups */
5615     Status = SampRemoveUserFromAllGroups(UserObject);
5616     if (!NT_SUCCESS(Status))
5617     {
5618         TRACE("SampRemoveUserFromAllGroups() failed (Status 0x%08lx)\n", Status);
5619         goto done;
5620     }
5621 
5622     /* Remove the user from all aliases */
5623     Status = SampRemoveUserFromAllAliases(UserObject);
5624     if (!NT_SUCCESS(Status))
5625     {
5626         TRACE("SampRemoveUserFromAllAliases() failed (Status 0x%08lx)\n", Status);
5627         goto done;
5628     }
5629 
5630     /* Delete the user from the database */
5631     Status = SampDeleteAccountDbObject(UserObject);
5632     if (!NT_SUCCESS(Status))
5633     {
5634         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5635         goto done;
5636     }
5637 
5638     /* Invalidate the handle */
5639     *UserHandle = NULL;
5640 
5641 done:
5642     RtlReleaseResource(&SampResource);
5643 
5644     return Status;
5645 }
5646 
5647 
5648 static
5649 NTSTATUS
5650 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5651                      PSAMPR_USER_INFO_BUFFER *Buffer)
5652 {
5653     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5654     SAM_USER_FIXED_DATA FixedData;
5655     ULONG Length = 0;
5656     NTSTATUS Status;
5657 
5658     *Buffer = NULL;
5659 
5660     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5661     if (InfoBuffer == NULL)
5662         return STATUS_INSUFFICIENT_RESOURCES;
5663 
5664     Length = sizeof(SAM_USER_FIXED_DATA);
5665     Status = SampGetObjectAttribute(UserObject,
5666                                     L"F",
5667                                     NULL,
5668                                     (PVOID)&FixedData,
5669                                     &Length);
5670     if (!NT_SUCCESS(Status))
5671         goto done;
5672 
5673     InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5674 
5675     /* Get the Name string */
5676     Status = SampGetObjectAttributeString(UserObject,
5677                                           L"Name",
5678                                           &InfoBuffer->General.UserName);
5679     if (!NT_SUCCESS(Status))
5680     {
5681         TRACE("Status 0x%08lx\n", Status);
5682         goto done;
5683     }
5684 
5685     /* Get the FullName string */
5686     Status = SampGetObjectAttributeString(UserObject,
5687                                           L"FullName",
5688                                           &InfoBuffer->General.FullName);
5689     if (!NT_SUCCESS(Status))
5690     {
5691         TRACE("Status 0x%08lx\n", Status);
5692         goto done;
5693     }
5694 
5695     /* Get the AdminComment string */
5696     Status = SampGetObjectAttributeString(UserObject,
5697                                           L"AdminComment",
5698                                           &InfoBuffer->General.AdminComment);
5699     if (!NT_SUCCESS(Status))
5700     {
5701         TRACE("Status 0x%08lx\n", Status);
5702         goto done;
5703     }
5704 
5705     /* Get the UserComment string */
5706     Status = SampGetObjectAttributeString(UserObject,
5707                                           L"UserComment",
5708                                           &InfoBuffer->General.UserComment);
5709     if (!NT_SUCCESS(Status))
5710     {
5711         TRACE("Status 0x%08lx\n", Status);
5712         goto done;
5713     }
5714 
5715     *Buffer = InfoBuffer;
5716 
5717 done:
5718     if (!NT_SUCCESS(Status))
5719     {
5720         if (InfoBuffer != NULL)
5721         {
5722             if (InfoBuffer->General.UserName.Buffer != NULL)
5723                 midl_user_free(InfoBuffer->General.UserName.Buffer);
5724 
5725             if (InfoBuffer->General.FullName.Buffer != NULL)
5726                 midl_user_free(InfoBuffer->General.FullName.Buffer);
5727 
5728             if (InfoBuffer->General.AdminComment.Buffer != NULL)
5729                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5730 
5731             if (InfoBuffer->General.UserComment.Buffer != NULL)
5732                 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5733 
5734             midl_user_free(InfoBuffer);
5735         }
5736     }
5737 
5738     return Status;
5739 }
5740 
5741 
5742 static
5743 NTSTATUS
5744 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5745                          PSAMPR_USER_INFO_BUFFER *Buffer)
5746 {
5747     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5748     SAM_USER_FIXED_DATA FixedData;
5749     ULONG Length = 0;
5750     NTSTATUS Status;
5751 
5752     *Buffer = NULL;
5753 
5754     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5755     if (InfoBuffer == NULL)
5756         return STATUS_INSUFFICIENT_RESOURCES;
5757 
5758     Length = sizeof(SAM_USER_FIXED_DATA);
5759     Status = SampGetObjectAttribute(UserObject,
5760                                     L"F",
5761                                     NULL,
5762                                     (PVOID)&FixedData,
5763                                     &Length);
5764     if (!NT_SUCCESS(Status))
5765         goto done;
5766 
5767     InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5768     InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5769 
5770     /* Get the UserComment string */
5771     Status = SampGetObjectAttributeString(UserObject,
5772                                           L"UserComment",
5773                                           &InfoBuffer->Preferences.UserComment);
5774     if (!NT_SUCCESS(Status))
5775     {
5776         TRACE("Status 0x%08lx\n", Status);
5777         goto done;
5778     }
5779 
5780     *Buffer = InfoBuffer;
5781 
5782 done:
5783     if (!NT_SUCCESS(Status))
5784     {
5785         if (InfoBuffer != NULL)
5786         {
5787             if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5788                 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5789 
5790             midl_user_free(InfoBuffer);
5791         }
5792     }
5793 
5794     return Status;
5795 }
5796 
5797 
5798 static
5799 NTSTATUS
5800 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5801                    PSAMPR_USER_INFO_BUFFER *Buffer)
5802 {
5803     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5804     SAM_DOMAIN_FIXED_DATA DomainFixedData;
5805     SAM_USER_FIXED_DATA FixedData;
5806     LARGE_INTEGER PasswordCanChange;
5807     LARGE_INTEGER PasswordMustChange;
5808     ULONG Length = 0;
5809     NTSTATUS Status;
5810 
5811     *Buffer = NULL;
5812 
5813     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5814     if (InfoBuffer == NULL)
5815         return STATUS_INSUFFICIENT_RESOURCES;
5816 
5817     /* Get the fixed size domain data */
5818     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5819     Status = SampGetObjectAttribute(UserObject->ParentObject,
5820                                     L"F",
5821                                     NULL,
5822                                     (PVOID)&DomainFixedData,
5823                                     &Length);
5824     if (!NT_SUCCESS(Status))
5825         goto done;
5826 
5827     /* Get the fixed size user data */
5828     Length = sizeof(SAM_USER_FIXED_DATA);
5829     Status = SampGetObjectAttribute(UserObject,
5830                                     L"F",
5831                                     NULL,
5832                                     (PVOID)&FixedData,
5833                                     &Length);
5834     if (!NT_SUCCESS(Status))
5835         goto done;
5836 
5837     InfoBuffer->Logon.UserId = FixedData.UserId;
5838     InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5839     InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5840     InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5841     InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5842     InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5843     InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5844     InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5845     InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5846     InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5847     InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5848 
5849     PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5850                                                   DomainFixedData.MinPasswordAge);
5851     InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5852     InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5853 
5854     PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5855                                                    DomainFixedData.MaxPasswordAge);
5856     InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5857     InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5858 
5859     /* Get the Name string */
5860     Status = SampGetObjectAttributeString(UserObject,
5861                                           L"Name",
5862                                           &InfoBuffer->Logon.UserName);
5863     if (!NT_SUCCESS(Status))
5864     {
5865         TRACE("Status 0x%08lx\n", Status);
5866         goto done;
5867     }
5868 
5869     /* Get the FullName string */
5870     Status = SampGetObjectAttributeString(UserObject,
5871                                           L"FullName",
5872                                           &InfoBuffer->Logon.FullName);
5873     if (!NT_SUCCESS(Status))
5874     {
5875         TRACE("Status 0x%08lx\n", Status);
5876         goto done;
5877     }
5878 
5879     /* Get the HomeDirectory string */
5880     Status = SampGetObjectAttributeString(UserObject,
5881                                           L"HomeDirectory",
5882                                           &InfoBuffer->Logon.HomeDirectory);
5883     if (!NT_SUCCESS(Status))
5884     {
5885         TRACE("Status 0x%08lx\n", Status);
5886         goto done;
5887     }
5888 
5889     /* Get the HomeDirectoryDrive string */
5890     Status = SampGetObjectAttributeString(UserObject,
5891                                           L"HomeDirectoryDrive",
5892                                           &InfoBuffer->Logon.HomeDirectoryDrive);
5893     if (!NT_SUCCESS(Status))
5894     {
5895         TRACE("Status 0x%08lx\n", Status);
5896         goto done;
5897     }
5898 
5899     /* Get the ScriptPath string */
5900     Status = SampGetObjectAttributeString(UserObject,
5901                                           L"ScriptPath",
5902                                           &InfoBuffer->Logon.ScriptPath);
5903     if (!NT_SUCCESS(Status))
5904     {
5905         TRACE("Status 0x%08lx\n", Status);
5906         goto done;
5907     }
5908 
5909     /* Get the ProfilePath string */
5910     Status = SampGetObjectAttributeString(UserObject,
5911                                           L"ProfilePath",
5912                                           &InfoBuffer->Logon.ProfilePath);
5913     if (!NT_SUCCESS(Status))
5914     {
5915         TRACE("Status 0x%08lx\n", Status);
5916         goto done;
5917     }
5918 
5919     /* Get the WorkStations string */
5920     Status = SampGetObjectAttributeString(UserObject,
5921                                           L"WorkStations",
5922                                           &InfoBuffer->Logon.WorkStations);
5923     if (!NT_SUCCESS(Status))
5924     {
5925         TRACE("Status 0x%08lx\n", Status);
5926         goto done;
5927     }
5928 
5929     /* Get the LogonHours attribute */
5930     Status = SampGetLogonHoursAttribute(UserObject,
5931                                        &InfoBuffer->Logon.LogonHours);
5932     if (!NT_SUCCESS(Status))
5933     {
5934         TRACE("Status 0x%08lx\n", Status);
5935         goto done;
5936     }
5937 
5938     *Buffer = InfoBuffer;
5939 
5940 done:
5941     if (!NT_SUCCESS(Status))
5942     {
5943         if (InfoBuffer != NULL)
5944         {
5945             if (InfoBuffer->Logon.UserName.Buffer != NULL)
5946                 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5947 
5948             if (InfoBuffer->Logon.FullName.Buffer != NULL)
5949                 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5950 
5951             if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5952                 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5953 
5954             if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5955                 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5956 
5957             if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5958                 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5959 
5960             if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5961                 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5962 
5963             if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5964                 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5965 
5966             if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5967                 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5968 
5969             midl_user_free(InfoBuffer);
5970         }
5971     }
5972 
5973     return Status;
5974 }
5975 
5976 
5977 static
5978 NTSTATUS
5979 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5980                      PSAMPR_USER_INFO_BUFFER *Buffer)
5981 {
5982     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5983     SAM_USER_FIXED_DATA FixedData;
5984     ULONG Length = 0;
5985     NTSTATUS Status;
5986 
5987     *Buffer = NULL;
5988 
5989     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5990     if (InfoBuffer == NULL)
5991         return STATUS_INSUFFICIENT_RESOURCES;
5992 
5993     Length = sizeof(SAM_USER_FIXED_DATA);
5994     Status = SampGetObjectAttribute(UserObject,
5995                                     L"F",
5996                                     NULL,
5997                                     (PVOID)&FixedData,
5998                                     &Length);
5999     if (!NT_SUCCESS(Status))
6000         goto done;
6001 
6002     InfoBuffer->Account.UserId = FixedData.UserId;
6003     InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
6004     InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6005     InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6006     InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6007     InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6008     InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
6009     InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
6010     InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6011     InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6012     InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
6013     InfoBuffer->Account.LogonCount = FixedData.LogonCount;
6014     InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
6015 
6016     /* Get the Name string */
6017     Status = SampGetObjectAttributeString(UserObject,
6018                                           L"Name",
6019                                           &InfoBuffer->Account.UserName);
6020     if (!NT_SUCCESS(Status))
6021     {
6022         TRACE("Status 0x%08lx\n", Status);
6023         goto done;
6024     }
6025 
6026     /* Get the FullName string */
6027     Status = SampGetObjectAttributeString(UserObject,
6028                                           L"FullName",
6029                                           &InfoBuffer->Account.FullName);
6030     if (!NT_SUCCESS(Status))
6031     {
6032         TRACE("Status 0x%08lx\n", Status);
6033         goto done;
6034     }
6035 
6036     /* Get the HomeDirectory string */
6037     Status = SampGetObjectAttributeString(UserObject,
6038                                           L"HomeDirectory",
6039                                           &InfoBuffer->Account.HomeDirectory);
6040     if (!NT_SUCCESS(Status))
6041     {
6042         TRACE("Status 0x%08lx\n", Status);
6043         goto done;
6044     }
6045 
6046     /* Get the HomeDirectoryDrive string */
6047     Status = SampGetObjectAttributeString(UserObject,
6048                                           L"HomeDirectoryDrive",
6049                                           &InfoBuffer->Account.HomeDirectoryDrive);
6050     if (!NT_SUCCESS(Status))
6051     {
6052         TRACE("Status 0x%08lx\n", Status);
6053         goto done;
6054     }
6055 
6056     /* Get the ScriptPath string */
6057     Status = SampGetObjectAttributeString(UserObject,
6058                                           L"ScriptPath",
6059                                           &InfoBuffer->Account.ScriptPath);
6060     if (!NT_SUCCESS(Status))
6061     {
6062         TRACE("Status 0x%08lx\n", Status);
6063         goto done;
6064     }
6065 
6066     /* Get the ProfilePath string */
6067     Status = SampGetObjectAttributeString(UserObject,
6068                                           L"ProfilePath",
6069                                           &InfoBuffer->Account.ProfilePath);
6070     if (!NT_SUCCESS(Status))
6071     {
6072         TRACE("Status 0x%08lx\n", Status);
6073         goto done;
6074     }
6075 
6076     /* Get the AdminComment string */
6077     Status = SampGetObjectAttributeString(UserObject,
6078                                           L"AdminComment",
6079                                           &InfoBuffer->Account.AdminComment);
6080     if (!NT_SUCCESS(Status))
6081     {
6082         TRACE("Status 0x%08lx\n", Status);
6083         goto done;
6084     }
6085 
6086     /* Get the WorkStations string */
6087     Status = SampGetObjectAttributeString(UserObject,
6088                                           L"WorkStations",
6089                                           &InfoBuffer->Account.WorkStations);
6090     if (!NT_SUCCESS(Status))
6091     {
6092         TRACE("Status 0x%08lx\n", Status);
6093         goto done;
6094     }
6095 
6096     /* Get the LogonHours attribute */
6097     Status = SampGetLogonHoursAttribute(UserObject,
6098                                        &InfoBuffer->Account.LogonHours);
6099     if (!NT_SUCCESS(Status))
6100     {
6101         TRACE("Status 0x%08lx\n", Status);
6102         goto done;
6103     }
6104 
6105     *Buffer = InfoBuffer;
6106 
6107 done:
6108     if (!NT_SUCCESS(Status))
6109     {
6110         if (InfoBuffer != NULL)
6111         {
6112             if (InfoBuffer->Account.UserName.Buffer != NULL)
6113                 midl_user_free(InfoBuffer->Account.UserName.Buffer);
6114 
6115             if (InfoBuffer->Account.FullName.Buffer != NULL)
6116                 midl_user_free(InfoBuffer->Account.FullName.Buffer);
6117 
6118             if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
6119                 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
6120 
6121             if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
6122                 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
6123 
6124             if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
6125                 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
6126 
6127             if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
6128                 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
6129 
6130             if (InfoBuffer->Account.AdminComment.Buffer != NULL)
6131                 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
6132 
6133             if (InfoBuffer->Account.WorkStations.Buffer != NULL)
6134                 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
6135 
6136             if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
6137                 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
6138 
6139             midl_user_free(InfoBuffer);
6140         }
6141     }
6142 
6143     return Status;
6144 }
6145 
6146 
6147 static
6148 NTSTATUS
6149 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
6150                         PSAMPR_USER_INFO_BUFFER *Buffer)
6151 {
6152     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6153     NTSTATUS Status;
6154 
6155     TRACE("(%p %p)\n", UserObject, Buffer);
6156 
6157     *Buffer = NULL;
6158 
6159     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6160     if (InfoBuffer == NULL)
6161     {
6162         TRACE("Failed to allocate InfoBuffer!\n");
6163         return STATUS_INSUFFICIENT_RESOURCES;
6164     }
6165 
6166     Status = SampGetLogonHoursAttribute(UserObject,
6167                                         &InfoBuffer->LogonHours.LogonHours);
6168     if (!NT_SUCCESS(Status))
6169     {
6170         TRACE("SampGetLogonHoursAttribute failed (Status 0x%08lx)\n", Status);
6171         goto done;
6172     }
6173 
6174     *Buffer = InfoBuffer;
6175 
6176 done:
6177     if (!NT_SUCCESS(Status))
6178     {
6179         if (InfoBuffer != NULL)
6180         {
6181             if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
6182                 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
6183 
6184             midl_user_free(InfoBuffer);
6185         }
6186     }
6187 
6188     return Status;
6189 }
6190 
6191 
6192 static
6193 NTSTATUS
6194 SampQueryUserName(PSAM_DB_OBJECT UserObject,
6195                   PSAMPR_USER_INFO_BUFFER *Buffer)
6196 {
6197     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6198     NTSTATUS Status;
6199 
6200     *Buffer = NULL;
6201 
6202     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6203     if (InfoBuffer == NULL)
6204         return STATUS_INSUFFICIENT_RESOURCES;
6205 
6206     /* Get the Name string */
6207     Status = SampGetObjectAttributeString(UserObject,
6208                                           L"Name",
6209                                           &InfoBuffer->Name.UserName);
6210     if (!NT_SUCCESS(Status))
6211     {
6212         TRACE("Status 0x%08lx\n", Status);
6213         goto done;
6214     }
6215 
6216     /* Get the FullName string */
6217     Status = SampGetObjectAttributeString(UserObject,
6218                                           L"FullName",
6219                                           &InfoBuffer->Name.FullName);
6220     if (!NT_SUCCESS(Status))
6221     {
6222         TRACE("Status 0x%08lx\n", Status);
6223         goto done;
6224     }
6225 
6226     *Buffer = InfoBuffer;
6227 
6228 done:
6229     if (!NT_SUCCESS(Status))
6230     {
6231         if (InfoBuffer != NULL)
6232         {
6233             if (InfoBuffer->Name.UserName.Buffer != NULL)
6234                 midl_user_free(InfoBuffer->Name.UserName.Buffer);
6235 
6236             if (InfoBuffer->Name.FullName.Buffer != NULL)
6237                 midl_user_free(InfoBuffer->Name.FullName.Buffer);
6238 
6239             midl_user_free(InfoBuffer);
6240         }
6241     }
6242 
6243     return Status;
6244 }
6245 
6246 
6247 static NTSTATUS
6248 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
6249                          PSAMPR_USER_INFO_BUFFER *Buffer)
6250 {
6251     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6252     NTSTATUS Status;
6253 
6254     *Buffer = NULL;
6255 
6256     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6257     if (InfoBuffer == NULL)
6258         return STATUS_INSUFFICIENT_RESOURCES;
6259 
6260     /* Get the Name string */
6261     Status = SampGetObjectAttributeString(UserObject,
6262                                           L"Name",
6263                                           &InfoBuffer->AccountName.UserName);
6264     if (!NT_SUCCESS(Status))
6265     {
6266         TRACE("Status 0x%08lx\n", Status);
6267         goto done;
6268     }
6269 
6270     *Buffer = InfoBuffer;
6271 
6272 done:
6273     if (!NT_SUCCESS(Status))
6274     {
6275         if (InfoBuffer != NULL)
6276         {
6277             if (InfoBuffer->AccountName.UserName.Buffer != NULL)
6278                 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
6279 
6280             midl_user_free(InfoBuffer);
6281         }
6282     }
6283 
6284     return Status;
6285 }
6286 
6287 
6288 static NTSTATUS
6289 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
6290                       PSAMPR_USER_INFO_BUFFER *Buffer)
6291 {
6292     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6293     NTSTATUS Status;
6294 
6295     *Buffer = NULL;
6296 
6297     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6298     if (InfoBuffer == NULL)
6299         return STATUS_INSUFFICIENT_RESOURCES;
6300 
6301     /* Get the FullName string */
6302     Status = SampGetObjectAttributeString(UserObject,
6303                                           L"FullName",
6304                                           &InfoBuffer->FullName.FullName);
6305     if (!NT_SUCCESS(Status))
6306     {
6307         TRACE("Status 0x%08lx\n", Status);
6308         goto done;
6309     }
6310 
6311     *Buffer = InfoBuffer;
6312 
6313 done:
6314     if (!NT_SUCCESS(Status))
6315     {
6316         if (InfoBuffer != NULL)
6317         {
6318             if (InfoBuffer->FullName.FullName.Buffer != NULL)
6319                 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
6320 
6321             midl_user_free(InfoBuffer);
6322         }
6323     }
6324 
6325     return Status;
6326 }
6327 
6328 
6329 static
6330 NTSTATUS
6331 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6332                           PSAMPR_USER_INFO_BUFFER *Buffer)
6333 {
6334     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6335     SAM_USER_FIXED_DATA FixedData;
6336     ULONG Length = 0;
6337     NTSTATUS Status;
6338 
6339     *Buffer = NULL;
6340 
6341     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6342     if (InfoBuffer == NULL)
6343         return STATUS_INSUFFICIENT_RESOURCES;
6344 
6345     Length = sizeof(SAM_USER_FIXED_DATA);
6346     Status = SampGetObjectAttribute(UserObject,
6347                                     L"F",
6348                                     NULL,
6349                                     (PVOID)&FixedData,
6350                                     &Length);
6351     if (!NT_SUCCESS(Status))
6352         goto done;
6353 
6354     InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
6355 
6356     *Buffer = InfoBuffer;
6357 
6358 done:
6359     if (!NT_SUCCESS(Status))
6360     {
6361         if (InfoBuffer != NULL)
6362         {
6363             midl_user_free(InfoBuffer);
6364         }
6365     }
6366 
6367     return Status;
6368 }
6369 
6370 
6371 static NTSTATUS
6372 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
6373                   PSAMPR_USER_INFO_BUFFER *Buffer)
6374 {
6375     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6376     NTSTATUS Status;
6377 
6378     *Buffer = NULL;
6379 
6380     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6381     if (InfoBuffer == NULL)
6382         return STATUS_INSUFFICIENT_RESOURCES;
6383 
6384     /* Get the HomeDirectory string */
6385     Status = SampGetObjectAttributeString(UserObject,
6386                                           L"HomeDirectory",
6387                                           &InfoBuffer->Home.HomeDirectory);
6388     if (!NT_SUCCESS(Status))
6389     {
6390         TRACE("Status 0x%08lx\n", Status);
6391         goto done;
6392     }
6393 
6394     /* Get the HomeDirectoryDrive string */
6395     Status = SampGetObjectAttributeString(UserObject,
6396                                           L"HomeDirectoryDrive",
6397                                           &InfoBuffer->Home.HomeDirectoryDrive);
6398     if (!NT_SUCCESS(Status))
6399     {
6400         TRACE("Status 0x%08lx\n", Status);
6401         goto done;
6402     }
6403 
6404     *Buffer = InfoBuffer;
6405 
6406 done:
6407     if (!NT_SUCCESS(Status))
6408     {
6409         if (InfoBuffer != NULL)
6410         {
6411             if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
6412                 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
6413 
6414             if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
6415                 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
6416 
6417             midl_user_free(InfoBuffer);
6418         }
6419     }
6420 
6421     return Status;
6422 }
6423 
6424 
6425 static NTSTATUS
6426 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
6427                     PSAMPR_USER_INFO_BUFFER *Buffer)
6428 {
6429     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6430     NTSTATUS Status;
6431 
6432     *Buffer = NULL;
6433 
6434     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6435     if (InfoBuffer == NULL)
6436         return STATUS_INSUFFICIENT_RESOURCES;
6437 
6438     /* Get the ScriptPath string */
6439     Status = SampGetObjectAttributeString(UserObject,
6440                                           L"ScriptPath",
6441                                           &InfoBuffer->Script.ScriptPath);
6442     if (!NT_SUCCESS(Status))
6443     {
6444         TRACE("Status 0x%08lx\n", Status);
6445         goto done;
6446     }
6447 
6448     *Buffer = InfoBuffer;
6449 
6450 done:
6451     if (!NT_SUCCESS(Status))
6452     {
6453         if (InfoBuffer != NULL)
6454         {
6455             if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
6456                 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
6457 
6458             midl_user_free(InfoBuffer);
6459         }
6460     }
6461 
6462     return Status;
6463 }
6464 
6465 
6466 static NTSTATUS
6467 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
6468                      PSAMPR_USER_INFO_BUFFER *Buffer)
6469 {
6470     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6471     NTSTATUS Status;
6472 
6473     *Buffer = NULL;
6474 
6475     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6476     if (InfoBuffer == NULL)
6477         return STATUS_INSUFFICIENT_RESOURCES;
6478 
6479     /* Get the ProfilePath string */
6480     Status = SampGetObjectAttributeString(UserObject,
6481                                           L"ProfilePath",
6482                                           &InfoBuffer->Profile.ProfilePath);
6483     if (!NT_SUCCESS(Status))
6484     {
6485         TRACE("Status 0x%08lx\n", Status);
6486         goto done;
6487     }
6488 
6489     *Buffer = InfoBuffer;
6490 
6491 done:
6492     if (!NT_SUCCESS(Status))
6493     {
6494         if (InfoBuffer != NULL)
6495         {
6496             if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
6497                 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
6498 
6499             midl_user_free(InfoBuffer);
6500         }
6501     }
6502 
6503     return Status;
6504 }
6505 
6506 
6507 static NTSTATUS
6508 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6509                           PSAMPR_USER_INFO_BUFFER *Buffer)
6510 {
6511     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6512     NTSTATUS Status;
6513 
6514     *Buffer = NULL;
6515 
6516     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6517     if (InfoBuffer == NULL)
6518         return STATUS_INSUFFICIENT_RESOURCES;
6519 
6520     /* Get the AdminComment string */
6521     Status = SampGetObjectAttributeString(UserObject,
6522                                           L"AdminComment",
6523                                           &InfoBuffer->AdminComment.AdminComment);
6524     if (!NT_SUCCESS(Status))
6525     {
6526         TRACE("Status 0x%08lx\n", Status);
6527         goto done;
6528     }
6529 
6530     *Buffer = InfoBuffer;
6531 
6532 done:
6533     if (!NT_SUCCESS(Status))
6534     {
6535         if (InfoBuffer != NULL)
6536         {
6537             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6538                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6539 
6540             midl_user_free(InfoBuffer);
6541         }
6542     }
6543 
6544     return Status;
6545 }
6546 
6547 
6548 static NTSTATUS
6549 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6550                           PSAMPR_USER_INFO_BUFFER *Buffer)
6551 {
6552     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6553     NTSTATUS Status;
6554 
6555     *Buffer = NULL;
6556 
6557     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6558     if (InfoBuffer == NULL)
6559         return STATUS_INSUFFICIENT_RESOURCES;
6560 
6561     /* Get the WorkStations string */
6562     Status = SampGetObjectAttributeString(UserObject,
6563                                           L"WorkStations",
6564                                           &InfoBuffer->WorkStations.WorkStations);
6565     if (!NT_SUCCESS(Status))
6566     {
6567         TRACE("Status 0x%08lx\n", Status);
6568         goto done;
6569     }
6570 
6571     *Buffer = InfoBuffer;
6572 
6573 done:
6574     if (!NT_SUCCESS(Status))
6575     {
6576         if (InfoBuffer != NULL)
6577         {
6578             if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6579                 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6580 
6581             midl_user_free(InfoBuffer);
6582         }
6583     }
6584 
6585     return Status;
6586 }
6587 
6588 
6589 static
6590 NTSTATUS
6591 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6592                      PSAMPR_USER_INFO_BUFFER *Buffer)
6593 {
6594     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6595     SAM_USER_FIXED_DATA FixedData;
6596     ULONG Length = 0;
6597     NTSTATUS Status;
6598 
6599     *Buffer = NULL;
6600 
6601     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6602     if (InfoBuffer == NULL)
6603         return STATUS_INSUFFICIENT_RESOURCES;
6604 
6605     Length = sizeof(SAM_USER_FIXED_DATA);
6606     Status = SampGetObjectAttribute(UserObject,
6607                                     L"F",
6608                                     NULL,
6609                                     (PVOID)&FixedData,
6610                                     &Length);
6611     if (!NT_SUCCESS(Status))
6612         goto done;
6613 
6614     InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6615 
6616     *Buffer = InfoBuffer;
6617 
6618 done:
6619     if (!NT_SUCCESS(Status))
6620     {
6621         if (InfoBuffer != NULL)
6622         {
6623             midl_user_free(InfoBuffer);
6624         }
6625     }
6626 
6627     return Status;
6628 }
6629 
6630 
6631 static
6632 NTSTATUS
6633 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6634                      PSAMPR_USER_INFO_BUFFER *Buffer)
6635 {
6636     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6637     SAM_USER_FIXED_DATA FixedData;
6638     ULONG Length = 0;
6639     NTSTATUS Status;
6640 
6641     *Buffer = NULL;
6642 
6643     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6644     if (InfoBuffer == NULL)
6645         return STATUS_INSUFFICIENT_RESOURCES;
6646 
6647     Length = sizeof(SAM_USER_FIXED_DATA);
6648     Status = SampGetObjectAttribute(UserObject,
6649                                     L"F",
6650                                     NULL,
6651                                     (PVOID)&FixedData,
6652                                     &Length);
6653     if (!NT_SUCCESS(Status))
6654         goto done;
6655 
6656     InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6657     InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6658 
6659     *Buffer = InfoBuffer;
6660 
6661 done:
6662     if (!NT_SUCCESS(Status))
6663     {
6664         if (InfoBuffer != NULL)
6665         {
6666             midl_user_free(InfoBuffer);
6667         }
6668     }
6669 
6670     return Status;
6671 }
6672 
6673 
6674 static
6675 NTSTATUS
6676 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6677                        PSAMPR_USER_INFO_BUFFER *Buffer)
6678 {
6679     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6680     ULONG Length = 0;
6681     NTSTATUS Status = STATUS_SUCCESS;
6682 
6683     /* Fail, if the caller is not a trusted caller */
6684     if (UserObject->Trusted == FALSE)
6685         return STATUS_INVALID_INFO_CLASS;
6686 
6687     *Buffer = NULL;
6688 
6689     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6690     if (InfoBuffer == NULL)
6691         return STATUS_INSUFFICIENT_RESOURCES;
6692 
6693     InfoBuffer->Internal1.LmPasswordPresent = FALSE;
6694     InfoBuffer->Internal1.NtPasswordPresent = FALSE;
6695 
6696     /* Get the NT password */
6697     Length = 0;
6698     SampGetObjectAttribute(UserObject,
6699                            L"NTPwd",
6700                            NULL,
6701                            NULL,
6702                            &Length);
6703 
6704     if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6705     {
6706         Status = SampGetObjectAttribute(UserObject,
6707                                         L"NTPwd",
6708                                         NULL,
6709                                         (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6710                                         &Length);
6711         if (!NT_SUCCESS(Status))
6712             goto done;
6713 
6714         if (memcmp(&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6715                    &EmptyNtHash,
6716                    sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
6717             InfoBuffer->Internal1.NtPasswordPresent = TRUE;
6718     }
6719 
6720 
6721     /* Get the LM password */
6722     Length = 0;
6723     SampGetObjectAttribute(UserObject,
6724                            L"LMPwd",
6725                            NULL,
6726                            NULL,
6727                            &Length);
6728 
6729     if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6730     {
6731         Status = SampGetObjectAttribute(UserObject,
6732                                         L"LMPwd",
6733                                         NULL,
6734                                         (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6735                                         &Length);
6736         if (!NT_SUCCESS(Status))
6737             goto done;
6738 
6739         if (memcmp(&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6740                    &EmptyLmHash,
6741                    sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
6742             InfoBuffer->Internal1.LmPasswordPresent = TRUE;
6743     }
6744 
6745     InfoBuffer->Internal1.PasswordExpired = FALSE;
6746 
6747     *Buffer = InfoBuffer;
6748 
6749 done:
6750     if (!NT_SUCCESS(Status))
6751     {
6752         if (InfoBuffer != NULL)
6753         {
6754             midl_user_free(InfoBuffer);
6755         }
6756     }
6757 
6758     return Status;
6759 }
6760 
6761 
6762 static
6763 NTSTATUS
6764 SampQueryUserInternal2(PSAM_DB_OBJECT UserObject,
6765                        PSAMPR_USER_INFO_BUFFER *Buffer)
6766 {
6767     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6768     SAM_USER_FIXED_DATA FixedData;
6769     ULONG Length = 0;
6770     NTSTATUS Status;
6771 
6772     *Buffer = NULL;
6773 
6774     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6775     if (InfoBuffer == NULL)
6776         return STATUS_INSUFFICIENT_RESOURCES;
6777 
6778     Length = sizeof(SAM_USER_FIXED_DATA);
6779     Status = SampGetObjectAttribute(UserObject,
6780                                     L"F",
6781                                     NULL,
6782                                     (PVOID)&FixedData,
6783                                     &Length);
6784     if (!NT_SUCCESS(Status))
6785         goto done;
6786 
6787     InfoBuffer->Internal2.Flags = 0;
6788     InfoBuffer->Internal2.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6789     InfoBuffer->Internal2.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6790     InfoBuffer->Internal2.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6791     InfoBuffer->Internal2.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6792     InfoBuffer->Internal2.BadPasswordCount = FixedData.BadPasswordCount;
6793     InfoBuffer->Internal2.LogonCount = FixedData.LogonCount;
6794 
6795     *Buffer = InfoBuffer;
6796 
6797 done:
6798     if (!NT_SUCCESS(Status))
6799     {
6800         if (InfoBuffer != NULL)
6801         {
6802             midl_user_free(InfoBuffer);
6803         }
6804     }
6805 
6806     return Status;
6807 }
6808 
6809 
6810 static NTSTATUS
6811 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6812                         PSAMPR_USER_INFO_BUFFER *Buffer)
6813 {
6814     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6815     NTSTATUS Status;
6816 
6817     *Buffer = NULL;
6818 
6819     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6820     if (InfoBuffer == NULL)
6821         return STATUS_INSUFFICIENT_RESOURCES;
6822 
6823     /* Get the Parameters string */
6824     Status = SampGetObjectAttributeString(UserObject,
6825                                           L"Parameters",
6826                                           &InfoBuffer->Parameters.Parameters);
6827     if (!NT_SUCCESS(Status))
6828     {
6829         TRACE("Status 0x%08lx\n", Status);
6830         goto done;
6831     }
6832 
6833     *Buffer = InfoBuffer;
6834 
6835 done:
6836     if (!NT_SUCCESS(Status))
6837     {
6838         if (InfoBuffer != NULL)
6839         {
6840             if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6841                 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6842 
6843             midl_user_free(InfoBuffer);
6844         }
6845     }
6846 
6847     return Status;
6848 }
6849 
6850 
6851 static NTSTATUS
6852 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6853                  PSAMPR_USER_INFO_BUFFER *Buffer)
6854 {
6855     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6856     SAM_DOMAIN_FIXED_DATA DomainFixedData;
6857     SAM_USER_FIXED_DATA FixedData;
6858     LARGE_INTEGER PasswordCanChange;
6859     LARGE_INTEGER PasswordMustChange;
6860     ULONG Length = 0;
6861     NTSTATUS Status;
6862 
6863     *Buffer = NULL;
6864 
6865     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6866     if (InfoBuffer == NULL)
6867         return STATUS_INSUFFICIENT_RESOURCES;
6868 
6869     /* Get the fixed size domain data */
6870     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6871     Status = SampGetObjectAttribute(UserObject->ParentObject,
6872                                     L"F",
6873                                     NULL,
6874                                     (PVOID)&DomainFixedData,
6875                                     &Length);
6876     if (!NT_SUCCESS(Status))
6877         goto done;
6878 
6879     /* Get the fixed size user data */
6880     Length = sizeof(SAM_USER_FIXED_DATA);
6881     Status = SampGetObjectAttribute(UserObject,
6882                                     L"F",
6883                                     NULL,
6884                                     (PVOID)&FixedData,
6885                                     &Length);
6886     if (!NT_SUCCESS(Status))
6887         goto done;
6888 
6889     /* Set the fields to be returned */
6890     if (UserObject->Trusted)
6891     {
6892         InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
6893                                       USER_ALL_READ_LOGON_MASK |
6894                                       USER_ALL_READ_ACCOUNT_MASK |
6895                                       USER_ALL_READ_PREFERENCES_MASK |
6896                                       USER_ALL_READ_TRUSTED_MASK;
6897     }
6898     else
6899     {
6900         InfoBuffer->All.WhichFields = 0;
6901 
6902         if (UserObject->Access & USER_READ_GENERAL)
6903             InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6904 
6905         if (UserObject->Access & USER_READ_LOGON)
6906             InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
6907 
6908         if (UserObject->Access & USER_READ_ACCOUNT)
6909             InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6910 
6911         if (UserObject->Access & USER_READ_PREFERENCES)
6912             InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6913     }
6914 
6915     /* Fail, if no fields are to be returned */
6916     if (InfoBuffer->All.WhichFields == 0)
6917     {
6918         Status = STATUS_ACCESS_DENIED;
6919         goto done;
6920     }
6921 
6922     /* Get the UserName attribute */
6923     if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
6924     {
6925         Status = SampGetObjectAttributeString(UserObject,
6926                                               L"Name",
6927                                               &InfoBuffer->All.UserName);
6928         if (!NT_SUCCESS(Status))
6929         {
6930             TRACE("Status 0x%08lx\n", Status);
6931             goto done;
6932         }
6933     }
6934 
6935     /* Get the FullName attribute */
6936     if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
6937     {
6938         Status = SampGetObjectAttributeString(UserObject,
6939                                               L"FullName",
6940                                               &InfoBuffer->All.FullName);
6941         if (!NT_SUCCESS(Status))
6942         {
6943             TRACE("Status 0x%08lx\n", Status);
6944             goto done;
6945         }
6946     }
6947 
6948     /* Get the UserId attribute */
6949     if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
6950     {
6951         InfoBuffer->All.UserId = FixedData.UserId;
6952     }
6953 
6954     /* Get the PrimaryGroupId attribute */
6955     if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
6956     {
6957         InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6958     }
6959 
6960     /* Get the AdminComment attribute */
6961     if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
6962     {
6963         Status = SampGetObjectAttributeString(UserObject,
6964                                               L"AdminComment",
6965                                               &InfoBuffer->All.AdminComment);
6966         if (!NT_SUCCESS(Status))
6967         {
6968             TRACE("Status 0x%08lx\n", Status);
6969             goto done;
6970         }
6971     }
6972 
6973     /* Get the UserComment attribute */
6974     if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
6975     {
6976         Status = SampGetObjectAttributeString(UserObject,
6977                                               L"UserComment",
6978                                               &InfoBuffer->All.UserComment);
6979         if (!NT_SUCCESS(Status))
6980         {
6981             TRACE("Status 0x%08lx\n", Status);
6982             goto done;
6983         }
6984     }
6985 
6986     /* Get the HomeDirectory attribute */
6987     if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
6988     {
6989         Status = SampGetObjectAttributeString(UserObject,
6990                                               L"HomeDirectory",
6991                                               &InfoBuffer->All.HomeDirectory);
6992         if (!NT_SUCCESS(Status))
6993         {
6994             TRACE("Status 0x%08lx\n", Status);
6995             goto done;
6996         }
6997     }
6998 
6999     /* Get the HomeDirectoryDrive attribute */
7000     if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7001     {
7002         Status = SampGetObjectAttributeString(UserObject,
7003                                               L"HomeDirectoryDrive",
7004                                               &InfoBuffer->Home.HomeDirectoryDrive);
7005         if (!NT_SUCCESS(Status))
7006         {
7007             TRACE("Status 0x%08lx\n", Status);
7008             goto done;
7009         }
7010     }
7011 
7012     /* Get the ScriptPath attribute */
7013     if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
7014     {
7015         Status = SampGetObjectAttributeString(UserObject,
7016                                               L"ScriptPath",
7017                                               &InfoBuffer->All.ScriptPath);
7018         if (!NT_SUCCESS(Status))
7019         {
7020             TRACE("Status 0x%08lx\n", Status);
7021             goto done;
7022         }
7023     }
7024 
7025     /* Get the ProfilePath attribute */
7026     if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
7027     {
7028         Status = SampGetObjectAttributeString(UserObject,
7029                                               L"ProfilePath",
7030                                               &InfoBuffer->All.ProfilePath);
7031         if (!NT_SUCCESS(Status))
7032         {
7033             TRACE("Status 0x%08lx\n", Status);
7034             goto done;
7035         }
7036     }
7037 
7038     /* Get the WorkStations attribute */
7039     if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
7040     {
7041         Status = SampGetObjectAttributeString(UserObject,
7042                                               L"WorkStations",
7043                                               &InfoBuffer->All.WorkStations);
7044         if (!NT_SUCCESS(Status))
7045         {
7046             TRACE("Status 0x%08lx\n", Status);
7047             goto done;
7048         }
7049     }
7050 
7051     /* Get the LastLogon attribute */
7052     if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
7053     {
7054         InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
7055         InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
7056     }
7057 
7058     /* Get the LastLogoff attribute */
7059     if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
7060     {
7061         InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
7062         InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
7063     }
7064 
7065     /* Get the LogonHours attribute */
7066     if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
7067     {
7068         Status = SampGetLogonHoursAttribute(UserObject,
7069                                             &InfoBuffer->All.LogonHours);
7070         if (!NT_SUCCESS(Status))
7071         {
7072             TRACE("Status 0x%08lx\n", Status);
7073             goto done;
7074         }
7075     }
7076 
7077     /* Get the BadPasswordCount attribute */
7078     if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
7079     {
7080         InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
7081     }
7082 
7083     /* Get the LogonCount attribute */
7084     if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
7085     {
7086         InfoBuffer->All.LogonCount = FixedData.LogonCount;
7087     }
7088 
7089     /* Get the PasswordCanChange attribute */
7090     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
7091     {
7092         PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7093                                                       DomainFixedData.MinPasswordAge);
7094         InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
7095         InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
7096     }
7097 
7098     /* Get the PasswordMustChange attribute */
7099     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
7100     {
7101         PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7102                                                        DomainFixedData.MaxPasswordAge);
7103         InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
7104         InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
7105     }
7106 
7107     /* Get the PasswordLastSet attribute */
7108     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
7109     {
7110         InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
7111         InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
7112     }
7113 
7114     /* Get the AccountExpires attribute */
7115     if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
7116     {
7117         InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
7118         InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
7119     }
7120 
7121     /* Get the UserAccountControl attribute */
7122     if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
7123     {
7124         InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
7125     }
7126 
7127     /* Get the Parameters attribute */
7128     if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
7129     {
7130         Status = SampGetObjectAttributeString(UserObject,
7131                                               L"Parameters",
7132                                               &InfoBuffer->All.Parameters);
7133         if (!NT_SUCCESS(Status))
7134         {
7135             TRACE("Status 0x%08lx\n", Status);
7136             goto done;
7137         }
7138     }
7139 
7140     /* Get the CountryCode attribute */
7141     if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
7142     {
7143         InfoBuffer->All.CountryCode = FixedData.CountryCode;
7144     }
7145 
7146     /* Get the CodePage attribute */
7147     if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
7148     {
7149         InfoBuffer->All.CodePage = FixedData.CodePage;
7150     }
7151 
7152     /* Get the LmPassword and NtPassword attributes */
7153     if (InfoBuffer->All.WhichFields & (USER_ALL_NTPASSWORDPRESENT | USER_ALL_LMPASSWORDPRESENT))
7154     {
7155         InfoBuffer->All.LmPasswordPresent = FALSE;
7156         InfoBuffer->All.NtPasswordPresent = FALSE;
7157 
7158         /* Get the NT password */
7159         Length = 0;
7160         SampGetObjectAttribute(UserObject,
7161                                L"NTPwd",
7162                                NULL,
7163                                NULL,
7164                                &Length);
7165 
7166         if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
7167         {
7168             InfoBuffer->All.NtOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_NT_OWF_PASSWORD));
7169             if (InfoBuffer->All.NtOwfPassword.Buffer == NULL)
7170             {
7171                 Status = STATUS_INSUFFICIENT_RESOURCES;
7172                 goto done;
7173             }
7174 
7175             InfoBuffer->All.NtOwfPassword.Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7176             InfoBuffer->All.NtOwfPassword.MaximumLength = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7177 
7178             Status = SampGetObjectAttribute(UserObject,
7179                                             L"NTPwd",
7180                                             NULL,
7181                                             (PVOID)InfoBuffer->All.NtOwfPassword.Buffer,
7182                                             &Length);
7183             if (!NT_SUCCESS(Status))
7184                 goto done;
7185 
7186             if (memcmp(InfoBuffer->All.NtOwfPassword.Buffer,
7187                        &EmptyNtHash,
7188                        sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
7189                 InfoBuffer->All.NtPasswordPresent = TRUE;
7190         }
7191 
7192         /* Get the LM password */
7193         Length = 0;
7194         SampGetObjectAttribute(UserObject,
7195                                L"LMPwd",
7196                                NULL,
7197                                NULL,
7198                                &Length);
7199 
7200         if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
7201         {
7202             InfoBuffer->All.LmOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_LM_OWF_PASSWORD));
7203             if (InfoBuffer->All.LmOwfPassword.Buffer == NULL)
7204             {
7205                 Status = STATUS_INSUFFICIENT_RESOURCES;
7206                 goto done;
7207             }
7208 
7209             InfoBuffer->All.LmOwfPassword.Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7210             InfoBuffer->All.LmOwfPassword.MaximumLength = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7211 
7212             Status = SampGetObjectAttribute(UserObject,
7213                                             L"LMPwd",
7214                                             NULL,
7215                                             (PVOID)InfoBuffer->All.LmOwfPassword.Buffer,
7216                                             &Length);
7217             if (!NT_SUCCESS(Status))
7218                 goto done;
7219 
7220             if (memcmp(InfoBuffer->All.LmOwfPassword.Buffer,
7221                        &EmptyLmHash,
7222                        sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7223                 InfoBuffer->All.LmPasswordPresent = TRUE;
7224         }
7225     }
7226 
7227     if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
7228     {
7229         Status = SampGetObjectAttributeString(UserObject,
7230                                               L"PrivateData",
7231                                               &InfoBuffer->All.PrivateData);
7232         if (!NT_SUCCESS(Status))
7233         {
7234             TRACE("Status 0x%08lx\n", Status);
7235             goto done;
7236         }
7237     }
7238 
7239     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
7240     {
7241         /* FIXME */
7242     }
7243 
7244     if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7245     {
7246         Length = 0;
7247         SampGetObjectAttribute(UserObject,
7248                                L"SecDesc",
7249                                NULL,
7250                                NULL,
7251                                &Length);
7252 
7253         if (Length > 0)
7254         {
7255             InfoBuffer->All.SecurityDescriptor.SecurityDescriptor = midl_user_allocate(Length);
7256             if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor == NULL)
7257             {
7258                 Status = STATUS_INSUFFICIENT_RESOURCES;
7259                 goto done;
7260             }
7261 
7262             InfoBuffer->All.SecurityDescriptor.Length = Length;
7263 
7264             Status = SampGetObjectAttribute(UserObject,
7265                                             L"SecDesc",
7266                                             NULL,
7267                                             (PVOID)InfoBuffer->All.SecurityDescriptor.SecurityDescriptor,
7268                                             &Length);
7269             if (!NT_SUCCESS(Status))
7270                 goto done;
7271         }
7272     }
7273 
7274     *Buffer = InfoBuffer;
7275 
7276 done:
7277     if (!NT_SUCCESS(Status))
7278     {
7279         if (InfoBuffer != NULL)
7280         {
7281             if (InfoBuffer->All.UserName.Buffer != NULL)
7282                 midl_user_free(InfoBuffer->All.UserName.Buffer);
7283 
7284             if (InfoBuffer->All.FullName.Buffer != NULL)
7285                 midl_user_free(InfoBuffer->All.FullName.Buffer);
7286 
7287             if (InfoBuffer->All.AdminComment.Buffer != NULL)
7288                 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
7289 
7290             if (InfoBuffer->All.UserComment.Buffer != NULL)
7291                 midl_user_free(InfoBuffer->All.UserComment.Buffer);
7292 
7293             if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
7294                 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
7295 
7296             if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
7297                 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
7298 
7299             if (InfoBuffer->All.ScriptPath.Buffer != NULL)
7300                 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
7301 
7302             if (InfoBuffer->All.ProfilePath.Buffer != NULL)
7303                 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
7304 
7305             if (InfoBuffer->All.WorkStations.Buffer != NULL)
7306                 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
7307 
7308             if (InfoBuffer->All.LogonHours.LogonHours != NULL)
7309                 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
7310 
7311             if (InfoBuffer->All.Parameters.Buffer != NULL)
7312                 midl_user_free(InfoBuffer->All.Parameters.Buffer);
7313 
7314             if (InfoBuffer->All.LmOwfPassword.Buffer != NULL)
7315                 midl_user_free(InfoBuffer->All.LmOwfPassword.Buffer);
7316 
7317             if (InfoBuffer->All.NtOwfPassword.Buffer != NULL)
7318                 midl_user_free(InfoBuffer->All.NtOwfPassword.Buffer);
7319 
7320             if (InfoBuffer->All.PrivateData.Buffer != NULL)
7321                 midl_user_free(InfoBuffer->All.PrivateData.Buffer);
7322 
7323             if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor != NULL)
7324                 midl_user_free(InfoBuffer->All.SecurityDescriptor.SecurityDescriptor);
7325 
7326             midl_user_free(InfoBuffer);
7327         }
7328     }
7329 
7330     return Status;
7331 }
7332 
7333 
7334 /* Function 36 */
7335 NTSTATUS
7336 NTAPI
7337 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
7338                          IN USER_INFORMATION_CLASS UserInformationClass,
7339                          OUT PSAMPR_USER_INFO_BUFFER *Buffer)
7340 {
7341     PSAM_DB_OBJECT UserObject;
7342     ACCESS_MASK DesiredAccess;
7343     NTSTATUS Status;
7344 
7345     TRACE("SamrQueryInformationUser(%p %lu %p)\n",
7346           UserHandle, UserInformationClass, Buffer);
7347 
7348     switch (UserInformationClass)
7349     {
7350         case UserGeneralInformation:
7351         case UserNameInformation:
7352         case UserAccountNameInformation:
7353         case UserFullNameInformation:
7354         case UserPrimaryGroupInformation:
7355         case UserAdminCommentInformation:
7356             DesiredAccess = USER_READ_GENERAL;
7357             break;
7358 
7359         case UserLogonHoursInformation:
7360         case UserHomeInformation:
7361         case UserScriptInformation:
7362         case UserProfileInformation:
7363         case UserWorkStationsInformation:
7364             DesiredAccess = USER_READ_LOGON;
7365             break;
7366 
7367         case UserControlInformation:
7368         case UserExpiresInformation:
7369         case UserParametersInformation:
7370             DesiredAccess = USER_READ_ACCOUNT;
7371             break;
7372 
7373         case UserPreferencesInformation:
7374             DesiredAccess = USER_READ_GENERAL |
7375                             USER_READ_PREFERENCES;
7376             break;
7377 
7378         case UserLogonInformation:
7379         case UserAccountInformation:
7380             DesiredAccess = USER_READ_GENERAL |
7381                             USER_READ_PREFERENCES |
7382                             USER_READ_LOGON |
7383                             USER_READ_ACCOUNT;
7384             break;
7385 
7386         case UserInternal1Information:
7387         case UserInternal2Information:
7388         case UserAllInformation:
7389             DesiredAccess = 0;
7390             break;
7391 
7392         default:
7393             return STATUS_INVALID_INFO_CLASS;
7394     }
7395 
7396     RtlAcquireResourceShared(&SampResource,
7397                              TRUE);
7398 
7399     /* Validate the domain handle */
7400     Status = SampValidateDbObject(UserHandle,
7401                                   SamDbUserObject,
7402                                   DesiredAccess,
7403                                   &UserObject);
7404     if (!NT_SUCCESS(Status))
7405     {
7406         TRACE("failed with status 0x%08lx\n", Status);
7407         goto done;
7408     }
7409 
7410     switch (UserInformationClass)
7411     {
7412         case UserGeneralInformation:
7413             Status = SampQueryUserGeneral(UserObject,
7414                                           Buffer);
7415             break;
7416 
7417         case UserPreferencesInformation:
7418             Status = SampQueryUserPreferences(UserObject,
7419                                               Buffer);
7420             break;
7421 
7422         case UserLogonInformation:
7423             Status = SampQueryUserLogon(UserObject,
7424                                         Buffer);
7425             break;
7426 
7427         case UserLogonHoursInformation:
7428             Status = SampQueryUserLogonHours(UserObject,
7429                                              Buffer);
7430             break;
7431 
7432         case UserAccountInformation:
7433             Status = SampQueryUserAccount(UserObject,
7434                                           Buffer);
7435             break;
7436 
7437         case UserNameInformation:
7438             Status = SampQueryUserName(UserObject,
7439                                        Buffer);
7440             break;
7441 
7442         case UserAccountNameInformation:
7443             Status = SampQueryUserAccountName(UserObject,
7444                                               Buffer);
7445             break;
7446 
7447         case UserFullNameInformation:
7448             Status = SampQueryUserFullName(UserObject,
7449                                            Buffer);
7450             break;
7451 
7452         case UserPrimaryGroupInformation:
7453             Status = SampQueryUserPrimaryGroup(UserObject,
7454                                                Buffer);
7455             break;
7456 
7457         case UserHomeInformation:
7458             Status = SampQueryUserHome(UserObject,
7459                                        Buffer);
7460 
7461         case UserScriptInformation:
7462             Status = SampQueryUserScript(UserObject,
7463                                          Buffer);
7464             break;
7465 
7466         case UserProfileInformation:
7467             Status = SampQueryUserProfile(UserObject,
7468                                           Buffer);
7469             break;
7470 
7471         case UserAdminCommentInformation:
7472             Status = SampQueryUserAdminComment(UserObject,
7473                                                Buffer);
7474             break;
7475 
7476         case UserWorkStationsInformation:
7477             Status = SampQueryUserWorkStations(UserObject,
7478                                                Buffer);
7479             break;
7480 
7481         case UserControlInformation:
7482             Status = SampQueryUserControl(UserObject,
7483                                           Buffer);
7484             break;
7485 
7486         case UserExpiresInformation:
7487             Status = SampQueryUserExpires(UserObject,
7488                                           Buffer);
7489             break;
7490 
7491         case UserInternal1Information:
7492             Status = SampQueryUserInternal1(UserObject,
7493                                             Buffer);
7494             break;
7495 
7496         case UserInternal2Information:
7497             Status = SampQueryUserInternal2(UserObject,
7498                                             Buffer);
7499             break;
7500 
7501         case UserParametersInformation:
7502             Status = SampQueryUserParameters(UserObject,
7503                                              Buffer);
7504             break;
7505 
7506         case UserAllInformation:
7507             Status = SampQueryUserAll(UserObject,
7508                                       Buffer);
7509             break;
7510 
7511 //        case UserInternal4Information:
7512 //        case UserInternal5Information:
7513 //        case UserInternal4InformationNew:
7514 //        case UserInternal5InformationNew:
7515 
7516         default:
7517             Status = STATUS_INVALID_INFO_CLASS;
7518     }
7519 
7520 done:
7521     RtlReleaseResource(&SampResource);
7522 
7523     return Status;
7524 }
7525 
7526 
7527 static NTSTATUS
7528 SampSetUserName(PSAM_DB_OBJECT UserObject,
7529                 PRPC_UNICODE_STRING NewUserName)
7530 {
7531     UNICODE_STRING OldUserName = {0, 0, NULL};
7532     NTSTATUS Status;
7533 
7534     /* Check the account name */
7535     Status = SampCheckAccountName(NewUserName, 20);
7536     if (!NT_SUCCESS(Status))
7537     {
7538         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
7539         return Status;
7540     }
7541 
7542     Status = SampGetObjectAttributeString(UserObject,
7543                                           L"Name",
7544                                           (PRPC_UNICODE_STRING)&OldUserName);
7545     if (!NT_SUCCESS(Status))
7546     {
7547         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
7548         goto done;
7549     }
7550 
7551     if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
7552     {
7553         Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
7554                                               NewUserName->Buffer);
7555         if (!NT_SUCCESS(Status))
7556         {
7557             TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7558                   NewUserName->Buffer, Status);
7559             goto done;
7560         }
7561     }
7562 
7563     Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7564                                         L"Users",
7565                                         NewUserName->Buffer,
7566                                         UserObject->RelativeId);
7567     if (!NT_SUCCESS(Status))
7568     {
7569         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7570         goto done;
7571     }
7572 
7573     Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7574                                              L"Users",
7575                                              OldUserName.Buffer);
7576     if (!NT_SUCCESS(Status))
7577     {
7578         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7579         goto done;
7580     }
7581 
7582     Status = SampSetObjectAttributeString(UserObject,
7583                                           L"Name",
7584                                           NewUserName);
7585     if (!NT_SUCCESS(Status))
7586     {
7587         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7588     }
7589 
7590 done:
7591     if (OldUserName.Buffer != NULL)
7592         midl_user_free(OldUserName.Buffer);
7593 
7594     return Status;
7595 }
7596 
7597 
7598 static NTSTATUS
7599 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7600                    PSAMPR_USER_INFO_BUFFER Buffer)
7601 {
7602     SAM_USER_FIXED_DATA FixedData;
7603     ULONG Length = 0;
7604     NTSTATUS Status;
7605 
7606     Length = sizeof(SAM_USER_FIXED_DATA);
7607     Status = SampGetObjectAttribute(UserObject,
7608                                     L"F",
7609                                     NULL,
7610                                     (PVOID)&FixedData,
7611                                     &Length);
7612     if (!NT_SUCCESS(Status))
7613         goto done;
7614 
7615     FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7616 
7617     Status = SampSetObjectAttribute(UserObject,
7618                                     L"F",
7619                                     REG_BINARY,
7620                                     &FixedData,
7621                                     Length);
7622     if (!NT_SUCCESS(Status))
7623         goto done;
7624 
7625     Status = SampSetUserName(UserObject,
7626                              &Buffer->General.UserName);
7627     if (!NT_SUCCESS(Status))
7628         goto done;
7629 
7630     Status = SampSetObjectAttributeString(UserObject,
7631                                           L"FullName",
7632                                           &Buffer->General.FullName);
7633     if (!NT_SUCCESS(Status))
7634         goto done;
7635 
7636     Status = SampSetObjectAttributeString(UserObject,
7637                                           L"AdminComment",
7638                                           &Buffer->General.AdminComment);
7639     if (!NT_SUCCESS(Status))
7640         goto done;
7641 
7642     Status = SampSetObjectAttributeString(UserObject,
7643                                           L"UserComment",
7644                                           &Buffer->General.UserComment);
7645 
7646 done:
7647     return Status;
7648 }
7649 
7650 
7651 static NTSTATUS
7652 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7653                        PSAMPR_USER_INFO_BUFFER Buffer)
7654 {
7655     SAM_USER_FIXED_DATA FixedData;
7656     ULONG Length = 0;
7657     NTSTATUS Status;
7658 
7659     Length = sizeof(SAM_USER_FIXED_DATA);
7660     Status = SampGetObjectAttribute(UserObject,
7661                                     L"F",
7662                                     NULL,
7663                                     (PVOID)&FixedData,
7664                                     &Length);
7665     if (!NT_SUCCESS(Status))
7666         goto done;
7667 
7668     FixedData.CountryCode = Buffer->Preferences.CountryCode;
7669     FixedData.CodePage = Buffer->Preferences.CodePage;
7670 
7671     Status = SampSetObjectAttribute(UserObject,
7672                                     L"F",
7673                                     REG_BINARY,
7674                                     &FixedData,
7675                                     Length);
7676     if (!NT_SUCCESS(Status))
7677         goto done;
7678 
7679     Status = SampSetObjectAttributeString(UserObject,
7680                                           L"UserComment",
7681                                           &Buffer->Preferences.UserComment);
7682 
7683 done:
7684     return Status;
7685 }
7686 
7687 
7688 static NTSTATUS
7689 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7690                         PSAMPR_USER_INFO_BUFFER Buffer)
7691 {
7692     SAM_USER_FIXED_DATA FixedData;
7693     ULONG Length = 0;
7694     NTSTATUS Status;
7695 
7696     Length = sizeof(SAM_USER_FIXED_DATA);
7697     Status = SampGetObjectAttribute(UserObject,
7698                                     L"F",
7699                                     NULL,
7700                                     (PVOID)&FixedData,
7701                                     &Length);
7702     if (!NT_SUCCESS(Status))
7703         goto done;
7704 
7705     FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7706 
7707     Status = SampSetObjectAttribute(UserObject,
7708                                     L"F",
7709                                     REG_BINARY,
7710                                     &FixedData,
7711                                     Length);
7712 
7713 done:
7714     return Status;
7715 }
7716 
7717 
7718 static NTSTATUS
7719 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7720                    PSAMPR_USER_INFO_BUFFER Buffer)
7721 {
7722     SAM_USER_FIXED_DATA FixedData;
7723     ULONG Length = 0;
7724     NTSTATUS Status;
7725 
7726     Length = sizeof(SAM_USER_FIXED_DATA);
7727     Status = SampGetObjectAttribute(UserObject,
7728                                     L"F",
7729                                     NULL,
7730                                     (PVOID)&FixedData,
7731                                     &Length);
7732     if (!NT_SUCCESS(Status))
7733         goto done;
7734 
7735     FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7736 
7737     Status = SampSetObjectAttribute(UserObject,
7738                                     L"F",
7739                                     REG_BINARY,
7740                                     &FixedData,
7741                                     Length);
7742 
7743 done:
7744     return Status;
7745 }
7746 
7747 
7748 static NTSTATUS
7749 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7750                    PSAMPR_USER_INFO_BUFFER Buffer)
7751 {
7752     SAM_USER_FIXED_DATA FixedData;
7753     ULONG Length = 0;
7754     NTSTATUS Status;
7755 
7756     Length = sizeof(SAM_USER_FIXED_DATA);
7757     Status = SampGetObjectAttribute(UserObject,
7758                                     L"F",
7759                                     NULL,
7760                                     (PVOID)&FixedData,
7761                                     &Length);
7762     if (!NT_SUCCESS(Status))
7763         goto done;
7764 
7765     FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7766     FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7767 
7768     Status = SampSetObjectAttribute(UserObject,
7769                                     L"F",
7770                                     REG_BINARY,
7771                                     &FixedData,
7772                                     Length);
7773 
7774 done:
7775     return Status;
7776 }
7777 
7778 
7779 static NTSTATUS
7780 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7781                      PSAMPR_USER_INFO_BUFFER Buffer)
7782 {
7783     SAM_USER_FIXED_DATA FixedData;
7784     ULONG Length = 0;
7785     NTSTATUS Status = STATUS_SUCCESS;
7786 
7787     /* FIXME: Decrypt NT password */
7788     /* FIXME: Decrypt LM password */
7789 
7790     Status = SampSetUserPassword(UserObject,
7791                                  &Buffer->Internal1.EncryptedNtOwfPassword,
7792                                  Buffer->Internal1.NtPasswordPresent,
7793                                  &Buffer->Internal1.EncryptedLmOwfPassword,
7794                                  Buffer->Internal1.LmPasswordPresent);
7795     if (!NT_SUCCESS(Status))
7796         goto done;
7797 
7798     /* Get the fixed user attributes */
7799     Length = sizeof(SAM_USER_FIXED_DATA);
7800     Status = SampGetObjectAttribute(UserObject,
7801                                     L"F",
7802                                     NULL,
7803                                     (PVOID)&FixedData,
7804                                     &Length);
7805     if (!NT_SUCCESS(Status))
7806         goto done;
7807 
7808     if (Buffer->Internal1.PasswordExpired)
7809     {
7810         /* The password was last set ages ago */
7811         FixedData.PasswordLastSet.LowPart = 0;
7812         FixedData.PasswordLastSet.HighPart = 0;
7813     }
7814     else
7815     {
7816         /* The password was last set right now */
7817         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7818         if (!NT_SUCCESS(Status))
7819             goto done;
7820     }
7821 
7822     /* Set the fixed user attributes */
7823     Status = SampSetObjectAttribute(UserObject,
7824                                     L"F",
7825                                     REG_BINARY,
7826                                     &FixedData,
7827                                     Length);
7828 
7829 done:
7830     return Status;
7831 }
7832 
7833 
7834 static NTSTATUS
7835 SampSetUserInternal2(PSAM_DB_OBJECT UserObject,
7836                      PSAMPR_USER_INFO_BUFFER Buffer)
7837 {
7838     SAM_USER_FIXED_DATA FixedData;
7839     ULONG Length = 0;
7840     NTSTATUS Status = STATUS_SUCCESS;
7841 
7842     /* Get the fixed user attributes */
7843     Length = sizeof(SAM_USER_FIXED_DATA);
7844     Status = SampGetObjectAttribute(UserObject,
7845                                     L"F",
7846                                     NULL,
7847                                     (PVOID)&FixedData,
7848                                     &Length);
7849     if (!NT_SUCCESS(Status))
7850         goto done;
7851 
7852     if ((Buffer->Internal2.Flags & USER_LOGON_SUCCESS) &&
7853         ((Buffer->Internal2.Flags & ~USER_LOGON_SUCCESS) == 0))
7854     {
7855         /* Update the LastLogon time */
7856         Status = NtQuerySystemTime(&FixedData.LastLogon);
7857         if (!NT_SUCCESS(Status))
7858             goto done;
7859 
7860         FixedData.LogonCount++;
7861         FixedData.BadPasswordCount = 0;
7862     }
7863 
7864     if ((Buffer->Internal2.Flags & USER_LOGON_BAD_PASSWORD) &&
7865         ((Buffer->Internal2.Flags & ~USER_LOGON_BAD_PASSWORD) == 0))
7866     {
7867         /* Update the LastBadPasswordTime */
7868         Status = NtQuerySystemTime(&FixedData.LastBadPasswordTime);
7869         if (!NT_SUCCESS(Status))
7870             goto done;
7871 
7872         FixedData.BadPasswordCount++;
7873     }
7874 
7875     /* Set the fixed user attributes */
7876     Status = SampSetObjectAttribute(UserObject,
7877                                     L"F",
7878                                     REG_BINARY,
7879                                     &FixedData,
7880                                     Length);
7881 
7882 done:
7883     return Status;
7884 }
7885 
7886 
7887 static NTSTATUS
7888 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7889                PSAMPR_USER_INFO_BUFFER Buffer)
7890 {
7891     SAM_USER_FIXED_DATA FixedData;
7892     ULONG Length = 0;
7893     ULONG WhichFields;
7894     PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7895     PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7896     BOOLEAN NtPasswordPresent = FALSE;
7897     BOOLEAN LmPasswordPresent = FALSE;
7898     BOOLEAN WriteFixedData = FALSE;
7899     NTSTATUS Status = STATUS_SUCCESS;
7900 
7901     WhichFields = Buffer->All.WhichFields;
7902 
7903     /* Get the fixed size attributes */
7904     Length = sizeof(SAM_USER_FIXED_DATA);
7905     Status = SampGetObjectAttribute(UserObject,
7906                                     L"F",
7907                                     NULL,
7908                                     (PVOID)&FixedData,
7909                                     &Length);
7910     if (!NT_SUCCESS(Status))
7911         goto done;
7912 
7913     if (WhichFields & USER_ALL_USERNAME)
7914     {
7915         Status = SampSetUserName(UserObject,
7916                                  &Buffer->All.UserName);
7917         if (!NT_SUCCESS(Status))
7918             goto done;
7919     }
7920 
7921     if (WhichFields & USER_ALL_FULLNAME)
7922     {
7923         Status = SampSetObjectAttributeString(UserObject,
7924                                               L"FullName",
7925                                               &Buffer->All.FullName);
7926         if (!NT_SUCCESS(Status))
7927             goto done;
7928     }
7929 
7930     if (WhichFields & USER_ALL_ADMINCOMMENT)
7931     {
7932         Status = SampSetObjectAttributeString(UserObject,
7933                                               L"AdminComment",
7934                                               &Buffer->All.AdminComment);
7935         if (!NT_SUCCESS(Status))
7936             goto done;
7937     }
7938 
7939     if (WhichFields & USER_ALL_USERCOMMENT)
7940     {
7941         Status = SampSetObjectAttributeString(UserObject,
7942                                               L"UserComment",
7943                                               &Buffer->All.UserComment);
7944         if (!NT_SUCCESS(Status))
7945             goto done;
7946     }
7947 
7948     if (WhichFields & USER_ALL_HOMEDIRECTORY)
7949     {
7950         Status = SampSetObjectAttributeString(UserObject,
7951                                               L"HomeDirectory",
7952                                               &Buffer->All.HomeDirectory);
7953         if (!NT_SUCCESS(Status))
7954             goto done;
7955     }
7956 
7957     if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7958     {
7959         Status = SampSetObjectAttributeString(UserObject,
7960                                               L"HomeDirectoryDrive",
7961                                               &Buffer->All.HomeDirectoryDrive);
7962         if (!NT_SUCCESS(Status))
7963             goto done;
7964     }
7965 
7966     if (WhichFields & USER_ALL_SCRIPTPATH)
7967     {
7968         Status = SampSetObjectAttributeString(UserObject,
7969                                               L"ScriptPath",
7970                                               &Buffer->All.ScriptPath);
7971         if (!NT_SUCCESS(Status))
7972             goto done;
7973     }
7974 
7975     if (WhichFields & USER_ALL_PROFILEPATH)
7976     {
7977         Status = SampSetObjectAttributeString(UserObject,
7978                                               L"ProfilePath",
7979                                               &Buffer->All.ProfilePath);
7980         if (!NT_SUCCESS(Status))
7981             goto done;
7982     }
7983 
7984     if (WhichFields & USER_ALL_WORKSTATIONS)
7985     {
7986         Status = SampSetObjectAttributeString(UserObject,
7987                                               L"WorkStations",
7988                                               &Buffer->All.WorkStations);
7989         if (!NT_SUCCESS(Status))
7990             goto done;
7991     }
7992 
7993     if (WhichFields & USER_ALL_PARAMETERS)
7994     {
7995         Status = SampSetObjectAttributeString(UserObject,
7996                                               L"Parameters",
7997                                               &Buffer->All.Parameters);
7998         if (!NT_SUCCESS(Status))
7999             goto done;
8000     }
8001 
8002     if (WhichFields & USER_ALL_LOGONHOURS)
8003     {
8004         Status = SampSetLogonHoursAttribute(UserObject,
8005                                            &Buffer->All.LogonHours);
8006         if (!NT_SUCCESS(Status))
8007             goto done;
8008     }
8009 
8010     if (WhichFields & USER_ALL_PRIMARYGROUPID)
8011     {
8012         FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
8013         WriteFixedData = TRUE;
8014     }
8015 
8016     if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
8017     {
8018         FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
8019         FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
8020         WriteFixedData = TRUE;
8021     }
8022 
8023     if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
8024     {
8025         FixedData.UserAccountControl = Buffer->All.UserAccountControl;
8026         WriteFixedData = TRUE;
8027     }
8028 
8029     if (WhichFields & USER_ALL_COUNTRYCODE)
8030     {
8031         FixedData.CountryCode = Buffer->All.CountryCode;
8032         WriteFixedData = TRUE;
8033     }
8034 
8035     if (WhichFields & USER_ALL_CODEPAGE)
8036     {
8037         FixedData.CodePage = Buffer->All.CodePage;
8038         WriteFixedData = TRUE;
8039     }
8040 
8041     if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
8042                        USER_ALL_LMPASSWORDPRESENT))
8043     {
8044         if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
8045         {
8046             NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
8047             NtPasswordPresent = Buffer->All.NtPasswordPresent;
8048         }
8049 
8050         if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
8051         {
8052             LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
8053             LmPasswordPresent = Buffer->All.LmPasswordPresent;
8054         }
8055 
8056         Status = SampSetUserPassword(UserObject,
8057                                      NtPassword,
8058                                      NtPasswordPresent,
8059                                      LmPassword,
8060                                      LmPasswordPresent);
8061         if (!NT_SUCCESS(Status))
8062             goto done;
8063 
8064         /* The password has just been set */
8065         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8066         if (!NT_SUCCESS(Status))
8067             goto done;
8068 
8069         WriteFixedData = TRUE;
8070     }
8071 
8072     if (WhichFields & USER_ALL_PRIVATEDATA)
8073     {
8074         Status = SampSetObjectAttributeString(UserObject,
8075                                               L"PrivateData",
8076                                               &Buffer->All.PrivateData);
8077         if (!NT_SUCCESS(Status))
8078             goto done;
8079     }
8080 
8081     if (WhichFields & USER_ALL_PASSWORDEXPIRED)
8082     {
8083         if (Buffer->All.PasswordExpired)
8084         {
8085             /* The password was last set ages ago */
8086             FixedData.PasswordLastSet.LowPart = 0;
8087             FixedData.PasswordLastSet.HighPart = 0;
8088         }
8089         else
8090         {
8091             /* The password was last set right now */
8092             Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8093             if (!NT_SUCCESS(Status))
8094                 goto done;
8095         }
8096 
8097         WriteFixedData = TRUE;
8098     }
8099 
8100     if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
8101     {
8102         Status = SampSetObjectAttribute(UserObject,
8103                                         L"SecDesc",
8104                                         REG_BINARY,
8105                                         Buffer->All.SecurityDescriptor.SecurityDescriptor,
8106                                         Buffer->All.SecurityDescriptor.Length);
8107     }
8108 
8109     if (WriteFixedData != FALSE)
8110     {
8111         Status = SampSetObjectAttribute(UserObject,
8112                                         L"F",
8113                                         REG_BINARY,
8114                                         &FixedData,
8115                                         Length);
8116         if (!NT_SUCCESS(Status))
8117             goto done;
8118     }
8119 
8120 done:
8121     return Status;
8122 }
8123 
8124 
8125 /* Function 37 */
8126 NTSTATUS
8127 NTAPI
8128 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
8129                        IN USER_INFORMATION_CLASS UserInformationClass,
8130                        IN PSAMPR_USER_INFO_BUFFER Buffer)
8131 {
8132     PSAM_DB_OBJECT UserObject;
8133     ACCESS_MASK DesiredAccess;
8134     NTSTATUS Status;
8135 
8136     TRACE("SamrSetInformationUser(%p %lu %p)\n",
8137           UserHandle, UserInformationClass, Buffer);
8138 
8139     switch (UserInformationClass)
8140     {
8141         case UserLogonHoursInformation:
8142         case UserNameInformation:
8143         case UserAccountNameInformation:
8144         case UserFullNameInformation:
8145         case UserPrimaryGroupInformation:
8146         case UserHomeInformation:
8147         case UserScriptInformation:
8148         case UserProfileInformation:
8149         case UserAdminCommentInformation:
8150         case UserWorkStationsInformation:
8151         case UserControlInformation:
8152         case UserExpiresInformation:
8153         case UserParametersInformation:
8154             DesiredAccess = USER_WRITE_ACCOUNT;
8155             break;
8156 
8157         case UserGeneralInformation:
8158             DesiredAccess = USER_WRITE_ACCOUNT |
8159                             USER_WRITE_PREFERENCES;
8160             break;
8161 
8162         case UserPreferencesInformation:
8163             DesiredAccess = USER_WRITE_PREFERENCES;
8164             break;
8165 
8166         case UserSetPasswordInformation:
8167         case UserInternal1Information:
8168             DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
8169             break;
8170 
8171         case UserAllInformation:
8172         case UserInternal2Information:
8173             DesiredAccess = 0; /* FIXME */
8174             break;
8175 
8176         default:
8177             return STATUS_INVALID_INFO_CLASS;
8178     }
8179 
8180     RtlAcquireResourceExclusive(&SampResource,
8181                                 TRUE);
8182 
8183     /* Validate the domain handle */
8184     Status = SampValidateDbObject(UserHandle,
8185                                   SamDbUserObject,
8186                                   DesiredAccess,
8187                                   &UserObject);
8188     if (!NT_SUCCESS(Status))
8189     {
8190         TRACE("failed with status 0x%08lx\n", Status);
8191         goto done;
8192     }
8193 
8194     switch (UserInformationClass)
8195     {
8196         case UserGeneralInformation:
8197             Status = SampSetUserGeneral(UserObject,
8198                                         Buffer);
8199             break;
8200 
8201         case UserPreferencesInformation:
8202             Status = SampSetUserPreferences(UserObject,
8203                                             Buffer);
8204             break;
8205 
8206         case UserLogonHoursInformation:
8207             Status = SampSetLogonHoursAttribute(UserObject,
8208                                                &Buffer->LogonHours.LogonHours);
8209             break;
8210 
8211         case UserNameInformation:
8212             Status = SampSetUserName(UserObject,
8213                                      &Buffer->Name.UserName);
8214             if (!NT_SUCCESS(Status))
8215                 break;
8216 
8217             Status = SampSetObjectAttributeString(UserObject,
8218                                                   L"FullName",
8219                                                   &Buffer->Name.FullName);
8220             break;
8221 
8222         case UserAccountNameInformation:
8223             Status = SampSetUserName(UserObject,
8224                                      &Buffer->AccountName.UserName);
8225             break;
8226 
8227         case UserFullNameInformation:
8228             Status = SampSetObjectAttributeString(UserObject,
8229                                                   L"FullName",
8230                                                   &Buffer->FullName.FullName);
8231             break;
8232 
8233         case UserPrimaryGroupInformation:
8234             Status = SampSetUserPrimaryGroup(UserObject,
8235                                              Buffer);
8236             break;
8237 
8238         case UserHomeInformation:
8239             Status = SampSetObjectAttributeString(UserObject,
8240                                                   L"HomeDirectory",
8241                                                   &Buffer->Home.HomeDirectory);
8242             if (!NT_SUCCESS(Status))
8243                 break;
8244 
8245             Status = SampSetObjectAttributeString(UserObject,
8246                                                   L"HomeDirectoryDrive",
8247                                                   &Buffer->Home.HomeDirectoryDrive);
8248             break;
8249 
8250         case UserScriptInformation:
8251             Status = SampSetObjectAttributeString(UserObject,
8252                                                   L"ScriptPath",
8253                                                   &Buffer->Script.ScriptPath);
8254             break;
8255 
8256         case UserProfileInformation:
8257             Status = SampSetObjectAttributeString(UserObject,
8258                                                   L"ProfilePath",
8259                                                   &Buffer->Profile.ProfilePath);
8260             break;
8261 
8262         case UserAdminCommentInformation:
8263             Status = SampSetObjectAttributeString(UserObject,
8264                                                   L"AdminComment",
8265                                                   &Buffer->AdminComment.AdminComment);
8266             break;
8267 
8268         case UserWorkStationsInformation:
8269             Status = SampSetObjectAttributeString(UserObject,
8270                                                   L"WorkStations",
8271                                                   &Buffer->WorkStations.WorkStations);
8272             break;
8273 
8274         case UserSetPasswordInformation:
8275             TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
8276             TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
8277 
8278             Status = SampSetObjectAttributeString(UserObject,
8279                                                   L"Password",
8280                                                   &Buffer->SetPassword.Password);
8281             break;
8282 
8283         case UserControlInformation:
8284             Status = SampSetUserControl(UserObject,
8285                                         Buffer);
8286             break;
8287 
8288         case UserExpiresInformation:
8289             Status = SampSetUserExpires(UserObject,
8290                                         Buffer);
8291             break;
8292 
8293         case UserInternal1Information:
8294             Status = SampSetUserInternal1(UserObject,
8295                                           Buffer);
8296             break;
8297 
8298         case UserInternal2Information:
8299             Status = SampSetUserInternal2(UserObject,
8300                                           Buffer);
8301             break;
8302 
8303         case UserParametersInformation:
8304             Status = SampSetObjectAttributeString(UserObject,
8305                                                   L"Parameters",
8306                                                   &Buffer->Parameters.Parameters);
8307             break;
8308 
8309         case UserAllInformation:
8310             Status = SampSetUserAll(UserObject,
8311                                     Buffer);
8312             break;
8313 
8314 //        case UserInternal4Information:
8315 //        case UserInternal5Information:
8316 //        case UserInternal4InformationNew:
8317 //        case UserInternal5InformationNew:
8318 
8319         default:
8320             Status = STATUS_INVALID_INFO_CLASS;
8321     }
8322 
8323 done:
8324     RtlReleaseResource(&SampResource);
8325 
8326     return Status;
8327 }
8328 
8329 
8330 /* Function 38 */
8331 NTSTATUS
8332 NTAPI
8333 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
8334                        IN unsigned char LmPresent,
8335                        IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
8336                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
8337                        IN unsigned char NtPresent,
8338                        IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
8339                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
8340                        IN unsigned char NtCrossEncryptionPresent,
8341                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
8342                        IN unsigned char LmCrossEncryptionPresent,
8343                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
8344 {
8345     ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
8346     ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
8347     LM_OWF_PASSWORD OldLmPassword;
8348     LM_OWF_PASSWORD NewLmPassword;
8349     NT_OWF_PASSWORD OldNtPassword;
8350     NT_OWF_PASSWORD NewNtPassword;
8351     BOOLEAN StoredLmPresent = FALSE;
8352     BOOLEAN StoredNtPresent = FALSE;
8353     BOOLEAN StoredLmEmpty = TRUE;
8354     BOOLEAN StoredNtEmpty = TRUE;
8355     PSAM_DB_OBJECT UserObject;
8356     ULONG Length;
8357     SAM_USER_FIXED_DATA UserFixedData;
8358     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8359     LARGE_INTEGER SystemTime;
8360     NTSTATUS Status;
8361 
8362     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
8363     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
8364     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
8365 
8366     TRACE("SamrChangePasswordUser(%p %u %p %p %u %p %p %u %p %u %p)\n",
8367           UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
8368           NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
8369           NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
8370 
8371     RtlAcquireResourceExclusive(&SampResource,
8372                                 TRUE);
8373 
8374     /* Validate the user handle */
8375     Status = SampValidateDbObject(UserHandle,
8376                                   SamDbUserObject,
8377                                   USER_CHANGE_PASSWORD,
8378                                   &UserObject);
8379     if (!NT_SUCCESS(Status))
8380     {
8381         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8382         goto done;
8383     }
8384 
8385     /* Get the current time */
8386     Status = NtQuerySystemTime(&SystemTime);
8387     if (!NT_SUCCESS(Status))
8388     {
8389         TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
8390         goto done;
8391     }
8392 
8393     /* Retrieve the LM password */
8394     Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
8395     Status = SampGetObjectAttribute(UserObject,
8396                                     L"LMPwd",
8397                                     NULL,
8398                                     &StoredLmPassword,
8399                                     &Length);
8400     if (NT_SUCCESS(Status))
8401     {
8402         if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
8403         {
8404             StoredLmPresent = TRUE;
8405             if (!RtlEqualMemory(&StoredLmPassword,
8406                                 &EmptyLmHash,
8407                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8408                 StoredLmEmpty = FALSE;
8409         }
8410     }
8411 
8412     /* Retrieve the NT password */
8413     Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
8414     Status = SampGetObjectAttribute(UserObject,
8415                                     L"NTPwd",
8416                                     NULL,
8417                                     &StoredNtPassword,
8418                                     &Length);
8419     if (NT_SUCCESS(Status))
8420     {
8421         if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
8422         {
8423             StoredNtPresent = TRUE;
8424             if (!RtlEqualMemory(&StoredNtPassword,
8425                                 &EmptyNtHash,
8426                                 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
8427                 StoredNtEmpty = FALSE;
8428         }
8429     }
8430 
8431     /* Retrieve the fixed size user data */
8432     Length = sizeof(SAM_USER_FIXED_DATA);
8433     Status = SampGetObjectAttribute(UserObject,
8434                                     L"F",
8435                                     NULL,
8436                                     &UserFixedData,
8437                                     &Length);
8438     if (!NT_SUCCESS(Status))
8439     {
8440         TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
8441         goto done;
8442     }
8443 
8444     /* Check if we can change the password at this time */
8445     if ((StoredLmEmpty == FALSE) || (StoredNtEmpty == FALSE))
8446     {
8447         /* Get fixed domain data */
8448         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8449         Status = SampGetObjectAttribute(UserObject->ParentObject,
8450                                         L"F",
8451                                         NULL,
8452                                         &DomainFixedData,
8453                                         &Length);
8454         if (!NT_SUCCESS(Status))
8455         {
8456             TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
8457             goto done;
8458         }
8459 
8460         if (DomainFixedData.MinPasswordAge.QuadPart > 0)
8461         {
8462             if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
8463             {
8464                 Status = STATUS_ACCOUNT_RESTRICTION;
8465                 goto done;
8466             }
8467         }
8468     }
8469 
8470     /* Decrypt the LM passwords, if present */
8471     if (LmPresent)
8472     {
8473         Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
8474                                    (const BYTE *)&StoredLmPassword,
8475                                    (LPBYTE)&NewLmPassword);
8476         if (!NT_SUCCESS(Status))
8477         {
8478             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8479             goto done;
8480         }
8481 
8482         Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
8483                                    (const BYTE *)&NewLmPassword,
8484                                    (LPBYTE)&OldLmPassword);
8485         if (!NT_SUCCESS(Status))
8486         {
8487             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8488             goto done;
8489         }
8490     }
8491 
8492     /* Decrypt the NT passwords, if present */
8493     if (NtPresent)
8494     {
8495         Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
8496                                    (const BYTE *)&StoredNtPassword,
8497                                    (LPBYTE)&NewNtPassword);
8498         if (!NT_SUCCESS(Status))
8499         {
8500             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8501             goto done;
8502         }
8503 
8504         Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
8505                                    (const BYTE *)&NewNtPassword,
8506                                    (LPBYTE)&OldNtPassword);
8507         if (!NT_SUCCESS(Status))
8508         {
8509             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8510             goto done;
8511         }
8512     }
8513 
8514     /* Check if the old passwords match the stored ones */
8515     if (NtPresent)
8516     {
8517         if (LmPresent)
8518         {
8519             if (!RtlEqualMemory(&StoredLmPassword,
8520                                 &OldLmPassword,
8521                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8522             {
8523                 TRACE("Old LM Password does not match!\n");
8524                 Status = STATUS_WRONG_PASSWORD;
8525             }
8526             else
8527             {
8528                 if (!RtlEqualMemory(&StoredNtPassword,
8529                                     &OldNtPassword,
8530                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8531                 {
8532                     TRACE("Old NT Password does not match!\n");
8533                     Status = STATUS_WRONG_PASSWORD;
8534                 }
8535             }
8536         }
8537         else
8538         {
8539             if (!RtlEqualMemory(&StoredNtPassword,
8540                                 &OldNtPassword,
8541                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8542             {
8543                 TRACE("Old NT Password does not match!\n");
8544                 Status = STATUS_WRONG_PASSWORD;
8545             }
8546         }
8547     }
8548     else
8549     {
8550         if (LmPresent)
8551         {
8552             if (!RtlEqualMemory(&StoredLmPassword,
8553                                 &OldLmPassword,
8554                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8555             {
8556                 TRACE("Old LM Password does not match!\n");
8557                 Status = STATUS_WRONG_PASSWORD;
8558             }
8559         }
8560         else
8561         {
8562             Status = STATUS_INVALID_PARAMETER;
8563         }
8564     }
8565 
8566     /* Store the new password hashes */
8567     if (NT_SUCCESS(Status))
8568     {
8569         Status = SampSetUserPassword(UserObject,
8570                                      &NewNtPassword,
8571                                      NtPresent,
8572                                      &NewLmPassword,
8573                                      LmPresent);
8574         if (NT_SUCCESS(Status))
8575         {
8576             /* Update PasswordLastSet */
8577             UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
8578 
8579             /* Set the fixed size user data */
8580             Length = sizeof(SAM_USER_FIXED_DATA);
8581             Status = SampSetObjectAttribute(UserObject,
8582                                             L"F",
8583                                             REG_BINARY,
8584                                             &UserFixedData,
8585                                             Length);
8586         }
8587     }
8588 
8589     if (Status == STATUS_WRONG_PASSWORD)
8590     {
8591         /* Update BadPasswordCount and LastBadPasswordTime */
8592         UserFixedData.BadPasswordCount++;
8593         UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
8594 
8595         /* Set the fixed size user data */
8596         Length = sizeof(SAM_USER_FIXED_DATA);
8597         Status = SampSetObjectAttribute(UserObject,
8598                                         L"F",
8599                                         REG_BINARY,
8600                                         &UserFixedData,
8601                                         Length);
8602     }
8603 
8604 done:
8605     RtlReleaseResource(&SampResource);
8606 
8607     return Status;
8608 }
8609 
8610 
8611 /* Function 39 */
8612 NTSTATUS
8613 NTAPI
8614 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
8615                      OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
8616 {
8617     PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
8618     PSAM_DB_OBJECT UserObject;
8619     ULONG Length = 0;
8620     NTSTATUS Status;
8621 
8622     TRACE("SamrGetGroupsForUser(%p %p)\n",
8623           UserHandle, Groups);
8624 
8625     RtlAcquireResourceShared(&SampResource,
8626                              TRUE);
8627 
8628     /* Validate the user handle */
8629     Status = SampValidateDbObject(UserHandle,
8630                                   SamDbUserObject,
8631                                   USER_LIST_GROUPS,
8632                                   &UserObject);
8633     if (!NT_SUCCESS(Status))
8634     {
8635         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8636         goto done;
8637     }
8638 
8639     /* Allocate the groups buffer */
8640     GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
8641     if (GroupsBuffer == NULL)
8642     {
8643         Status = STATUS_INSUFFICIENT_RESOURCES;
8644         goto done;
8645     }
8646 
8647     /*
8648      * Get the size of the Groups attribute.
8649      * Do not check the status code because in case of an error
8650      * Length will be 0. And that is all we need.
8651      */
8652     SampGetObjectAttribute(UserObject,
8653                            L"Groups",
8654                            NULL,
8655                            NULL,
8656                            &Length);
8657 
8658     /* If there is no Groups attribute, return a groups buffer without an array */
8659     if (Length == 0)
8660     {
8661         GroupsBuffer->MembershipCount = 0;
8662         GroupsBuffer->Groups = NULL;
8663 
8664         *Groups = GroupsBuffer;
8665 
8666         Status = STATUS_SUCCESS;
8667         goto done;
8668     }
8669 
8670     /* Allocate a buffer for the Groups attribute */
8671     GroupsBuffer->Groups = midl_user_allocate(Length);
8672     if (GroupsBuffer->Groups == NULL)
8673     {
8674         Status = STATUS_INSUFFICIENT_RESOURCES;
8675         goto done;
8676     }
8677 
8678     /* Retrieve the Grous attribute */
8679     Status = SampGetObjectAttribute(UserObject,
8680                                     L"Groups",
8681                                     NULL,
8682                                     GroupsBuffer->Groups,
8683                                     &Length);
8684     if (!NT_SUCCESS(Status))
8685     {
8686         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8687         goto done;
8688     }
8689 
8690     /* Calculate the membership count */
8691     GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8692 
8693     /* Return the groups buffer to the caller */
8694     *Groups = GroupsBuffer;
8695 
8696 done:
8697     if (!NT_SUCCESS(Status))
8698     {
8699         if (GroupsBuffer != NULL)
8700         {
8701             if (GroupsBuffer->Groups != NULL)
8702                 midl_user_free(GroupsBuffer->Groups);
8703 
8704             midl_user_free(GroupsBuffer);
8705         }
8706     }
8707 
8708     RtlReleaseResource(&SampResource);
8709 
8710     return Status;
8711 }
8712 
8713 
8714 /* Function 40 */
8715 NTSTATUS
8716 NTAPI
8717 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8718                             IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8719                             IN unsigned long Index,
8720                             IN unsigned long EntryCount,
8721                             IN unsigned long PreferredMaximumLength,
8722                             OUT unsigned long *TotalAvailable,
8723                             OUT unsigned long *TotalReturned,
8724                             OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8725 {
8726     UNIMPLEMENTED;
8727     return STATUS_NOT_IMPLEMENTED;
8728 }
8729 
8730 /* Function 41 */
8731 NTSTATUS
8732 NTAPI
8733 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8734                                IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8735                                IN PRPC_UNICODE_STRING Prefix,
8736                                OUT unsigned long *Index)
8737 {
8738     UNIMPLEMENTED;
8739     return STATUS_NOT_IMPLEMENTED;
8740 }
8741 
8742 /* Function 42 */
8743 NTSTATUS
8744 NTAPI
8745 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8746 {
8747     UNIMPLEMENTED;
8748     return STATUS_NOT_IMPLEMENTED;
8749 }
8750 
8751 /* Function 43 */
8752 NTSTATUS
8753 NTAPI
8754 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8755 {
8756     UNIMPLEMENTED;
8757     return STATUS_NOT_IMPLEMENTED;
8758 }
8759 
8760 
8761 /* Function 44 */
8762 NTSTATUS
8763 NTAPI
8764 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8765                                      OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8766 {
8767     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8768     SAM_USER_FIXED_DATA UserFixedData;
8769     PSAM_DB_OBJECT DomainObject;
8770     PSAM_DB_OBJECT UserObject;
8771     ULONG Length = 0;
8772     NTSTATUS Status;
8773 
8774     TRACE("SamrGetUserDomainPasswordInformation(%p %p)\n",
8775           UserHandle, PasswordInformation);
8776 
8777     RtlAcquireResourceShared(&SampResource,
8778                              TRUE);
8779 
8780     /* Validate the user handle */
8781     Status = SampValidateDbObject(UserHandle,
8782                                   SamDbUserObject,
8783                                   0,
8784                                   &UserObject);
8785     if (!NT_SUCCESS(Status))
8786     {
8787         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8788         goto done;
8789     }
8790 
8791     /* Validate the domain object */
8792     Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8793                                   SamDbDomainObject,
8794                                   DOMAIN_READ_PASSWORD_PARAMETERS,
8795                                   &DomainObject);
8796     if (!NT_SUCCESS(Status))
8797     {
8798         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8799         goto done;
8800     }
8801 
8802     /* Get fixed user data */
8803     Length = sizeof(SAM_USER_FIXED_DATA);
8804     Status = SampGetObjectAttribute(UserObject,
8805                                     L"F",
8806                                     NULL,
8807                                     (PVOID)&UserFixedData,
8808                                     &Length);
8809     if (!NT_SUCCESS(Status))
8810     {
8811         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8812         goto done;
8813     }
8814 
8815     if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8816         (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8817                                              USER_WORKSTATION_TRUST_ACCOUNT |
8818                                              USER_SERVER_TRUST_ACCOUNT)))
8819     {
8820         PasswordInformation->MinPasswordLength = 0;
8821         PasswordInformation->PasswordProperties = 0;
8822     }
8823     else
8824     {
8825         /* Get fixed domain data */
8826         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8827         Status = SampGetObjectAttribute(DomainObject,
8828                                         L"F",
8829                                         NULL,
8830                                         (PVOID)&DomainFixedData,
8831                                         &Length);
8832         if (!NT_SUCCESS(Status))
8833         {
8834             TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8835             goto done;
8836         }
8837 
8838         PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8839         PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8840     }
8841 
8842 done:
8843     RtlReleaseResource(&SampResource);
8844 
8845     return STATUS_SUCCESS;
8846 }
8847 
8848 
8849 /* Function 45 */
8850 NTSTATUS
8851 NTAPI
8852 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8853                                   IN PRPC_SID MemberSid)
8854 {
8855     PSAM_DB_OBJECT DomainObject;
8856     ULONG Rid = 0;
8857     NTSTATUS Status;
8858 
8859     TRACE("SamrRemoveMemberFromForeignDomain(%p %p)\n",
8860           DomainHandle, MemberSid);
8861 
8862     RtlAcquireResourceExclusive(&SampResource,
8863                                 TRUE);
8864 
8865     /* Validate the domain object */
8866     Status = SampValidateDbObject(DomainHandle,
8867                                   SamDbDomainObject,
8868                                   DOMAIN_LOOKUP,
8869                                   &DomainObject);
8870     if (!NT_SUCCESS(Status))
8871     {
8872         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8873         goto done;
8874     }
8875 
8876     /* Retrieve the RID from the MemberSID */
8877     Status = SampGetRidFromSid((PSID)MemberSid,
8878                                &Rid);
8879     if (!NT_SUCCESS(Status))
8880     {
8881         TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8882         goto done;
8883     }
8884 
8885     /* Fail, if the RID represents a special account */
8886     if (Rid < 1000)
8887     {
8888         TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8889         Status = STATUS_SPECIAL_ACCOUNT;
8890         goto done;
8891     }
8892 
8893     /* Remove the member from all aliases in the domain */
8894     Status = SampRemoveMemberFromAllAliases(DomainObject,
8895                                             MemberSid);
8896     if (!NT_SUCCESS(Status))
8897     {
8898         TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8899     }
8900 
8901 done:
8902     RtlReleaseResource(&SampResource);
8903 
8904     return Status;
8905 }
8906 
8907 
8908 /* Function 46 */
8909 NTSTATUS
8910 NTAPI
8911 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8912                             IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8913                             OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8914 {
8915     TRACE("SamrQueryInformationDomain2(%p %lu %p)\n",
8916           DomainHandle, DomainInformationClass, Buffer);
8917 
8918     return SamrQueryInformationDomain(DomainHandle,
8919                                       DomainInformationClass,
8920                                       Buffer);
8921 }
8922 
8923 
8924 /* Function 47 */
8925 NTSTATUS
8926 NTAPI
8927 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8928                           IN USER_INFORMATION_CLASS UserInformationClass,
8929                           OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8930 {
8931     TRACE("SamrQueryInformationUser2(%p %lu %p)\n",
8932           UserHandle, UserInformationClass, Buffer);
8933 
8934     return SamrQueryInformationUser(UserHandle,
8935                                     UserInformationClass,
8936                                     Buffer);
8937 }
8938 
8939 
8940 /* Function 48 */
8941 NTSTATUS
8942 NTAPI
8943 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8944                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8945                              IN unsigned long Index,
8946                              IN unsigned long EntryCount,
8947                              IN unsigned long PreferredMaximumLength,
8948                              OUT unsigned long *TotalAvailable,
8949                              OUT unsigned long *TotalReturned,
8950                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8951 {
8952     TRACE("SamrQueryDisplayInformation2(%p %lu %lu %lu %lu %p %p %p)\n",
8953           DomainHandle, DisplayInformationClass, Index,
8954           EntryCount, PreferredMaximumLength, TotalAvailable,
8955           TotalReturned, Buffer);
8956 
8957     return SamrQueryDisplayInformation(DomainHandle,
8958                                        DisplayInformationClass,
8959                                        Index,
8960                                        EntryCount,
8961                                        PreferredMaximumLength,
8962                                        TotalAvailable,
8963                                        TotalReturned,
8964                                        Buffer);
8965 }
8966 
8967 
8968 /* Function 49 */
8969 NTSTATUS
8970 NTAPI
8971 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8972                                 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8973                                 IN PRPC_UNICODE_STRING Prefix,
8974                                 OUT unsigned long *Index)
8975 {
8976     TRACE("SamrGetDisplayEnumerationIndex2(%p %lu %p %p)\n",
8977           DomainHandle, DisplayInformationClass, Prefix, Index);
8978 
8979     return SamrGetDisplayEnumerationIndex(DomainHandle,
8980                                           DisplayInformationClass,
8981                                           Prefix,
8982                                           Index);
8983 }
8984 
8985 
8986 /* Function 50 */
8987 NTSTATUS
8988 NTAPI
8989 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8990                         IN PRPC_UNICODE_STRING Name,
8991                         IN unsigned long AccountType,
8992                         IN ACCESS_MASK DesiredAccess,
8993                         OUT SAMPR_HANDLE *UserHandle,
8994                         OUT unsigned long *GrantedAccess,
8995                         OUT unsigned long *RelativeId)
8996 {
8997     SAM_DOMAIN_FIXED_DATA FixedDomainData;
8998     SAM_USER_FIXED_DATA FixedUserData;
8999     PSAM_DB_OBJECT DomainObject;
9000     PSAM_DB_OBJECT UserObject;
9001     GROUP_MEMBERSHIP GroupMembership;
9002     UCHAR LogonHours[23];
9003     ULONG ulSize;
9004     ULONG ulRid;
9005     WCHAR szRid[9];
9006     PSECURITY_DESCRIPTOR Sd = NULL;
9007     ULONG SdSize = 0;
9008     PSID UserSid = NULL;
9009     NTSTATUS Status;
9010 
9011     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
9012           DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
9013 
9014     if (Name == NULL ||
9015         Name->Length == 0 ||
9016         Name->Buffer == NULL ||
9017         UserHandle == NULL ||
9018         RelativeId == NULL)
9019         return STATUS_INVALID_PARAMETER;
9020 
9021     /* Check for valid account type */
9022     if (AccountType != USER_NORMAL_ACCOUNT &&
9023         AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
9024         AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
9025         AccountType != USER_SERVER_TRUST_ACCOUNT &&
9026         AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
9027         return STATUS_INVALID_PARAMETER;
9028 
9029     /* Map generic access rights */
9030     RtlMapGenericMask(&DesiredAccess,
9031                       &UserMapping);
9032 
9033     RtlAcquireResourceExclusive(&SampResource,
9034                                 TRUE);
9035 
9036     /* Validate the domain handle */
9037     Status = SampValidateDbObject(DomainHandle,
9038                                   SamDbDomainObject,
9039                                   DOMAIN_CREATE_USER,
9040                                   &DomainObject);
9041     if (!NT_SUCCESS(Status))
9042     {
9043         TRACE("failed with status 0x%08lx\n", Status);
9044         goto done;
9045     }
9046 
9047     /* Check the user account name */
9048     Status = SampCheckAccountName(Name, 20);
9049     if (!NT_SUCCESS(Status))
9050     {
9051         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
9052         goto done;
9053     }
9054 
9055     /* Check if the user name already exists in the domain */
9056     Status = SampCheckAccountNameInDomain(DomainObject,
9057                                           Name->Buffer);
9058     if (!NT_SUCCESS(Status))
9059     {
9060         TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
9061               Name->Buffer, Status);
9062         goto done;
9063     }
9064 
9065     /* Get the fixed domain attributes */
9066     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
9067     Status = SampGetObjectAttribute(DomainObject,
9068                                     L"F",
9069                                     NULL,
9070                                     (PVOID)&FixedDomainData,
9071                                     &ulSize);
9072     if (!NT_SUCCESS(Status))
9073     {
9074         TRACE("failed with status 0x%08lx\n", Status);
9075         goto done;
9076     }
9077 
9078     /* Increment the NextRid attribute */
9079     ulRid = FixedDomainData.NextRid;
9080     FixedDomainData.NextRid++;
9081 
9082     TRACE("RID: %lx\n", ulRid);
9083 
9084     /* Create the user SID */
9085     Status = SampCreateAccountSid(DomainObject,
9086                                   ulRid,
9087                                   &UserSid);
9088     if (!NT_SUCCESS(Status))
9089     {
9090         TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
9091         goto done;
9092     }
9093 
9094     /* Create the security descriptor */
9095     Status = SampCreateUserSD(UserSid,
9096                               &Sd,
9097                               &SdSize);
9098     if (!NT_SUCCESS(Status))
9099     {
9100         TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
9101         goto done;
9102     }
9103 
9104     /* Store the fixed domain attributes */
9105     Status = SampSetObjectAttribute(DomainObject,
9106                                     L"F",
9107                                     REG_BINARY,
9108                                     &FixedDomainData,
9109                                     ulSize);
9110     if (!NT_SUCCESS(Status))
9111     {
9112         TRACE("failed with status 0x%08lx\n", Status);
9113         goto done;
9114     }
9115 
9116     /* Convert the RID into a string (hex) */
9117     swprintf(szRid, L"%08lX", ulRid);
9118 
9119     /* Create the user object */
9120     Status = SampCreateDbObject(DomainObject,
9121                                 L"Users",
9122                                 szRid,
9123                                 ulRid,
9124                                 SamDbUserObject,
9125                                 DesiredAccess,
9126                                 &UserObject);
9127     if (!NT_SUCCESS(Status))
9128     {
9129         TRACE("failed with status 0x%08lx\n", Status);
9130         goto done;
9131     }
9132 
9133     /* Add the account name for the user object */
9134     Status = SampSetAccountNameInDomain(DomainObject,
9135                                         L"Users",
9136                                         Name->Buffer,
9137                                         ulRid);
9138     if (!NT_SUCCESS(Status))
9139     {
9140         TRACE("failed with status 0x%08lx\n", Status);
9141         goto done;
9142     }
9143 
9144     /* Initialize fixed user data */
9145     FixedUserData.Version = 1;
9146     FixedUserData.Reserved = 0;
9147     FixedUserData.LastLogon.QuadPart = 0;
9148     FixedUserData.LastLogoff.QuadPart = 0;
9149     FixedUserData.PasswordLastSet.QuadPart = 0;
9150     FixedUserData.AccountExpires.LowPart = MAXULONG;
9151     FixedUserData.AccountExpires.HighPart = MAXLONG;
9152     FixedUserData.LastBadPasswordTime.QuadPart = 0;
9153     FixedUserData.UserId = ulRid;
9154     FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
9155     FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
9156                                        USER_PASSWORD_NOT_REQUIRED |
9157                                        AccountType;
9158     FixedUserData.CountryCode = 0;
9159     FixedUserData.CodePage = 0;
9160     FixedUserData.BadPasswordCount = 0;
9161     FixedUserData.LogonCount = 0;
9162     FixedUserData.AdminCount = 0;
9163     FixedUserData.OperatorCount = 0;
9164 
9165     /* Set fixed user data attribute */
9166     Status = SampSetObjectAttribute(UserObject,
9167                                     L"F",
9168                                     REG_BINARY,
9169                                     (LPVOID)&FixedUserData,
9170                                     sizeof(SAM_USER_FIXED_DATA));
9171     if (!NT_SUCCESS(Status))
9172     {
9173         TRACE("failed with status 0x%08lx\n", Status);
9174         goto done;
9175     }
9176 
9177     /* Set the Name attribute */
9178     Status = SampSetObjectAttributeString(UserObject,
9179                                           L"Name",
9180                                           Name);
9181     if (!NT_SUCCESS(Status))
9182     {
9183         TRACE("failed with status 0x%08lx\n", Status);
9184         goto done;
9185     }
9186 
9187     /* Set the FullName attribute */
9188     Status = SampSetObjectAttributeString(UserObject,
9189                                           L"FullName",
9190                                           NULL);
9191     if (!NT_SUCCESS(Status))
9192     {
9193         TRACE("failed with status 0x%08lx\n", Status);
9194         goto done;
9195     }
9196 
9197     /* Set the HomeDirectory attribute */
9198     Status = SampSetObjectAttributeString(UserObject,
9199                                           L"HomeDirectory",
9200                                           NULL);
9201     if (!NT_SUCCESS(Status))
9202     {
9203         TRACE("failed with status 0x%08lx\n", Status);
9204         goto done;
9205     }
9206 
9207     /* Set the HomeDirectoryDrive attribute */
9208     Status = SampSetObjectAttributeString(UserObject,
9209                                           L"HomeDirectoryDrive",
9210                                           NULL);
9211     if (!NT_SUCCESS(Status))
9212     {
9213         TRACE("failed with status 0x%08lx\n", Status);
9214         goto done;
9215     }
9216 
9217     /* Set the ScriptPath attribute */
9218     Status = SampSetObjectAttributeString(UserObject,
9219                                           L"ScriptPath",
9220                                           NULL);
9221     if (!NT_SUCCESS(Status))
9222     {
9223         TRACE("failed with status 0x%08lx\n", Status);
9224         goto done;
9225     }
9226 
9227     /* Set the ProfilePath attribute */
9228     Status = SampSetObjectAttributeString(UserObject,
9229                                           L"ProfilePath",
9230                                           NULL);
9231     if (!NT_SUCCESS(Status))
9232     {
9233         TRACE("failed with status 0x%08lx\n", Status);
9234         goto done;
9235     }
9236 
9237     /* Set the AdminComment attribute */
9238     Status = SampSetObjectAttributeString(UserObject,
9239                                           L"AdminComment",
9240                                           NULL);
9241     if (!NT_SUCCESS(Status))
9242     {
9243         TRACE("failed with status 0x%08lx\n", Status);
9244         goto done;
9245     }
9246 
9247     /* Set the UserComment attribute */
9248     Status = SampSetObjectAttributeString(UserObject,
9249                                           L"UserComment",
9250                                           NULL);
9251     if (!NT_SUCCESS(Status))
9252     {
9253         TRACE("failed with status 0x%08lx\n", Status);
9254         goto done;
9255     }
9256 
9257     /* Set the WorkStations attribute */
9258     Status = SampSetObjectAttributeString(UserObject,
9259                                           L"WorkStations",
9260                                           NULL);
9261     if (!NT_SUCCESS(Status))
9262     {
9263         TRACE("failed with status 0x%08lx\n", Status);
9264         goto done;
9265     }
9266 
9267     /* Set the Parameters attribute */
9268     Status = SampSetObjectAttributeString(UserObject,
9269                                           L"Parameters",
9270                                           NULL);
9271     if (!NT_SUCCESS(Status))
9272     {
9273         TRACE("failed with status 0x%08lx\n", Status);
9274         goto done;
9275     }
9276 
9277     /* Set LogonHours attribute*/
9278     *((PUSHORT)LogonHours) = 168;
9279     memset(&(LogonHours[2]), 0xff, 21);
9280 
9281     Status = SampSetObjectAttribute(UserObject,
9282                                     L"LogonHours",
9283                                     REG_BINARY,
9284                                     &LogonHours,
9285                                     sizeof(LogonHours));
9286     if (!NT_SUCCESS(Status))
9287     {
9288         TRACE("failed with status 0x%08lx\n", Status);
9289         goto done;
9290     }
9291 
9292     /* Set Groups attribute*/
9293     GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
9294     GroupMembership.Attributes = SE_GROUP_MANDATORY |
9295                                  SE_GROUP_ENABLED |
9296                                  SE_GROUP_ENABLED_BY_DEFAULT;
9297 
9298     Status = SampSetObjectAttribute(UserObject,
9299                                     L"Groups",
9300                                     REG_BINARY,
9301                                     &GroupMembership,
9302                                     sizeof(GROUP_MEMBERSHIP));
9303     if (!NT_SUCCESS(Status))
9304     {
9305         TRACE("failed with status 0x%08lx\n", Status);
9306         goto done;
9307     }
9308 
9309     /* Set LMPwd attribute*/
9310     Status = SampSetObjectAttribute(UserObject,
9311                                     L"LMPwd",
9312                                     REG_BINARY,
9313                                     NULL,
9314                                     0);
9315     if (!NT_SUCCESS(Status))
9316     {
9317         TRACE("failed with status 0x%08lx\n", Status);
9318         goto done;
9319     }
9320 
9321     /* Set NTPwd attribute*/
9322     Status = SampSetObjectAttribute(UserObject,
9323                                     L"NTPwd",
9324                                     REG_BINARY,
9325                                     NULL,
9326                                     0);
9327     if (!NT_SUCCESS(Status))
9328     {
9329         TRACE("failed with status 0x%08lx\n", Status);
9330         goto done;
9331     }
9332 
9333     /* Set LMPwdHistory attribute*/
9334     Status = SampSetObjectAttribute(UserObject,
9335                                     L"LMPwdHistory",
9336                                     REG_BINARY,
9337                                     NULL,
9338                                     0);
9339     if (!NT_SUCCESS(Status))
9340     {
9341         TRACE("failed with status 0x%08lx\n", Status);
9342         goto done;
9343     }
9344 
9345     /* Set NTPwdHistory attribute*/
9346     Status = SampSetObjectAttribute(UserObject,
9347                                     L"NTPwdHistory",
9348                                     REG_BINARY,
9349                                     NULL,
9350                                     0);
9351     if (!NT_SUCCESS(Status))
9352     {
9353         TRACE("failed with status 0x%08lx\n", Status);
9354         goto done;
9355     }
9356 
9357     /* Set the PrivateData attribute */
9358     Status = SampSetObjectAttributeString(UserObject,
9359                                           L"PrivateData",
9360                                           NULL);
9361     if (!NT_SUCCESS(Status))
9362     {
9363         TRACE("failed with status 0x%08lx\n", Status);
9364         goto done;
9365     }
9366 
9367     /* Set the SecDesc attribute*/
9368     Status = SampSetObjectAttribute(UserObject,
9369                                     L"SecDesc",
9370                                     REG_BINARY,
9371                                     Sd,
9372                                     SdSize);
9373     if (!NT_SUCCESS(Status))
9374     {
9375         TRACE("failed with status 0x%08lx\n", Status);
9376         goto done;
9377     }
9378 
9379     if (NT_SUCCESS(Status))
9380     {
9381         *UserHandle = (SAMPR_HANDLE)UserObject;
9382         *RelativeId = ulRid;
9383         *GrantedAccess = UserObject->Access;
9384     }
9385 
9386 done:
9387     if (Sd != NULL)
9388         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
9389 
9390     if (UserSid != NULL)
9391         RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
9392 
9393     RtlReleaseResource(&SampResource);
9394 
9395     TRACE("returns with status 0x%08lx\n", Status);
9396 
9397     return Status;
9398 }
9399 
9400 
9401 /* Function 51 */
9402 NTSTATUS
9403 NTAPI
9404 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
9405                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
9406                              IN unsigned long Index,
9407                              IN unsigned long EntryCount,
9408                              IN unsigned long PreferredMaximumLength,
9409                              OUT unsigned long *TotalAvailable,
9410                              OUT unsigned long *TotalReturned,
9411                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
9412 {
9413     TRACE("SamrQueryDisplayInformation3(%p %lu %lu %lu %lu %p %p %p)\n",
9414           DomainHandle, DisplayInformationClass, Index,
9415           EntryCount, PreferredMaximumLength, TotalAvailable,
9416           TotalReturned, Buffer);
9417 
9418     return SamrQueryDisplayInformation(DomainHandle,
9419                                        DisplayInformationClass,
9420                                        Index,
9421                                        EntryCount,
9422                                        PreferredMaximumLength,
9423                                        TotalAvailable,
9424                                        TotalReturned,
9425                                        Buffer);
9426 }
9427 
9428 
9429 /* Function 52 */
9430 NTSTATUS
9431 NTAPI
9432 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
9433                               IN PSAMPR_PSID_ARRAY MembersBuffer)
9434 {
9435     ULONG i;
9436     NTSTATUS Status = STATUS_SUCCESS;
9437 
9438     TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
9439           AliasHandle, MembersBuffer);
9440 
9441     for (i = 0; i < MembersBuffer->Count; i++)
9442     {
9443         Status = SamrAddMemberToAlias(AliasHandle,
9444                                       ((PSID *)MembersBuffer->Sids)[i]);
9445 
9446         if (Status == STATUS_MEMBER_IN_ALIAS)
9447             Status = STATUS_SUCCESS;
9448 
9449         if (!NT_SUCCESS(Status))
9450             break;
9451     }
9452 
9453     return Status;
9454 }
9455 
9456 
9457 /* Function 53 */
9458 NTSTATUS
9459 NTAPI
9460 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
9461                                    IN PSAMPR_PSID_ARRAY MembersBuffer)
9462 {
9463     ULONG i;
9464     NTSTATUS Status = STATUS_SUCCESS;
9465 
9466     TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
9467           AliasHandle, MembersBuffer);
9468 
9469     for (i = 0; i < MembersBuffer->Count; i++)
9470     {
9471         Status = SamrRemoveMemberFromAlias(AliasHandle,
9472                                            ((PSID *)MembersBuffer->Sids)[i]);
9473 
9474         if (Status == STATUS_MEMBER_IN_ALIAS)
9475             Status = STATUS_SUCCESS;
9476 
9477         if (!NT_SUCCESS(Status))
9478             break;
9479     }
9480 
9481     return Status;
9482 }
9483 
9484 
9485 /* Function 54 */
9486 NTSTATUS
9487 NTAPI
9488 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
9489                            IN PRPC_STRING ServerName,
9490                            IN PRPC_STRING UserName,
9491                            IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9492                            IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
9493 {
9494     UNIMPLEMENTED;
9495     return STATUS_NOT_IMPLEMENTED;
9496 }
9497 
9498 /* Function 55 */
9499 NTSTATUS
9500 NTAPI
9501 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
9502                                IN PRPC_UNICODE_STRING ServerName,
9503                                IN PRPC_UNICODE_STRING UserName,
9504                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
9505                                IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
9506                                IN unsigned char LmPresent,
9507                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9508                                IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
9509 {
9510     UNIMPLEMENTED;
9511     return STATUS_NOT_IMPLEMENTED;
9512 }
9513 
9514 
9515 /* Function 56 */
9516 NTSTATUS
9517 NTAPI
9518 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
9519                                  IN PRPC_UNICODE_STRING Unused,
9520                                  OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
9521 {
9522     SAMPR_HANDLE ServerHandle = NULL;
9523     PSAM_DB_OBJECT DomainObject = NULL;
9524     SAM_DOMAIN_FIXED_DATA FixedData;
9525     ULONG Length;
9526     NTSTATUS Status;
9527 
9528     TRACE("SamrGetDomainPasswordInformation(%p %p %p)\n",
9529           BindingHandle, Unused, PasswordInformation);
9530 
9531     Status = SamrConnect(NULL,
9532                          &ServerHandle,
9533                          SAM_SERVER_LOOKUP_DOMAIN);
9534     if (!NT_SUCCESS(Status))
9535     {
9536         TRACE("SamrConnect() failed (Status 0x%08lx)\n", Status);
9537         goto done;
9538     }
9539 
9540     Status = SampOpenDbObject((PSAM_DB_OBJECT)ServerHandle,
9541                               L"Domains",
9542                               L"Account",
9543                               0,
9544                               SamDbDomainObject,
9545                               DOMAIN_READ_PASSWORD_PARAMETERS,
9546                               &DomainObject);
9547     if (!NT_SUCCESS(Status))
9548     {
9549         TRACE("SampOpenDbObject() failed (Status 0x%08lx)\n", Status);
9550         goto done;
9551     }
9552 
9553     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
9554     Status = SampGetObjectAttribute(DomainObject,
9555                                     L"F",
9556                                     NULL,
9557                                     &FixedData,
9558                                     &Length);
9559     if (!NT_SUCCESS(Status))
9560     {
9561         TRACE("SampGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
9562         goto done;
9563     }
9564 
9565     PasswordInformation->MinPasswordLength = FixedData.MinPasswordLength;
9566     PasswordInformation->PasswordProperties = FixedData.PasswordProperties;
9567 
9568 done:
9569     if (DomainObject != NULL)
9570         SampCloseDbObject(DomainObject);
9571 
9572     if (ServerHandle != NULL)
9573         SamrCloseHandle(ServerHandle);
9574 
9575     return Status;
9576 }
9577 
9578 
9579 /* Function 57 */
9580 NTSTATUS
9581 NTAPI
9582 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
9583              OUT SAMPR_HANDLE *ServerHandle,
9584              IN ACCESS_MASK DesiredAccess)
9585 {
9586     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9587     ULONG OutVersion;
9588 
9589     TRACE("SamrConnect2(%p %p %lx)\n",
9590           ServerName, ServerHandle, DesiredAccess);
9591 
9592     InRevisionInfo.V1.Revision = 1;
9593     InRevisionInfo.V1.SupportedFeatures = 0;
9594 
9595     return SamrConnect5(ServerName,
9596                         DesiredAccess,
9597                         1,
9598                         &InRevisionInfo,
9599                         &OutVersion,
9600                         &OutRevisionInfo,
9601                         ServerHandle);
9602 }
9603 
9604 
9605 /* Function 58 */
9606 NTSTATUS
9607 NTAPI
9608 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
9609                         IN USER_INFORMATION_CLASS UserInformationClass,
9610                         IN PSAMPR_USER_INFO_BUFFER Buffer)
9611 {
9612     TRACE("SamrSetInformationUser2(%p %lu %p)\n",
9613           UserHandle, UserInformationClass, Buffer);
9614 
9615     return SamrSetInformationUser(UserHandle,
9616                                   UserInformationClass,
9617                                   Buffer);
9618 }
9619 
9620 
9621 /* Function 59 */
9622 NTSTATUS
9623 NTAPI
9624 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9625 {
9626     UNIMPLEMENTED;
9627     return STATUS_NOT_IMPLEMENTED;
9628 }
9629 
9630 /* Function 60 */
9631 NTSTATUS
9632 NTAPI
9633 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9634 {
9635     UNIMPLEMENTED;
9636     return STATUS_NOT_IMPLEMENTED;
9637 }
9638 
9639 /* Function 61 */
9640 NTSTATUS
9641 NTAPI
9642 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
9643 {
9644     UNIMPLEMENTED;
9645     return STATUS_NOT_IMPLEMENTED;
9646 }
9647 
9648 
9649 /* Function 62 */
9650 NTSTATUS
9651 NTAPI
9652 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
9653              OUT SAMPR_HANDLE *ServerHandle,
9654              IN unsigned long ClientRevision,
9655              IN ACCESS_MASK DesiredAccess)
9656 {
9657     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9658     ULONG OutVersion;
9659 
9660     TRACE("SamrConnect4(%p %p %lu 0x%lx)\n",
9661           ServerName, ServerHandle, ClientRevision, DesiredAccess);
9662 
9663     InRevisionInfo.V1.Revision = 2;
9664     InRevisionInfo.V1.SupportedFeatures = 0;
9665 
9666     return SamrConnect5(ServerName,
9667                         DesiredAccess,
9668                         1,
9669                         &InRevisionInfo,
9670                         &OutVersion,
9671                         &OutRevisionInfo,
9672                         ServerHandle);
9673 }
9674 
9675 
9676 /* Function 63 */
9677 NTSTATUS
9678 NTAPI
9679 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
9680 {
9681     UNIMPLEMENTED;
9682     return STATUS_NOT_IMPLEMENTED;
9683 }
9684 
9685 
9686 /* Function 64 */
9687 NTSTATUS
9688 NTAPI
9689 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
9690              IN ACCESS_MASK DesiredAccess,
9691              IN unsigned long InVersion,
9692              IN SAMPR_REVISION_INFO *InRevisionInfo,
9693              OUT unsigned long *OutVersion,
9694              OUT SAMPR_REVISION_INFO *OutRevisionInfo,
9695              OUT SAMPR_HANDLE *ServerHandle)
9696 {
9697     PSAM_DB_OBJECT ServerObject;
9698     NTSTATUS Status;
9699 
9700     TRACE("SamrConnect5(%p 0x%lx %lu %p %p %p %p)\n",
9701           ServerName, DesiredAccess, InVersion, InRevisionInfo,
9702           OutVersion, OutRevisionInfo, ServerHandle);
9703 
9704     if (InVersion != 1)
9705         return STATUS_NOT_SUPPORTED;
9706 
9707     RtlAcquireResourceShared(&SampResource,
9708                              TRUE);
9709 
9710     /* Map generic access rights */
9711     RtlMapGenericMask(&DesiredAccess,
9712                       &ServerMapping);
9713 
9714     /* Open the Server Object */
9715     Status = SampOpenDbObject(NULL,
9716                               NULL,
9717                               L"SAM",
9718                               0,
9719                               SamDbServerObject,
9720                               DesiredAccess,
9721                               &ServerObject);
9722     if (NT_SUCCESS(Status))
9723     {
9724         *OutVersion = 1;
9725 
9726         OutRevisionInfo->V1.Revision = 3;
9727         OutRevisionInfo->V1.SupportedFeatures = 0;
9728 
9729         *ServerHandle = (SAMPR_HANDLE)ServerObject;
9730     }
9731 
9732     RtlReleaseResource(&SampResource);
9733 
9734     TRACE("SamrConnect5 done (Status 0x%08lx)\n", Status);
9735 
9736     return Status;
9737 }
9738 
9739 
9740 /* Function 65 */
9741 NTSTATUS
9742 NTAPI
9743 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
9744              IN unsigned long Rid,
9745              OUT PRPC_SID *Sid)
9746 {
9747     UNIMPLEMENTED;
9748     return STATUS_NOT_IMPLEMENTED;
9749 }
9750 
9751 /* Function 66 */
9752 NTSTATUS
9753 NTAPI
9754 SamrSetDSRMPassword(IN handle_t BindingHandle,
9755                     IN PRPC_UNICODE_STRING Unused,
9756                     IN unsigned long UserId,
9757                     IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
9758 {
9759     UNIMPLEMENTED;
9760     return STATUS_NOT_IMPLEMENTED;
9761 }
9762 
9763 /* Function 67 */
9764 NTSTATUS
9765 NTAPI
9766 SamrValidatePassword(IN handle_t Handle,
9767                      IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
9768                      IN PSAM_VALIDATE_INPUT_ARG InputArg,
9769                      OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
9770 {
9771     UNIMPLEMENTED;
9772     return STATUS_NOT_IMPLEMENTED;
9773 }
9774 
9775 /* EOF */
9776