xref: /reactos/dll/win32/samsrv/samrpc.c (revision c8d07514)
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             break;
7461 
7462         case UserScriptInformation:
7463             Status = SampQueryUserScript(UserObject,
7464                                          Buffer);
7465             break;
7466 
7467         case UserProfileInformation:
7468             Status = SampQueryUserProfile(UserObject,
7469                                           Buffer);
7470             break;
7471 
7472         case UserAdminCommentInformation:
7473             Status = SampQueryUserAdminComment(UserObject,
7474                                                Buffer);
7475             break;
7476 
7477         case UserWorkStationsInformation:
7478             Status = SampQueryUserWorkStations(UserObject,
7479                                                Buffer);
7480             break;
7481 
7482         case UserControlInformation:
7483             Status = SampQueryUserControl(UserObject,
7484                                           Buffer);
7485             break;
7486 
7487         case UserExpiresInformation:
7488             Status = SampQueryUserExpires(UserObject,
7489                                           Buffer);
7490             break;
7491 
7492         case UserInternal1Information:
7493             Status = SampQueryUserInternal1(UserObject,
7494                                             Buffer);
7495             break;
7496 
7497         case UserInternal2Information:
7498             Status = SampQueryUserInternal2(UserObject,
7499                                             Buffer);
7500             break;
7501 
7502         case UserParametersInformation:
7503             Status = SampQueryUserParameters(UserObject,
7504                                              Buffer);
7505             break;
7506 
7507         case UserAllInformation:
7508             Status = SampQueryUserAll(UserObject,
7509                                       Buffer);
7510             break;
7511 
7512 //        case UserInternal4Information:
7513 //        case UserInternal5Information:
7514 //        case UserInternal4InformationNew:
7515 //        case UserInternal5InformationNew:
7516 
7517         default:
7518             Status = STATUS_INVALID_INFO_CLASS;
7519     }
7520 
7521 done:
7522     RtlReleaseResource(&SampResource);
7523 
7524     return Status;
7525 }
7526 
7527 
7528 static NTSTATUS
7529 SampSetUserName(PSAM_DB_OBJECT UserObject,
7530                 PRPC_UNICODE_STRING NewUserName)
7531 {
7532     UNICODE_STRING OldUserName = {0, 0, NULL};
7533     NTSTATUS Status;
7534 
7535     /* Check the account name */
7536     Status = SampCheckAccountName(NewUserName, 20);
7537     if (!NT_SUCCESS(Status))
7538     {
7539         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
7540         return Status;
7541     }
7542 
7543     Status = SampGetObjectAttributeString(UserObject,
7544                                           L"Name",
7545                                           (PRPC_UNICODE_STRING)&OldUserName);
7546     if (!NT_SUCCESS(Status))
7547     {
7548         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
7549         goto done;
7550     }
7551 
7552     if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
7553     {
7554         Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
7555                                               NewUserName->Buffer);
7556         if (!NT_SUCCESS(Status))
7557         {
7558             TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7559                   NewUserName->Buffer, Status);
7560             goto done;
7561         }
7562     }
7563 
7564     Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7565                                         L"Users",
7566                                         NewUserName->Buffer,
7567                                         UserObject->RelativeId);
7568     if (!NT_SUCCESS(Status))
7569     {
7570         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7571         goto done;
7572     }
7573 
7574     Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7575                                              L"Users",
7576                                              OldUserName.Buffer);
7577     if (!NT_SUCCESS(Status))
7578     {
7579         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7580         goto done;
7581     }
7582 
7583     Status = SampSetObjectAttributeString(UserObject,
7584                                           L"Name",
7585                                           NewUserName);
7586     if (!NT_SUCCESS(Status))
7587     {
7588         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7589     }
7590 
7591 done:
7592     if (OldUserName.Buffer != NULL)
7593         midl_user_free(OldUserName.Buffer);
7594 
7595     return Status;
7596 }
7597 
7598 
7599 static NTSTATUS
7600 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7601                    PSAMPR_USER_INFO_BUFFER Buffer)
7602 {
7603     SAM_USER_FIXED_DATA FixedData;
7604     ULONG Length = 0;
7605     NTSTATUS Status;
7606 
7607     Length = sizeof(SAM_USER_FIXED_DATA);
7608     Status = SampGetObjectAttribute(UserObject,
7609                                     L"F",
7610                                     NULL,
7611                                     (PVOID)&FixedData,
7612                                     &Length);
7613     if (!NT_SUCCESS(Status))
7614         goto done;
7615 
7616     FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7617 
7618     Status = SampSetObjectAttribute(UserObject,
7619                                     L"F",
7620                                     REG_BINARY,
7621                                     &FixedData,
7622                                     Length);
7623     if (!NT_SUCCESS(Status))
7624         goto done;
7625 
7626     Status = SampSetUserName(UserObject,
7627                              &Buffer->General.UserName);
7628     if (!NT_SUCCESS(Status))
7629         goto done;
7630 
7631     Status = SampSetObjectAttributeString(UserObject,
7632                                           L"FullName",
7633                                           &Buffer->General.FullName);
7634     if (!NT_SUCCESS(Status))
7635         goto done;
7636 
7637     Status = SampSetObjectAttributeString(UserObject,
7638                                           L"AdminComment",
7639                                           &Buffer->General.AdminComment);
7640     if (!NT_SUCCESS(Status))
7641         goto done;
7642 
7643     Status = SampSetObjectAttributeString(UserObject,
7644                                           L"UserComment",
7645                                           &Buffer->General.UserComment);
7646 
7647 done:
7648     return Status;
7649 }
7650 
7651 
7652 static NTSTATUS
7653 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7654                        PSAMPR_USER_INFO_BUFFER Buffer)
7655 {
7656     SAM_USER_FIXED_DATA FixedData;
7657     ULONG Length = 0;
7658     NTSTATUS Status;
7659 
7660     Length = sizeof(SAM_USER_FIXED_DATA);
7661     Status = SampGetObjectAttribute(UserObject,
7662                                     L"F",
7663                                     NULL,
7664                                     (PVOID)&FixedData,
7665                                     &Length);
7666     if (!NT_SUCCESS(Status))
7667         goto done;
7668 
7669     FixedData.CountryCode = Buffer->Preferences.CountryCode;
7670     FixedData.CodePage = Buffer->Preferences.CodePage;
7671 
7672     Status = SampSetObjectAttribute(UserObject,
7673                                     L"F",
7674                                     REG_BINARY,
7675                                     &FixedData,
7676                                     Length);
7677     if (!NT_SUCCESS(Status))
7678         goto done;
7679 
7680     Status = SampSetObjectAttributeString(UserObject,
7681                                           L"UserComment",
7682                                           &Buffer->Preferences.UserComment);
7683 
7684 done:
7685     return Status;
7686 }
7687 
7688 
7689 static NTSTATUS
7690 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7691                         PSAMPR_USER_INFO_BUFFER Buffer)
7692 {
7693     SAM_USER_FIXED_DATA FixedData;
7694     ULONG Length = 0;
7695     NTSTATUS Status;
7696 
7697     Length = sizeof(SAM_USER_FIXED_DATA);
7698     Status = SampGetObjectAttribute(UserObject,
7699                                     L"F",
7700                                     NULL,
7701                                     (PVOID)&FixedData,
7702                                     &Length);
7703     if (!NT_SUCCESS(Status))
7704         goto done;
7705 
7706     FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7707 
7708     Status = SampSetObjectAttribute(UserObject,
7709                                     L"F",
7710                                     REG_BINARY,
7711                                     &FixedData,
7712                                     Length);
7713 
7714 done:
7715     return Status;
7716 }
7717 
7718 
7719 static NTSTATUS
7720 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7721                    PSAMPR_USER_INFO_BUFFER Buffer)
7722 {
7723     SAM_USER_FIXED_DATA FixedData;
7724     ULONG Length = 0;
7725     NTSTATUS Status;
7726 
7727     Length = sizeof(SAM_USER_FIXED_DATA);
7728     Status = SampGetObjectAttribute(UserObject,
7729                                     L"F",
7730                                     NULL,
7731                                     (PVOID)&FixedData,
7732                                     &Length);
7733     if (!NT_SUCCESS(Status))
7734         goto done;
7735 
7736     FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7737 
7738     Status = SampSetObjectAttribute(UserObject,
7739                                     L"F",
7740                                     REG_BINARY,
7741                                     &FixedData,
7742                                     Length);
7743 
7744 done:
7745     return Status;
7746 }
7747 
7748 
7749 static NTSTATUS
7750 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7751                    PSAMPR_USER_INFO_BUFFER Buffer)
7752 {
7753     SAM_USER_FIXED_DATA FixedData;
7754     ULONG Length = 0;
7755     NTSTATUS Status;
7756 
7757     Length = sizeof(SAM_USER_FIXED_DATA);
7758     Status = SampGetObjectAttribute(UserObject,
7759                                     L"F",
7760                                     NULL,
7761                                     (PVOID)&FixedData,
7762                                     &Length);
7763     if (!NT_SUCCESS(Status))
7764         goto done;
7765 
7766     FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7767     FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7768 
7769     Status = SampSetObjectAttribute(UserObject,
7770                                     L"F",
7771                                     REG_BINARY,
7772                                     &FixedData,
7773                                     Length);
7774 
7775 done:
7776     return Status;
7777 }
7778 
7779 
7780 static NTSTATUS
7781 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7782                      PSAMPR_USER_INFO_BUFFER Buffer)
7783 {
7784     SAM_USER_FIXED_DATA FixedData;
7785     ULONG Length = 0;
7786     NTSTATUS Status = STATUS_SUCCESS;
7787 
7788     /* FIXME: Decrypt NT password */
7789     /* FIXME: Decrypt LM password */
7790 
7791     Status = SampSetUserPassword(UserObject,
7792                                  &Buffer->Internal1.EncryptedNtOwfPassword,
7793                                  Buffer->Internal1.NtPasswordPresent,
7794                                  &Buffer->Internal1.EncryptedLmOwfPassword,
7795                                  Buffer->Internal1.LmPasswordPresent);
7796     if (!NT_SUCCESS(Status))
7797         goto done;
7798 
7799     /* Get the fixed user attributes */
7800     Length = sizeof(SAM_USER_FIXED_DATA);
7801     Status = SampGetObjectAttribute(UserObject,
7802                                     L"F",
7803                                     NULL,
7804                                     (PVOID)&FixedData,
7805                                     &Length);
7806     if (!NT_SUCCESS(Status))
7807         goto done;
7808 
7809     if (Buffer->Internal1.PasswordExpired)
7810     {
7811         /* The password was last set ages ago */
7812         FixedData.PasswordLastSet.LowPart = 0;
7813         FixedData.PasswordLastSet.HighPart = 0;
7814     }
7815     else
7816     {
7817         /* The password was last set right now */
7818         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7819         if (!NT_SUCCESS(Status))
7820             goto done;
7821     }
7822 
7823     /* Set the fixed user attributes */
7824     Status = SampSetObjectAttribute(UserObject,
7825                                     L"F",
7826                                     REG_BINARY,
7827                                     &FixedData,
7828                                     Length);
7829 
7830 done:
7831     return Status;
7832 }
7833 
7834 
7835 static NTSTATUS
7836 SampSetUserInternal2(PSAM_DB_OBJECT UserObject,
7837                      PSAMPR_USER_INFO_BUFFER Buffer)
7838 {
7839     SAM_USER_FIXED_DATA FixedData;
7840     ULONG Length = 0;
7841     NTSTATUS Status = STATUS_SUCCESS;
7842 
7843     /* Get the fixed user attributes */
7844     Length = sizeof(SAM_USER_FIXED_DATA);
7845     Status = SampGetObjectAttribute(UserObject,
7846                                     L"F",
7847                                     NULL,
7848                                     (PVOID)&FixedData,
7849                                     &Length);
7850     if (!NT_SUCCESS(Status))
7851         goto done;
7852 
7853     if ((Buffer->Internal2.Flags & USER_LOGON_SUCCESS) &&
7854         ((Buffer->Internal2.Flags & ~USER_LOGON_SUCCESS) == 0))
7855     {
7856         /* Update the LastLogon time */
7857         Status = NtQuerySystemTime(&FixedData.LastLogon);
7858         if (!NT_SUCCESS(Status))
7859             goto done;
7860 
7861         FixedData.LogonCount++;
7862         FixedData.BadPasswordCount = 0;
7863     }
7864 
7865     if ((Buffer->Internal2.Flags & USER_LOGON_BAD_PASSWORD) &&
7866         ((Buffer->Internal2.Flags & ~USER_LOGON_BAD_PASSWORD) == 0))
7867     {
7868         /* Update the LastBadPasswordTime */
7869         Status = NtQuerySystemTime(&FixedData.LastBadPasswordTime);
7870         if (!NT_SUCCESS(Status))
7871             goto done;
7872 
7873         FixedData.BadPasswordCount++;
7874     }
7875 
7876     /* Set the fixed user attributes */
7877     Status = SampSetObjectAttribute(UserObject,
7878                                     L"F",
7879                                     REG_BINARY,
7880                                     &FixedData,
7881                                     Length);
7882 
7883 done:
7884     return Status;
7885 }
7886 
7887 
7888 static NTSTATUS
7889 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7890                PSAMPR_USER_INFO_BUFFER Buffer)
7891 {
7892     SAM_USER_FIXED_DATA FixedData;
7893     ULONG Length = 0;
7894     ULONG WhichFields;
7895     PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7896     PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7897     BOOLEAN NtPasswordPresent = FALSE;
7898     BOOLEAN LmPasswordPresent = FALSE;
7899     BOOLEAN WriteFixedData = FALSE;
7900     NTSTATUS Status = STATUS_SUCCESS;
7901 
7902     WhichFields = Buffer->All.WhichFields;
7903 
7904     /* Get the fixed size attributes */
7905     Length = sizeof(SAM_USER_FIXED_DATA);
7906     Status = SampGetObjectAttribute(UserObject,
7907                                     L"F",
7908                                     NULL,
7909                                     (PVOID)&FixedData,
7910                                     &Length);
7911     if (!NT_SUCCESS(Status))
7912         goto done;
7913 
7914     if (WhichFields & USER_ALL_USERNAME)
7915     {
7916         Status = SampSetUserName(UserObject,
7917                                  &Buffer->All.UserName);
7918         if (!NT_SUCCESS(Status))
7919             goto done;
7920     }
7921 
7922     if (WhichFields & USER_ALL_FULLNAME)
7923     {
7924         Status = SampSetObjectAttributeString(UserObject,
7925                                               L"FullName",
7926                                               &Buffer->All.FullName);
7927         if (!NT_SUCCESS(Status))
7928             goto done;
7929     }
7930 
7931     if (WhichFields & USER_ALL_ADMINCOMMENT)
7932     {
7933         Status = SampSetObjectAttributeString(UserObject,
7934                                               L"AdminComment",
7935                                               &Buffer->All.AdminComment);
7936         if (!NT_SUCCESS(Status))
7937             goto done;
7938     }
7939 
7940     if (WhichFields & USER_ALL_USERCOMMENT)
7941     {
7942         Status = SampSetObjectAttributeString(UserObject,
7943                                               L"UserComment",
7944                                               &Buffer->All.UserComment);
7945         if (!NT_SUCCESS(Status))
7946             goto done;
7947     }
7948 
7949     if (WhichFields & USER_ALL_HOMEDIRECTORY)
7950     {
7951         Status = SampSetObjectAttributeString(UserObject,
7952                                               L"HomeDirectory",
7953                                               &Buffer->All.HomeDirectory);
7954         if (!NT_SUCCESS(Status))
7955             goto done;
7956     }
7957 
7958     if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7959     {
7960         Status = SampSetObjectAttributeString(UserObject,
7961                                               L"HomeDirectoryDrive",
7962                                               &Buffer->All.HomeDirectoryDrive);
7963         if (!NT_SUCCESS(Status))
7964             goto done;
7965     }
7966 
7967     if (WhichFields & USER_ALL_SCRIPTPATH)
7968     {
7969         Status = SampSetObjectAttributeString(UserObject,
7970                                               L"ScriptPath",
7971                                               &Buffer->All.ScriptPath);
7972         if (!NT_SUCCESS(Status))
7973             goto done;
7974     }
7975 
7976     if (WhichFields & USER_ALL_PROFILEPATH)
7977     {
7978         Status = SampSetObjectAttributeString(UserObject,
7979                                               L"ProfilePath",
7980                                               &Buffer->All.ProfilePath);
7981         if (!NT_SUCCESS(Status))
7982             goto done;
7983     }
7984 
7985     if (WhichFields & USER_ALL_WORKSTATIONS)
7986     {
7987         Status = SampSetObjectAttributeString(UserObject,
7988                                               L"WorkStations",
7989                                               &Buffer->All.WorkStations);
7990         if (!NT_SUCCESS(Status))
7991             goto done;
7992     }
7993 
7994     if (WhichFields & USER_ALL_PARAMETERS)
7995     {
7996         Status = SampSetObjectAttributeString(UserObject,
7997                                               L"Parameters",
7998                                               &Buffer->All.Parameters);
7999         if (!NT_SUCCESS(Status))
8000             goto done;
8001     }
8002 
8003     if (WhichFields & USER_ALL_LOGONHOURS)
8004     {
8005         Status = SampSetLogonHoursAttribute(UserObject,
8006                                            &Buffer->All.LogonHours);
8007         if (!NT_SUCCESS(Status))
8008             goto done;
8009     }
8010 
8011     if (WhichFields & USER_ALL_PRIMARYGROUPID)
8012     {
8013         FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
8014         WriteFixedData = TRUE;
8015     }
8016 
8017     if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
8018     {
8019         FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
8020         FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
8021         WriteFixedData = TRUE;
8022     }
8023 
8024     if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
8025     {
8026         FixedData.UserAccountControl = Buffer->All.UserAccountControl;
8027         WriteFixedData = TRUE;
8028     }
8029 
8030     if (WhichFields & USER_ALL_COUNTRYCODE)
8031     {
8032         FixedData.CountryCode = Buffer->All.CountryCode;
8033         WriteFixedData = TRUE;
8034     }
8035 
8036     if (WhichFields & USER_ALL_CODEPAGE)
8037     {
8038         FixedData.CodePage = Buffer->All.CodePage;
8039         WriteFixedData = TRUE;
8040     }
8041 
8042     if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
8043                        USER_ALL_LMPASSWORDPRESENT))
8044     {
8045         if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
8046         {
8047             NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
8048             NtPasswordPresent = Buffer->All.NtPasswordPresent;
8049         }
8050 
8051         if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
8052         {
8053             LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
8054             LmPasswordPresent = Buffer->All.LmPasswordPresent;
8055         }
8056 
8057         Status = SampSetUserPassword(UserObject,
8058                                      NtPassword,
8059                                      NtPasswordPresent,
8060                                      LmPassword,
8061                                      LmPasswordPresent);
8062         if (!NT_SUCCESS(Status))
8063             goto done;
8064 
8065         /* The password has just been set */
8066         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8067         if (!NT_SUCCESS(Status))
8068             goto done;
8069 
8070         WriteFixedData = TRUE;
8071     }
8072 
8073     if (WhichFields & USER_ALL_PRIVATEDATA)
8074     {
8075         Status = SampSetObjectAttributeString(UserObject,
8076                                               L"PrivateData",
8077                                               &Buffer->All.PrivateData);
8078         if (!NT_SUCCESS(Status))
8079             goto done;
8080     }
8081 
8082     if (WhichFields & USER_ALL_PASSWORDEXPIRED)
8083     {
8084         if (Buffer->All.PasswordExpired)
8085         {
8086             /* The password was last set ages ago */
8087             FixedData.PasswordLastSet.LowPart = 0;
8088             FixedData.PasswordLastSet.HighPart = 0;
8089         }
8090         else
8091         {
8092             /* The password was last set right now */
8093             Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8094             if (!NT_SUCCESS(Status))
8095                 goto done;
8096         }
8097 
8098         WriteFixedData = TRUE;
8099     }
8100 
8101     if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
8102     {
8103         Status = SampSetObjectAttribute(UserObject,
8104                                         L"SecDesc",
8105                                         REG_BINARY,
8106                                         Buffer->All.SecurityDescriptor.SecurityDescriptor,
8107                                         Buffer->All.SecurityDescriptor.Length);
8108     }
8109 
8110     if (WriteFixedData != FALSE)
8111     {
8112         Status = SampSetObjectAttribute(UserObject,
8113                                         L"F",
8114                                         REG_BINARY,
8115                                         &FixedData,
8116                                         Length);
8117         if (!NT_SUCCESS(Status))
8118             goto done;
8119     }
8120 
8121 done:
8122     return Status;
8123 }
8124 
8125 
8126 /* Function 37 */
8127 NTSTATUS
8128 NTAPI
8129 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
8130                        IN USER_INFORMATION_CLASS UserInformationClass,
8131                        IN PSAMPR_USER_INFO_BUFFER Buffer)
8132 {
8133     PSAM_DB_OBJECT UserObject;
8134     ACCESS_MASK DesiredAccess;
8135     NTSTATUS Status;
8136 
8137     TRACE("SamrSetInformationUser(%p %lu %p)\n",
8138           UserHandle, UserInformationClass, Buffer);
8139 
8140     switch (UserInformationClass)
8141     {
8142         case UserLogonHoursInformation:
8143         case UserNameInformation:
8144         case UserAccountNameInformation:
8145         case UserFullNameInformation:
8146         case UserPrimaryGroupInformation:
8147         case UserHomeInformation:
8148         case UserScriptInformation:
8149         case UserProfileInformation:
8150         case UserAdminCommentInformation:
8151         case UserWorkStationsInformation:
8152         case UserControlInformation:
8153         case UserExpiresInformation:
8154         case UserParametersInformation:
8155             DesiredAccess = USER_WRITE_ACCOUNT;
8156             break;
8157 
8158         case UserGeneralInformation:
8159             DesiredAccess = USER_WRITE_ACCOUNT |
8160                             USER_WRITE_PREFERENCES;
8161             break;
8162 
8163         case UserPreferencesInformation:
8164             DesiredAccess = USER_WRITE_PREFERENCES;
8165             break;
8166 
8167         case UserSetPasswordInformation:
8168         case UserInternal1Information:
8169             DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
8170             break;
8171 
8172         case UserAllInformation:
8173         case UserInternal2Information:
8174             DesiredAccess = 0; /* FIXME */
8175             break;
8176 
8177         default:
8178             return STATUS_INVALID_INFO_CLASS;
8179     }
8180 
8181     RtlAcquireResourceExclusive(&SampResource,
8182                                 TRUE);
8183 
8184     /* Validate the domain handle */
8185     Status = SampValidateDbObject(UserHandle,
8186                                   SamDbUserObject,
8187                                   DesiredAccess,
8188                                   &UserObject);
8189     if (!NT_SUCCESS(Status))
8190     {
8191         TRACE("failed with status 0x%08lx\n", Status);
8192         goto done;
8193     }
8194 
8195     switch (UserInformationClass)
8196     {
8197         case UserGeneralInformation:
8198             Status = SampSetUserGeneral(UserObject,
8199                                         Buffer);
8200             break;
8201 
8202         case UserPreferencesInformation:
8203             Status = SampSetUserPreferences(UserObject,
8204                                             Buffer);
8205             break;
8206 
8207         case UserLogonHoursInformation:
8208             Status = SampSetLogonHoursAttribute(UserObject,
8209                                                &Buffer->LogonHours.LogonHours);
8210             break;
8211 
8212         case UserNameInformation:
8213             Status = SampSetUserName(UserObject,
8214                                      &Buffer->Name.UserName);
8215             if (!NT_SUCCESS(Status))
8216                 break;
8217 
8218             Status = SampSetObjectAttributeString(UserObject,
8219                                                   L"FullName",
8220                                                   &Buffer->Name.FullName);
8221             break;
8222 
8223         case UserAccountNameInformation:
8224             Status = SampSetUserName(UserObject,
8225                                      &Buffer->AccountName.UserName);
8226             break;
8227 
8228         case UserFullNameInformation:
8229             Status = SampSetObjectAttributeString(UserObject,
8230                                                   L"FullName",
8231                                                   &Buffer->FullName.FullName);
8232             break;
8233 
8234         case UserPrimaryGroupInformation:
8235             Status = SampSetUserPrimaryGroup(UserObject,
8236                                              Buffer);
8237             break;
8238 
8239         case UserHomeInformation:
8240             Status = SampSetObjectAttributeString(UserObject,
8241                                                   L"HomeDirectory",
8242                                                   &Buffer->Home.HomeDirectory);
8243             if (!NT_SUCCESS(Status))
8244                 break;
8245 
8246             Status = SampSetObjectAttributeString(UserObject,
8247                                                   L"HomeDirectoryDrive",
8248                                                   &Buffer->Home.HomeDirectoryDrive);
8249             break;
8250 
8251         case UserScriptInformation:
8252             Status = SampSetObjectAttributeString(UserObject,
8253                                                   L"ScriptPath",
8254                                                   &Buffer->Script.ScriptPath);
8255             break;
8256 
8257         case UserProfileInformation:
8258             Status = SampSetObjectAttributeString(UserObject,
8259                                                   L"ProfilePath",
8260                                                   &Buffer->Profile.ProfilePath);
8261             break;
8262 
8263         case UserAdminCommentInformation:
8264             Status = SampSetObjectAttributeString(UserObject,
8265                                                   L"AdminComment",
8266                                                   &Buffer->AdminComment.AdminComment);
8267             break;
8268 
8269         case UserWorkStationsInformation:
8270             Status = SampSetObjectAttributeString(UserObject,
8271                                                   L"WorkStations",
8272                                                   &Buffer->WorkStations.WorkStations);
8273             break;
8274 
8275         case UserSetPasswordInformation:
8276             TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
8277             TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
8278 
8279             Status = SampSetObjectAttributeString(UserObject,
8280                                                   L"Password",
8281                                                   &Buffer->SetPassword.Password);
8282             break;
8283 
8284         case UserControlInformation:
8285             Status = SampSetUserControl(UserObject,
8286                                         Buffer);
8287             break;
8288 
8289         case UserExpiresInformation:
8290             Status = SampSetUserExpires(UserObject,
8291                                         Buffer);
8292             break;
8293 
8294         case UserInternal1Information:
8295             Status = SampSetUserInternal1(UserObject,
8296                                           Buffer);
8297             break;
8298 
8299         case UserInternal2Information:
8300             Status = SampSetUserInternal2(UserObject,
8301                                           Buffer);
8302             break;
8303 
8304         case UserParametersInformation:
8305             Status = SampSetObjectAttributeString(UserObject,
8306                                                   L"Parameters",
8307                                                   &Buffer->Parameters.Parameters);
8308             break;
8309 
8310         case UserAllInformation:
8311             Status = SampSetUserAll(UserObject,
8312                                     Buffer);
8313             break;
8314 
8315 //        case UserInternal4Information:
8316 //        case UserInternal5Information:
8317 //        case UserInternal4InformationNew:
8318 //        case UserInternal5InformationNew:
8319 
8320         default:
8321             Status = STATUS_INVALID_INFO_CLASS;
8322     }
8323 
8324 done:
8325     RtlReleaseResource(&SampResource);
8326 
8327     return Status;
8328 }
8329 
8330 
8331 /* Function 38 */
8332 NTSTATUS
8333 NTAPI
8334 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
8335                        IN unsigned char LmPresent,
8336                        IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
8337                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
8338                        IN unsigned char NtPresent,
8339                        IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
8340                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
8341                        IN unsigned char NtCrossEncryptionPresent,
8342                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
8343                        IN unsigned char LmCrossEncryptionPresent,
8344                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
8345 {
8346     ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
8347     ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
8348     LM_OWF_PASSWORD OldLmPassword;
8349     LM_OWF_PASSWORD NewLmPassword;
8350     NT_OWF_PASSWORD OldNtPassword;
8351     NT_OWF_PASSWORD NewNtPassword;
8352     BOOLEAN StoredLmPresent = FALSE;
8353     BOOLEAN StoredNtPresent = FALSE;
8354     BOOLEAN StoredLmEmpty = TRUE;
8355     BOOLEAN StoredNtEmpty = TRUE;
8356     PSAM_DB_OBJECT UserObject;
8357     ULONG Length;
8358     SAM_USER_FIXED_DATA UserFixedData;
8359     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8360     LARGE_INTEGER SystemTime;
8361     NTSTATUS Status;
8362 
8363     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
8364     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
8365     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
8366 
8367     TRACE("SamrChangePasswordUser(%p %u %p %p %u %p %p %u %p %u %p)\n",
8368           UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
8369           NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
8370           NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
8371 
8372     RtlAcquireResourceExclusive(&SampResource,
8373                                 TRUE);
8374 
8375     /* Validate the user handle */
8376     Status = SampValidateDbObject(UserHandle,
8377                                   SamDbUserObject,
8378                                   USER_CHANGE_PASSWORD,
8379                                   &UserObject);
8380     if (!NT_SUCCESS(Status))
8381     {
8382         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8383         goto done;
8384     }
8385 
8386     /* Get the current time */
8387     Status = NtQuerySystemTime(&SystemTime);
8388     if (!NT_SUCCESS(Status))
8389     {
8390         TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
8391         goto done;
8392     }
8393 
8394     /* Retrieve the LM password */
8395     Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
8396     Status = SampGetObjectAttribute(UserObject,
8397                                     L"LMPwd",
8398                                     NULL,
8399                                     &StoredLmPassword,
8400                                     &Length);
8401     if (NT_SUCCESS(Status))
8402     {
8403         if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
8404         {
8405             StoredLmPresent = TRUE;
8406             if (!RtlEqualMemory(&StoredLmPassword,
8407                                 &EmptyLmHash,
8408                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8409                 StoredLmEmpty = FALSE;
8410         }
8411     }
8412 
8413     /* Retrieve the NT password */
8414     Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
8415     Status = SampGetObjectAttribute(UserObject,
8416                                     L"NTPwd",
8417                                     NULL,
8418                                     &StoredNtPassword,
8419                                     &Length);
8420     if (NT_SUCCESS(Status))
8421     {
8422         if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
8423         {
8424             StoredNtPresent = TRUE;
8425             if (!RtlEqualMemory(&StoredNtPassword,
8426                                 &EmptyNtHash,
8427                                 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
8428                 StoredNtEmpty = FALSE;
8429         }
8430     }
8431 
8432     /* Retrieve the fixed size user data */
8433     Length = sizeof(SAM_USER_FIXED_DATA);
8434     Status = SampGetObjectAttribute(UserObject,
8435                                     L"F",
8436                                     NULL,
8437                                     &UserFixedData,
8438                                     &Length);
8439     if (!NT_SUCCESS(Status))
8440     {
8441         TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
8442         goto done;
8443     }
8444 
8445     /* Check if we can change the password at this time */
8446     if ((StoredLmEmpty == FALSE) || (StoredNtEmpty == FALSE))
8447     {
8448         /* Get fixed domain data */
8449         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8450         Status = SampGetObjectAttribute(UserObject->ParentObject,
8451                                         L"F",
8452                                         NULL,
8453                                         &DomainFixedData,
8454                                         &Length);
8455         if (!NT_SUCCESS(Status))
8456         {
8457             TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
8458             goto done;
8459         }
8460 
8461         if (DomainFixedData.MinPasswordAge.QuadPart > 0)
8462         {
8463             if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
8464             {
8465                 Status = STATUS_ACCOUNT_RESTRICTION;
8466                 goto done;
8467             }
8468         }
8469     }
8470 
8471     /* Decrypt the LM passwords, if present */
8472     if (LmPresent)
8473     {
8474         Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
8475                                    (const BYTE *)&StoredLmPassword,
8476                                    (LPBYTE)&NewLmPassword);
8477         if (!NT_SUCCESS(Status))
8478         {
8479             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8480             goto done;
8481         }
8482 
8483         Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
8484                                    (const BYTE *)&NewLmPassword,
8485                                    (LPBYTE)&OldLmPassword);
8486         if (!NT_SUCCESS(Status))
8487         {
8488             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8489             goto done;
8490         }
8491     }
8492 
8493     /* Decrypt the NT passwords, if present */
8494     if (NtPresent)
8495     {
8496         Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
8497                                    (const BYTE *)&StoredNtPassword,
8498                                    (LPBYTE)&NewNtPassword);
8499         if (!NT_SUCCESS(Status))
8500         {
8501             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8502             goto done;
8503         }
8504 
8505         Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
8506                                    (const BYTE *)&NewNtPassword,
8507                                    (LPBYTE)&OldNtPassword);
8508         if (!NT_SUCCESS(Status))
8509         {
8510             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8511             goto done;
8512         }
8513     }
8514 
8515     /* Check if the old passwords match the stored ones */
8516     if (NtPresent)
8517     {
8518         if (LmPresent)
8519         {
8520             if (!RtlEqualMemory(&StoredLmPassword,
8521                                 &OldLmPassword,
8522                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8523             {
8524                 TRACE("Old LM Password does not match!\n");
8525                 Status = STATUS_WRONG_PASSWORD;
8526             }
8527             else
8528             {
8529                 if (!RtlEqualMemory(&StoredNtPassword,
8530                                     &OldNtPassword,
8531                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8532                 {
8533                     TRACE("Old NT Password does not match!\n");
8534                     Status = STATUS_WRONG_PASSWORD;
8535                 }
8536             }
8537         }
8538         else
8539         {
8540             if (!RtlEqualMemory(&StoredNtPassword,
8541                                 &OldNtPassword,
8542                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8543             {
8544                 TRACE("Old NT Password does not match!\n");
8545                 Status = STATUS_WRONG_PASSWORD;
8546             }
8547         }
8548     }
8549     else
8550     {
8551         if (LmPresent)
8552         {
8553             if (!RtlEqualMemory(&StoredLmPassword,
8554                                 &OldLmPassword,
8555                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8556             {
8557                 TRACE("Old LM Password does not match!\n");
8558                 Status = STATUS_WRONG_PASSWORD;
8559             }
8560         }
8561         else
8562         {
8563             Status = STATUS_INVALID_PARAMETER;
8564         }
8565     }
8566 
8567     /* Store the new password hashes */
8568     if (NT_SUCCESS(Status))
8569     {
8570         Status = SampSetUserPassword(UserObject,
8571                                      &NewNtPassword,
8572                                      NtPresent,
8573                                      &NewLmPassword,
8574                                      LmPresent);
8575         if (NT_SUCCESS(Status))
8576         {
8577             /* Update PasswordLastSet */
8578             UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
8579 
8580             /* Set the fixed size user data */
8581             Length = sizeof(SAM_USER_FIXED_DATA);
8582             Status = SampSetObjectAttribute(UserObject,
8583                                             L"F",
8584                                             REG_BINARY,
8585                                             &UserFixedData,
8586                                             Length);
8587         }
8588     }
8589 
8590     if (Status == STATUS_WRONG_PASSWORD)
8591     {
8592         /* Update BadPasswordCount and LastBadPasswordTime */
8593         UserFixedData.BadPasswordCount++;
8594         UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
8595 
8596         /* Set the fixed size user data */
8597         Length = sizeof(SAM_USER_FIXED_DATA);
8598         Status = SampSetObjectAttribute(UserObject,
8599                                         L"F",
8600                                         REG_BINARY,
8601                                         &UserFixedData,
8602                                         Length);
8603     }
8604 
8605 done:
8606     RtlReleaseResource(&SampResource);
8607 
8608     return Status;
8609 }
8610 
8611 
8612 /* Function 39 */
8613 NTSTATUS
8614 NTAPI
8615 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
8616                      OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
8617 {
8618     PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
8619     PSAM_DB_OBJECT UserObject;
8620     ULONG Length = 0;
8621     NTSTATUS Status;
8622 
8623     TRACE("SamrGetGroupsForUser(%p %p)\n",
8624           UserHandle, Groups);
8625 
8626     RtlAcquireResourceShared(&SampResource,
8627                              TRUE);
8628 
8629     /* Validate the user handle */
8630     Status = SampValidateDbObject(UserHandle,
8631                                   SamDbUserObject,
8632                                   USER_LIST_GROUPS,
8633                                   &UserObject);
8634     if (!NT_SUCCESS(Status))
8635     {
8636         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8637         goto done;
8638     }
8639 
8640     /* Allocate the groups buffer */
8641     GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
8642     if (GroupsBuffer == NULL)
8643     {
8644         Status = STATUS_INSUFFICIENT_RESOURCES;
8645         goto done;
8646     }
8647 
8648     /*
8649      * Get the size of the Groups attribute.
8650      * Do not check the status code because in case of an error
8651      * Length will be 0. And that is all we need.
8652      */
8653     SampGetObjectAttribute(UserObject,
8654                            L"Groups",
8655                            NULL,
8656                            NULL,
8657                            &Length);
8658 
8659     /* If there is no Groups attribute, return a groups buffer without an array */
8660     if (Length == 0)
8661     {
8662         GroupsBuffer->MembershipCount = 0;
8663         GroupsBuffer->Groups = NULL;
8664 
8665         *Groups = GroupsBuffer;
8666 
8667         Status = STATUS_SUCCESS;
8668         goto done;
8669     }
8670 
8671     /* Allocate a buffer for the Groups attribute */
8672     GroupsBuffer->Groups = midl_user_allocate(Length);
8673     if (GroupsBuffer->Groups == NULL)
8674     {
8675         Status = STATUS_INSUFFICIENT_RESOURCES;
8676         goto done;
8677     }
8678 
8679     /* Retrieve the Grous attribute */
8680     Status = SampGetObjectAttribute(UserObject,
8681                                     L"Groups",
8682                                     NULL,
8683                                     GroupsBuffer->Groups,
8684                                     &Length);
8685     if (!NT_SUCCESS(Status))
8686     {
8687         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8688         goto done;
8689     }
8690 
8691     /* Calculate the membership count */
8692     GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8693 
8694     /* Return the groups buffer to the caller */
8695     *Groups = GroupsBuffer;
8696 
8697 done:
8698     if (!NT_SUCCESS(Status))
8699     {
8700         if (GroupsBuffer != NULL)
8701         {
8702             if (GroupsBuffer->Groups != NULL)
8703                 midl_user_free(GroupsBuffer->Groups);
8704 
8705             midl_user_free(GroupsBuffer);
8706         }
8707     }
8708 
8709     RtlReleaseResource(&SampResource);
8710 
8711     return Status;
8712 }
8713 
8714 
8715 /* Function 40 */
8716 NTSTATUS
8717 NTAPI
8718 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8719                             IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8720                             IN unsigned long Index,
8721                             IN unsigned long EntryCount,
8722                             IN unsigned long PreferredMaximumLength,
8723                             OUT unsigned long *TotalAvailable,
8724                             OUT unsigned long *TotalReturned,
8725                             OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8726 {
8727     UNIMPLEMENTED;
8728     return STATUS_NOT_IMPLEMENTED;
8729 }
8730 
8731 /* Function 41 */
8732 NTSTATUS
8733 NTAPI
8734 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8735                                IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8736                                IN PRPC_UNICODE_STRING Prefix,
8737                                OUT unsigned long *Index)
8738 {
8739     UNIMPLEMENTED;
8740     return STATUS_NOT_IMPLEMENTED;
8741 }
8742 
8743 /* Function 42 */
8744 NTSTATUS
8745 NTAPI
8746 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8747 {
8748     UNIMPLEMENTED;
8749     return STATUS_NOT_IMPLEMENTED;
8750 }
8751 
8752 /* Function 43 */
8753 NTSTATUS
8754 NTAPI
8755 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8756 {
8757     UNIMPLEMENTED;
8758     return STATUS_NOT_IMPLEMENTED;
8759 }
8760 
8761 
8762 /* Function 44 */
8763 NTSTATUS
8764 NTAPI
8765 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8766                                      OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8767 {
8768     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8769     SAM_USER_FIXED_DATA UserFixedData;
8770     PSAM_DB_OBJECT DomainObject;
8771     PSAM_DB_OBJECT UserObject;
8772     ULONG Length = 0;
8773     NTSTATUS Status;
8774 
8775     TRACE("SamrGetUserDomainPasswordInformation(%p %p)\n",
8776           UserHandle, PasswordInformation);
8777 
8778     RtlAcquireResourceShared(&SampResource,
8779                              TRUE);
8780 
8781     /* Validate the user handle */
8782     Status = SampValidateDbObject(UserHandle,
8783                                   SamDbUserObject,
8784                                   0,
8785                                   &UserObject);
8786     if (!NT_SUCCESS(Status))
8787     {
8788         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8789         goto done;
8790     }
8791 
8792     /* Validate the domain object */
8793     Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8794                                   SamDbDomainObject,
8795                                   DOMAIN_READ_PASSWORD_PARAMETERS,
8796                                   &DomainObject);
8797     if (!NT_SUCCESS(Status))
8798     {
8799         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8800         goto done;
8801     }
8802 
8803     /* Get fixed user data */
8804     Length = sizeof(SAM_USER_FIXED_DATA);
8805     Status = SampGetObjectAttribute(UserObject,
8806                                     L"F",
8807                                     NULL,
8808                                     (PVOID)&UserFixedData,
8809                                     &Length);
8810     if (!NT_SUCCESS(Status))
8811     {
8812         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8813         goto done;
8814     }
8815 
8816     if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8817         (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8818                                              USER_WORKSTATION_TRUST_ACCOUNT |
8819                                              USER_SERVER_TRUST_ACCOUNT)))
8820     {
8821         PasswordInformation->MinPasswordLength = 0;
8822         PasswordInformation->PasswordProperties = 0;
8823     }
8824     else
8825     {
8826         /* Get fixed domain data */
8827         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8828         Status = SampGetObjectAttribute(DomainObject,
8829                                         L"F",
8830                                         NULL,
8831                                         (PVOID)&DomainFixedData,
8832                                         &Length);
8833         if (!NT_SUCCESS(Status))
8834         {
8835             TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8836             goto done;
8837         }
8838 
8839         PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8840         PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8841     }
8842 
8843 done:
8844     RtlReleaseResource(&SampResource);
8845 
8846     return STATUS_SUCCESS;
8847 }
8848 
8849 
8850 /* Function 45 */
8851 NTSTATUS
8852 NTAPI
8853 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8854                                   IN PRPC_SID MemberSid)
8855 {
8856     PSAM_DB_OBJECT DomainObject;
8857     ULONG Rid = 0;
8858     NTSTATUS Status;
8859 
8860     TRACE("SamrRemoveMemberFromForeignDomain(%p %p)\n",
8861           DomainHandle, MemberSid);
8862 
8863     RtlAcquireResourceExclusive(&SampResource,
8864                                 TRUE);
8865 
8866     /* Validate the domain object */
8867     Status = SampValidateDbObject(DomainHandle,
8868                                   SamDbDomainObject,
8869                                   DOMAIN_LOOKUP,
8870                                   &DomainObject);
8871     if (!NT_SUCCESS(Status))
8872     {
8873         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8874         goto done;
8875     }
8876 
8877     /* Retrieve the RID from the MemberSID */
8878     Status = SampGetRidFromSid((PSID)MemberSid,
8879                                &Rid);
8880     if (!NT_SUCCESS(Status))
8881     {
8882         TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8883         goto done;
8884     }
8885 
8886     /* Fail, if the RID represents a special account */
8887     if (Rid < 1000)
8888     {
8889         TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8890         Status = STATUS_SPECIAL_ACCOUNT;
8891         goto done;
8892     }
8893 
8894     /* Remove the member from all aliases in the domain */
8895     Status = SampRemoveMemberFromAllAliases(DomainObject,
8896                                             MemberSid);
8897     if (!NT_SUCCESS(Status))
8898     {
8899         TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8900     }
8901 
8902 done:
8903     RtlReleaseResource(&SampResource);
8904 
8905     return Status;
8906 }
8907 
8908 
8909 /* Function 46 */
8910 NTSTATUS
8911 NTAPI
8912 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8913                             IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8914                             OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8915 {
8916     TRACE("SamrQueryInformationDomain2(%p %lu %p)\n",
8917           DomainHandle, DomainInformationClass, Buffer);
8918 
8919     return SamrQueryInformationDomain(DomainHandle,
8920                                       DomainInformationClass,
8921                                       Buffer);
8922 }
8923 
8924 
8925 /* Function 47 */
8926 NTSTATUS
8927 NTAPI
8928 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8929                           IN USER_INFORMATION_CLASS UserInformationClass,
8930                           OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8931 {
8932     TRACE("SamrQueryInformationUser2(%p %lu %p)\n",
8933           UserHandle, UserInformationClass, Buffer);
8934 
8935     return SamrQueryInformationUser(UserHandle,
8936                                     UserInformationClass,
8937                                     Buffer);
8938 }
8939 
8940 
8941 /* Function 48 */
8942 NTSTATUS
8943 NTAPI
8944 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8945                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8946                              IN unsigned long Index,
8947                              IN unsigned long EntryCount,
8948                              IN unsigned long PreferredMaximumLength,
8949                              OUT unsigned long *TotalAvailable,
8950                              OUT unsigned long *TotalReturned,
8951                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8952 {
8953     TRACE("SamrQueryDisplayInformation2(%p %lu %lu %lu %lu %p %p %p)\n",
8954           DomainHandle, DisplayInformationClass, Index,
8955           EntryCount, PreferredMaximumLength, TotalAvailable,
8956           TotalReturned, Buffer);
8957 
8958     return SamrQueryDisplayInformation(DomainHandle,
8959                                        DisplayInformationClass,
8960                                        Index,
8961                                        EntryCount,
8962                                        PreferredMaximumLength,
8963                                        TotalAvailable,
8964                                        TotalReturned,
8965                                        Buffer);
8966 }
8967 
8968 
8969 /* Function 49 */
8970 NTSTATUS
8971 NTAPI
8972 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8973                                 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8974                                 IN PRPC_UNICODE_STRING Prefix,
8975                                 OUT unsigned long *Index)
8976 {
8977     TRACE("SamrGetDisplayEnumerationIndex2(%p %lu %p %p)\n",
8978           DomainHandle, DisplayInformationClass, Prefix, Index);
8979 
8980     return SamrGetDisplayEnumerationIndex(DomainHandle,
8981                                           DisplayInformationClass,
8982                                           Prefix,
8983                                           Index);
8984 }
8985 
8986 
8987 /* Function 50 */
8988 NTSTATUS
8989 NTAPI
8990 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8991                         IN PRPC_UNICODE_STRING Name,
8992                         IN unsigned long AccountType,
8993                         IN ACCESS_MASK DesiredAccess,
8994                         OUT SAMPR_HANDLE *UserHandle,
8995                         OUT unsigned long *GrantedAccess,
8996                         OUT unsigned long *RelativeId)
8997 {
8998     SAM_DOMAIN_FIXED_DATA FixedDomainData;
8999     SAM_USER_FIXED_DATA FixedUserData;
9000     PSAM_DB_OBJECT DomainObject;
9001     PSAM_DB_OBJECT UserObject;
9002     GROUP_MEMBERSHIP GroupMembership;
9003     UCHAR LogonHours[23];
9004     ULONG ulSize;
9005     ULONG ulRid;
9006     WCHAR szRid[9];
9007     PSECURITY_DESCRIPTOR Sd = NULL;
9008     ULONG SdSize = 0;
9009     PSID UserSid = NULL;
9010     NTSTATUS Status;
9011 
9012     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
9013           DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
9014 
9015     if (Name == NULL ||
9016         Name->Length == 0 ||
9017         Name->Buffer == NULL ||
9018         UserHandle == NULL ||
9019         RelativeId == NULL)
9020         return STATUS_INVALID_PARAMETER;
9021 
9022     /* Check for valid account type */
9023     if (AccountType != USER_NORMAL_ACCOUNT &&
9024         AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
9025         AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
9026         AccountType != USER_SERVER_TRUST_ACCOUNT &&
9027         AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
9028         return STATUS_INVALID_PARAMETER;
9029 
9030     /* Map generic access rights */
9031     RtlMapGenericMask(&DesiredAccess,
9032                       &UserMapping);
9033 
9034     RtlAcquireResourceExclusive(&SampResource,
9035                                 TRUE);
9036 
9037     /* Validate the domain handle */
9038     Status = SampValidateDbObject(DomainHandle,
9039                                   SamDbDomainObject,
9040                                   DOMAIN_CREATE_USER,
9041                                   &DomainObject);
9042     if (!NT_SUCCESS(Status))
9043     {
9044         TRACE("failed with status 0x%08lx\n", Status);
9045         goto done;
9046     }
9047 
9048     /* Check the user account name */
9049     Status = SampCheckAccountName(Name, 20);
9050     if (!NT_SUCCESS(Status))
9051     {
9052         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
9053         goto done;
9054     }
9055 
9056     /* Check if the user name already exists in the domain */
9057     Status = SampCheckAccountNameInDomain(DomainObject,
9058                                           Name->Buffer);
9059     if (!NT_SUCCESS(Status))
9060     {
9061         TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
9062               Name->Buffer, Status);
9063         goto done;
9064     }
9065 
9066     /* Get the fixed domain attributes */
9067     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
9068     Status = SampGetObjectAttribute(DomainObject,
9069                                     L"F",
9070                                     NULL,
9071                                     (PVOID)&FixedDomainData,
9072                                     &ulSize);
9073     if (!NT_SUCCESS(Status))
9074     {
9075         TRACE("failed with status 0x%08lx\n", Status);
9076         goto done;
9077     }
9078 
9079     /* Increment the NextRid attribute */
9080     ulRid = FixedDomainData.NextRid;
9081     FixedDomainData.NextRid++;
9082 
9083     TRACE("RID: %lx\n", ulRid);
9084 
9085     /* Create the user SID */
9086     Status = SampCreateAccountSid(DomainObject,
9087                                   ulRid,
9088                                   &UserSid);
9089     if (!NT_SUCCESS(Status))
9090     {
9091         TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
9092         goto done;
9093     }
9094 
9095     /* Create the security descriptor */
9096     Status = SampCreateUserSD(UserSid,
9097                               &Sd,
9098                               &SdSize);
9099     if (!NT_SUCCESS(Status))
9100     {
9101         TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
9102         goto done;
9103     }
9104 
9105     /* Store the fixed domain attributes */
9106     Status = SampSetObjectAttribute(DomainObject,
9107                                     L"F",
9108                                     REG_BINARY,
9109                                     &FixedDomainData,
9110                                     ulSize);
9111     if (!NT_SUCCESS(Status))
9112     {
9113         TRACE("failed with status 0x%08lx\n", Status);
9114         goto done;
9115     }
9116 
9117     /* Convert the RID into a string (hex) */
9118     swprintf(szRid, L"%08lX", ulRid);
9119 
9120     /* Create the user object */
9121     Status = SampCreateDbObject(DomainObject,
9122                                 L"Users",
9123                                 szRid,
9124                                 ulRid,
9125                                 SamDbUserObject,
9126                                 DesiredAccess,
9127                                 &UserObject);
9128     if (!NT_SUCCESS(Status))
9129     {
9130         TRACE("failed with status 0x%08lx\n", Status);
9131         goto done;
9132     }
9133 
9134     /* Add the account name for the user object */
9135     Status = SampSetAccountNameInDomain(DomainObject,
9136                                         L"Users",
9137                                         Name->Buffer,
9138                                         ulRid);
9139     if (!NT_SUCCESS(Status))
9140     {
9141         TRACE("failed with status 0x%08lx\n", Status);
9142         goto done;
9143     }
9144 
9145     /* Initialize fixed user data */
9146     FixedUserData.Version = 1;
9147     FixedUserData.Reserved = 0;
9148     FixedUserData.LastLogon.QuadPart = 0;
9149     FixedUserData.LastLogoff.QuadPart = 0;
9150     FixedUserData.PasswordLastSet.QuadPart = 0;
9151     FixedUserData.AccountExpires.LowPart = MAXULONG;
9152     FixedUserData.AccountExpires.HighPart = MAXLONG;
9153     FixedUserData.LastBadPasswordTime.QuadPart = 0;
9154     FixedUserData.UserId = ulRid;
9155     FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
9156     FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
9157                                        USER_PASSWORD_NOT_REQUIRED |
9158                                        AccountType;
9159     FixedUserData.CountryCode = 0;
9160     FixedUserData.CodePage = 0;
9161     FixedUserData.BadPasswordCount = 0;
9162     FixedUserData.LogonCount = 0;
9163     FixedUserData.AdminCount = 0;
9164     FixedUserData.OperatorCount = 0;
9165 
9166     /* Set fixed user data attribute */
9167     Status = SampSetObjectAttribute(UserObject,
9168                                     L"F",
9169                                     REG_BINARY,
9170                                     (LPVOID)&FixedUserData,
9171                                     sizeof(SAM_USER_FIXED_DATA));
9172     if (!NT_SUCCESS(Status))
9173     {
9174         TRACE("failed with status 0x%08lx\n", Status);
9175         goto done;
9176     }
9177 
9178     /* Set the Name attribute */
9179     Status = SampSetObjectAttributeString(UserObject,
9180                                           L"Name",
9181                                           Name);
9182     if (!NT_SUCCESS(Status))
9183     {
9184         TRACE("failed with status 0x%08lx\n", Status);
9185         goto done;
9186     }
9187 
9188     /* Set the FullName attribute */
9189     Status = SampSetObjectAttributeString(UserObject,
9190                                           L"FullName",
9191                                           NULL);
9192     if (!NT_SUCCESS(Status))
9193     {
9194         TRACE("failed with status 0x%08lx\n", Status);
9195         goto done;
9196     }
9197 
9198     /* Set the HomeDirectory attribute */
9199     Status = SampSetObjectAttributeString(UserObject,
9200                                           L"HomeDirectory",
9201                                           NULL);
9202     if (!NT_SUCCESS(Status))
9203     {
9204         TRACE("failed with status 0x%08lx\n", Status);
9205         goto done;
9206     }
9207 
9208     /* Set the HomeDirectoryDrive attribute */
9209     Status = SampSetObjectAttributeString(UserObject,
9210                                           L"HomeDirectoryDrive",
9211                                           NULL);
9212     if (!NT_SUCCESS(Status))
9213     {
9214         TRACE("failed with status 0x%08lx\n", Status);
9215         goto done;
9216     }
9217 
9218     /* Set the ScriptPath attribute */
9219     Status = SampSetObjectAttributeString(UserObject,
9220                                           L"ScriptPath",
9221                                           NULL);
9222     if (!NT_SUCCESS(Status))
9223     {
9224         TRACE("failed with status 0x%08lx\n", Status);
9225         goto done;
9226     }
9227 
9228     /* Set the ProfilePath attribute */
9229     Status = SampSetObjectAttributeString(UserObject,
9230                                           L"ProfilePath",
9231                                           NULL);
9232     if (!NT_SUCCESS(Status))
9233     {
9234         TRACE("failed with status 0x%08lx\n", Status);
9235         goto done;
9236     }
9237 
9238     /* Set the AdminComment attribute */
9239     Status = SampSetObjectAttributeString(UserObject,
9240                                           L"AdminComment",
9241                                           NULL);
9242     if (!NT_SUCCESS(Status))
9243     {
9244         TRACE("failed with status 0x%08lx\n", Status);
9245         goto done;
9246     }
9247 
9248     /* Set the UserComment attribute */
9249     Status = SampSetObjectAttributeString(UserObject,
9250                                           L"UserComment",
9251                                           NULL);
9252     if (!NT_SUCCESS(Status))
9253     {
9254         TRACE("failed with status 0x%08lx\n", Status);
9255         goto done;
9256     }
9257 
9258     /* Set the WorkStations attribute */
9259     Status = SampSetObjectAttributeString(UserObject,
9260                                           L"WorkStations",
9261                                           NULL);
9262     if (!NT_SUCCESS(Status))
9263     {
9264         TRACE("failed with status 0x%08lx\n", Status);
9265         goto done;
9266     }
9267 
9268     /* Set the Parameters attribute */
9269     Status = SampSetObjectAttributeString(UserObject,
9270                                           L"Parameters",
9271                                           NULL);
9272     if (!NT_SUCCESS(Status))
9273     {
9274         TRACE("failed with status 0x%08lx\n", Status);
9275         goto done;
9276     }
9277 
9278     /* Set LogonHours attribute*/
9279     *((PUSHORT)LogonHours) = 168;
9280     memset(&(LogonHours[2]), 0xff, 21);
9281 
9282     Status = SampSetObjectAttribute(UserObject,
9283                                     L"LogonHours",
9284                                     REG_BINARY,
9285                                     &LogonHours,
9286                                     sizeof(LogonHours));
9287     if (!NT_SUCCESS(Status))
9288     {
9289         TRACE("failed with status 0x%08lx\n", Status);
9290         goto done;
9291     }
9292 
9293     /* Set Groups attribute*/
9294     GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
9295     GroupMembership.Attributes = SE_GROUP_MANDATORY |
9296                                  SE_GROUP_ENABLED |
9297                                  SE_GROUP_ENABLED_BY_DEFAULT;
9298 
9299     Status = SampSetObjectAttribute(UserObject,
9300                                     L"Groups",
9301                                     REG_BINARY,
9302                                     &GroupMembership,
9303                                     sizeof(GROUP_MEMBERSHIP));
9304     if (!NT_SUCCESS(Status))
9305     {
9306         TRACE("failed with status 0x%08lx\n", Status);
9307         goto done;
9308     }
9309 
9310     /* Set LMPwd attribute*/
9311     Status = SampSetObjectAttribute(UserObject,
9312                                     L"LMPwd",
9313                                     REG_BINARY,
9314                                     NULL,
9315                                     0);
9316     if (!NT_SUCCESS(Status))
9317     {
9318         TRACE("failed with status 0x%08lx\n", Status);
9319         goto done;
9320     }
9321 
9322     /* Set NTPwd attribute*/
9323     Status = SampSetObjectAttribute(UserObject,
9324                                     L"NTPwd",
9325                                     REG_BINARY,
9326                                     NULL,
9327                                     0);
9328     if (!NT_SUCCESS(Status))
9329     {
9330         TRACE("failed with status 0x%08lx\n", Status);
9331         goto done;
9332     }
9333 
9334     /* Set LMPwdHistory attribute*/
9335     Status = SampSetObjectAttribute(UserObject,
9336                                     L"LMPwdHistory",
9337                                     REG_BINARY,
9338                                     NULL,
9339                                     0);
9340     if (!NT_SUCCESS(Status))
9341     {
9342         TRACE("failed with status 0x%08lx\n", Status);
9343         goto done;
9344     }
9345 
9346     /* Set NTPwdHistory attribute*/
9347     Status = SampSetObjectAttribute(UserObject,
9348                                     L"NTPwdHistory",
9349                                     REG_BINARY,
9350                                     NULL,
9351                                     0);
9352     if (!NT_SUCCESS(Status))
9353     {
9354         TRACE("failed with status 0x%08lx\n", Status);
9355         goto done;
9356     }
9357 
9358     /* Set the PrivateData attribute */
9359     Status = SampSetObjectAttributeString(UserObject,
9360                                           L"PrivateData",
9361                                           NULL);
9362     if (!NT_SUCCESS(Status))
9363     {
9364         TRACE("failed with status 0x%08lx\n", Status);
9365         goto done;
9366     }
9367 
9368     /* Set the SecDesc attribute*/
9369     Status = SampSetObjectAttribute(UserObject,
9370                                     L"SecDesc",
9371                                     REG_BINARY,
9372                                     Sd,
9373                                     SdSize);
9374     if (!NT_SUCCESS(Status))
9375     {
9376         TRACE("failed with status 0x%08lx\n", Status);
9377         goto done;
9378     }
9379 
9380     if (NT_SUCCESS(Status))
9381     {
9382         *UserHandle = (SAMPR_HANDLE)UserObject;
9383         *RelativeId = ulRid;
9384         *GrantedAccess = UserObject->Access;
9385     }
9386 
9387 done:
9388     if (Sd != NULL)
9389         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
9390 
9391     if (UserSid != NULL)
9392         RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
9393 
9394     RtlReleaseResource(&SampResource);
9395 
9396     TRACE("returns with status 0x%08lx\n", Status);
9397 
9398     return Status;
9399 }
9400 
9401 
9402 /* Function 51 */
9403 NTSTATUS
9404 NTAPI
9405 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
9406                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
9407                              IN unsigned long Index,
9408                              IN unsigned long EntryCount,
9409                              IN unsigned long PreferredMaximumLength,
9410                              OUT unsigned long *TotalAvailable,
9411                              OUT unsigned long *TotalReturned,
9412                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
9413 {
9414     TRACE("SamrQueryDisplayInformation3(%p %lu %lu %lu %lu %p %p %p)\n",
9415           DomainHandle, DisplayInformationClass, Index,
9416           EntryCount, PreferredMaximumLength, TotalAvailable,
9417           TotalReturned, Buffer);
9418 
9419     return SamrQueryDisplayInformation(DomainHandle,
9420                                        DisplayInformationClass,
9421                                        Index,
9422                                        EntryCount,
9423                                        PreferredMaximumLength,
9424                                        TotalAvailable,
9425                                        TotalReturned,
9426                                        Buffer);
9427 }
9428 
9429 
9430 /* Function 52 */
9431 NTSTATUS
9432 NTAPI
9433 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
9434                               IN PSAMPR_PSID_ARRAY MembersBuffer)
9435 {
9436     ULONG i;
9437     NTSTATUS Status = STATUS_SUCCESS;
9438 
9439     TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
9440           AliasHandle, MembersBuffer);
9441 
9442     for (i = 0; i < MembersBuffer->Count; i++)
9443     {
9444         Status = SamrAddMemberToAlias(AliasHandle,
9445                                       ((PSID *)MembersBuffer->Sids)[i]);
9446 
9447         if (Status == STATUS_MEMBER_IN_ALIAS)
9448             Status = STATUS_SUCCESS;
9449 
9450         if (!NT_SUCCESS(Status))
9451             break;
9452     }
9453 
9454     return Status;
9455 }
9456 
9457 
9458 /* Function 53 */
9459 NTSTATUS
9460 NTAPI
9461 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
9462                                    IN PSAMPR_PSID_ARRAY MembersBuffer)
9463 {
9464     ULONG i;
9465     NTSTATUS Status = STATUS_SUCCESS;
9466 
9467     TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
9468           AliasHandle, MembersBuffer);
9469 
9470     for (i = 0; i < MembersBuffer->Count; i++)
9471     {
9472         Status = SamrRemoveMemberFromAlias(AliasHandle,
9473                                            ((PSID *)MembersBuffer->Sids)[i]);
9474 
9475         if (Status == STATUS_MEMBER_IN_ALIAS)
9476             Status = STATUS_SUCCESS;
9477 
9478         if (!NT_SUCCESS(Status))
9479             break;
9480     }
9481 
9482     return Status;
9483 }
9484 
9485 
9486 /* Function 54 */
9487 NTSTATUS
9488 NTAPI
9489 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
9490                            IN PRPC_STRING ServerName,
9491                            IN PRPC_STRING UserName,
9492                            IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9493                            IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
9494 {
9495     UNIMPLEMENTED;
9496     return STATUS_NOT_IMPLEMENTED;
9497 }
9498 
9499 /* Function 55 */
9500 NTSTATUS
9501 NTAPI
9502 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
9503                                IN PRPC_UNICODE_STRING ServerName,
9504                                IN PRPC_UNICODE_STRING UserName,
9505                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
9506                                IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
9507                                IN unsigned char LmPresent,
9508                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9509                                IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
9510 {
9511     UNIMPLEMENTED;
9512     return STATUS_NOT_IMPLEMENTED;
9513 }
9514 
9515 
9516 /* Function 56 */
9517 NTSTATUS
9518 NTAPI
9519 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
9520                                  IN PRPC_UNICODE_STRING Unused,
9521                                  OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
9522 {
9523     SAMPR_HANDLE ServerHandle = NULL;
9524     PSAM_DB_OBJECT DomainObject = NULL;
9525     SAM_DOMAIN_FIXED_DATA FixedData;
9526     ULONG Length;
9527     NTSTATUS Status;
9528 
9529     TRACE("SamrGetDomainPasswordInformation(%p %p %p)\n",
9530           BindingHandle, Unused, PasswordInformation);
9531 
9532     Status = SamrConnect(NULL,
9533                          &ServerHandle,
9534                          SAM_SERVER_LOOKUP_DOMAIN);
9535     if (!NT_SUCCESS(Status))
9536     {
9537         TRACE("SamrConnect() failed (Status 0x%08lx)\n", Status);
9538         goto done;
9539     }
9540 
9541     Status = SampOpenDbObject((PSAM_DB_OBJECT)ServerHandle,
9542                               L"Domains",
9543                               L"Account",
9544                               0,
9545                               SamDbDomainObject,
9546                               DOMAIN_READ_PASSWORD_PARAMETERS,
9547                               &DomainObject);
9548     if (!NT_SUCCESS(Status))
9549     {
9550         TRACE("SampOpenDbObject() failed (Status 0x%08lx)\n", Status);
9551         goto done;
9552     }
9553 
9554     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
9555     Status = SampGetObjectAttribute(DomainObject,
9556                                     L"F",
9557                                     NULL,
9558                                     &FixedData,
9559                                     &Length);
9560     if (!NT_SUCCESS(Status))
9561     {
9562         TRACE("SampGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
9563         goto done;
9564     }
9565 
9566     PasswordInformation->MinPasswordLength = FixedData.MinPasswordLength;
9567     PasswordInformation->PasswordProperties = FixedData.PasswordProperties;
9568 
9569 done:
9570     if (DomainObject != NULL)
9571         SampCloseDbObject(DomainObject);
9572 
9573     if (ServerHandle != NULL)
9574         SamrCloseHandle(ServerHandle);
9575 
9576     return Status;
9577 }
9578 
9579 
9580 /* Function 57 */
9581 NTSTATUS
9582 NTAPI
9583 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
9584              OUT SAMPR_HANDLE *ServerHandle,
9585              IN ACCESS_MASK DesiredAccess)
9586 {
9587     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9588     ULONG OutVersion;
9589 
9590     TRACE("SamrConnect2(%p %p %lx)\n",
9591           ServerName, ServerHandle, DesiredAccess);
9592 
9593     InRevisionInfo.V1.Revision = 1;
9594     InRevisionInfo.V1.SupportedFeatures = 0;
9595 
9596     return SamrConnect5(ServerName,
9597                         DesiredAccess,
9598                         1,
9599                         &InRevisionInfo,
9600                         &OutVersion,
9601                         &OutRevisionInfo,
9602                         ServerHandle);
9603 }
9604 
9605 
9606 /* Function 58 */
9607 NTSTATUS
9608 NTAPI
9609 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
9610                         IN USER_INFORMATION_CLASS UserInformationClass,
9611                         IN PSAMPR_USER_INFO_BUFFER Buffer)
9612 {
9613     TRACE("SamrSetInformationUser2(%p %lu %p)\n",
9614           UserHandle, UserInformationClass, Buffer);
9615 
9616     return SamrSetInformationUser(UserHandle,
9617                                   UserInformationClass,
9618                                   Buffer);
9619 }
9620 
9621 
9622 /* Function 59 */
9623 NTSTATUS
9624 NTAPI
9625 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9626 {
9627     UNIMPLEMENTED;
9628     return STATUS_NOT_IMPLEMENTED;
9629 }
9630 
9631 /* Function 60 */
9632 NTSTATUS
9633 NTAPI
9634 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9635 {
9636     UNIMPLEMENTED;
9637     return STATUS_NOT_IMPLEMENTED;
9638 }
9639 
9640 /* Function 61 */
9641 NTSTATUS
9642 NTAPI
9643 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
9644 {
9645     UNIMPLEMENTED;
9646     return STATUS_NOT_IMPLEMENTED;
9647 }
9648 
9649 
9650 /* Function 62 */
9651 NTSTATUS
9652 NTAPI
9653 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
9654              OUT SAMPR_HANDLE *ServerHandle,
9655              IN unsigned long ClientRevision,
9656              IN ACCESS_MASK DesiredAccess)
9657 {
9658     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9659     ULONG OutVersion;
9660 
9661     TRACE("SamrConnect4(%p %p %lu 0x%lx)\n",
9662           ServerName, ServerHandle, ClientRevision, DesiredAccess);
9663 
9664     InRevisionInfo.V1.Revision = 2;
9665     InRevisionInfo.V1.SupportedFeatures = 0;
9666 
9667     return SamrConnect5(ServerName,
9668                         DesiredAccess,
9669                         1,
9670                         &InRevisionInfo,
9671                         &OutVersion,
9672                         &OutRevisionInfo,
9673                         ServerHandle);
9674 }
9675 
9676 
9677 /* Function 63 */
9678 NTSTATUS
9679 NTAPI
9680 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
9681 {
9682     UNIMPLEMENTED;
9683     return STATUS_NOT_IMPLEMENTED;
9684 }
9685 
9686 
9687 /* Function 64 */
9688 NTSTATUS
9689 NTAPI
9690 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
9691              IN ACCESS_MASK DesiredAccess,
9692              IN unsigned long InVersion,
9693              IN SAMPR_REVISION_INFO *InRevisionInfo,
9694              OUT unsigned long *OutVersion,
9695              OUT SAMPR_REVISION_INFO *OutRevisionInfo,
9696              OUT SAMPR_HANDLE *ServerHandle)
9697 {
9698     PSAM_DB_OBJECT ServerObject;
9699     NTSTATUS Status;
9700 
9701     TRACE("SamrConnect5(%p 0x%lx %lu %p %p %p %p)\n",
9702           ServerName, DesiredAccess, InVersion, InRevisionInfo,
9703           OutVersion, OutRevisionInfo, ServerHandle);
9704 
9705     if (InVersion != 1)
9706         return STATUS_NOT_SUPPORTED;
9707 
9708     RtlAcquireResourceShared(&SampResource,
9709                              TRUE);
9710 
9711     /* Map generic access rights */
9712     RtlMapGenericMask(&DesiredAccess,
9713                       &ServerMapping);
9714 
9715     /* Open the Server Object */
9716     Status = SampOpenDbObject(NULL,
9717                               NULL,
9718                               L"SAM",
9719                               0,
9720                               SamDbServerObject,
9721                               DesiredAccess,
9722                               &ServerObject);
9723     if (NT_SUCCESS(Status))
9724     {
9725         *OutVersion = 1;
9726 
9727         OutRevisionInfo->V1.Revision = 3;
9728         OutRevisionInfo->V1.SupportedFeatures = 0;
9729 
9730         *ServerHandle = (SAMPR_HANDLE)ServerObject;
9731     }
9732 
9733     RtlReleaseResource(&SampResource);
9734 
9735     TRACE("SamrConnect5 done (Status 0x%08lx)\n", Status);
9736 
9737     return Status;
9738 }
9739 
9740 
9741 /* Function 65 */
9742 NTSTATUS
9743 NTAPI
9744 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
9745              IN unsigned long Rid,
9746              OUT PRPC_SID *Sid)
9747 {
9748     UNIMPLEMENTED;
9749     return STATUS_NOT_IMPLEMENTED;
9750 }
9751 
9752 /* Function 66 */
9753 NTSTATUS
9754 NTAPI
9755 SamrSetDSRMPassword(IN handle_t BindingHandle,
9756                     IN PRPC_UNICODE_STRING Unused,
9757                     IN unsigned long UserId,
9758                     IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
9759 {
9760     UNIMPLEMENTED;
9761     return STATUS_NOT_IMPLEMENTED;
9762 }
9763 
9764 /* Function 67 */
9765 NTSTATUS
9766 NTAPI
9767 SamrValidatePassword(IN handle_t Handle,
9768                      IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
9769                      IN PSAM_VALIDATE_INPUT_ARG InputArg,
9770                      OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
9771 {
9772     UNIMPLEMENTED;
9773     return STATUS_NOT_IMPLEMENTED;
9774 }
9775 
9776 /* EOF */
9777