xref: /reactos/dll/win32/samsrv/samrpc.c (revision 8540ab04)
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         goto done;
2294 
2295     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2296     if (EnumBuffer->Buffer == NULL)
2297     {
2298         Status = STATUS_INSUFFICIENT_RESOURCES;
2299         goto done;
2300     }
2301 
2302     TRACE("Part 2\n");
2303 
2304     EnumIndex = *EnumerationContext;
2305     for (i = 0; i < EnumCount; i++, EnumIndex++)
2306     {
2307         NameLength = 64 * sizeof(WCHAR);
2308         DataLength = sizeof(ULONG);
2309         Status = SampRegEnumerateValue(NamesKeyHandle,
2310                                        EnumIndex,
2311                                        GroupName,
2312                                        &NameLength,
2313                                        NULL,
2314                                        &Rid,
2315                                        &DataLength);
2316         if (!NT_SUCCESS(Status))
2317         {
2318             if (Status == STATUS_NO_MORE_ENTRIES)
2319                 Status = STATUS_SUCCESS;
2320             break;
2321         }
2322 
2323         TRACE("EnumIndex: %lu\n", EnumIndex);
2324         TRACE("Group name: %S\n", GroupName);
2325         TRACE("Name length: %lu\n", NameLength);
2326         TRACE("RID: %lu\n", Rid);
2327 
2328         EnumBuffer->Buffer[i].RelativeId = Rid;
2329 
2330         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2331         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2332 
2333 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2334 #if 0
2335         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2336         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2337         {
2338             Status = STATUS_INSUFFICIENT_RESOURCES;
2339             goto done;
2340         }
2341 
2342         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2343                GroupName,
2344                EnumBuffer->Buffer[i].Name.Length);
2345 #endif
2346     }
2347 
2348 done:
2349     if (NT_SUCCESS(Status))
2350     {
2351         *EnumerationContext += EnumCount;
2352         *Buffer = EnumBuffer;
2353         *CountReturned = EnumCount;
2354     }
2355     else
2356     {
2357         *EnumerationContext = 0;
2358         *Buffer = NULL;
2359         *CountReturned = 0;
2360 
2361         if (EnumBuffer != NULL)
2362         {
2363             if (EnumBuffer->Buffer != NULL)
2364             {
2365                 if (EnumBuffer->EntriesRead != 0)
2366                 {
2367                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
2368                     {
2369                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2370                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2371                     }
2372                 }
2373 
2374                 midl_user_free(EnumBuffer->Buffer);
2375             }
2376 
2377             midl_user_free(EnumBuffer);
2378         }
2379     }
2380 
2381     SampRegCloseKey(&NamesKeyHandle);
2382     SampRegCloseKey(&GroupsKeyHandle);
2383 
2384     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2385         Status = STATUS_MORE_ENTRIES;
2386 
2387     RtlReleaseResource(&SampResource);
2388 
2389     return Status;
2390 }
2391 
2392 
2393 /* Function 12 */
2394 NTSTATUS
2395 NTAPI
2396 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2397                        IN PRPC_UNICODE_STRING Name,
2398                        IN ACCESS_MASK DesiredAccess,
2399                        OUT SAMPR_HANDLE *UserHandle,
2400                        OUT unsigned long *RelativeId)
2401 {
2402     SAM_DOMAIN_FIXED_DATA FixedDomainData;
2403     SAM_USER_FIXED_DATA FixedUserData;
2404     PSAM_DB_OBJECT DomainObject;
2405     PSAM_DB_OBJECT UserObject;
2406     GROUP_MEMBERSHIP GroupMembership;
2407     UCHAR LogonHours[23];
2408     ULONG ulSize;
2409     ULONG ulRid;
2410     WCHAR szRid[9];
2411     PSECURITY_DESCRIPTOR Sd = NULL;
2412     ULONG SdSize = 0;
2413     PSID UserSid = NULL;
2414     NTSTATUS Status;
2415 
2416     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2417           DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2418 
2419     if (Name == NULL ||
2420         Name->Length == 0 ||
2421         Name->Buffer == NULL ||
2422         UserHandle == NULL ||
2423         RelativeId == NULL)
2424         return STATUS_INVALID_PARAMETER;
2425 
2426     /* Map generic access rights */
2427     RtlMapGenericMask(&DesiredAccess,
2428                       &UserMapping);
2429 
2430     RtlAcquireResourceExclusive(&SampResource,
2431                                 TRUE);
2432 
2433     /* Validate the domain handle */
2434     Status = SampValidateDbObject(DomainHandle,
2435                                   SamDbDomainObject,
2436                                   DOMAIN_CREATE_USER,
2437                                   &DomainObject);
2438     if (!NT_SUCCESS(Status))
2439     {
2440         TRACE("failed with status 0x%08lx\n", Status);
2441         goto done;
2442     }
2443 
2444     /* Check the user account name */
2445     Status = SampCheckAccountName(Name, 20);
2446     if (!NT_SUCCESS(Status))
2447     {
2448         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2449         goto done;
2450     }
2451 
2452     /* Check if the user name already exists in the domain */
2453     Status = SampCheckAccountNameInDomain(DomainObject,
2454                                           Name->Buffer);
2455     if (!NT_SUCCESS(Status))
2456     {
2457         TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2458               Name->Buffer, Status);
2459         goto done;
2460     }
2461 
2462     /* Get the fixed domain attributes */
2463     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2464     Status = SampGetObjectAttribute(DomainObject,
2465                                     L"F",
2466                                     NULL,
2467                                     (PVOID)&FixedDomainData,
2468                                     &ulSize);
2469     if (!NT_SUCCESS(Status))
2470     {
2471         TRACE("failed with status 0x%08lx\n", Status);
2472         goto done;
2473     }
2474 
2475     /* Increment the NextRid attribute */
2476     ulRid = FixedDomainData.NextRid;
2477     FixedDomainData.NextRid++;
2478 
2479     TRACE("RID: %lx\n", ulRid);
2480 
2481     /* Create the user SID */
2482     Status = SampCreateAccountSid(DomainObject,
2483                                   ulRid,
2484                                   &UserSid);
2485     if (!NT_SUCCESS(Status))
2486     {
2487         TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
2488         goto done;
2489     }
2490 
2491     /* Create the security descriptor */
2492     Status = SampCreateUserSD(UserSid,
2493                               &Sd,
2494                               &SdSize);
2495     if (!NT_SUCCESS(Status))
2496     {
2497         TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
2498         goto done;
2499     }
2500 
2501     /* Store the fixed domain attributes */
2502     Status = SampSetObjectAttribute(DomainObject,
2503                                     L"F",
2504                                     REG_BINARY,
2505                                     &FixedDomainData,
2506                                     ulSize);
2507     if (!NT_SUCCESS(Status))
2508     {
2509         TRACE("failed with status 0x%08lx\n", Status);
2510         goto done;
2511     }
2512 
2513     /* Convert the RID into a string (hex) */
2514     swprintf(szRid, L"%08lX", ulRid);
2515 
2516     /* Create the user object */
2517     Status = SampCreateDbObject(DomainObject,
2518                                 L"Users",
2519                                 szRid,
2520                                 ulRid,
2521                                 SamDbUserObject,
2522                                 DesiredAccess,
2523                                 &UserObject);
2524     if (!NT_SUCCESS(Status))
2525     {
2526         TRACE("failed with status 0x%08lx\n", Status);
2527         goto done;
2528     }
2529 
2530     /* Add the account name for the user object */
2531     Status = SampSetAccountNameInDomain(DomainObject,
2532                                         L"Users",
2533                                         Name->Buffer,
2534                                         ulRid);
2535     if (!NT_SUCCESS(Status))
2536     {
2537         TRACE("failed with status 0x%08lx\n", Status);
2538         goto done;
2539     }
2540 
2541     /* Initialize fixed user data */
2542     memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2543     FixedUserData.Version = 1;
2544     FixedUserData.Reserved = 0;
2545     FixedUserData.LastLogon.QuadPart = 0;
2546     FixedUserData.LastLogoff.QuadPart = 0;
2547     FixedUserData.PasswordLastSet.QuadPart = 0;
2548     FixedUserData.AccountExpires.QuadPart = MAXLONGLONG;
2549     FixedUserData.LastBadPasswordTime.QuadPart = 0;
2550     FixedUserData.UserId = ulRid;
2551     FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2552     FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2553                                        USER_PASSWORD_NOT_REQUIRED |
2554                                        USER_NORMAL_ACCOUNT;
2555     FixedUserData.CountryCode = 0;
2556     FixedUserData.CodePage = 0;
2557     FixedUserData.BadPasswordCount = 0;
2558     FixedUserData.LogonCount = 0;
2559     FixedUserData.AdminCount = 0;
2560     FixedUserData.OperatorCount = 0;
2561 
2562     /* Set fixed user data attribute */
2563     Status = SampSetObjectAttribute(UserObject,
2564                                     L"F",
2565                                     REG_BINARY,
2566                                     (LPVOID)&FixedUserData,
2567                                     sizeof(SAM_USER_FIXED_DATA));
2568     if (!NT_SUCCESS(Status))
2569     {
2570         TRACE("failed with status 0x%08lx\n", Status);
2571         goto done;
2572     }
2573 
2574     /* Set the Name attribute */
2575     Status = SampSetObjectAttributeString(UserObject,
2576                                           L"Name",
2577                                           Name);
2578     if (!NT_SUCCESS(Status))
2579     {
2580         TRACE("failed with status 0x%08lx\n", Status);
2581         goto done;
2582     }
2583 
2584     /* Set the FullName attribute */
2585     Status = SampSetObjectAttributeString(UserObject,
2586                                           L"FullName",
2587                                           NULL);
2588     if (!NT_SUCCESS(Status))
2589     {
2590         TRACE("failed with status 0x%08lx\n", Status);
2591         goto done;
2592     }
2593 
2594     /* Set the HomeDirectory attribute */
2595     Status = SampSetObjectAttributeString(UserObject,
2596                                           L"HomeDirectory",
2597                                           NULL);
2598     if (!NT_SUCCESS(Status))
2599     {
2600         TRACE("failed with status 0x%08lx\n", Status);
2601         goto done;
2602     }
2603 
2604     /* Set the HomeDirectoryDrive attribute */
2605     Status = SampSetObjectAttributeString(UserObject,
2606                                           L"HomeDirectoryDrive",
2607                                           NULL);
2608     if (!NT_SUCCESS(Status))
2609     {
2610         TRACE("failed with status 0x%08lx\n", Status);
2611         goto done;
2612     }
2613 
2614     /* Set the ScriptPath attribute */
2615     Status = SampSetObjectAttributeString(UserObject,
2616                                           L"ScriptPath",
2617                                           NULL);
2618     if (!NT_SUCCESS(Status))
2619     {
2620         TRACE("failed with status 0x%08lx\n", Status);
2621         goto done;
2622     }
2623 
2624     /* Set the ProfilePath attribute */
2625     Status = SampSetObjectAttributeString(UserObject,
2626                                           L"ProfilePath",
2627                                           NULL);
2628     if (!NT_SUCCESS(Status))
2629     {
2630         TRACE("failed with status 0x%08lx\n", Status);
2631         goto done;
2632     }
2633 
2634     /* Set the AdminComment attribute */
2635     Status = SampSetObjectAttributeString(UserObject,
2636                                           L"AdminComment",
2637                                           NULL);
2638     if (!NT_SUCCESS(Status))
2639     {
2640         TRACE("failed with status 0x%08lx\n", Status);
2641         goto done;
2642     }
2643 
2644     /* Set the UserComment attribute */
2645     Status = SampSetObjectAttributeString(UserObject,
2646                                           L"UserComment",
2647                                           NULL);
2648     if (!NT_SUCCESS(Status))
2649     {
2650         TRACE("failed with status 0x%08lx\n", Status);
2651         goto done;
2652     }
2653 
2654     /* Set the WorkStations attribute */
2655     Status = SampSetObjectAttributeString(UserObject,
2656                                           L"WorkStations",
2657                                           NULL);
2658     if (!NT_SUCCESS(Status))
2659     {
2660         TRACE("failed with status 0x%08lx\n", Status);
2661         goto done;
2662     }
2663 
2664     /* Set the Parameters attribute */
2665     Status = SampSetObjectAttributeString(UserObject,
2666                                           L"Parameters",
2667                                           NULL);
2668     if (!NT_SUCCESS(Status))
2669     {
2670         TRACE("failed with status 0x%08lx\n", Status);
2671         goto done;
2672     }
2673 
2674     /* Set LogonHours attribute*/
2675     *((PUSHORT)LogonHours) = 168;
2676     memset(&(LogonHours[2]), 0xff, 21);
2677 
2678     Status = SampSetObjectAttribute(UserObject,
2679                                     L"LogonHours",
2680                                     REG_BINARY,
2681                                     &LogonHours,
2682                                     sizeof(LogonHours));
2683     if (!NT_SUCCESS(Status))
2684     {
2685         TRACE("failed with status 0x%08lx\n", Status);
2686         goto done;
2687     }
2688 
2689     /* Set Groups attribute*/
2690     GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2691     GroupMembership.Attributes = SE_GROUP_MANDATORY |
2692                                  SE_GROUP_ENABLED |
2693                                  SE_GROUP_ENABLED_BY_DEFAULT;
2694 
2695     Status = SampSetObjectAttribute(UserObject,
2696                                     L"Groups",
2697                                     REG_BINARY,
2698                                     &GroupMembership,
2699                                     sizeof(GROUP_MEMBERSHIP));
2700     if (!NT_SUCCESS(Status))
2701     {
2702         TRACE("failed with status 0x%08lx\n", Status);
2703         goto done;
2704     }
2705 
2706     /* Set LMPwd attribute*/
2707     Status = SampSetObjectAttribute(UserObject,
2708                                     L"LMPwd",
2709                                     REG_BINARY,
2710                                     &EmptyLmHash,
2711                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2712     if (!NT_SUCCESS(Status))
2713     {
2714         TRACE("failed with status 0x%08lx\n", Status);
2715         goto done;
2716     }
2717 
2718     /* Set NTPwd attribute*/
2719     Status = SampSetObjectAttribute(UserObject,
2720                                     L"NTPwd",
2721                                     REG_BINARY,
2722                                     &EmptyNtHash,
2723                                     sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2724     if (!NT_SUCCESS(Status))
2725     {
2726         TRACE("failed with status 0x%08lx\n", Status);
2727         goto done;
2728     }
2729 
2730     /* Set LMPwdHistory attribute*/
2731     Status = SampSetObjectAttribute(UserObject,
2732                                     L"LMPwdHistory",
2733                                     REG_BINARY,
2734                                     NULL,
2735                                     0);
2736     if (!NT_SUCCESS(Status))
2737     {
2738         TRACE("failed with status 0x%08lx\n", Status);
2739         goto done;
2740     }
2741 
2742     /* Set NTPwdHistory attribute*/
2743     Status = SampSetObjectAttribute(UserObject,
2744                                     L"NTPwdHistory",
2745                                     REG_BINARY,
2746                                     NULL,
2747                                     0);
2748     if (!NT_SUCCESS(Status))
2749     {
2750         TRACE("failed with status 0x%08lx\n", Status);
2751         goto done;
2752     }
2753 
2754     /* Set the PrivateData attribute */
2755     Status = SampSetObjectAttributeString(UserObject,
2756                                           L"PrivateData",
2757                                           NULL);
2758     if (!NT_SUCCESS(Status))
2759     {
2760         TRACE("failed with status 0x%08lx\n", Status);
2761         goto done;
2762     }
2763 
2764     /* Set the SecDesc attribute*/
2765     Status = SampSetObjectAttribute(UserObject,
2766                                     L"SecDesc",
2767                                     REG_BINARY,
2768                                     Sd,
2769                                     SdSize);
2770     if (!NT_SUCCESS(Status))
2771     {
2772         TRACE("failed with status 0x%08lx\n", Status);
2773         goto done;
2774     }
2775 
2776     if (NT_SUCCESS(Status))
2777     {
2778         *UserHandle = (SAMPR_HANDLE)UserObject;
2779         *RelativeId = ulRid;
2780     }
2781 
2782 done:
2783     if (Sd != NULL)
2784         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2785 
2786     if (UserSid != NULL)
2787         RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2788 
2789     RtlReleaseResource(&SampResource);
2790 
2791     TRACE("returns with status 0x%08lx\n", Status);
2792 
2793     return Status;
2794 }
2795 
2796 
2797 /* Function 13 */
2798 NTSTATUS
2799 NTAPI
2800 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2801                            IN OUT unsigned long *EnumerationContext,
2802                            IN unsigned long UserAccountControl,
2803                            OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2804                            IN unsigned long PreferedMaximumLength,
2805                            OUT unsigned long *CountReturned)
2806 {
2807     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2808     PSAM_DB_OBJECT DomainObject;
2809     HANDLE UsersKeyHandle = NULL;
2810     HANDLE NamesKeyHandle = NULL;
2811     WCHAR UserName[64];
2812     ULONG EnumIndex;
2813     ULONG EnumCount = 0;
2814     ULONG RequiredLength = 0;
2815     ULONG NameLength;
2816     ULONG DataLength;
2817     ULONG Rid;
2818     ULONG i;
2819     BOOLEAN MoreEntries = FALSE;
2820     NTSTATUS Status;
2821 
2822     TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2823           DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2824           PreferedMaximumLength, CountReturned);
2825 
2826     RtlAcquireResourceShared(&SampResource,
2827                              TRUE);
2828 
2829     /* Validate the domain handle */
2830     Status = SampValidateDbObject(DomainHandle,
2831                                   SamDbDomainObject,
2832                                   DOMAIN_LIST_ACCOUNTS,
2833                                   &DomainObject);
2834     if (!NT_SUCCESS(Status))
2835         goto done;
2836 
2837     Status = SampRegOpenKey(DomainObject->KeyHandle,
2838                             L"Users",
2839                             KEY_READ,
2840                             &UsersKeyHandle);
2841     if (!NT_SUCCESS(Status))
2842         goto done;
2843 
2844     Status = SampRegOpenKey(UsersKeyHandle,
2845                             L"Names",
2846                             KEY_READ,
2847                             &NamesKeyHandle);
2848     if (!NT_SUCCESS(Status))
2849         goto done;
2850 
2851     TRACE("Part 1\n");
2852 
2853     EnumIndex = *EnumerationContext;
2854 
2855     while (TRUE)
2856     {
2857         NameLength = 64 * sizeof(WCHAR);
2858         Status = SampRegEnumerateValue(NamesKeyHandle,
2859                                        EnumIndex,
2860                                        UserName,
2861                                        &NameLength,
2862                                        NULL,
2863                                        NULL,
2864                                        NULL);
2865         if (!NT_SUCCESS(Status))
2866         {
2867             if (Status == STATUS_NO_MORE_ENTRIES)
2868                 Status = STATUS_SUCCESS;
2869             break;
2870         }
2871 
2872         TRACE("EnumIndex: %lu\n", EnumIndex);
2873         TRACE("User name: %S\n", UserName);
2874         TRACE("Name length: %lu\n", NameLength);
2875 
2876         if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2877         {
2878             MoreEntries = TRUE;
2879             break;
2880         }
2881 
2882         RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2883         EnumCount++;
2884 
2885         EnumIndex++;
2886     }
2887 
2888     TRACE("EnumCount: %lu\n", EnumCount);
2889     TRACE("RequiredLength: %lu\n", RequiredLength);
2890 
2891     if (!NT_SUCCESS(Status))
2892         goto done;
2893 
2894     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2895     if (EnumBuffer == NULL)
2896     {
2897         Status = STATUS_INSUFFICIENT_RESOURCES;
2898         goto done;
2899     }
2900 
2901     EnumBuffer->EntriesRead = EnumCount;
2902     if (EnumCount == 0)
2903         goto done;
2904 
2905     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2906     if (EnumBuffer->Buffer == NULL)
2907     {
2908         Status = STATUS_INSUFFICIENT_RESOURCES;
2909         goto done;
2910     }
2911 
2912     TRACE("Part 2\n");
2913 
2914     EnumIndex = *EnumerationContext;
2915     for (i = 0; i < EnumCount; i++, EnumIndex++)
2916     {
2917         NameLength = 64 * sizeof(WCHAR);
2918         DataLength = sizeof(ULONG);
2919         Status = SampRegEnumerateValue(NamesKeyHandle,
2920                                        EnumIndex,
2921                                        UserName,
2922                                        &NameLength,
2923                                        NULL,
2924                                        &Rid,
2925                                        &DataLength);
2926         if (!NT_SUCCESS(Status))
2927         {
2928             if (Status == STATUS_NO_MORE_ENTRIES)
2929                 Status = STATUS_SUCCESS;
2930             break;
2931         }
2932 
2933         TRACE("EnumIndex: %lu\n", EnumIndex);
2934         TRACE("User name: %S\n", UserName);
2935         TRACE("Name length: %lu\n", NameLength);
2936         TRACE("RID: %lu\n", Rid);
2937 
2938         EnumBuffer->Buffer[i].RelativeId = Rid;
2939 
2940         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2941         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2942 
2943 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2944 #if 0
2945         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2946         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2947         {
2948             Status = STATUS_INSUFFICIENT_RESOURCES;
2949             goto done;
2950         }
2951 
2952         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2953                UserName,
2954                EnumBuffer->Buffer[i].Name.Length);
2955 #endif
2956     }
2957 
2958 done:
2959     if (NT_SUCCESS(Status))
2960     {
2961         *EnumerationContext += EnumCount;
2962         *Buffer = EnumBuffer;
2963         *CountReturned = EnumCount;
2964     }
2965     else
2966     {
2967         *EnumerationContext = 0;
2968         *Buffer = NULL;
2969         *CountReturned = 0;
2970 
2971         if (EnumBuffer != NULL)
2972         {
2973             if (EnumBuffer->Buffer != NULL)
2974             {
2975                 if (EnumBuffer->EntriesRead != 0)
2976                 {
2977                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
2978                     {
2979                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2980                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2981                     }
2982                 }
2983 
2984                 midl_user_free(EnumBuffer->Buffer);
2985             }
2986 
2987             midl_user_free(EnumBuffer);
2988         }
2989     }
2990 
2991     SampRegCloseKey(&NamesKeyHandle);
2992     SampRegCloseKey(&UsersKeyHandle);
2993 
2994     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
2995         Status = STATUS_MORE_ENTRIES;
2996 
2997     RtlReleaseResource(&SampResource);
2998 
2999     return Status;
3000 }
3001 
3002 
3003 /* Function 14 */
3004 NTSTATUS
3005 NTAPI
3006 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
3007                         IN PRPC_UNICODE_STRING AccountName,
3008                         IN ACCESS_MASK DesiredAccess,
3009                         OUT SAMPR_HANDLE *AliasHandle,
3010                         OUT unsigned long *RelativeId)
3011 {
3012     SAM_DOMAIN_FIXED_DATA FixedDomainData;
3013     PSAM_DB_OBJECT DomainObject;
3014     PSAM_DB_OBJECT AliasObject;
3015     PSECURITY_DESCRIPTOR Sd = NULL;
3016     ULONG SdSize = 0;
3017     ULONG ulSize;
3018     ULONG ulRid;
3019     WCHAR szRid[9];
3020     NTSTATUS Status;
3021 
3022     TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
3023           DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
3024 
3025     /* Map generic access rights */
3026     RtlMapGenericMask(&DesiredAccess,
3027                       &AliasMapping);
3028 
3029     RtlAcquireResourceExclusive(&SampResource,
3030                                 TRUE);
3031 
3032     /* Validate the domain handle */
3033     Status = SampValidateDbObject(DomainHandle,
3034                                   SamDbDomainObject,
3035                                   DOMAIN_CREATE_ALIAS,
3036                                   &DomainObject);
3037     if (!NT_SUCCESS(Status))
3038     {
3039         TRACE("failed with status 0x%08lx\n", Status);
3040         goto done;
3041     }
3042 
3043     /* Check the alias account name */
3044     Status = SampCheckAccountName(AccountName, 256);
3045     if (!NT_SUCCESS(Status))
3046     {
3047         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
3048         goto done;
3049     }
3050 
3051     /* Check if the alias name already exists in the domain */
3052     Status = SampCheckAccountNameInDomain(DomainObject,
3053                                           AccountName->Buffer);
3054     if (!NT_SUCCESS(Status))
3055     {
3056         TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
3057               AccountName->Buffer, Status);
3058         goto done;
3059     }
3060 
3061     /* Create the security descriptor */
3062     Status = SampCreateAliasSD(&Sd,
3063                                &SdSize);
3064     if (!NT_SUCCESS(Status))
3065     {
3066         TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
3067         goto done;
3068     }
3069 
3070     /* Get the fixed domain attributes */
3071     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
3072     Status = SampGetObjectAttribute(DomainObject,
3073                                     L"F",
3074                                     NULL,
3075                                     (PVOID)&FixedDomainData,
3076                                     &ulSize);
3077     if (!NT_SUCCESS(Status))
3078     {
3079         TRACE("failed with status 0x%08lx\n", Status);
3080         goto done;
3081     }
3082 
3083     /* Increment the NextRid attribute */
3084     ulRid = FixedDomainData.NextRid;
3085     FixedDomainData.NextRid++;
3086 
3087     /* Store the fixed domain attributes */
3088     Status = SampSetObjectAttribute(DomainObject,
3089                            L"F",
3090                            REG_BINARY,
3091                            &FixedDomainData,
3092                            ulSize);
3093     if (!NT_SUCCESS(Status))
3094     {
3095         TRACE("failed with status 0x%08lx\n", Status);
3096         goto done;
3097     }
3098 
3099     TRACE("RID: %lx\n", ulRid);
3100 
3101     /* Convert the RID into a string (hex) */
3102     swprintf(szRid, L"%08lX", ulRid);
3103 
3104     /* Create the alias object */
3105     Status = SampCreateDbObject(DomainObject,
3106                                 L"Aliases",
3107                                 szRid,
3108                                 ulRid,
3109                                 SamDbAliasObject,
3110                                 DesiredAccess,
3111                                 &AliasObject);
3112     if (!NT_SUCCESS(Status))
3113     {
3114         TRACE("failed with status 0x%08lx\n", Status);
3115         goto done;
3116     }
3117 
3118     /* Add the account name for the alias object */
3119     Status = SampSetAccountNameInDomain(DomainObject,
3120                                         L"Aliases",
3121                                         AccountName->Buffer,
3122                                         ulRid);
3123     if (!NT_SUCCESS(Status))
3124     {
3125         TRACE("failed with status 0x%08lx\n", Status);
3126         goto done;
3127     }
3128 
3129     /* Set the Name attribute */
3130     Status = SampSetObjectAttributeString(AliasObject,
3131                                           L"Name",
3132                                           AccountName);
3133     if (!NT_SUCCESS(Status))
3134     {
3135         TRACE("failed with status 0x%08lx\n", Status);
3136         goto done;
3137     }
3138 
3139     /* Set the Description attribute */
3140     Status = SampSetObjectAttributeString(AliasObject,
3141                                           L"Description",
3142                                           NULL);
3143     if (!NT_SUCCESS(Status))
3144     {
3145         TRACE("failed with status 0x%08lx\n", Status);
3146         goto done;
3147     }
3148 
3149     /* Set the SecDesc attribute*/
3150     Status = SampSetObjectAttribute(AliasObject,
3151                                     L"SecDesc",
3152                                     REG_BINARY,
3153                                     Sd,
3154                                     SdSize);
3155     if (!NT_SUCCESS(Status))
3156     {
3157         TRACE("failed with status 0x%08lx\n", Status);
3158         goto done;
3159     }
3160 
3161     if (NT_SUCCESS(Status))
3162     {
3163         *AliasHandle = (SAMPR_HANDLE)AliasObject;
3164         *RelativeId = ulRid;
3165     }
3166 
3167 done:
3168     if (Sd != NULL)
3169         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
3170 
3171     RtlReleaseResource(&SampResource);
3172 
3173     TRACE("returns with status 0x%08lx\n", Status);
3174 
3175     return Status;
3176 }
3177 
3178 
3179 /* Function 15 */
3180 NTSTATUS
3181 NTAPI
3182 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
3183                              IN OUT unsigned long *EnumerationContext,
3184                              OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
3185                              IN unsigned long PreferedMaximumLength,
3186                              OUT unsigned long *CountReturned)
3187 {
3188     PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
3189     PSAM_DB_OBJECT DomainObject;
3190     HANDLE AliasesKeyHandle = NULL;
3191     HANDLE NamesKeyHandle = NULL;
3192     WCHAR AliasName[64];
3193     ULONG EnumIndex;
3194     ULONG EnumCount = 0;
3195     ULONG RequiredLength = 0;
3196     ULONG NameLength;
3197     ULONG DataLength;
3198     ULONG Rid;
3199     ULONG i;
3200     BOOLEAN MoreEntries = FALSE;
3201     NTSTATUS Status;
3202 
3203     TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
3204           DomainHandle, EnumerationContext, Buffer,
3205           PreferedMaximumLength, CountReturned);
3206 
3207     RtlAcquireResourceShared(&SampResource,
3208                              TRUE);
3209 
3210     /* Validate the domain handle */
3211     Status = SampValidateDbObject(DomainHandle,
3212                                   SamDbDomainObject,
3213                                   DOMAIN_LIST_ACCOUNTS,
3214                                   &DomainObject);
3215     if (!NT_SUCCESS(Status))
3216         goto done;
3217 
3218     Status = SampRegOpenKey(DomainObject->KeyHandle,
3219                             L"Aliases",
3220                             KEY_READ,
3221                             &AliasesKeyHandle);
3222     if (!NT_SUCCESS(Status))
3223         goto done;
3224 
3225     Status = SampRegOpenKey(AliasesKeyHandle,
3226                             L"Names",
3227                             KEY_READ,
3228                             &NamesKeyHandle);
3229     if (!NT_SUCCESS(Status))
3230         goto done;
3231 
3232     TRACE("Part 1\n");
3233 
3234     EnumIndex = *EnumerationContext;
3235 
3236     while (TRUE)
3237     {
3238         NameLength = 64 * sizeof(WCHAR);
3239         Status = SampRegEnumerateValue(NamesKeyHandle,
3240                                        EnumIndex,
3241                                        AliasName,
3242                                        &NameLength,
3243                                        NULL,
3244                                        NULL,
3245                                        NULL);
3246         if (!NT_SUCCESS(Status))
3247         {
3248             if (Status == STATUS_NO_MORE_ENTRIES)
3249                 Status = STATUS_SUCCESS;
3250             break;
3251         }
3252 
3253         TRACE("EnumIndex: %lu\n", EnumIndex);
3254         TRACE("Alias name: %S\n", AliasName);
3255         TRACE("Name length: %lu\n", NameLength);
3256 
3257         if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3258         {
3259             MoreEntries = TRUE;
3260             break;
3261         }
3262 
3263         RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3264         EnumCount++;
3265 
3266         EnumIndex++;
3267     }
3268 
3269     TRACE("EnumCount: %lu\n", EnumCount);
3270     TRACE("RequiredLength: %lu\n", RequiredLength);
3271 
3272     if (!NT_SUCCESS(Status))
3273         goto done;
3274 
3275     EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3276     if (EnumBuffer == NULL)
3277     {
3278         Status = STATUS_INSUFFICIENT_RESOURCES;
3279         goto done;
3280     }
3281 
3282     EnumBuffer->EntriesRead = EnumCount;
3283     if (EnumCount == 0)
3284         goto done;
3285 
3286     EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3287     if (EnumBuffer->Buffer == NULL)
3288     {
3289         Status = STATUS_INSUFFICIENT_RESOURCES;
3290         goto done;
3291     }
3292 
3293     TRACE("Part 2\n");
3294 
3295     EnumIndex = *EnumerationContext;
3296     for (i = 0; i < EnumCount; i++, EnumIndex++)
3297     {
3298         NameLength = 64 * sizeof(WCHAR);
3299         DataLength = sizeof(ULONG);
3300         Status = SampRegEnumerateValue(NamesKeyHandle,
3301                                        EnumIndex,
3302                                        AliasName,
3303                                        &NameLength,
3304                                        NULL,
3305                                        &Rid,
3306                                        &DataLength);
3307         if (!NT_SUCCESS(Status))
3308         {
3309             if (Status == STATUS_NO_MORE_ENTRIES)
3310                 Status = STATUS_SUCCESS;
3311             break;
3312         }
3313 
3314         TRACE("EnumIndex: %lu\n", EnumIndex);
3315         TRACE("Alias name: %S\n", AliasName);
3316         TRACE("Name length: %lu\n", NameLength);
3317         TRACE("RID: %lu\n", Rid);
3318 
3319         EnumBuffer->Buffer[i].RelativeId = Rid;
3320 
3321         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3322         EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
3323 
3324 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3325 #if 0
3326         EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3327         if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3328         {
3329             Status = STATUS_INSUFFICIENT_RESOURCES;
3330             goto done;
3331         }
3332 
3333         memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3334                AliasName,
3335                EnumBuffer->Buffer[i].Name.Length);
3336 #endif
3337     }
3338 
3339 done:
3340     if (NT_SUCCESS(Status))
3341     {
3342         *EnumerationContext += EnumCount;
3343         *Buffer = EnumBuffer;
3344         *CountReturned = EnumCount;
3345     }
3346     else
3347     {
3348         *EnumerationContext = 0;
3349         *Buffer = NULL;
3350         *CountReturned = 0;
3351 
3352         if (EnumBuffer != NULL)
3353         {
3354             if (EnumBuffer->Buffer != NULL)
3355             {
3356                 if (EnumBuffer->EntriesRead != 0)
3357                 {
3358                     for (i = 0; i < EnumBuffer->EntriesRead; i++)
3359                     {
3360                         if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3361                             midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3362                     }
3363                 }
3364 
3365                 midl_user_free(EnumBuffer->Buffer);
3366             }
3367 
3368             midl_user_free(EnumBuffer);
3369         }
3370     }
3371 
3372     SampRegCloseKey(&NamesKeyHandle);
3373     SampRegCloseKey(&AliasesKeyHandle);
3374 
3375     if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3376         Status = STATUS_MORE_ENTRIES;
3377 
3378     RtlReleaseResource(&SampResource);
3379 
3380     return Status;
3381 }
3382 
3383 
3384 /* Function 16 */
3385 NTSTATUS
3386 NTAPI
3387 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3388                        IN PSAMPR_PSID_ARRAY SidArray,
3389                        OUT PSAMPR_ULONG_ARRAY Membership)
3390 {
3391     PSAM_DB_OBJECT DomainObject;
3392     HANDLE AliasesKeyHandle = NULL;
3393     HANDLE MembersKeyHandle = NULL;
3394     HANDLE MemberKeyHandle = NULL;
3395     LPWSTR MemberSidString = NULL;
3396     PULONG RidArray = NULL;
3397     ULONG MaxSidCount = 0;
3398     ULONG ValueCount;
3399     ULONG DataLength;
3400     ULONG i, j;
3401     ULONG RidIndex;
3402     NTSTATUS Status;
3403     WCHAR NameBuffer[9];
3404 
3405     TRACE("SamrGetAliasMembership(%p %p %p)\n",
3406           DomainHandle, SidArray, Membership);
3407 
3408     RtlAcquireResourceShared(&SampResource,
3409                              TRUE);
3410 
3411     /* Validate the domain handle */
3412     Status = SampValidateDbObject(DomainHandle,
3413                                   SamDbDomainObject,
3414                                   DOMAIN_GET_ALIAS_MEMBERSHIP,
3415                                   &DomainObject);
3416     if (!NT_SUCCESS(Status))
3417         goto done;
3418 
3419     Status = SampRegOpenKey(DomainObject->KeyHandle,
3420                             L"Aliases",
3421                             KEY_READ,
3422                             &AliasesKeyHandle);
3423     TRACE("SampRegOpenKey returned %08lX\n", Status);
3424     if (!NT_SUCCESS(Status))
3425         goto done;
3426 
3427     Status = SampRegOpenKey(AliasesKeyHandle,
3428                             L"Members",
3429                             KEY_READ,
3430                             &MembersKeyHandle);
3431     TRACE("SampRegOpenKey returned %08lX\n", Status);
3432 
3433     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3434     {
3435         Status = STATUS_SUCCESS;
3436         goto done;
3437     }
3438 
3439     if (!NT_SUCCESS(Status))
3440         goto done;
3441 
3442     for (i = 0; i < SidArray->Count; i++)
3443     {
3444         ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3445 TRACE("Open %S\n", MemberSidString);
3446 
3447         Status = SampRegOpenKey(MembersKeyHandle,
3448                                 MemberSidString,
3449                                 KEY_READ,
3450                                 &MemberKeyHandle);
3451         TRACE("SampRegOpenKey returned %08lX\n", Status);
3452         if (NT_SUCCESS(Status))
3453         {
3454             Status = SampRegQueryKeyInfo(MemberKeyHandle,
3455                                          NULL,
3456                                          &ValueCount);
3457             if (NT_SUCCESS(Status))
3458             {
3459                 TRACE("Found %lu values\n", ValueCount);
3460                 MaxSidCount += ValueCount;
3461             }
3462 
3463             SampRegCloseKey(&MemberKeyHandle);
3464         }
3465 
3466         if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3467             Status = STATUS_SUCCESS;
3468 
3469         LocalFree(MemberSidString);
3470     }
3471 
3472     if (MaxSidCount == 0)
3473     {
3474         Status = STATUS_SUCCESS;
3475         goto done;
3476     }
3477 
3478     TRACE("Maximum sid count: %lu\n", MaxSidCount);
3479     RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3480     if (RidArray == NULL)
3481     {
3482         Status = STATUS_INSUFFICIENT_RESOURCES;
3483         goto done;
3484     }
3485 
3486     RidIndex = 0;
3487     for (i = 0; i < SidArray->Count; i++)
3488     {
3489         ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3490 TRACE("Open %S\n", MemberSidString);
3491 
3492         Status = SampRegOpenKey(MembersKeyHandle,
3493                                 MemberSidString,
3494                                 KEY_READ,
3495                                 &MemberKeyHandle);
3496         TRACE("SampRegOpenKey returned %08lX\n", Status);
3497         if (NT_SUCCESS(Status))
3498         {
3499             Status = SampRegQueryKeyInfo(MemberKeyHandle,
3500                                          NULL,
3501                                          &ValueCount);
3502             if (NT_SUCCESS(Status))
3503             {
3504                 TRACE("Found %lu values\n", ValueCount);
3505 
3506                 for (j = 0; j < ValueCount; j++)
3507                 {
3508                     DataLength = 9 * sizeof(WCHAR);
3509                     Status = SampRegEnumerateValue(MemberKeyHandle,
3510                                                    j,
3511                                                    NameBuffer,
3512                                                    &DataLength,
3513                                                    NULL,
3514                                                    NULL,
3515                                                    NULL);
3516                     if (NT_SUCCESS(Status))
3517                     {
3518                         /* FIXME: Do not return each RID more than once. */
3519                         RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
3520                         RidIndex++;
3521                     }
3522                 }
3523             }
3524 
3525             SampRegCloseKey(&MemberKeyHandle);
3526         }
3527 
3528         if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3529             Status = STATUS_SUCCESS;
3530 
3531         LocalFree(MemberSidString);
3532     }
3533 
3534 done:
3535     SampRegCloseKey(&MembersKeyHandle);
3536     SampRegCloseKey(&AliasesKeyHandle);
3537 
3538     if (NT_SUCCESS(Status))
3539     {
3540         Membership->Count = MaxSidCount;
3541         Membership->Element = RidArray;
3542     }
3543     else
3544     {
3545         if (RidArray != NULL)
3546             midl_user_free(RidArray);
3547     }
3548 
3549     RtlReleaseResource(&SampResource);
3550 
3551     return Status;
3552 }
3553 
3554 
3555 /* Function 17 */
3556 NTSTATUS
3557 NTAPI
3558 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3559                         IN ULONG Count,
3560                         IN RPC_UNICODE_STRING Names[],
3561                         OUT PSAMPR_ULONG_ARRAY RelativeIds,
3562                         OUT PSAMPR_ULONG_ARRAY Use)
3563 {
3564     PSAM_DB_OBJECT DomainObject;
3565     HANDLE AccountsKeyHandle = NULL;
3566     HANDLE NamesKeyHandle = NULL;
3567     ULONG MappedCount = 0;
3568     ULONG DataLength;
3569     ULONG i;
3570     ULONG RelativeId;
3571     NTSTATUS Status;
3572 
3573     TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3574           DomainHandle, Count, Names, RelativeIds, Use);
3575 
3576     RtlAcquireResourceShared(&SampResource,
3577                              TRUE);
3578 
3579     /* Validate the domain handle */
3580     Status = SampValidateDbObject(DomainHandle,
3581                                   SamDbDomainObject,
3582                                   DOMAIN_LOOKUP,
3583                                   &DomainObject);
3584     if (!NT_SUCCESS(Status))
3585     {
3586         TRACE("failed with status 0x%08lx\n", Status);
3587         goto done;
3588     }
3589 
3590     RelativeIds->Count = 0;
3591     Use->Count = 0;
3592 
3593     if (Count == 0)
3594     {
3595         Status = STATUS_SUCCESS;
3596         goto done;
3597     }
3598 
3599     /* Allocate the relative IDs array */
3600     RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3601     if (RelativeIds->Element == NULL)
3602     {
3603         Status = STATUS_INSUFFICIENT_RESOURCES;
3604         goto done;
3605     }
3606 
3607     /* Allocate the use array */
3608     Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3609     if (Use->Element == NULL)
3610     {
3611         Status = STATUS_INSUFFICIENT_RESOURCES;
3612         goto done;
3613     }
3614 
3615     RelativeIds->Count = Count;
3616     Use->Count = Count;
3617 
3618     for (i = 0; i < Count; i++)
3619     {
3620         TRACE("Name: %S\n", Names[i].Buffer);
3621 
3622         RelativeId = 0;
3623 
3624         /* Lookup aliases */
3625         Status = SampRegOpenKey(DomainObject->KeyHandle,
3626                                 L"Aliases",
3627                                 KEY_READ,
3628                                 &AccountsKeyHandle);
3629         if (NT_SUCCESS(Status))
3630         {
3631             Status = SampRegOpenKey(AccountsKeyHandle,
3632                                     L"Names",
3633                                     KEY_READ,
3634                                     &NamesKeyHandle);
3635             if (NT_SUCCESS(Status))
3636             {
3637                 DataLength = sizeof(ULONG);
3638                 Status = SampRegQueryValue(NamesKeyHandle,
3639                                            Names[i].Buffer,
3640                                            NULL,
3641                                            &RelativeId,
3642                                            &DataLength);
3643 
3644                 SampRegCloseKey(&NamesKeyHandle);
3645             }
3646 
3647             SampRegCloseKey(&AccountsKeyHandle);
3648         }
3649 
3650         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3651             break;
3652 
3653         /* Return alias account */
3654         if (NT_SUCCESS(Status) && RelativeId != 0)
3655         {
3656             TRACE("Rid: %lu\n", RelativeId);
3657             RelativeIds->Element[i] = RelativeId;
3658             Use->Element[i] = SidTypeAlias;
3659             MappedCount++;
3660             continue;
3661         }
3662 
3663         /* Lookup groups */
3664         Status = SampRegOpenKey(DomainObject->KeyHandle,
3665                                 L"Groups",
3666                                 KEY_READ,
3667                                 &AccountsKeyHandle);
3668         if (NT_SUCCESS(Status))
3669         {
3670             Status = SampRegOpenKey(AccountsKeyHandle,
3671                                     L"Names",
3672                                     KEY_READ,
3673                                     &NamesKeyHandle);
3674             if (NT_SUCCESS(Status))
3675             {
3676                 DataLength = sizeof(ULONG);
3677                 Status = SampRegQueryValue(NamesKeyHandle,
3678                                            Names[i].Buffer,
3679                                            NULL,
3680                                            &RelativeId,
3681                                            &DataLength);
3682 
3683                 SampRegCloseKey(&NamesKeyHandle);
3684             }
3685 
3686             SampRegCloseKey(&AccountsKeyHandle);
3687         }
3688 
3689         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3690             break;
3691 
3692         /* Return group account */
3693         if (NT_SUCCESS(Status) && RelativeId != 0)
3694         {
3695             TRACE("Rid: %lu\n", RelativeId);
3696             RelativeIds->Element[i] = RelativeId;
3697             Use->Element[i] = SidTypeGroup;
3698             MappedCount++;
3699             continue;
3700         }
3701 
3702         /* Lookup users */
3703         Status = SampRegOpenKey(DomainObject->KeyHandle,
3704                                 L"Users",
3705                                 KEY_READ,
3706                                 &AccountsKeyHandle);
3707         if (NT_SUCCESS(Status))
3708         {
3709             Status = SampRegOpenKey(AccountsKeyHandle,
3710                                     L"Names",
3711                                     KEY_READ,
3712                                     &NamesKeyHandle);
3713             if (NT_SUCCESS(Status))
3714             {
3715                 DataLength = sizeof(ULONG);
3716                 Status = SampRegQueryValue(NamesKeyHandle,
3717                                            Names[i].Buffer,
3718                                            NULL,
3719                                            &RelativeId,
3720                                            &DataLength);
3721 
3722                 SampRegCloseKey(&NamesKeyHandle);
3723             }
3724 
3725             SampRegCloseKey(&AccountsKeyHandle);
3726         }
3727 
3728         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3729             break;
3730 
3731         /* Return user account */
3732         if (NT_SUCCESS(Status) && RelativeId != 0)
3733         {
3734             TRACE("Rid: %lu\n", RelativeId);
3735             RelativeIds->Element[i] = RelativeId;
3736             Use->Element[i] = SidTypeUser;
3737             MappedCount++;
3738             continue;
3739         }
3740 
3741         /* Return unknown account */
3742         RelativeIds->Element[i] = 0;
3743         Use->Element[i] = SidTypeUnknown;
3744     }
3745 
3746 done:
3747     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3748         Status = STATUS_SUCCESS;
3749 
3750     if (NT_SUCCESS(Status))
3751     {
3752         if (MappedCount == 0)
3753             Status = STATUS_NONE_MAPPED;
3754         else if (MappedCount < Count)
3755             Status = STATUS_SOME_NOT_MAPPED;
3756     }
3757     else
3758     {
3759         if (RelativeIds->Element != NULL)
3760         {
3761             midl_user_free(RelativeIds->Element);
3762             RelativeIds->Element = NULL;
3763         }
3764 
3765         RelativeIds->Count = 0;
3766 
3767         if (Use->Element != NULL)
3768         {
3769             midl_user_free(Use->Element);
3770             Use->Element = NULL;
3771         }
3772 
3773         Use->Count = 0;
3774     }
3775 
3776     RtlReleaseResource(&SampResource);
3777 
3778     TRACE("Returned Status %lx\n", Status);
3779 
3780     return Status;
3781 }
3782 
3783 
3784 /* Function 18 */
3785 NTSTATUS
3786 NTAPI
3787 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3788                       IN ULONG Count,
3789                       IN ULONG *RelativeIds,
3790                       OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3791                       OUT PSAMPR_ULONG_ARRAY Use)
3792 {
3793     PSAM_DB_OBJECT DomainObject;
3794     WCHAR RidString[9];
3795     HANDLE AccountsKeyHandle = NULL;
3796     HANDLE AccountKeyHandle = NULL;
3797     ULONG MappedCount = 0;
3798     ULONG DataLength;
3799     ULONG i;
3800     NTSTATUS Status;
3801 
3802     TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3803           DomainHandle, Count, RelativeIds, Names, Use);
3804 
3805     RtlAcquireResourceShared(&SampResource,
3806                              TRUE);
3807 
3808     /* Validate the domain handle */
3809     Status = SampValidateDbObject(DomainHandle,
3810                                   SamDbDomainObject,
3811                                   DOMAIN_LOOKUP,
3812                                   &DomainObject);
3813     if (!NT_SUCCESS(Status))
3814     {
3815         TRACE("failed with status 0x%08lx\n", Status);
3816         goto done;
3817     }
3818 
3819     Names->Count = 0;
3820     Use->Count = 0;
3821 
3822     if (Count == 0)
3823     {
3824         Status = STATUS_SUCCESS;
3825         goto done;
3826     }
3827 
3828     /* Allocate the names array */
3829     Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
3830     if (Names->Element == NULL)
3831     {
3832         Status = STATUS_INSUFFICIENT_RESOURCES;
3833         goto done;
3834     }
3835 
3836     /* Allocate the use array */
3837     Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
3838     if (Use->Element == NULL)
3839     {
3840         Status = STATUS_INSUFFICIENT_RESOURCES;
3841         goto done;
3842     }
3843 
3844     Names->Count = Count;
3845     Use->Count = Count;
3846 
3847     for (i = 0; i < Count; i++)
3848     {
3849         TRACE("RID: %lu\n", RelativeIds[i]);
3850 
3851         swprintf(RidString, L"%08lx", RelativeIds[i]);
3852 
3853         /* Lookup aliases */
3854         Status = SampRegOpenKey(DomainObject->KeyHandle,
3855                                 L"Aliases",
3856                                 KEY_READ,
3857                                 &AccountsKeyHandle);
3858         if (NT_SUCCESS(Status))
3859         {
3860             Status = SampRegOpenKey(AccountsKeyHandle,
3861                                     RidString,
3862                                     KEY_READ,
3863                                     &AccountKeyHandle);
3864             if (NT_SUCCESS(Status))
3865             {
3866                 DataLength = 0;
3867                 Status = SampRegQueryValue(AccountKeyHandle,
3868                                            L"Name",
3869                                            NULL,
3870                                            NULL,
3871                                            &DataLength);
3872                 if (NT_SUCCESS(Status))
3873                 {
3874                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3875                     if (Names->Element[i].Buffer == NULL)
3876                         Status = STATUS_INSUFFICIENT_RESOURCES;
3877 
3878                     if (NT_SUCCESS(Status))
3879                     {
3880                         Names->Element[i].MaximumLength = (USHORT)DataLength;
3881                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3882 
3883                         Status = SampRegQueryValue(AccountKeyHandle,
3884                                                    L"Name",
3885                                                    NULL,
3886                                                    Names->Element[i].Buffer,
3887                                                    &DataLength);
3888                     }
3889                 }
3890 
3891                 SampRegCloseKey(&AccountKeyHandle);
3892             }
3893 
3894             SampRegCloseKey(&AccountsKeyHandle);
3895         }
3896 
3897         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3898             break;
3899 
3900         /* Return alias account */
3901         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3902         {
3903             TRACE("Name: %S\n", Names->Element[i].Buffer);
3904             Use->Element[i] = SidTypeAlias;
3905             MappedCount++;
3906             continue;
3907         }
3908 
3909         /* Lookup groups */
3910         Status = SampRegOpenKey(DomainObject->KeyHandle,
3911                                 L"Groups",
3912                                 KEY_READ,
3913                                 &AccountsKeyHandle);
3914         if (NT_SUCCESS(Status))
3915         {
3916             Status = SampRegOpenKey(AccountsKeyHandle,
3917                                     RidString,
3918                                     KEY_READ,
3919                                     &AccountKeyHandle);
3920             if (NT_SUCCESS(Status))
3921             {
3922                 DataLength = 0;
3923                 Status = SampRegQueryValue(AccountKeyHandle,
3924                                            L"Name",
3925                                            NULL,
3926                                            NULL,
3927                                            &DataLength);
3928                 if (NT_SUCCESS(Status))
3929                 {
3930                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3931                     if (Names->Element[i].Buffer == NULL)
3932                         Status = STATUS_INSUFFICIENT_RESOURCES;
3933 
3934                     if (NT_SUCCESS(Status))
3935                     {
3936                         Names->Element[i].MaximumLength = (USHORT)DataLength;
3937                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3938 
3939                         Status = SampRegQueryValue(AccountKeyHandle,
3940                                                    L"Name",
3941                                                    NULL,
3942                                                    Names->Element[i].Buffer,
3943                                                    &DataLength);
3944                     }
3945                 }
3946 
3947                 SampRegCloseKey(&AccountKeyHandle);
3948             }
3949 
3950             SampRegCloseKey(&AccountsKeyHandle);
3951         }
3952 
3953         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3954             break;
3955 
3956         /* Return group account */
3957         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3958         {
3959             TRACE("Name: %S\n", Names->Element[i].Buffer);
3960             Use->Element[i] = SidTypeGroup;
3961             MappedCount++;
3962             continue;
3963         }
3964 
3965         /* Lookup users */
3966         Status = SampRegOpenKey(DomainObject->KeyHandle,
3967                                 L"Users",
3968                                 KEY_READ,
3969                                 &AccountsKeyHandle);
3970         if (NT_SUCCESS(Status))
3971         {
3972             Status = SampRegOpenKey(AccountsKeyHandle,
3973                                     RidString,
3974                                     KEY_READ,
3975                                     &AccountKeyHandle);
3976             if (NT_SUCCESS(Status))
3977             {
3978                 DataLength = 0;
3979                 Status = SampRegQueryValue(AccountKeyHandle,
3980                                            L"Name",
3981                                            NULL,
3982                                            NULL,
3983                                            &DataLength);
3984                 if (NT_SUCCESS(Status))
3985                 {
3986                     TRACE("DataLength: %lu\n", DataLength);
3987 
3988                     Names->Element[i].Buffer = midl_user_allocate(DataLength);
3989                     if (Names->Element[i].Buffer == NULL)
3990                         Status = STATUS_INSUFFICIENT_RESOURCES;
3991 
3992                     if (NT_SUCCESS(Status))
3993                     {
3994                         Names->Element[i].MaximumLength = (USHORT)DataLength;
3995                         Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3996 
3997                         Status = SampRegQueryValue(AccountKeyHandle,
3998                                                    L"Name",
3999                                                    NULL,
4000                                                    Names->Element[i].Buffer,
4001                                                    &DataLength);
4002                     }
4003                 }
4004 
4005                 SampRegCloseKey(&AccountKeyHandle);
4006             }
4007 
4008             SampRegCloseKey(&AccountsKeyHandle);
4009         }
4010 
4011         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4012             break;
4013 
4014         /* Return user account */
4015         if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
4016         {
4017             TRACE("Name: %S\n", Names->Element[i].Buffer);
4018             Use->Element[i] = SidTypeUser;
4019             MappedCount++;
4020             continue;
4021         }
4022 
4023         /* Return unknown account */
4024         Use->Element[i] = SidTypeUnknown;
4025     }
4026 
4027 done:
4028     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4029         Status = STATUS_SUCCESS;
4030 
4031     if (NT_SUCCESS(Status))
4032     {
4033         if (MappedCount == 0)
4034             Status = STATUS_NONE_MAPPED;
4035         else if (MappedCount < Count)
4036             Status = STATUS_SOME_NOT_MAPPED;
4037     }
4038     else
4039     {
4040         if (Names->Element != NULL)
4041         {
4042             for (i = 0; i < Count; i++)
4043             {
4044                 if (Names->Element[i].Buffer != NULL)
4045                     midl_user_free(Names->Element[i].Buffer);
4046             }
4047 
4048             midl_user_free(Names->Element);
4049             Names->Element = NULL;
4050         }
4051 
4052         Names->Count = 0;
4053 
4054         if (Use->Element != NULL)
4055         {
4056             midl_user_free(Use->Element);
4057             Use->Element = NULL;
4058         }
4059 
4060         Use->Count = 0;
4061     }
4062 
4063     RtlReleaseResource(&SampResource);
4064 
4065     return Status;
4066 }
4067 
4068 
4069 /* Function 19 */
4070 NTSTATUS
4071 NTAPI
4072 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
4073               IN ACCESS_MASK DesiredAccess,
4074               IN unsigned long GroupId,
4075               OUT SAMPR_HANDLE *GroupHandle)
4076 {
4077     PSAM_DB_OBJECT DomainObject;
4078     PSAM_DB_OBJECT GroupObject;
4079     WCHAR szRid[9];
4080     NTSTATUS Status;
4081 
4082     TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
4083           DomainHandle, DesiredAccess, GroupId, GroupHandle);
4084 
4085     /* Map generic access rights */
4086     RtlMapGenericMask(&DesiredAccess,
4087                       &GroupMapping);
4088 
4089     RtlAcquireResourceShared(&SampResource,
4090                              TRUE);
4091 
4092     /* Validate the domain handle */
4093     Status = SampValidateDbObject(DomainHandle,
4094                                   SamDbDomainObject,
4095                                   DOMAIN_LOOKUP,
4096                                   &DomainObject);
4097     if (!NT_SUCCESS(Status))
4098     {
4099         TRACE("failed with status 0x%08lx\n", Status);
4100         goto done;
4101     }
4102 
4103     /* Convert the RID into a string (hex) */
4104     swprintf(szRid, L"%08lX", GroupId);
4105 
4106     /* Create the group object */
4107     Status = SampOpenDbObject(DomainObject,
4108                               L"Groups",
4109                               szRid,
4110                               GroupId,
4111                               SamDbGroupObject,
4112                               DesiredAccess,
4113                               &GroupObject);
4114     if (!NT_SUCCESS(Status))
4115     {
4116         TRACE("failed with status 0x%08lx\n", Status);
4117         goto done;
4118     }
4119 
4120     *GroupHandle = (SAMPR_HANDLE)GroupObject;
4121 
4122 done:
4123     RtlReleaseResource(&SampResource);
4124 
4125     return Status;
4126 }
4127 
4128 
4129 static NTSTATUS
4130 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
4131                       PSAMPR_GROUP_INFO_BUFFER *Buffer)
4132 {
4133     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4134     SAM_GROUP_FIXED_DATA FixedData;
4135     ULONG MembersLength = 0;
4136     ULONG Length = 0;
4137     NTSTATUS Status;
4138 
4139     *Buffer = NULL;
4140 
4141     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4142     if (InfoBuffer == NULL)
4143         return STATUS_INSUFFICIENT_RESOURCES;
4144 
4145     Status = SampGetObjectAttributeString(GroupObject,
4146                                           L"Name",
4147                                           &InfoBuffer->General.Name);
4148     if (!NT_SUCCESS(Status))
4149     {
4150         TRACE("Status 0x%08lx\n", Status);
4151         goto done;
4152     }
4153 
4154     Status = SampGetObjectAttributeString(GroupObject,
4155                                           L"AdminComment",
4156                                           &InfoBuffer->General.AdminComment);
4157     if (!NT_SUCCESS(Status))
4158     {
4159         TRACE("Status 0x%08lx\n", Status);
4160         goto done;
4161     }
4162 
4163     Length = sizeof(SAM_GROUP_FIXED_DATA);
4164     Status = SampGetObjectAttribute(GroupObject,
4165                                     L"F",
4166                                     NULL,
4167                                     (PVOID)&FixedData,
4168                                     &Length);
4169     if (!NT_SUCCESS(Status))
4170     {
4171         TRACE("Status 0x%08lx\n", Status);
4172         goto done;
4173     }
4174 
4175     InfoBuffer->General.Attributes = FixedData.Attributes;
4176 
4177     Status = SampGetObjectAttribute(GroupObject,
4178                                     L"Members",
4179                                     NULL,
4180                                     NULL,
4181                                     &MembersLength);
4182     if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4183     {
4184         TRACE("Status 0x%08lx\n", Status);
4185         goto done;
4186     }
4187 
4188     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4189     {
4190         InfoBuffer->General.MemberCount = 0;
4191         Status = STATUS_SUCCESS;
4192     }
4193     else
4194     {
4195         InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4196     }
4197 
4198     *Buffer = InfoBuffer;
4199 
4200 done:
4201     if (!NT_SUCCESS(Status))
4202     {
4203         if (InfoBuffer != NULL)
4204         {
4205             if (InfoBuffer->General.Name.Buffer != NULL)
4206                 midl_user_free(InfoBuffer->General.Name.Buffer);
4207 
4208             if (InfoBuffer->General.AdminComment.Buffer != NULL)
4209                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4210 
4211             midl_user_free(InfoBuffer);
4212         }
4213     }
4214 
4215     return Status;
4216 }
4217 
4218 
4219 static NTSTATUS
4220 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
4221                    PSAMPR_GROUP_INFO_BUFFER *Buffer)
4222 {
4223     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4224     NTSTATUS Status;
4225 
4226     *Buffer = NULL;
4227 
4228     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4229     if (InfoBuffer == NULL)
4230         return STATUS_INSUFFICIENT_RESOURCES;
4231 
4232     Status = SampGetObjectAttributeString(GroupObject,
4233                                           L"Name",
4234                                           &InfoBuffer->Name.Name);
4235     if (!NT_SUCCESS(Status))
4236     {
4237         TRACE("Status 0x%08lx\n", Status);
4238         goto done;
4239     }
4240 
4241     *Buffer = InfoBuffer;
4242 
4243 done:
4244     if (!NT_SUCCESS(Status))
4245     {
4246         if (InfoBuffer != NULL)
4247         {
4248             if (InfoBuffer->Name.Name.Buffer != NULL)
4249                 midl_user_free(InfoBuffer->Name.Name.Buffer);
4250 
4251             midl_user_free(InfoBuffer);
4252         }
4253     }
4254 
4255     return Status;
4256 }
4257 
4258 
4259 static NTSTATUS
4260 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
4261                         PSAMPR_GROUP_INFO_BUFFER *Buffer)
4262 {
4263     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4264     SAM_GROUP_FIXED_DATA FixedData;
4265     ULONG Length = 0;
4266     NTSTATUS Status;
4267 
4268     *Buffer = NULL;
4269 
4270     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4271     if (InfoBuffer == NULL)
4272         return STATUS_INSUFFICIENT_RESOURCES;
4273 
4274     Length = sizeof(SAM_GROUP_FIXED_DATA);
4275     Status = SampGetObjectAttribute(GroupObject,
4276                                     L"F",
4277                                     NULL,
4278                                     (PVOID)&FixedData,
4279                                     &Length);
4280     if (!NT_SUCCESS(Status))
4281     {
4282         TRACE("Status 0x%08lx\n", Status);
4283         goto done;
4284     }
4285 
4286     InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4287 
4288     *Buffer = InfoBuffer;
4289 
4290 done:
4291     if (!NT_SUCCESS(Status))
4292     {
4293         if (InfoBuffer != NULL)
4294         {
4295             midl_user_free(InfoBuffer);
4296         }
4297     }
4298 
4299     return Status;
4300 }
4301 
4302 
4303 static NTSTATUS
4304 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
4305                            PSAMPR_GROUP_INFO_BUFFER *Buffer)
4306 {
4307     PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4308     NTSTATUS Status;
4309 
4310     *Buffer = NULL;
4311 
4312     InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4313     if (InfoBuffer == NULL)
4314         return STATUS_INSUFFICIENT_RESOURCES;
4315 
4316     Status = SampGetObjectAttributeString(GroupObject,
4317                                           L"AdminComment",
4318                                           &InfoBuffer->AdminComment.AdminComment);
4319     if (!NT_SUCCESS(Status))
4320     {
4321         TRACE("Status 0x%08lx\n", Status);
4322         goto done;
4323     }
4324 
4325     *Buffer = InfoBuffer;
4326 
4327 done:
4328     if (!NT_SUCCESS(Status))
4329     {
4330         if (InfoBuffer != NULL)
4331         {
4332             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4333                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4334 
4335             midl_user_free(InfoBuffer);
4336         }
4337     }
4338 
4339     return Status;
4340 }
4341 
4342 
4343 /* Function 20 */
4344 NTSTATUS
4345 NTAPI
4346 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
4347                           IN GROUP_INFORMATION_CLASS GroupInformationClass,
4348                           OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
4349 {
4350     PSAM_DB_OBJECT GroupObject;
4351     NTSTATUS Status;
4352 
4353     TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4354           GroupHandle, GroupInformationClass, Buffer);
4355 
4356     RtlAcquireResourceShared(&SampResource,
4357                              TRUE);
4358 
4359     /* Validate the group handle */
4360     Status = SampValidateDbObject(GroupHandle,
4361                                   SamDbGroupObject,
4362                                   GROUP_READ_INFORMATION,
4363                                   &GroupObject);
4364     if (!NT_SUCCESS(Status))
4365         goto done;
4366 
4367     switch (GroupInformationClass)
4368     {
4369         case GroupGeneralInformation:
4370             Status = SampQueryGroupGeneral(GroupObject,
4371                                            Buffer);
4372             break;
4373 
4374         case GroupNameInformation:
4375             Status = SampQueryGroupName(GroupObject,
4376                                         Buffer);
4377             break;
4378 
4379         case GroupAttributeInformation:
4380             Status = SampQueryGroupAttribute(GroupObject,
4381                                              Buffer);
4382             break;
4383 
4384         case GroupAdminCommentInformation:
4385             Status = SampQueryGroupAdminComment(GroupObject,
4386                                                 Buffer);
4387             break;
4388 
4389         default:
4390             Status = STATUS_INVALID_INFO_CLASS;
4391             break;
4392     }
4393 
4394 done:
4395     RtlReleaseResource(&SampResource);
4396 
4397     return Status;
4398 }
4399 
4400 
4401 static NTSTATUS
4402 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
4403                  PSAMPR_GROUP_INFO_BUFFER Buffer)
4404 {
4405     UNICODE_STRING OldGroupName = {0, 0, NULL};
4406     UNICODE_STRING NewGroupName;
4407     NTSTATUS Status;
4408 
4409     Status = SampGetObjectAttributeString(GroupObject,
4410                                           L"Name",
4411                                           (PRPC_UNICODE_STRING)&OldGroupName);
4412     if (!NT_SUCCESS(Status))
4413     {
4414         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4415         goto done;
4416     }
4417 
4418     /* Check the new account name */
4419     Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4420     if (!NT_SUCCESS(Status))
4421     {
4422         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4423         return Status;
4424     }
4425 
4426     NewGroupName.Length = Buffer->Name.Name.Length;
4427     NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4428     NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4429 
4430     if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4431     {
4432         Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
4433                                               NewGroupName.Buffer);
4434         if (!NT_SUCCESS(Status))
4435         {
4436             TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4437                   NewGroupName.Buffer, Status);
4438             goto done;
4439         }
4440     }
4441 
4442     Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
4443                                         L"Groups",
4444                                         NewGroupName.Buffer,
4445                                         GroupObject->RelativeId);
4446     if (!NT_SUCCESS(Status))
4447     {
4448         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4449         goto done;
4450     }
4451 
4452     Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4453                                              L"Groups",
4454                                              OldGroupName.Buffer);
4455     if (!NT_SUCCESS(Status))
4456     {
4457         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4458         goto done;
4459     }
4460 
4461     Status = SampSetObjectAttributeString(GroupObject,
4462                                           L"Name",
4463                                           (PRPC_UNICODE_STRING)&NewGroupName);
4464     if (!NT_SUCCESS(Status))
4465     {
4466         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4467     }
4468 
4469 done:
4470     if (OldGroupName.Buffer != NULL)
4471         midl_user_free(OldGroupName.Buffer);
4472 
4473     return Status;
4474 }
4475 
4476 
4477 static NTSTATUS
4478 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4479                       PSAMPR_GROUP_INFO_BUFFER Buffer)
4480 {
4481     SAM_GROUP_FIXED_DATA FixedData;
4482     ULONG Length = 0;
4483     NTSTATUS Status;
4484 
4485     Length = sizeof(SAM_GROUP_FIXED_DATA);
4486     Status = SampGetObjectAttribute(GroupObject,
4487                                     L"F",
4488                                     NULL,
4489                                     (PVOID)&FixedData,
4490                                     &Length);
4491     if (!NT_SUCCESS(Status))
4492         goto done;
4493 
4494     FixedData.Attributes = Buffer->Attribute.Attributes;
4495 
4496     Status = SampSetObjectAttribute(GroupObject,
4497                                     L"F",
4498                                     REG_BINARY,
4499                                     &FixedData,
4500                                     Length);
4501 
4502 done:
4503     return Status;
4504 }
4505 
4506 
4507 /* Function 21 */
4508 NTSTATUS
4509 NTAPI
4510 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4511                         IN GROUP_INFORMATION_CLASS GroupInformationClass,
4512                         IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4513 {
4514     PSAM_DB_OBJECT GroupObject;
4515     NTSTATUS Status;
4516 
4517     TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4518           GroupHandle, GroupInformationClass, Buffer);
4519 
4520     RtlAcquireResourceExclusive(&SampResource,
4521                                 TRUE);
4522 
4523     /* Validate the group handle */
4524     Status = SampValidateDbObject(GroupHandle,
4525                                   SamDbGroupObject,
4526                                   GROUP_WRITE_ACCOUNT,
4527                                   &GroupObject);
4528     if (!NT_SUCCESS(Status))
4529         goto done;
4530 
4531     switch (GroupInformationClass)
4532     {
4533         case GroupNameInformation:
4534             Status = SampSetGroupName(GroupObject,
4535                                       Buffer);
4536             break;
4537 
4538         case GroupAttributeInformation:
4539             Status = SampSetGroupAttribute(GroupObject,
4540                                            Buffer);
4541             break;
4542 
4543         case GroupAdminCommentInformation:
4544             Status = SampSetObjectAttributeString(GroupObject,
4545                                                   L"AdminComment",
4546                                                   &Buffer->AdminComment.AdminComment);
4547             break;
4548 
4549         default:
4550             Status = STATUS_INVALID_INFO_CLASS;
4551             break;
4552     }
4553 
4554 done:
4555     RtlReleaseResource(&SampResource);
4556 
4557     return Status;
4558 }
4559 
4560 
4561 /* Function 22 */
4562 NTSTATUS
4563 NTAPI
4564 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4565                      IN unsigned long MemberId,
4566                      IN unsigned long Attributes)
4567 {
4568     PSAM_DB_OBJECT GroupObject;
4569     PSAM_DB_OBJECT UserObject = NULL;
4570     NTSTATUS Status;
4571 
4572     TRACE("SamrAddMemberToGroup(%p %lu %lx)\n",
4573           GroupHandle, MemberId, Attributes);
4574 
4575     RtlAcquireResourceExclusive(&SampResource,
4576                                 TRUE);
4577 
4578     /* Validate the group handle */
4579     Status = SampValidateDbObject(GroupHandle,
4580                                   SamDbGroupObject,
4581                                   GROUP_ADD_MEMBER,
4582                                   &GroupObject);
4583     if (!NT_SUCCESS(Status))
4584         goto done;
4585 
4586     /* Open the user object in the same domain */
4587     Status = SampOpenUserObject(GroupObject->ParentObject,
4588                                 MemberId,
4589                                 0,
4590                                 &UserObject);
4591     if (!NT_SUCCESS(Status))
4592     {
4593         TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4594         goto done;
4595     }
4596 
4597     /* Add group membership to the user object */
4598     Status = SampAddGroupMembershipToUser(UserObject,
4599                                           GroupObject->RelativeId,
4600                                           Attributes);
4601     if (!NT_SUCCESS(Status))
4602     {
4603         TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4604         goto done;
4605     }
4606 
4607     /* Add the member to the group object */
4608     Status = SampAddMemberToGroup(GroupObject,
4609                                   MemberId);
4610     if (!NT_SUCCESS(Status))
4611     {
4612         TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4613     }
4614 
4615 done:
4616     if (UserObject)
4617         SampCloseDbObject(UserObject);
4618 
4619     RtlReleaseResource(&SampResource);
4620 
4621     return Status;
4622 }
4623 
4624 
4625 /* Function 23 */
4626 NTSTATUS
4627 NTAPI
4628 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4629 {
4630     PSAM_DB_OBJECT GroupObject;
4631     ULONG Length = 0;
4632     NTSTATUS Status;
4633 
4634     TRACE("SamrDeleteGroup(%p)\n", GroupHandle);
4635 
4636     RtlAcquireResourceExclusive(&SampResource,
4637                                 TRUE);
4638 
4639     /* Validate the group handle */
4640     Status = SampValidateDbObject(*GroupHandle,
4641                                   SamDbGroupObject,
4642                                   DELETE,
4643                                   &GroupObject);
4644     if (!NT_SUCCESS(Status))
4645     {
4646         TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4647         goto done;
4648     }
4649 
4650     /* Fail, if the group is built-in */
4651     if (GroupObject->RelativeId < 1000)
4652     {
4653         TRACE("You can not delete a special account!\n");
4654         Status = STATUS_SPECIAL_ACCOUNT;
4655         goto done;
4656     }
4657 
4658     /* Get the length of the Members attribute */
4659     SampGetObjectAttribute(GroupObject,
4660                            L"Members",
4661                            NULL,
4662                            NULL,
4663                            &Length);
4664 
4665     /* Fail, if the group has members */
4666     if (Length != 0)
4667     {
4668         TRACE("There are still members in the group!\n");
4669         Status = STATUS_MEMBER_IN_GROUP;
4670         goto done;
4671     }
4672 
4673     /* FIXME: Remove the group from all aliases */
4674 
4675     /* Delete the group from the database */
4676     Status = SampDeleteAccountDbObject(GroupObject);
4677     if (!NT_SUCCESS(Status))
4678     {
4679         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4680         goto done;
4681     }
4682 
4683     /* Invalidate the handle */
4684     *GroupHandle = NULL;
4685 
4686 done:
4687     RtlReleaseResource(&SampResource);
4688 
4689     return Status;
4690 }
4691 
4692 
4693 /* Function 24 */
4694 NTSTATUS
4695 NTAPI
4696 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4697                           IN unsigned long MemberId)
4698 {
4699     PSAM_DB_OBJECT GroupObject;
4700     PSAM_DB_OBJECT UserObject = NULL;
4701     NTSTATUS Status;
4702 
4703     TRACE("SamrRemoveMemberFromGroup(%p %lu)\n",
4704           GroupHandle, MemberId);
4705 
4706     RtlAcquireResourceExclusive(&SampResource,
4707                                 TRUE);
4708 
4709     /* Validate the group handle */
4710     Status = SampValidateDbObject(GroupHandle,
4711                                   SamDbGroupObject,
4712                                   GROUP_REMOVE_MEMBER,
4713                                   &GroupObject);
4714     if (!NT_SUCCESS(Status))
4715         goto done;
4716 
4717     /* Open the user object in the same domain */
4718     Status = SampOpenUserObject(GroupObject->ParentObject,
4719                                 MemberId,
4720                                 0,
4721                                 &UserObject);
4722     if (!NT_SUCCESS(Status))
4723     {
4724         ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4725         goto done;
4726     }
4727 
4728     /* Remove group membership from the user object */
4729     Status = SampRemoveGroupMembershipFromUser(UserObject,
4730                                                GroupObject->RelativeId);
4731     if (!NT_SUCCESS(Status))
4732     {
4733         ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4734         goto done;
4735     }
4736 
4737     /* Remove the member from the group object */
4738     Status = SampRemoveMemberFromGroup(GroupObject,
4739                                        MemberId);
4740     if (!NT_SUCCESS(Status))
4741     {
4742         ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4743     }
4744 
4745 done:
4746     if (UserObject)
4747         SampCloseDbObject(UserObject);
4748 
4749     RtlReleaseResource(&SampResource);
4750 
4751     return Status;
4752 }
4753 
4754 
4755 /* Function 25 */
4756 NTSTATUS
4757 NTAPI
4758 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4759                       OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4760 {
4761     PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4762     PSAM_DB_OBJECT GroupObject;
4763     ULONG Length = 0;
4764     ULONG i;
4765     NTSTATUS Status;
4766 
4767     TRACE("SamrGetMembersInGroup(%p %p)\n",
4768           GroupHandle, Members);
4769 
4770     RtlAcquireResourceShared(&SampResource,
4771                              TRUE);
4772 
4773     /* Validate the group handle */
4774     Status = SampValidateDbObject(GroupHandle,
4775                                   SamDbGroupObject,
4776                                   GROUP_LIST_MEMBERS,
4777                                   &GroupObject);
4778     if (!NT_SUCCESS(Status))
4779         goto done;
4780 
4781     MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4782     if (MembersBuffer == NULL)
4783     {
4784         Status = STATUS_INSUFFICIENT_RESOURCES;
4785         goto done;
4786     }
4787 
4788     SampGetObjectAttribute(GroupObject,
4789                            L"Members",
4790                            NULL,
4791                            NULL,
4792                            &Length);
4793 
4794     if (Length == 0)
4795     {
4796         MembersBuffer->MemberCount = 0;
4797         MembersBuffer->Members = NULL;
4798         MembersBuffer->Attributes = NULL;
4799 
4800         *Members = MembersBuffer;
4801 
4802         Status = STATUS_SUCCESS;
4803         goto done;
4804     }
4805 
4806     MembersBuffer->Members = midl_user_allocate(Length);
4807     if (MembersBuffer->Members == NULL)
4808     {
4809         Status = STATUS_INSUFFICIENT_RESOURCES;
4810         goto done;
4811     }
4812 
4813     MembersBuffer->Attributes = midl_user_allocate(Length);
4814     if (MembersBuffer->Attributes == NULL)
4815     {
4816         Status = STATUS_INSUFFICIENT_RESOURCES;
4817         goto done;
4818     }
4819 
4820     Status = SampGetObjectAttribute(GroupObject,
4821                                     L"Members",
4822                                     NULL,
4823                                     MembersBuffer->Members,
4824                                     &Length);
4825     if (!NT_SUCCESS(Status))
4826     {
4827         TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4828         goto done;
4829     }
4830 
4831     MembersBuffer->MemberCount = Length / sizeof(ULONG);
4832 
4833     for (i = 0; i < MembersBuffer->MemberCount; i++)
4834     {
4835         Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4836                                             MembersBuffer->Members[i],
4837                                             GroupObject->RelativeId,
4838                                             &(MembersBuffer->Attributes[i]));
4839         if (!NT_SUCCESS(Status))
4840         {
4841             TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4842             goto done;
4843         }
4844     }
4845 
4846     *Members = MembersBuffer;
4847 
4848 done:
4849     if (!NT_SUCCESS(Status))
4850     {
4851         if (MembersBuffer != NULL)
4852         {
4853             if (MembersBuffer->Members != NULL)
4854                 midl_user_free(MembersBuffer->Members);
4855 
4856             if (MembersBuffer->Attributes != NULL)
4857                 midl_user_free(MembersBuffer->Attributes);
4858 
4859             midl_user_free(MembersBuffer);
4860         }
4861     }
4862 
4863     RtlReleaseResource(&SampResource);
4864 
4865     return Status;
4866 }
4867 
4868 
4869 /* Function 26 */
4870 NTSTATUS
4871 NTAPI
4872 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4873                                IN unsigned long MemberId,
4874                                IN unsigned long Attributes)
4875 {
4876     PSAM_DB_OBJECT GroupObject;
4877     NTSTATUS Status;
4878 
4879     TRACE("SamrSetMemberAttributesOfGroup(%p %lu %lx)\n",
4880           GroupHandle, MemberId, Attributes);
4881 
4882     RtlAcquireResourceExclusive(&SampResource,
4883                                 TRUE);
4884 
4885     /* Validate the group handle */
4886     Status = SampValidateDbObject(GroupHandle,
4887                                   SamDbGroupObject,
4888                                   GROUP_ADD_MEMBER,
4889                                   &GroupObject);
4890     if (!NT_SUCCESS(Status))
4891     {
4892         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4893         goto done;
4894     }
4895 
4896     Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4897                                         MemberId,
4898                                         GroupObject->RelativeId,
4899                                         Attributes);
4900     if (!NT_SUCCESS(Status))
4901     {
4902         TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4903     }
4904 
4905 done:
4906     RtlReleaseResource(&SampResource);
4907 
4908     return Status;
4909 }
4910 
4911 
4912 /* Function 27 */
4913 NTSTATUS
4914 NTAPI
4915 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4916               IN ACCESS_MASK DesiredAccess,
4917               IN ULONG AliasId,
4918               OUT SAMPR_HANDLE *AliasHandle)
4919 {
4920     PSAM_DB_OBJECT DomainObject;
4921     PSAM_DB_OBJECT AliasObject;
4922     WCHAR szRid[9];
4923     NTSTATUS Status;
4924 
4925     TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4926           DomainHandle, DesiredAccess, AliasId, AliasHandle);
4927 
4928     /* Map generic access rights */
4929     RtlMapGenericMask(&DesiredAccess,
4930                       &AliasMapping);
4931 
4932     RtlAcquireResourceShared(&SampResource,
4933                              TRUE);
4934 
4935     /* Validate the domain handle */
4936     Status = SampValidateDbObject(DomainHandle,
4937                                   SamDbDomainObject,
4938                                   DOMAIN_LOOKUP,
4939                                   &DomainObject);
4940     if (!NT_SUCCESS(Status))
4941     {
4942         TRACE("failed with status 0x%08lx\n", Status);
4943         goto done;
4944     }
4945 
4946     /* Convert the RID into a string (hex) */
4947     swprintf(szRid, L"%08lX", AliasId);
4948 
4949     /* Create the alias object */
4950     Status = SampOpenDbObject(DomainObject,
4951                               L"Aliases",
4952                               szRid,
4953                               AliasId,
4954                               SamDbAliasObject,
4955                               DesiredAccess,
4956                               &AliasObject);
4957     if (!NT_SUCCESS(Status))
4958     {
4959         TRACE("failed with status 0x%08lx\n", Status);
4960         goto done;
4961     }
4962 
4963     *AliasHandle = (SAMPR_HANDLE)AliasObject;
4964 
4965 done:
4966     RtlReleaseResource(&SampResource);
4967 
4968     return Status;
4969 }
4970 
4971 
4972 static NTSTATUS
4973 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4974                       PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4975 {
4976     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4977     HANDLE MembersKeyHandle = NULL;
4978     NTSTATUS Status;
4979 
4980     *Buffer = NULL;
4981 
4982     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4983     if (InfoBuffer == NULL)
4984         return STATUS_INSUFFICIENT_RESOURCES;
4985 
4986     Status = SampGetObjectAttributeString(AliasObject,
4987                                           L"Name",
4988                                           &InfoBuffer->General.Name);
4989     if (!NT_SUCCESS(Status))
4990     {
4991         TRACE("Status 0x%08lx\n", Status);
4992         goto done;
4993     }
4994 
4995     Status = SampGetObjectAttributeString(AliasObject,
4996                                           L"Description",
4997                                           &InfoBuffer->General.AdminComment);
4998     if (!NT_SUCCESS(Status))
4999     {
5000         TRACE("Status 0x%08lx\n", Status);
5001         goto done;
5002     }
5003 
5004     /* Open the Members subkey */
5005     Status = SampRegOpenKey(AliasObject->KeyHandle,
5006                             L"Members",
5007                             KEY_READ,
5008                             &MembersKeyHandle);
5009     if (NT_SUCCESS(Status))
5010     {
5011         /* Retrieve the number of members of the alias */
5012         Status = SampRegQueryKeyInfo(MembersKeyHandle,
5013                                      NULL,
5014                                      &InfoBuffer->General.MemberCount);
5015         if (!NT_SUCCESS(Status))
5016         {
5017             TRACE("Status 0x%08lx\n", Status);
5018             goto done;
5019         }
5020     }
5021     else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
5022     {
5023         InfoBuffer->General.MemberCount = 0;
5024         Status = STATUS_SUCCESS;
5025     }
5026     else
5027     {
5028         TRACE("Status 0x%08lx\n", Status);
5029         goto done;
5030     }
5031 
5032     *Buffer = InfoBuffer;
5033 
5034 done:
5035     SampRegCloseKey(&MembersKeyHandle);
5036 
5037     if (!NT_SUCCESS(Status))
5038     {
5039         if (InfoBuffer != NULL)
5040         {
5041             if (InfoBuffer->General.Name.Buffer != NULL)
5042                 midl_user_free(InfoBuffer->General.Name.Buffer);
5043 
5044             if (InfoBuffer->General.AdminComment.Buffer != NULL)
5045                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5046 
5047             midl_user_free(InfoBuffer);
5048         }
5049     }
5050 
5051     return Status;
5052 }
5053 
5054 
5055 static NTSTATUS
5056 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
5057                    PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5058 {
5059     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5060     NTSTATUS Status;
5061 
5062     *Buffer = NULL;
5063 
5064     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5065     if (InfoBuffer == NULL)
5066         return STATUS_INSUFFICIENT_RESOURCES;
5067 
5068     Status = SampGetObjectAttributeString(AliasObject,
5069                                           L"Name",
5070                                           &InfoBuffer->Name.Name);
5071     if (!NT_SUCCESS(Status))
5072     {
5073         TRACE("Status 0x%08lx\n", Status);
5074         goto done;
5075     }
5076 
5077     *Buffer = InfoBuffer;
5078 
5079 done:
5080     if (!NT_SUCCESS(Status))
5081     {
5082         if (InfoBuffer != NULL)
5083         {
5084             if (InfoBuffer->Name.Name.Buffer != NULL)
5085                 midl_user_free(InfoBuffer->Name.Name.Buffer);
5086 
5087             midl_user_free(InfoBuffer);
5088         }
5089     }
5090 
5091     return Status;
5092 }
5093 
5094 
5095 static NTSTATUS
5096 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
5097                            PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5098 {
5099     PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5100     NTSTATUS Status;
5101 
5102     *Buffer = NULL;
5103 
5104     InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5105     if (InfoBuffer == NULL)
5106         return STATUS_INSUFFICIENT_RESOURCES;
5107 
5108     Status = SampGetObjectAttributeString(AliasObject,
5109                                           L"Description",
5110                                           &InfoBuffer->AdminComment.AdminComment);
5111     if (!NT_SUCCESS(Status))
5112     {
5113         TRACE("Status 0x%08lx\n", Status);
5114         goto done;
5115     }
5116 
5117     *Buffer = InfoBuffer;
5118 
5119 done:
5120     if (!NT_SUCCESS(Status))
5121     {
5122         if (InfoBuffer != NULL)
5123         {
5124             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
5125                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
5126 
5127             midl_user_free(InfoBuffer);
5128         }
5129     }
5130 
5131     return Status;
5132 }
5133 
5134 
5135 /* Function 28 */
5136 NTSTATUS
5137 NTAPI
5138 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
5139                           IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5140                           OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5141 {
5142     PSAM_DB_OBJECT AliasObject;
5143     NTSTATUS Status;
5144 
5145     TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
5146           AliasHandle, AliasInformationClass, Buffer);
5147 
5148     RtlAcquireResourceShared(&SampResource,
5149                              TRUE);
5150 
5151     /* Validate the alias handle */
5152     Status = SampValidateDbObject(AliasHandle,
5153                                   SamDbAliasObject,
5154                                   ALIAS_READ_INFORMATION,
5155                                   &AliasObject);
5156     if (!NT_SUCCESS(Status))
5157         goto done;
5158 
5159     switch (AliasInformationClass)
5160     {
5161         case AliasGeneralInformation:
5162             Status = SampQueryAliasGeneral(AliasObject,
5163                                            Buffer);
5164             break;
5165 
5166         case AliasNameInformation:
5167             Status = SampQueryAliasName(AliasObject,
5168                                         Buffer);
5169             break;
5170 
5171         case AliasAdminCommentInformation:
5172             Status = SampQueryAliasAdminComment(AliasObject,
5173                                                 Buffer);
5174             break;
5175 
5176         default:
5177             Status = STATUS_INVALID_INFO_CLASS;
5178             break;
5179     }
5180 
5181 done:
5182     RtlReleaseResource(&SampResource);
5183 
5184     return Status;
5185 }
5186 
5187 
5188 static NTSTATUS
5189 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
5190                  PSAMPR_ALIAS_INFO_BUFFER Buffer)
5191 {
5192     UNICODE_STRING OldAliasName = {0, 0, NULL};
5193     UNICODE_STRING NewAliasName;
5194     NTSTATUS Status;
5195 
5196     Status = SampGetObjectAttributeString(AliasObject,
5197                                           L"Name",
5198                                           (PRPC_UNICODE_STRING)&OldAliasName);
5199     if (!NT_SUCCESS(Status))
5200     {
5201         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
5202         goto done;
5203     }
5204 
5205     /* Check the new account name */
5206     Status = SampCheckAccountName(&Buffer->Name.Name, 256);
5207     if (!NT_SUCCESS(Status))
5208     {
5209         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
5210         return Status;
5211     }
5212 
5213     NewAliasName.Length = Buffer->Name.Name.Length;
5214     NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
5215     NewAliasName.Buffer = Buffer->Name.Name.Buffer;
5216 
5217     if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
5218     {
5219         Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
5220                                               NewAliasName.Buffer);
5221         if (!NT_SUCCESS(Status))
5222         {
5223             TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
5224                   NewAliasName.Buffer, Status);
5225             goto done;
5226         }
5227     }
5228 
5229     Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
5230                                         L"Aliases",
5231                                         NewAliasName.Buffer,
5232                                         AliasObject->RelativeId);
5233     if (!NT_SUCCESS(Status))
5234     {
5235         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
5236         goto done;
5237     }
5238 
5239     Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
5240                                              L"Aliases",
5241                                              OldAliasName.Buffer);
5242     if (!NT_SUCCESS(Status))
5243     {
5244         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
5245         goto done;
5246     }
5247 
5248     Status = SampSetObjectAttributeString(AliasObject,
5249                                           L"Name",
5250                                           (PRPC_UNICODE_STRING)&NewAliasName);
5251     if (!NT_SUCCESS(Status))
5252     {
5253         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
5254     }
5255 
5256 done:
5257     if (OldAliasName.Buffer != NULL)
5258         midl_user_free(OldAliasName.Buffer);
5259 
5260     return Status;
5261 }
5262 
5263 
5264 /* Function 29 */
5265 NTSTATUS
5266 NTAPI
5267 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
5268                         IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5269                         IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
5270 {
5271     PSAM_DB_OBJECT AliasObject;
5272     NTSTATUS Status;
5273 
5274     TRACE("SamrSetInformationAlias(%p %lu %p)\n",
5275           AliasHandle, AliasInformationClass, Buffer);
5276 
5277     RtlAcquireResourceExclusive(&SampResource,
5278                                 TRUE);
5279 
5280     /* Validate the alias handle */
5281     Status = SampValidateDbObject(AliasHandle,
5282                                   SamDbAliasObject,
5283                                   ALIAS_WRITE_ACCOUNT,
5284                                   &AliasObject);
5285     if (!NT_SUCCESS(Status))
5286         goto done;
5287 
5288     switch (AliasInformationClass)
5289     {
5290         case AliasNameInformation:
5291             Status = SampSetAliasName(AliasObject,
5292                                       Buffer);
5293             break;
5294 
5295         case AliasAdminCommentInformation:
5296             Status = SampSetObjectAttributeString(AliasObject,
5297                                                   L"Description",
5298                                                   &Buffer->AdminComment.AdminComment);
5299             break;
5300 
5301         default:
5302             Status = STATUS_INVALID_INFO_CLASS;
5303             break;
5304     }
5305 
5306 done:
5307     RtlReleaseResource(&SampResource);
5308 
5309     return Status;
5310 }
5311 
5312 
5313 /* Function 30 */
5314 NTSTATUS
5315 NTAPI
5316 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
5317 {
5318     PSAM_DB_OBJECT AliasObject;
5319     NTSTATUS Status;
5320 
5321     TRACE("SamrDeleteAlias(%p)\n", AliasHandle);
5322 
5323     RtlAcquireResourceExclusive(&SampResource,
5324                                 TRUE);
5325 
5326     /* Validate the alias handle */
5327     Status = SampValidateDbObject(*AliasHandle,
5328                                   SamDbAliasObject,
5329                                   DELETE,
5330                                   &AliasObject);
5331     if (!NT_SUCCESS(Status))
5332     {
5333         TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
5334         goto done;
5335     }
5336 
5337     /* Fail, if the alias is built-in */
5338     if (AliasObject->RelativeId < 1000)
5339     {
5340         TRACE("You can not delete a special account!\n");
5341         Status = STATUS_SPECIAL_ACCOUNT;
5342         goto done;
5343     }
5344 
5345     /* Remove all members from the alias */
5346     Status = SampRemoveAllMembersFromAlias(AliasObject);
5347     if (!NT_SUCCESS(Status))
5348     {
5349         TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
5350         goto done;
5351     }
5352 
5353     /* Delete the alias from the database */
5354     Status = SampDeleteAccountDbObject(AliasObject);
5355     if (!NT_SUCCESS(Status))
5356     {
5357         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5358         goto done;
5359     }
5360 
5361     /* Invalidate the handle */
5362     *AliasHandle = NULL;
5363 
5364 done:
5365     RtlReleaseResource(&SampResource);
5366 
5367     return Status;
5368 }
5369 
5370 
5371 /* Function 31 */
5372 NTSTATUS
5373 NTAPI
5374 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
5375                      IN PRPC_SID MemberId)
5376 {
5377     PSAM_DB_OBJECT AliasObject;
5378     NTSTATUS Status;
5379 
5380     TRACE("SamrAddMemberToAlias(%p %p)\n",
5381           AliasHandle, MemberId);
5382 
5383     RtlAcquireResourceExclusive(&SampResource,
5384                                 TRUE);
5385 
5386     /* Validate the alias handle */
5387     Status = SampValidateDbObject(AliasHandle,
5388                                   SamDbAliasObject,
5389                                   ALIAS_ADD_MEMBER,
5390                                   &AliasObject);
5391     if (!NT_SUCCESS(Status))
5392     {
5393         TRACE("failed with status 0x%08lx\n", Status);
5394         goto done;
5395     }
5396 
5397     Status = SampAddMemberToAlias(AliasObject,
5398                                   MemberId);
5399     if (!NT_SUCCESS(Status))
5400     {
5401         TRACE("failed with status 0x%08lx\n", Status);
5402     }
5403 
5404 done:
5405     RtlReleaseResource(&SampResource);
5406 
5407     return Status;
5408 }
5409 
5410 
5411 /* Function 32 */
5412 NTSTATUS
5413 NTAPI
5414 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
5415                           IN PRPC_SID MemberId)
5416 {
5417     PSAM_DB_OBJECT AliasObject;
5418     NTSTATUS Status;
5419 
5420     TRACE("SamrRemoveMemberFromAlias(%p %p)\n",
5421           AliasHandle, MemberId);
5422 
5423     RtlAcquireResourceExclusive(&SampResource,
5424                                 TRUE);
5425 
5426     /* Validate the alias handle */
5427     Status = SampValidateDbObject(AliasHandle,
5428                                   SamDbAliasObject,
5429                                   ALIAS_REMOVE_MEMBER,
5430                                   &AliasObject);
5431     if (!NT_SUCCESS(Status))
5432     {
5433         TRACE("failed with status 0x%08lx\n", Status);
5434         goto done;
5435     }
5436 
5437     Status = SampRemoveMemberFromAlias(AliasObject,
5438                                        MemberId);
5439     if (!NT_SUCCESS(Status))
5440     {
5441         TRACE("failed with status 0x%08lx\n", Status);
5442     }
5443 
5444 done:
5445     RtlReleaseResource(&SampResource);
5446 
5447     return Status;
5448 }
5449 
5450 
5451 /* Function 33 */
5452 NTSTATUS
5453 NTAPI
5454 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
5455                       OUT PSAMPR_PSID_ARRAY_OUT Members)
5456 {
5457     PSAM_DB_OBJECT AliasObject;
5458     PSAMPR_SID_INFORMATION MemberArray = NULL;
5459     ULONG MemberCount = 0;
5460     ULONG Index;
5461     NTSTATUS Status;
5462 
5463     TRACE("SamrGetMembersInAlias(%p %p %p)\n",
5464           AliasHandle, Members);
5465 
5466     RtlAcquireResourceShared(&SampResource,
5467                              TRUE);
5468 
5469     /* Validate the alias handle */
5470     Status = SampValidateDbObject(AliasHandle,
5471                                   SamDbAliasObject,
5472                                   ALIAS_LIST_MEMBERS,
5473                                   &AliasObject);
5474     if (!NT_SUCCESS(Status))
5475     {
5476         ERR("failed with status 0x%08lx\n", Status);
5477         goto done;
5478     }
5479 
5480     Status = SampGetMembersInAlias(AliasObject,
5481                                    &MemberCount,
5482                                    &MemberArray);
5483 
5484     /* Return the number of members and the member array */
5485     if (NT_SUCCESS(Status))
5486     {
5487         Members->Count = MemberCount;
5488         Members->Sids = MemberArray;
5489     }
5490 
5491 done:
5492     /* Clean up the members array and the SID buffers if something failed */
5493     if (!NT_SUCCESS(Status))
5494     {
5495         if (MemberArray != NULL)
5496         {
5497             for (Index = 0; Index < MemberCount; Index++)
5498             {
5499                 if (MemberArray[Index].SidPointer != NULL)
5500                     midl_user_free(MemberArray[Index].SidPointer);
5501             }
5502 
5503             midl_user_free(MemberArray);
5504         }
5505     }
5506 
5507     RtlReleaseResource(&SampResource);
5508 
5509     return Status;
5510 }
5511 
5512 
5513 /* Function 34 */
5514 NTSTATUS
5515 NTAPI
5516 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5517              IN ACCESS_MASK DesiredAccess,
5518              IN unsigned long UserId,
5519              OUT SAMPR_HANDLE *UserHandle)
5520 {
5521     PSAM_DB_OBJECT DomainObject;
5522     PSAM_DB_OBJECT UserObject;
5523     WCHAR szRid[9];
5524     NTSTATUS Status;
5525 
5526     TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5527           DomainHandle, DesiredAccess, UserId, UserHandle);
5528 
5529     /* Map generic access rights */
5530     RtlMapGenericMask(&DesiredAccess,
5531                       &UserMapping);
5532 
5533     RtlAcquireResourceShared(&SampResource,
5534                              TRUE);
5535 
5536     /* Validate the domain handle */
5537     Status = SampValidateDbObject(DomainHandle,
5538                                   SamDbDomainObject,
5539                                   DOMAIN_LOOKUP,
5540                                   &DomainObject);
5541     if (!NT_SUCCESS(Status))
5542     {
5543         TRACE("failed with status 0x%08lx\n", Status);
5544         goto done;
5545     }
5546 
5547     /* Convert the RID into a string (hex) */
5548     swprintf(szRid, L"%08lX", UserId);
5549 
5550     /* Create the user object */
5551     Status = SampOpenDbObject(DomainObject,
5552                               L"Users",
5553                               szRid,
5554                               UserId,
5555                               SamDbUserObject,
5556                               DesiredAccess,
5557                               &UserObject);
5558     if (!NT_SUCCESS(Status))
5559     {
5560         TRACE("failed with status 0x%08lx\n", Status);
5561         goto done;
5562     }
5563 
5564     *UserHandle = (SAMPR_HANDLE)UserObject;
5565 
5566 done:
5567     RtlReleaseResource(&SampResource);
5568 
5569     return Status;
5570 }
5571 
5572 
5573 /* Function 35 */
5574 NTSTATUS
5575 NTAPI
5576 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5577 {
5578     PSAM_DB_OBJECT UserObject;
5579     NTSTATUS Status;
5580 
5581     TRACE("SamrDeleteUser(%p)\n", UserHandle);
5582 
5583     RtlAcquireResourceExclusive(&SampResource,
5584                                 TRUE);
5585 
5586     /* Validate the user handle */
5587     Status = SampValidateDbObject(*UserHandle,
5588                                   SamDbUserObject,
5589                                   DELETE,
5590                                   &UserObject);
5591     if (!NT_SUCCESS(Status))
5592     {
5593         TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5594         goto done;
5595     }
5596 
5597     /* Fail, if the user is built-in */
5598     if (UserObject->RelativeId < 1000)
5599     {
5600         TRACE("You can not delete a special account!\n");
5601         Status = STATUS_SPECIAL_ACCOUNT;
5602         goto done;
5603     }
5604 
5605     /* Remove the user from all groups */
5606     Status = SampRemoveUserFromAllGroups(UserObject);
5607     if (!NT_SUCCESS(Status))
5608     {
5609         TRACE("SampRemoveUserFromAllGroups() failed (Status 0x%08lx)\n", Status);
5610         goto done;
5611     }
5612 
5613     /* Remove the user from all aliases */
5614     Status = SampRemoveUserFromAllAliases(UserObject);
5615     if (!NT_SUCCESS(Status))
5616     {
5617         TRACE("SampRemoveUserFromAllAliases() failed (Status 0x%08lx)\n", Status);
5618         goto done;
5619     }
5620 
5621     /* Delete the user from the database */
5622     Status = SampDeleteAccountDbObject(UserObject);
5623     if (!NT_SUCCESS(Status))
5624     {
5625         TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5626         goto done;
5627     }
5628 
5629     /* Invalidate the handle */
5630     *UserHandle = NULL;
5631 
5632 done:
5633     RtlReleaseResource(&SampResource);
5634 
5635     return Status;
5636 }
5637 
5638 
5639 static
5640 NTSTATUS
5641 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5642                      PSAMPR_USER_INFO_BUFFER *Buffer)
5643 {
5644     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5645     SAM_USER_FIXED_DATA FixedData;
5646     ULONG Length = 0;
5647     NTSTATUS Status;
5648 
5649     *Buffer = NULL;
5650 
5651     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5652     if (InfoBuffer == NULL)
5653         return STATUS_INSUFFICIENT_RESOURCES;
5654 
5655     Length = sizeof(SAM_USER_FIXED_DATA);
5656     Status = SampGetObjectAttribute(UserObject,
5657                                     L"F",
5658                                     NULL,
5659                                     (PVOID)&FixedData,
5660                                     &Length);
5661     if (!NT_SUCCESS(Status))
5662         goto done;
5663 
5664     InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5665 
5666     /* Get the Name string */
5667     Status = SampGetObjectAttributeString(UserObject,
5668                                           L"Name",
5669                                           &InfoBuffer->General.UserName);
5670     if (!NT_SUCCESS(Status))
5671     {
5672         TRACE("Status 0x%08lx\n", Status);
5673         goto done;
5674     }
5675 
5676     /* Get the FullName string */
5677     Status = SampGetObjectAttributeString(UserObject,
5678                                           L"FullName",
5679                                           &InfoBuffer->General.FullName);
5680     if (!NT_SUCCESS(Status))
5681     {
5682         TRACE("Status 0x%08lx\n", Status);
5683         goto done;
5684     }
5685 
5686     /* Get the AdminComment string */
5687     Status = SampGetObjectAttributeString(UserObject,
5688                                           L"AdminComment",
5689                                           &InfoBuffer->General.AdminComment);
5690     if (!NT_SUCCESS(Status))
5691     {
5692         TRACE("Status 0x%08lx\n", Status);
5693         goto done;
5694     }
5695 
5696     /* Get the UserComment string */
5697     Status = SampGetObjectAttributeString(UserObject,
5698                                           L"UserComment",
5699                                           &InfoBuffer->General.UserComment);
5700     if (!NT_SUCCESS(Status))
5701     {
5702         TRACE("Status 0x%08lx\n", Status);
5703         goto done;
5704     }
5705 
5706     *Buffer = InfoBuffer;
5707 
5708 done:
5709     if (!NT_SUCCESS(Status))
5710     {
5711         if (InfoBuffer != NULL)
5712         {
5713             if (InfoBuffer->General.UserName.Buffer != NULL)
5714                 midl_user_free(InfoBuffer->General.UserName.Buffer);
5715 
5716             if (InfoBuffer->General.FullName.Buffer != NULL)
5717                 midl_user_free(InfoBuffer->General.FullName.Buffer);
5718 
5719             if (InfoBuffer->General.AdminComment.Buffer != NULL)
5720                 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5721 
5722             if (InfoBuffer->General.UserComment.Buffer != NULL)
5723                 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5724 
5725             midl_user_free(InfoBuffer);
5726         }
5727     }
5728 
5729     return Status;
5730 }
5731 
5732 
5733 static
5734 NTSTATUS
5735 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5736                          PSAMPR_USER_INFO_BUFFER *Buffer)
5737 {
5738     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5739     SAM_USER_FIXED_DATA FixedData;
5740     ULONG Length = 0;
5741     NTSTATUS Status;
5742 
5743     *Buffer = NULL;
5744 
5745     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5746     if (InfoBuffer == NULL)
5747         return STATUS_INSUFFICIENT_RESOURCES;
5748 
5749     Length = sizeof(SAM_USER_FIXED_DATA);
5750     Status = SampGetObjectAttribute(UserObject,
5751                                     L"F",
5752                                     NULL,
5753                                     (PVOID)&FixedData,
5754                                     &Length);
5755     if (!NT_SUCCESS(Status))
5756         goto done;
5757 
5758     InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5759     InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5760 
5761     /* Get the UserComment string */
5762     Status = SampGetObjectAttributeString(UserObject,
5763                                           L"UserComment",
5764                                           &InfoBuffer->Preferences.UserComment);
5765     if (!NT_SUCCESS(Status))
5766     {
5767         TRACE("Status 0x%08lx\n", Status);
5768         goto done;
5769     }
5770 
5771     *Buffer = InfoBuffer;
5772 
5773 done:
5774     if (!NT_SUCCESS(Status))
5775     {
5776         if (InfoBuffer != NULL)
5777         {
5778             if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5779                 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5780 
5781             midl_user_free(InfoBuffer);
5782         }
5783     }
5784 
5785     return Status;
5786 }
5787 
5788 
5789 static
5790 NTSTATUS
5791 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5792                    PSAMPR_USER_INFO_BUFFER *Buffer)
5793 {
5794     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5795     SAM_DOMAIN_FIXED_DATA DomainFixedData;
5796     SAM_USER_FIXED_DATA FixedData;
5797     LARGE_INTEGER PasswordCanChange;
5798     LARGE_INTEGER PasswordMustChange;
5799     ULONG Length = 0;
5800     NTSTATUS Status;
5801 
5802     *Buffer = NULL;
5803 
5804     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5805     if (InfoBuffer == NULL)
5806         return STATUS_INSUFFICIENT_RESOURCES;
5807 
5808     /* Get the fixed size domain data */
5809     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5810     Status = SampGetObjectAttribute(UserObject->ParentObject,
5811                                     L"F",
5812                                     NULL,
5813                                     (PVOID)&DomainFixedData,
5814                                     &Length);
5815     if (!NT_SUCCESS(Status))
5816         goto done;
5817 
5818     /* Get the fixed size user data */
5819     Length = sizeof(SAM_USER_FIXED_DATA);
5820     Status = SampGetObjectAttribute(UserObject,
5821                                     L"F",
5822                                     NULL,
5823                                     (PVOID)&FixedData,
5824                                     &Length);
5825     if (!NT_SUCCESS(Status))
5826         goto done;
5827 
5828     InfoBuffer->Logon.UserId = FixedData.UserId;
5829     InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5830     InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5831     InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5832     InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5833     InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5834     InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5835     InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5836     InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5837     InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5838     InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5839 
5840     PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5841                                                   DomainFixedData.MinPasswordAge);
5842     InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5843     InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5844 
5845     PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5846                                                    DomainFixedData.MaxPasswordAge);
5847     InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5848     InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5849 
5850     /* Get the Name string */
5851     Status = SampGetObjectAttributeString(UserObject,
5852                                           L"Name",
5853                                           &InfoBuffer->Logon.UserName);
5854     if (!NT_SUCCESS(Status))
5855     {
5856         TRACE("Status 0x%08lx\n", Status);
5857         goto done;
5858     }
5859 
5860     /* Get the FullName string */
5861     Status = SampGetObjectAttributeString(UserObject,
5862                                           L"FullName",
5863                                           &InfoBuffer->Logon.FullName);
5864     if (!NT_SUCCESS(Status))
5865     {
5866         TRACE("Status 0x%08lx\n", Status);
5867         goto done;
5868     }
5869 
5870     /* Get the HomeDirectory string */
5871     Status = SampGetObjectAttributeString(UserObject,
5872                                           L"HomeDirectory",
5873                                           &InfoBuffer->Logon.HomeDirectory);
5874     if (!NT_SUCCESS(Status))
5875     {
5876         TRACE("Status 0x%08lx\n", Status);
5877         goto done;
5878     }
5879 
5880     /* Get the HomeDirectoryDrive string */
5881     Status = SampGetObjectAttributeString(UserObject,
5882                                           L"HomeDirectoryDrive",
5883                                           &InfoBuffer->Logon.HomeDirectoryDrive);
5884     if (!NT_SUCCESS(Status))
5885     {
5886         TRACE("Status 0x%08lx\n", Status);
5887         goto done;
5888     }
5889 
5890     /* Get the ScriptPath string */
5891     Status = SampGetObjectAttributeString(UserObject,
5892                                           L"ScriptPath",
5893                                           &InfoBuffer->Logon.ScriptPath);
5894     if (!NT_SUCCESS(Status))
5895     {
5896         TRACE("Status 0x%08lx\n", Status);
5897         goto done;
5898     }
5899 
5900     /* Get the ProfilePath string */
5901     Status = SampGetObjectAttributeString(UserObject,
5902                                           L"ProfilePath",
5903                                           &InfoBuffer->Logon.ProfilePath);
5904     if (!NT_SUCCESS(Status))
5905     {
5906         TRACE("Status 0x%08lx\n", Status);
5907         goto done;
5908     }
5909 
5910     /* Get the WorkStations string */
5911     Status = SampGetObjectAttributeString(UserObject,
5912                                           L"WorkStations",
5913                                           &InfoBuffer->Logon.WorkStations);
5914     if (!NT_SUCCESS(Status))
5915     {
5916         TRACE("Status 0x%08lx\n", Status);
5917         goto done;
5918     }
5919 
5920     /* Get the LogonHours attribute */
5921     Status = SampGetLogonHoursAttribute(UserObject,
5922                                        &InfoBuffer->Logon.LogonHours);
5923     if (!NT_SUCCESS(Status))
5924     {
5925         TRACE("Status 0x%08lx\n", Status);
5926         goto done;
5927     }
5928 
5929     *Buffer = InfoBuffer;
5930 
5931 done:
5932     if (!NT_SUCCESS(Status))
5933     {
5934         if (InfoBuffer != NULL)
5935         {
5936             if (InfoBuffer->Logon.UserName.Buffer != NULL)
5937                 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5938 
5939             if (InfoBuffer->Logon.FullName.Buffer != NULL)
5940                 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5941 
5942             if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5943                 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5944 
5945             if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5946                 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5947 
5948             if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5949                 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5950 
5951             if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5952                 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5953 
5954             if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5955                 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5956 
5957             if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5958                 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5959 
5960             midl_user_free(InfoBuffer);
5961         }
5962     }
5963 
5964     return Status;
5965 }
5966 
5967 
5968 static
5969 NTSTATUS
5970 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5971                      PSAMPR_USER_INFO_BUFFER *Buffer)
5972 {
5973     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5974     SAM_USER_FIXED_DATA FixedData;
5975     ULONG Length = 0;
5976     NTSTATUS Status;
5977 
5978     *Buffer = NULL;
5979 
5980     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5981     if (InfoBuffer == NULL)
5982         return STATUS_INSUFFICIENT_RESOURCES;
5983 
5984     Length = sizeof(SAM_USER_FIXED_DATA);
5985     Status = SampGetObjectAttribute(UserObject,
5986                                     L"F",
5987                                     NULL,
5988                                     (PVOID)&FixedData,
5989                                     &Length);
5990     if (!NT_SUCCESS(Status))
5991         goto done;
5992 
5993     InfoBuffer->Account.UserId = FixedData.UserId;
5994     InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5995     InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5996     InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5997     InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5998     InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5999     InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
6000     InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
6001     InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6002     InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6003     InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
6004     InfoBuffer->Account.LogonCount = FixedData.LogonCount;
6005     InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
6006 
6007     /* Get the Name string */
6008     Status = SampGetObjectAttributeString(UserObject,
6009                                           L"Name",
6010                                           &InfoBuffer->Account.UserName);
6011     if (!NT_SUCCESS(Status))
6012     {
6013         TRACE("Status 0x%08lx\n", Status);
6014         goto done;
6015     }
6016 
6017     /* Get the FullName string */
6018     Status = SampGetObjectAttributeString(UserObject,
6019                                           L"FullName",
6020                                           &InfoBuffer->Account.FullName);
6021     if (!NT_SUCCESS(Status))
6022     {
6023         TRACE("Status 0x%08lx\n", Status);
6024         goto done;
6025     }
6026 
6027     /* Get the HomeDirectory string */
6028     Status = SampGetObjectAttributeString(UserObject,
6029                                           L"HomeDirectory",
6030                                           &InfoBuffer->Account.HomeDirectory);
6031     if (!NT_SUCCESS(Status))
6032     {
6033         TRACE("Status 0x%08lx\n", Status);
6034         goto done;
6035     }
6036 
6037     /* Get the HomeDirectoryDrive string */
6038     Status = SampGetObjectAttributeString(UserObject,
6039                                           L"HomeDirectoryDrive",
6040                                           &InfoBuffer->Account.HomeDirectoryDrive);
6041     if (!NT_SUCCESS(Status))
6042     {
6043         TRACE("Status 0x%08lx\n", Status);
6044         goto done;
6045     }
6046 
6047     /* Get the ScriptPath string */
6048     Status = SampGetObjectAttributeString(UserObject,
6049                                           L"ScriptPath",
6050                                           &InfoBuffer->Account.ScriptPath);
6051     if (!NT_SUCCESS(Status))
6052     {
6053         TRACE("Status 0x%08lx\n", Status);
6054         goto done;
6055     }
6056 
6057     /* Get the ProfilePath string */
6058     Status = SampGetObjectAttributeString(UserObject,
6059                                           L"ProfilePath",
6060                                           &InfoBuffer->Account.ProfilePath);
6061     if (!NT_SUCCESS(Status))
6062     {
6063         TRACE("Status 0x%08lx\n", Status);
6064         goto done;
6065     }
6066 
6067     /* Get the AdminComment string */
6068     Status = SampGetObjectAttributeString(UserObject,
6069                                           L"AdminComment",
6070                                           &InfoBuffer->Account.AdminComment);
6071     if (!NT_SUCCESS(Status))
6072     {
6073         TRACE("Status 0x%08lx\n", Status);
6074         goto done;
6075     }
6076 
6077     /* Get the WorkStations string */
6078     Status = SampGetObjectAttributeString(UserObject,
6079                                           L"WorkStations",
6080                                           &InfoBuffer->Account.WorkStations);
6081     if (!NT_SUCCESS(Status))
6082     {
6083         TRACE("Status 0x%08lx\n", Status);
6084         goto done;
6085     }
6086 
6087     /* Get the LogonHours attribute */
6088     Status = SampGetLogonHoursAttribute(UserObject,
6089                                        &InfoBuffer->Account.LogonHours);
6090     if (!NT_SUCCESS(Status))
6091     {
6092         TRACE("Status 0x%08lx\n", Status);
6093         goto done;
6094     }
6095 
6096     *Buffer = InfoBuffer;
6097 
6098 done:
6099     if (!NT_SUCCESS(Status))
6100     {
6101         if (InfoBuffer != NULL)
6102         {
6103             if (InfoBuffer->Account.UserName.Buffer != NULL)
6104                 midl_user_free(InfoBuffer->Account.UserName.Buffer);
6105 
6106             if (InfoBuffer->Account.FullName.Buffer != NULL)
6107                 midl_user_free(InfoBuffer->Account.FullName.Buffer);
6108 
6109             if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
6110                 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
6111 
6112             if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
6113                 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
6114 
6115             if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
6116                 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
6117 
6118             if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
6119                 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
6120 
6121             if (InfoBuffer->Account.AdminComment.Buffer != NULL)
6122                 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
6123 
6124             if (InfoBuffer->Account.WorkStations.Buffer != NULL)
6125                 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
6126 
6127             if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
6128                 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
6129 
6130             midl_user_free(InfoBuffer);
6131         }
6132     }
6133 
6134     return Status;
6135 }
6136 
6137 
6138 static
6139 NTSTATUS
6140 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
6141                         PSAMPR_USER_INFO_BUFFER *Buffer)
6142 {
6143     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6144     NTSTATUS Status;
6145 
6146     TRACE("(%p %p)\n", UserObject, Buffer);
6147 
6148     *Buffer = NULL;
6149 
6150     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6151     if (InfoBuffer == NULL)
6152     {
6153         TRACE("Failed to allocate InfoBuffer!\n");
6154         return STATUS_INSUFFICIENT_RESOURCES;
6155     }
6156 
6157     Status = SampGetLogonHoursAttribute(UserObject,
6158                                        &InfoBuffer->LogonHours.LogonHours);
6159     if (!NT_SUCCESS(Status))
6160     {
6161         TRACE("SampGetLogonHoursAttribute failed (Status 0x%08lx)\n", Status);
6162         goto done;
6163     }
6164 
6165     *Buffer = InfoBuffer;
6166 
6167 done:
6168     if (!NT_SUCCESS(Status))
6169     {
6170         if (InfoBuffer != NULL)
6171         {
6172             if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
6173                 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
6174 
6175             midl_user_free(InfoBuffer);
6176         }
6177     }
6178 
6179     return Status;
6180 }
6181 
6182 
6183 static
6184 NTSTATUS
6185 SampQueryUserName(PSAM_DB_OBJECT UserObject,
6186                   PSAMPR_USER_INFO_BUFFER *Buffer)
6187 {
6188     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6189     NTSTATUS Status;
6190 
6191     *Buffer = NULL;
6192 
6193     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6194     if (InfoBuffer == NULL)
6195         return STATUS_INSUFFICIENT_RESOURCES;
6196 
6197     /* Get the Name string */
6198     Status = SampGetObjectAttributeString(UserObject,
6199                                           L"Name",
6200                                           &InfoBuffer->Name.UserName);
6201     if (!NT_SUCCESS(Status))
6202     {
6203         TRACE("Status 0x%08lx\n", Status);
6204         goto done;
6205     }
6206 
6207     /* Get the FullName string */
6208     Status = SampGetObjectAttributeString(UserObject,
6209                                           L"FullName",
6210                                           &InfoBuffer->Name.FullName);
6211     if (!NT_SUCCESS(Status))
6212     {
6213         TRACE("Status 0x%08lx\n", Status);
6214         goto done;
6215     }
6216 
6217     *Buffer = InfoBuffer;
6218 
6219 done:
6220     if (!NT_SUCCESS(Status))
6221     {
6222         if (InfoBuffer != NULL)
6223         {
6224             if (InfoBuffer->Name.UserName.Buffer != NULL)
6225                 midl_user_free(InfoBuffer->Name.UserName.Buffer);
6226 
6227             if (InfoBuffer->Name.FullName.Buffer != NULL)
6228                 midl_user_free(InfoBuffer->Name.FullName.Buffer);
6229 
6230             midl_user_free(InfoBuffer);
6231         }
6232     }
6233 
6234     return Status;
6235 }
6236 
6237 
6238 static NTSTATUS
6239 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
6240                          PSAMPR_USER_INFO_BUFFER *Buffer)
6241 {
6242     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6243     NTSTATUS Status;
6244 
6245     *Buffer = NULL;
6246 
6247     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6248     if (InfoBuffer == NULL)
6249         return STATUS_INSUFFICIENT_RESOURCES;
6250 
6251     /* Get the Name string */
6252     Status = SampGetObjectAttributeString(UserObject,
6253                                           L"Name",
6254                                           &InfoBuffer->AccountName.UserName);
6255     if (!NT_SUCCESS(Status))
6256     {
6257         TRACE("Status 0x%08lx\n", Status);
6258         goto done;
6259     }
6260 
6261     *Buffer = InfoBuffer;
6262 
6263 done:
6264     if (!NT_SUCCESS(Status))
6265     {
6266         if (InfoBuffer != NULL)
6267         {
6268             if (InfoBuffer->AccountName.UserName.Buffer != NULL)
6269                 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
6270 
6271             midl_user_free(InfoBuffer);
6272         }
6273     }
6274 
6275     return Status;
6276 }
6277 
6278 
6279 static NTSTATUS
6280 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
6281                       PSAMPR_USER_INFO_BUFFER *Buffer)
6282 {
6283     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6284     NTSTATUS Status;
6285 
6286     *Buffer = NULL;
6287 
6288     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6289     if (InfoBuffer == NULL)
6290         return STATUS_INSUFFICIENT_RESOURCES;
6291 
6292     /* Get the FullName string */
6293     Status = SampGetObjectAttributeString(UserObject,
6294                                           L"FullName",
6295                                           &InfoBuffer->FullName.FullName);
6296     if (!NT_SUCCESS(Status))
6297     {
6298         TRACE("Status 0x%08lx\n", Status);
6299         goto done;
6300     }
6301 
6302     *Buffer = InfoBuffer;
6303 
6304 done:
6305     if (!NT_SUCCESS(Status))
6306     {
6307         if (InfoBuffer != NULL)
6308         {
6309             if (InfoBuffer->FullName.FullName.Buffer != NULL)
6310                 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
6311 
6312             midl_user_free(InfoBuffer);
6313         }
6314     }
6315 
6316     return Status;
6317 }
6318 
6319 
6320 static
6321 NTSTATUS
6322 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6323                           PSAMPR_USER_INFO_BUFFER *Buffer)
6324 {
6325     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6326     SAM_USER_FIXED_DATA FixedData;
6327     ULONG Length = 0;
6328     NTSTATUS Status;
6329 
6330     *Buffer = NULL;
6331 
6332     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6333     if (InfoBuffer == NULL)
6334         return STATUS_INSUFFICIENT_RESOURCES;
6335 
6336     Length = sizeof(SAM_USER_FIXED_DATA);
6337     Status = SampGetObjectAttribute(UserObject,
6338                                     L"F",
6339                                     NULL,
6340                                     (PVOID)&FixedData,
6341                                     &Length);
6342     if (!NT_SUCCESS(Status))
6343         goto done;
6344 
6345     InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
6346 
6347     *Buffer = InfoBuffer;
6348 
6349 done:
6350     if (!NT_SUCCESS(Status))
6351     {
6352         if (InfoBuffer != NULL)
6353         {
6354             midl_user_free(InfoBuffer);
6355         }
6356     }
6357 
6358     return Status;
6359 }
6360 
6361 
6362 static NTSTATUS
6363 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
6364                   PSAMPR_USER_INFO_BUFFER *Buffer)
6365 {
6366     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6367     NTSTATUS Status;
6368 
6369     *Buffer = NULL;
6370 
6371     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6372     if (InfoBuffer == NULL)
6373         return STATUS_INSUFFICIENT_RESOURCES;
6374 
6375     /* Get the HomeDirectory string */
6376     Status = SampGetObjectAttributeString(UserObject,
6377                                           L"HomeDirectory",
6378                                           &InfoBuffer->Home.HomeDirectory);
6379     if (!NT_SUCCESS(Status))
6380     {
6381         TRACE("Status 0x%08lx\n", Status);
6382         goto done;
6383     }
6384 
6385     /* Get the HomeDirectoryDrive string */
6386     Status = SampGetObjectAttributeString(UserObject,
6387                                           L"HomeDirectoryDrive",
6388                                           &InfoBuffer->Home.HomeDirectoryDrive);
6389     if (!NT_SUCCESS(Status))
6390     {
6391         TRACE("Status 0x%08lx\n", Status);
6392         goto done;
6393     }
6394 
6395     *Buffer = InfoBuffer;
6396 
6397 done:
6398     if (!NT_SUCCESS(Status))
6399     {
6400         if (InfoBuffer != NULL)
6401         {
6402             if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
6403                 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
6404 
6405             if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
6406                 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
6407 
6408             midl_user_free(InfoBuffer);
6409         }
6410     }
6411 
6412     return Status;
6413 }
6414 
6415 
6416 static NTSTATUS
6417 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
6418                     PSAMPR_USER_INFO_BUFFER *Buffer)
6419 {
6420     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6421     NTSTATUS Status;
6422 
6423     *Buffer = NULL;
6424 
6425     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6426     if (InfoBuffer == NULL)
6427         return STATUS_INSUFFICIENT_RESOURCES;
6428 
6429     /* Get the ScriptPath string */
6430     Status = SampGetObjectAttributeString(UserObject,
6431                                           L"ScriptPath",
6432                                           &InfoBuffer->Script.ScriptPath);
6433     if (!NT_SUCCESS(Status))
6434     {
6435         TRACE("Status 0x%08lx\n", Status);
6436         goto done;
6437     }
6438 
6439     *Buffer = InfoBuffer;
6440 
6441 done:
6442     if (!NT_SUCCESS(Status))
6443     {
6444         if (InfoBuffer != NULL)
6445         {
6446             if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
6447                 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
6448 
6449             midl_user_free(InfoBuffer);
6450         }
6451     }
6452 
6453     return Status;
6454 }
6455 
6456 
6457 static NTSTATUS
6458 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
6459                      PSAMPR_USER_INFO_BUFFER *Buffer)
6460 {
6461     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6462     NTSTATUS Status;
6463 
6464     *Buffer = NULL;
6465 
6466     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6467     if (InfoBuffer == NULL)
6468         return STATUS_INSUFFICIENT_RESOURCES;
6469 
6470     /* Get the ProfilePath string */
6471     Status = SampGetObjectAttributeString(UserObject,
6472                                           L"ProfilePath",
6473                                           &InfoBuffer->Profile.ProfilePath);
6474     if (!NT_SUCCESS(Status))
6475     {
6476         TRACE("Status 0x%08lx\n", Status);
6477         goto done;
6478     }
6479 
6480     *Buffer = InfoBuffer;
6481 
6482 done:
6483     if (!NT_SUCCESS(Status))
6484     {
6485         if (InfoBuffer != NULL)
6486         {
6487             if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
6488                 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
6489 
6490             midl_user_free(InfoBuffer);
6491         }
6492     }
6493 
6494     return Status;
6495 }
6496 
6497 
6498 static NTSTATUS
6499 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6500                           PSAMPR_USER_INFO_BUFFER *Buffer)
6501 {
6502     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6503     NTSTATUS Status;
6504 
6505     *Buffer = NULL;
6506 
6507     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6508     if (InfoBuffer == NULL)
6509         return STATUS_INSUFFICIENT_RESOURCES;
6510 
6511     /* Get the AdminComment string */
6512     Status = SampGetObjectAttributeString(UserObject,
6513                                           L"AdminComment",
6514                                           &InfoBuffer->AdminComment.AdminComment);
6515     if (!NT_SUCCESS(Status))
6516     {
6517         TRACE("Status 0x%08lx\n", Status);
6518         goto done;
6519     }
6520 
6521     *Buffer = InfoBuffer;
6522 
6523 done:
6524     if (!NT_SUCCESS(Status))
6525     {
6526         if (InfoBuffer != NULL)
6527         {
6528             if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6529                 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6530 
6531             midl_user_free(InfoBuffer);
6532         }
6533     }
6534 
6535     return Status;
6536 }
6537 
6538 
6539 static NTSTATUS
6540 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6541                           PSAMPR_USER_INFO_BUFFER *Buffer)
6542 {
6543     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6544     NTSTATUS Status;
6545 
6546     *Buffer = NULL;
6547 
6548     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6549     if (InfoBuffer == NULL)
6550         return STATUS_INSUFFICIENT_RESOURCES;
6551 
6552     /* Get the WorkStations string */
6553     Status = SampGetObjectAttributeString(UserObject,
6554                                           L"WorkStations",
6555                                           &InfoBuffer->WorkStations.WorkStations);
6556     if (!NT_SUCCESS(Status))
6557     {
6558         TRACE("Status 0x%08lx\n", Status);
6559         goto done;
6560     }
6561 
6562     *Buffer = InfoBuffer;
6563 
6564 done:
6565     if (!NT_SUCCESS(Status))
6566     {
6567         if (InfoBuffer != NULL)
6568         {
6569             if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6570                 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6571 
6572             midl_user_free(InfoBuffer);
6573         }
6574     }
6575 
6576     return Status;
6577 }
6578 
6579 
6580 static
6581 NTSTATUS
6582 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6583                      PSAMPR_USER_INFO_BUFFER *Buffer)
6584 {
6585     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6586     SAM_USER_FIXED_DATA FixedData;
6587     ULONG Length = 0;
6588     NTSTATUS Status;
6589 
6590     *Buffer = NULL;
6591 
6592     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6593     if (InfoBuffer == NULL)
6594         return STATUS_INSUFFICIENT_RESOURCES;
6595 
6596     Length = sizeof(SAM_USER_FIXED_DATA);
6597     Status = SampGetObjectAttribute(UserObject,
6598                                     L"F",
6599                                     NULL,
6600                                     (PVOID)&FixedData,
6601                                     &Length);
6602     if (!NT_SUCCESS(Status))
6603         goto done;
6604 
6605     InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6606 
6607     *Buffer = InfoBuffer;
6608 
6609 done:
6610     if (!NT_SUCCESS(Status))
6611     {
6612         if (InfoBuffer != NULL)
6613         {
6614             midl_user_free(InfoBuffer);
6615         }
6616     }
6617 
6618     return Status;
6619 }
6620 
6621 
6622 static
6623 NTSTATUS
6624 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6625                      PSAMPR_USER_INFO_BUFFER *Buffer)
6626 {
6627     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6628     SAM_USER_FIXED_DATA FixedData;
6629     ULONG Length = 0;
6630     NTSTATUS Status;
6631 
6632     *Buffer = NULL;
6633 
6634     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6635     if (InfoBuffer == NULL)
6636         return STATUS_INSUFFICIENT_RESOURCES;
6637 
6638     Length = sizeof(SAM_USER_FIXED_DATA);
6639     Status = SampGetObjectAttribute(UserObject,
6640                                     L"F",
6641                                     NULL,
6642                                     (PVOID)&FixedData,
6643                                     &Length);
6644     if (!NT_SUCCESS(Status))
6645         goto done;
6646 
6647     InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6648     InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6649 
6650     *Buffer = InfoBuffer;
6651 
6652 done:
6653     if (!NT_SUCCESS(Status))
6654     {
6655         if (InfoBuffer != NULL)
6656         {
6657             midl_user_free(InfoBuffer);
6658         }
6659     }
6660 
6661     return Status;
6662 }
6663 
6664 
6665 static
6666 NTSTATUS
6667 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6668                        PSAMPR_USER_INFO_BUFFER *Buffer)
6669 {
6670     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6671     ULONG Length = 0;
6672     NTSTATUS Status = STATUS_SUCCESS;
6673 
6674     /* Fail, if the caller is not a trusted caller */
6675     if (UserObject->Trusted == FALSE)
6676         return STATUS_INVALID_INFO_CLASS;
6677 
6678     *Buffer = NULL;
6679 
6680     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6681     if (InfoBuffer == NULL)
6682         return STATUS_INSUFFICIENT_RESOURCES;
6683 
6684     InfoBuffer->Internal1.LmPasswordPresent = FALSE;
6685     InfoBuffer->Internal1.NtPasswordPresent = FALSE;
6686 
6687     /* Get the NT password */
6688     Length = 0;
6689     SampGetObjectAttribute(UserObject,
6690                            L"NTPwd",
6691                            NULL,
6692                            NULL,
6693                            &Length);
6694 
6695     if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6696     {
6697         Status = SampGetObjectAttribute(UserObject,
6698                                         L"NTPwd",
6699                                         NULL,
6700                                         (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6701                                         &Length);
6702         if (!NT_SUCCESS(Status))
6703             goto done;
6704 
6705         if (memcmp(&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6706                    &EmptyNtHash,
6707                    sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
6708             InfoBuffer->Internal1.NtPasswordPresent = TRUE;
6709     }
6710 
6711 
6712     /* Get the LM password */
6713     Length = 0;
6714     SampGetObjectAttribute(UserObject,
6715                            L"LMPwd",
6716                            NULL,
6717                            NULL,
6718                            &Length);
6719 
6720     if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6721     {
6722         Status = SampGetObjectAttribute(UserObject,
6723                                         L"LMPwd",
6724                                         NULL,
6725                                         (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6726                                         &Length);
6727         if (!NT_SUCCESS(Status))
6728             goto done;
6729 
6730         if (memcmp(&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6731                    &EmptyLmHash,
6732                    sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
6733             InfoBuffer->Internal1.LmPasswordPresent = TRUE;
6734     }
6735 
6736     InfoBuffer->Internal1.PasswordExpired = FALSE;
6737 
6738     *Buffer = InfoBuffer;
6739 
6740 done:
6741     if (!NT_SUCCESS(Status))
6742     {
6743         if (InfoBuffer != NULL)
6744         {
6745             midl_user_free(InfoBuffer);
6746         }
6747     }
6748 
6749     return Status;
6750 }
6751 
6752 
6753 static
6754 NTSTATUS
6755 SampQueryUserInternal2(PSAM_DB_OBJECT UserObject,
6756                        PSAMPR_USER_INFO_BUFFER *Buffer)
6757 {
6758     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6759     SAM_USER_FIXED_DATA FixedData;
6760     ULONG Length = 0;
6761     NTSTATUS Status;
6762 
6763     *Buffer = NULL;
6764 
6765     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6766     if (InfoBuffer == NULL)
6767         return STATUS_INSUFFICIENT_RESOURCES;
6768 
6769     Length = sizeof(SAM_USER_FIXED_DATA);
6770     Status = SampGetObjectAttribute(UserObject,
6771                                     L"F",
6772                                     NULL,
6773                                     (PVOID)&FixedData,
6774                                     &Length);
6775     if (!NT_SUCCESS(Status))
6776         goto done;
6777 
6778     InfoBuffer->Internal2.Flags = 0;
6779     InfoBuffer->Internal2.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6780     InfoBuffer->Internal2.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6781     InfoBuffer->Internal2.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6782     InfoBuffer->Internal2.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6783     InfoBuffer->Internal2.BadPasswordCount = FixedData.BadPasswordCount;
6784     InfoBuffer->Internal2.LogonCount = FixedData.LogonCount;
6785 
6786     *Buffer = InfoBuffer;
6787 
6788 done:
6789     if (!NT_SUCCESS(Status))
6790     {
6791         if (InfoBuffer != NULL)
6792         {
6793             midl_user_free(InfoBuffer);
6794         }
6795     }
6796 
6797     return Status;
6798 }
6799 
6800 
6801 static NTSTATUS
6802 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6803                         PSAMPR_USER_INFO_BUFFER *Buffer)
6804 {
6805     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6806     NTSTATUS Status;
6807 
6808     *Buffer = NULL;
6809 
6810     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6811     if (InfoBuffer == NULL)
6812         return STATUS_INSUFFICIENT_RESOURCES;
6813 
6814     /* Get the Parameters string */
6815     Status = SampGetObjectAttributeString(UserObject,
6816                                           L"Parameters",
6817                                           &InfoBuffer->Parameters.Parameters);
6818     if (!NT_SUCCESS(Status))
6819     {
6820         TRACE("Status 0x%08lx\n", Status);
6821         goto done;
6822     }
6823 
6824     *Buffer = InfoBuffer;
6825 
6826 done:
6827     if (!NT_SUCCESS(Status))
6828     {
6829         if (InfoBuffer != NULL)
6830         {
6831             if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6832                 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6833 
6834             midl_user_free(InfoBuffer);
6835         }
6836     }
6837 
6838     return Status;
6839 }
6840 
6841 
6842 static NTSTATUS
6843 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6844                  PSAMPR_USER_INFO_BUFFER *Buffer)
6845 {
6846     PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6847     SAM_DOMAIN_FIXED_DATA DomainFixedData;
6848     SAM_USER_FIXED_DATA FixedData;
6849     LARGE_INTEGER PasswordCanChange;
6850     LARGE_INTEGER PasswordMustChange;
6851     ULONG Length = 0;
6852     NTSTATUS Status;
6853 
6854     *Buffer = NULL;
6855 
6856     InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6857     if (InfoBuffer == NULL)
6858         return STATUS_INSUFFICIENT_RESOURCES;
6859 
6860     /* Get the fixed size domain data */
6861     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6862     Status = SampGetObjectAttribute(UserObject->ParentObject,
6863                                     L"F",
6864                                     NULL,
6865                                     (PVOID)&DomainFixedData,
6866                                     &Length);
6867     if (!NT_SUCCESS(Status))
6868         goto done;
6869 
6870     /* Get the fixed size user data */
6871     Length = sizeof(SAM_USER_FIXED_DATA);
6872     Status = SampGetObjectAttribute(UserObject,
6873                                     L"F",
6874                                     NULL,
6875                                     (PVOID)&FixedData,
6876                                     &Length);
6877     if (!NT_SUCCESS(Status))
6878         goto done;
6879 
6880     /* Set the fields to be returned */
6881     if (UserObject->Trusted)
6882     {
6883         InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
6884                                       USER_ALL_READ_LOGON_MASK |
6885                                       USER_ALL_READ_ACCOUNT_MASK |
6886                                       USER_ALL_READ_PREFERENCES_MASK |
6887                                       USER_ALL_READ_TRUSTED_MASK;
6888     }
6889     else
6890     {
6891         InfoBuffer->All.WhichFields = 0;
6892 
6893         if (UserObject->Access & USER_READ_GENERAL)
6894             InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6895 
6896         if (UserObject->Access & USER_READ_LOGON)
6897             InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
6898 
6899         if (UserObject->Access & USER_READ_ACCOUNT)
6900             InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6901 
6902         if (UserObject->Access & USER_READ_PREFERENCES)
6903             InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6904     }
6905 
6906     /* Fail, if no fields are to be returned */
6907     if (InfoBuffer->All.WhichFields == 0)
6908     {
6909         Status = STATUS_ACCESS_DENIED;
6910         goto done;
6911     }
6912 
6913     /* Get the UserName attribute */
6914     if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
6915     {
6916         Status = SampGetObjectAttributeString(UserObject,
6917                                               L"Name",
6918                                               &InfoBuffer->All.UserName);
6919         if (!NT_SUCCESS(Status))
6920         {
6921             TRACE("Status 0x%08lx\n", Status);
6922             goto done;
6923         }
6924     }
6925 
6926     /* Get the FullName attribute */
6927     if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
6928     {
6929         Status = SampGetObjectAttributeString(UserObject,
6930                                               L"FullName",
6931                                               &InfoBuffer->All.FullName);
6932         if (!NT_SUCCESS(Status))
6933         {
6934             TRACE("Status 0x%08lx\n", Status);
6935             goto done;
6936         }
6937     }
6938 
6939     /* Get the UserId attribute */
6940     if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
6941     {
6942         InfoBuffer->All.UserId = FixedData.UserId;
6943     }
6944 
6945     /* Get the PrimaryGroupId attribute */
6946     if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
6947     {
6948         InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6949     }
6950 
6951     /* Get the AdminComment attribute */
6952     if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
6953     {
6954         Status = SampGetObjectAttributeString(UserObject,
6955                                               L"AdminComment",
6956                                               &InfoBuffer->All.AdminComment);
6957         if (!NT_SUCCESS(Status))
6958         {
6959             TRACE("Status 0x%08lx\n", Status);
6960             goto done;
6961         }
6962     }
6963 
6964     /* Get the UserComment attribute */
6965     if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
6966     {
6967         Status = SampGetObjectAttributeString(UserObject,
6968                                               L"UserComment",
6969                                               &InfoBuffer->All.UserComment);
6970         if (!NT_SUCCESS(Status))
6971         {
6972             TRACE("Status 0x%08lx\n", Status);
6973             goto done;
6974         }
6975     }
6976 
6977     /* Get the HomeDirectory attribute */
6978     if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
6979     {
6980         Status = SampGetObjectAttributeString(UserObject,
6981                                               L"HomeDirectory",
6982                                               &InfoBuffer->All.HomeDirectory);
6983         if (!NT_SUCCESS(Status))
6984         {
6985             TRACE("Status 0x%08lx\n", Status);
6986             goto done;
6987         }
6988     }
6989 
6990     /* Get the HomeDirectoryDrive attribute */
6991     if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
6992     {
6993         Status = SampGetObjectAttributeString(UserObject,
6994                                               L"HomeDirectoryDrive",
6995                                               &InfoBuffer->Home.HomeDirectoryDrive);
6996         if (!NT_SUCCESS(Status))
6997         {
6998             TRACE("Status 0x%08lx\n", Status);
6999             goto done;
7000         }
7001     }
7002 
7003     /* Get the ScriptPath attribute */
7004     if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
7005     {
7006         Status = SampGetObjectAttributeString(UserObject,
7007                                               L"ScriptPath",
7008                                               &InfoBuffer->All.ScriptPath);
7009         if (!NT_SUCCESS(Status))
7010         {
7011             TRACE("Status 0x%08lx\n", Status);
7012             goto done;
7013         }
7014     }
7015 
7016     /* Get the ProfilePath attribute */
7017     if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
7018     {
7019         Status = SampGetObjectAttributeString(UserObject,
7020                                               L"ProfilePath",
7021                                               &InfoBuffer->All.ProfilePath);
7022         if (!NT_SUCCESS(Status))
7023         {
7024             TRACE("Status 0x%08lx\n", Status);
7025             goto done;
7026         }
7027     }
7028 
7029     /* Get the WorkStations attribute */
7030     if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
7031     {
7032         Status = SampGetObjectAttributeString(UserObject,
7033                                               L"WorkStations",
7034                                               &InfoBuffer->All.WorkStations);
7035         if (!NT_SUCCESS(Status))
7036         {
7037             TRACE("Status 0x%08lx\n", Status);
7038             goto done;
7039         }
7040     }
7041 
7042     /* Get the LastLogon attribute */
7043     if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
7044     {
7045         InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
7046         InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
7047     }
7048 
7049     /* Get the LastLogoff attribute */
7050     if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
7051     {
7052         InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
7053         InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
7054     }
7055 
7056     /* Get the LogonHours attribute */
7057     if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
7058     {
7059         Status = SampGetLogonHoursAttribute(UserObject,
7060                                            &InfoBuffer->All.LogonHours);
7061         if (!NT_SUCCESS(Status))
7062         {
7063             TRACE("Status 0x%08lx\n", Status);
7064             goto done;
7065         }
7066     }
7067 
7068     /* Get the BadPasswordCount attribute */
7069     if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
7070     {
7071         InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
7072     }
7073 
7074     /* Get the LogonCount attribute */
7075     if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
7076     {
7077         InfoBuffer->All.LogonCount = FixedData.LogonCount;
7078     }
7079 
7080     /* Get the PasswordCanChange attribute */
7081     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
7082     {
7083         PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7084                                                       DomainFixedData.MinPasswordAge);
7085         InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
7086         InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
7087     }
7088 
7089     /* Get the PasswordMustChange attribute */
7090     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
7091     {
7092         PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7093                                                        DomainFixedData.MaxPasswordAge);
7094         InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
7095         InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
7096     }
7097 
7098     /* Get the PasswordLastSet attribute */
7099     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
7100     {
7101         InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
7102         InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
7103     }
7104 
7105     /* Get the AccountExpires attribute */
7106     if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
7107     {
7108         InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
7109         InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
7110     }
7111 
7112     /* Get the UserAccountControl attribute */
7113     if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
7114     {
7115         InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
7116     }
7117 
7118     /* Get the Parameters attribute */
7119     if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
7120     {
7121         Status = SampGetObjectAttributeString(UserObject,
7122                                               L"Parameters",
7123                                               &InfoBuffer->All.Parameters);
7124         if (!NT_SUCCESS(Status))
7125         {
7126             TRACE("Status 0x%08lx\n", Status);
7127             goto done;
7128         }
7129     }
7130 
7131     /* Get the CountryCode attribute */
7132     if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
7133     {
7134         InfoBuffer->All.CountryCode = FixedData.CountryCode;
7135     }
7136 
7137     /* Get the CodePage attribute */
7138     if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
7139     {
7140         InfoBuffer->All.CodePage = FixedData.CodePage;
7141     }
7142 
7143     /* Get the LmPassword and NtPassword attributes */
7144     if (InfoBuffer->All.WhichFields & (USER_ALL_NTPASSWORDPRESENT | USER_ALL_LMPASSWORDPRESENT))
7145     {
7146         InfoBuffer->All.LmPasswordPresent = FALSE;
7147         InfoBuffer->All.NtPasswordPresent = FALSE;
7148 
7149         /* Get the NT password */
7150         Length = 0;
7151         SampGetObjectAttribute(UserObject,
7152                                L"NTPwd",
7153                                NULL,
7154                                NULL,
7155                                &Length);
7156 
7157         if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
7158         {
7159             InfoBuffer->All.NtOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_NT_OWF_PASSWORD));
7160             if (InfoBuffer->All.NtOwfPassword.Buffer == NULL)
7161             {
7162                 Status = STATUS_INSUFFICIENT_RESOURCES;
7163                 goto done;
7164             }
7165 
7166             InfoBuffer->All.NtOwfPassword.Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7167             InfoBuffer->All.NtOwfPassword.MaximumLength = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7168 
7169             Status = SampGetObjectAttribute(UserObject,
7170                                             L"NTPwd",
7171                                             NULL,
7172                                             (PVOID)InfoBuffer->All.NtOwfPassword.Buffer,
7173                                             &Length);
7174             if (!NT_SUCCESS(Status))
7175                 goto done;
7176 
7177             if (memcmp(InfoBuffer->All.NtOwfPassword.Buffer,
7178                        &EmptyNtHash,
7179                        sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
7180                 InfoBuffer->All.NtPasswordPresent = TRUE;
7181         }
7182 
7183         /* Get the LM password */
7184         Length = 0;
7185         SampGetObjectAttribute(UserObject,
7186                                L"LMPwd",
7187                                NULL,
7188                                NULL,
7189                                &Length);
7190 
7191         if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
7192         {
7193             InfoBuffer->All.LmOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_LM_OWF_PASSWORD));
7194             if (InfoBuffer->All.LmOwfPassword.Buffer == NULL)
7195             {
7196                 Status = STATUS_INSUFFICIENT_RESOURCES;
7197                 goto done;
7198             }
7199 
7200             InfoBuffer->All.LmOwfPassword.Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7201             InfoBuffer->All.LmOwfPassword.MaximumLength = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7202 
7203             Status = SampGetObjectAttribute(UserObject,
7204                                             L"LMPwd",
7205                                             NULL,
7206                                             (PVOID)InfoBuffer->All.LmOwfPassword.Buffer,
7207                                             &Length);
7208             if (!NT_SUCCESS(Status))
7209                 goto done;
7210 
7211             if (memcmp(InfoBuffer->All.LmOwfPassword.Buffer,
7212                        &EmptyLmHash,
7213                        sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7214                 InfoBuffer->All.LmPasswordPresent = TRUE;
7215         }
7216     }
7217 
7218     if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
7219     {
7220         Status = SampGetObjectAttributeString(UserObject,
7221                                               L"PrivateData",
7222                                               &InfoBuffer->All.PrivateData);
7223         if (!NT_SUCCESS(Status))
7224         {
7225             TRACE("Status 0x%08lx\n", Status);
7226             goto done;
7227         }
7228     }
7229 
7230     if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
7231     {
7232         /* FIXME */
7233     }
7234 
7235     if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7236     {
7237         Length = 0;
7238         SampGetObjectAttribute(UserObject,
7239                                L"SecDesc",
7240                                NULL,
7241                                NULL,
7242                                &Length);
7243 
7244         if (Length > 0)
7245         {
7246             InfoBuffer->All.SecurityDescriptor.SecurityDescriptor = midl_user_allocate(Length);
7247             if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor == NULL)
7248             {
7249                 Status = STATUS_INSUFFICIENT_RESOURCES;
7250                 goto done;
7251             }
7252 
7253             InfoBuffer->All.SecurityDescriptor.Length = Length;
7254 
7255             Status = SampGetObjectAttribute(UserObject,
7256                                             L"SecDesc",
7257                                             NULL,
7258                                             (PVOID)InfoBuffer->All.SecurityDescriptor.SecurityDescriptor,
7259                                             &Length);
7260             if (!NT_SUCCESS(Status))
7261                 goto done;
7262         }
7263     }
7264 
7265     *Buffer = InfoBuffer;
7266 
7267 done:
7268     if (!NT_SUCCESS(Status))
7269     {
7270         if (InfoBuffer != NULL)
7271         {
7272             if (InfoBuffer->All.UserName.Buffer != NULL)
7273                 midl_user_free(InfoBuffer->All.UserName.Buffer);
7274 
7275             if (InfoBuffer->All.FullName.Buffer != NULL)
7276                 midl_user_free(InfoBuffer->All.FullName.Buffer);
7277 
7278             if (InfoBuffer->All.AdminComment.Buffer != NULL)
7279                 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
7280 
7281             if (InfoBuffer->All.UserComment.Buffer != NULL)
7282                 midl_user_free(InfoBuffer->All.UserComment.Buffer);
7283 
7284             if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
7285                 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
7286 
7287             if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
7288                 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
7289 
7290             if (InfoBuffer->All.ScriptPath.Buffer != NULL)
7291                 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
7292 
7293             if (InfoBuffer->All.ProfilePath.Buffer != NULL)
7294                 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
7295 
7296             if (InfoBuffer->All.WorkStations.Buffer != NULL)
7297                 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
7298 
7299             if (InfoBuffer->All.LogonHours.LogonHours != NULL)
7300                 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
7301 
7302             if (InfoBuffer->All.Parameters.Buffer != NULL)
7303                 midl_user_free(InfoBuffer->All.Parameters.Buffer);
7304 
7305             if (InfoBuffer->All.LmOwfPassword.Buffer != NULL)
7306                 midl_user_free(InfoBuffer->All.LmOwfPassword.Buffer);
7307 
7308             if (InfoBuffer->All.NtOwfPassword.Buffer != NULL)
7309                 midl_user_free(InfoBuffer->All.NtOwfPassword.Buffer);
7310 
7311             if (InfoBuffer->All.PrivateData.Buffer != NULL)
7312                 midl_user_free(InfoBuffer->All.PrivateData.Buffer);
7313 
7314             if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor != NULL)
7315                 midl_user_free(InfoBuffer->All.SecurityDescriptor.SecurityDescriptor);
7316 
7317             midl_user_free(InfoBuffer);
7318         }
7319     }
7320 
7321     return Status;
7322 }
7323 
7324 
7325 /* Function 36 */
7326 NTSTATUS
7327 NTAPI
7328 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
7329                          IN USER_INFORMATION_CLASS UserInformationClass,
7330                          OUT PSAMPR_USER_INFO_BUFFER *Buffer)
7331 {
7332     PSAM_DB_OBJECT UserObject;
7333     ACCESS_MASK DesiredAccess;
7334     NTSTATUS Status;
7335 
7336     TRACE("SamrQueryInformationUser(%p %lu %p)\n",
7337           UserHandle, UserInformationClass, Buffer);
7338 
7339     switch (UserInformationClass)
7340     {
7341         case UserGeneralInformation:
7342         case UserNameInformation:
7343         case UserAccountNameInformation:
7344         case UserFullNameInformation:
7345         case UserPrimaryGroupInformation:
7346         case UserAdminCommentInformation:
7347             DesiredAccess = USER_READ_GENERAL;
7348             break;
7349 
7350         case UserLogonHoursInformation:
7351         case UserHomeInformation:
7352         case UserScriptInformation:
7353         case UserProfileInformation:
7354         case UserWorkStationsInformation:
7355             DesiredAccess = USER_READ_LOGON;
7356             break;
7357 
7358         case UserControlInformation:
7359         case UserExpiresInformation:
7360         case UserParametersInformation:
7361             DesiredAccess = USER_READ_ACCOUNT;
7362             break;
7363 
7364         case UserPreferencesInformation:
7365             DesiredAccess = USER_READ_GENERAL |
7366                             USER_READ_PREFERENCES;
7367             break;
7368 
7369         case UserLogonInformation:
7370         case UserAccountInformation:
7371             DesiredAccess = USER_READ_GENERAL |
7372                             USER_READ_PREFERENCES |
7373                             USER_READ_LOGON |
7374                             USER_READ_ACCOUNT;
7375             break;
7376 
7377         case UserInternal1Information:
7378         case UserInternal2Information:
7379         case UserAllInformation:
7380             DesiredAccess = 0;
7381             break;
7382 
7383         default:
7384             return STATUS_INVALID_INFO_CLASS;
7385     }
7386 
7387     RtlAcquireResourceShared(&SampResource,
7388                              TRUE);
7389 
7390     /* Validate the domain handle */
7391     Status = SampValidateDbObject(UserHandle,
7392                                   SamDbUserObject,
7393                                   DesiredAccess,
7394                                   &UserObject);
7395     if (!NT_SUCCESS(Status))
7396     {
7397         TRACE("failed with status 0x%08lx\n", Status);
7398         goto done;
7399     }
7400 
7401     switch (UserInformationClass)
7402     {
7403         case UserGeneralInformation:
7404             Status = SampQueryUserGeneral(UserObject,
7405                                           Buffer);
7406             break;
7407 
7408         case UserPreferencesInformation:
7409             Status = SampQueryUserPreferences(UserObject,
7410                                               Buffer);
7411             break;
7412 
7413         case UserLogonInformation:
7414             Status = SampQueryUserLogon(UserObject,
7415                                         Buffer);
7416             break;
7417 
7418         case UserLogonHoursInformation:
7419             Status = SampQueryUserLogonHours(UserObject,
7420                                              Buffer);
7421             break;
7422 
7423         case UserAccountInformation:
7424             Status = SampQueryUserAccount(UserObject,
7425                                           Buffer);
7426             break;
7427 
7428         case UserNameInformation:
7429             Status = SampQueryUserName(UserObject,
7430                                        Buffer);
7431             break;
7432 
7433         case UserAccountNameInformation:
7434             Status = SampQueryUserAccountName(UserObject,
7435                                               Buffer);
7436             break;
7437 
7438         case UserFullNameInformation:
7439             Status = SampQueryUserFullName(UserObject,
7440                                            Buffer);
7441             break;
7442 
7443         case UserPrimaryGroupInformation:
7444             Status = SampQueryUserPrimaryGroup(UserObject,
7445                                                Buffer);
7446             break;
7447 
7448         case UserHomeInformation:
7449             Status = SampQueryUserHome(UserObject,
7450                                        Buffer);
7451 
7452         case UserScriptInformation:
7453             Status = SampQueryUserScript(UserObject,
7454                                          Buffer);
7455             break;
7456 
7457         case UserProfileInformation:
7458             Status = SampQueryUserProfile(UserObject,
7459                                           Buffer);
7460             break;
7461 
7462         case UserAdminCommentInformation:
7463             Status = SampQueryUserAdminComment(UserObject,
7464                                                Buffer);
7465             break;
7466 
7467         case UserWorkStationsInformation:
7468             Status = SampQueryUserWorkStations(UserObject,
7469                                                Buffer);
7470             break;
7471 
7472         case UserControlInformation:
7473             Status = SampQueryUserControl(UserObject,
7474                                           Buffer);
7475             break;
7476 
7477         case UserExpiresInformation:
7478             Status = SampQueryUserExpires(UserObject,
7479                                           Buffer);
7480             break;
7481 
7482         case UserInternal1Information:
7483             Status = SampQueryUserInternal1(UserObject,
7484                                             Buffer);
7485             break;
7486 
7487         case UserInternal2Information:
7488             Status = SampQueryUserInternal2(UserObject,
7489                                             Buffer);
7490             break;
7491 
7492         case UserParametersInformation:
7493             Status = SampQueryUserParameters(UserObject,
7494                                              Buffer);
7495             break;
7496 
7497         case UserAllInformation:
7498             Status = SampQueryUserAll(UserObject,
7499                                       Buffer);
7500             break;
7501 
7502 //        case UserInternal4Information:
7503 //        case UserInternal5Information:
7504 //        case UserInternal4InformationNew:
7505 //        case UserInternal5InformationNew:
7506 
7507         default:
7508             Status = STATUS_INVALID_INFO_CLASS;
7509     }
7510 
7511 done:
7512     RtlReleaseResource(&SampResource);
7513 
7514     return Status;
7515 }
7516 
7517 
7518 static NTSTATUS
7519 SampSetUserName(PSAM_DB_OBJECT UserObject,
7520                 PRPC_UNICODE_STRING NewUserName)
7521 {
7522     UNICODE_STRING OldUserName = {0, 0, NULL};
7523     NTSTATUS Status;
7524 
7525     /* Check the account name */
7526     Status = SampCheckAccountName(NewUserName, 20);
7527     if (!NT_SUCCESS(Status))
7528     {
7529         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
7530         return Status;
7531     }
7532 
7533     Status = SampGetObjectAttributeString(UserObject,
7534                                           L"Name",
7535                                           (PRPC_UNICODE_STRING)&OldUserName);
7536     if (!NT_SUCCESS(Status))
7537     {
7538         TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
7539         goto done;
7540     }
7541 
7542     if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
7543     {
7544         Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
7545                                               NewUserName->Buffer);
7546         if (!NT_SUCCESS(Status))
7547         {
7548             TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7549                   NewUserName->Buffer, Status);
7550             goto done;
7551         }
7552     }
7553 
7554     Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7555                                         L"Users",
7556                                         NewUserName->Buffer,
7557                                         UserObject->RelativeId);
7558     if (!NT_SUCCESS(Status))
7559     {
7560         TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7561         goto done;
7562     }
7563 
7564     Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7565                                              L"Users",
7566                                              OldUserName.Buffer);
7567     if (!NT_SUCCESS(Status))
7568     {
7569         TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7570         goto done;
7571     }
7572 
7573     Status = SampSetObjectAttributeString(UserObject,
7574                                           L"Name",
7575                                           NewUserName);
7576     if (!NT_SUCCESS(Status))
7577     {
7578         TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7579     }
7580 
7581 done:
7582     if (OldUserName.Buffer != NULL)
7583         midl_user_free(OldUserName.Buffer);
7584 
7585     return Status;
7586 }
7587 
7588 
7589 static NTSTATUS
7590 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7591                    PSAMPR_USER_INFO_BUFFER Buffer)
7592 {
7593     SAM_USER_FIXED_DATA FixedData;
7594     ULONG Length = 0;
7595     NTSTATUS Status;
7596 
7597     Length = sizeof(SAM_USER_FIXED_DATA);
7598     Status = SampGetObjectAttribute(UserObject,
7599                                     L"F",
7600                                     NULL,
7601                                     (PVOID)&FixedData,
7602                                     &Length);
7603     if (!NT_SUCCESS(Status))
7604         goto done;
7605 
7606     FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7607 
7608     Status = SampSetObjectAttribute(UserObject,
7609                                     L"F",
7610                                     REG_BINARY,
7611                                     &FixedData,
7612                                     Length);
7613     if (!NT_SUCCESS(Status))
7614         goto done;
7615 
7616     Status = SampSetUserName(UserObject,
7617                              &Buffer->General.UserName);
7618     if (!NT_SUCCESS(Status))
7619         goto done;
7620 
7621     Status = SampSetObjectAttributeString(UserObject,
7622                                           L"FullName",
7623                                           &Buffer->General.FullName);
7624     if (!NT_SUCCESS(Status))
7625         goto done;
7626 
7627     Status = SampSetObjectAttributeString(UserObject,
7628                                           L"AdminComment",
7629                                           &Buffer->General.AdminComment);
7630     if (!NT_SUCCESS(Status))
7631         goto done;
7632 
7633     Status = SampSetObjectAttributeString(UserObject,
7634                                           L"UserComment",
7635                                           &Buffer->General.UserComment);
7636 
7637 done:
7638     return Status;
7639 }
7640 
7641 
7642 static NTSTATUS
7643 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7644                        PSAMPR_USER_INFO_BUFFER Buffer)
7645 {
7646     SAM_USER_FIXED_DATA FixedData;
7647     ULONG Length = 0;
7648     NTSTATUS Status;
7649 
7650     Length = sizeof(SAM_USER_FIXED_DATA);
7651     Status = SampGetObjectAttribute(UserObject,
7652                                     L"F",
7653                                     NULL,
7654                                     (PVOID)&FixedData,
7655                                     &Length);
7656     if (!NT_SUCCESS(Status))
7657         goto done;
7658 
7659     FixedData.CountryCode = Buffer->Preferences.CountryCode;
7660     FixedData.CodePage = Buffer->Preferences.CodePage;
7661 
7662     Status = SampSetObjectAttribute(UserObject,
7663                                     L"F",
7664                                     REG_BINARY,
7665                                     &FixedData,
7666                                     Length);
7667     if (!NT_SUCCESS(Status))
7668         goto done;
7669 
7670     Status = SampSetObjectAttributeString(UserObject,
7671                                           L"UserComment",
7672                                           &Buffer->Preferences.UserComment);
7673 
7674 done:
7675     return Status;
7676 }
7677 
7678 
7679 static NTSTATUS
7680 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7681                         PSAMPR_USER_INFO_BUFFER Buffer)
7682 {
7683     SAM_USER_FIXED_DATA FixedData;
7684     ULONG Length = 0;
7685     NTSTATUS Status;
7686 
7687     Length = sizeof(SAM_USER_FIXED_DATA);
7688     Status = SampGetObjectAttribute(UserObject,
7689                                     L"F",
7690                                     NULL,
7691                                     (PVOID)&FixedData,
7692                                     &Length);
7693     if (!NT_SUCCESS(Status))
7694         goto done;
7695 
7696     FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7697 
7698     Status = SampSetObjectAttribute(UserObject,
7699                                     L"F",
7700                                     REG_BINARY,
7701                                     &FixedData,
7702                                     Length);
7703 
7704 done:
7705     return Status;
7706 }
7707 
7708 
7709 static NTSTATUS
7710 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7711                    PSAMPR_USER_INFO_BUFFER Buffer)
7712 {
7713     SAM_USER_FIXED_DATA FixedData;
7714     ULONG Length = 0;
7715     NTSTATUS Status;
7716 
7717     Length = sizeof(SAM_USER_FIXED_DATA);
7718     Status = SampGetObjectAttribute(UserObject,
7719                                     L"F",
7720                                     NULL,
7721                                     (PVOID)&FixedData,
7722                                     &Length);
7723     if (!NT_SUCCESS(Status))
7724         goto done;
7725 
7726     FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7727 
7728     Status = SampSetObjectAttribute(UserObject,
7729                                     L"F",
7730                                     REG_BINARY,
7731                                     &FixedData,
7732                                     Length);
7733 
7734 done:
7735     return Status;
7736 }
7737 
7738 
7739 static NTSTATUS
7740 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7741                    PSAMPR_USER_INFO_BUFFER Buffer)
7742 {
7743     SAM_USER_FIXED_DATA FixedData;
7744     ULONG Length = 0;
7745     NTSTATUS Status;
7746 
7747     Length = sizeof(SAM_USER_FIXED_DATA);
7748     Status = SampGetObjectAttribute(UserObject,
7749                                     L"F",
7750                                     NULL,
7751                                     (PVOID)&FixedData,
7752                                     &Length);
7753     if (!NT_SUCCESS(Status))
7754         goto done;
7755 
7756     FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7757     FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7758 
7759     Status = SampSetObjectAttribute(UserObject,
7760                                     L"F",
7761                                     REG_BINARY,
7762                                     &FixedData,
7763                                     Length);
7764 
7765 done:
7766     return Status;
7767 }
7768 
7769 
7770 static NTSTATUS
7771 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7772                      PSAMPR_USER_INFO_BUFFER Buffer)
7773 {
7774     SAM_USER_FIXED_DATA FixedData;
7775     ULONG Length = 0;
7776     NTSTATUS Status = STATUS_SUCCESS;
7777 
7778     /* FIXME: Decrypt NT password */
7779     /* FIXME: Decrypt LM password */
7780 
7781     Status = SampSetUserPassword(UserObject,
7782                                  &Buffer->Internal1.EncryptedNtOwfPassword,
7783                                  Buffer->Internal1.NtPasswordPresent,
7784                                  &Buffer->Internal1.EncryptedLmOwfPassword,
7785                                  Buffer->Internal1.LmPasswordPresent);
7786     if (!NT_SUCCESS(Status))
7787         goto done;
7788 
7789     /* Get the fixed user attributes */
7790     Length = sizeof(SAM_USER_FIXED_DATA);
7791     Status = SampGetObjectAttribute(UserObject,
7792                                     L"F",
7793                                     NULL,
7794                                     (PVOID)&FixedData,
7795                                     &Length);
7796     if (!NT_SUCCESS(Status))
7797         goto done;
7798 
7799     if (Buffer->Internal1.PasswordExpired)
7800     {
7801         /* The password was last set ages ago */
7802         FixedData.PasswordLastSet.LowPart = 0;
7803         FixedData.PasswordLastSet.HighPart = 0;
7804     }
7805     else
7806     {
7807         /* The password was last set right now */
7808         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7809         if (!NT_SUCCESS(Status))
7810             goto done;
7811     }
7812 
7813     /* Set the fixed user attributes */
7814     Status = SampSetObjectAttribute(UserObject,
7815                                     L"F",
7816                                     REG_BINARY,
7817                                     &FixedData,
7818                                     Length);
7819 
7820 done:
7821     return Status;
7822 }
7823 
7824 
7825 static NTSTATUS
7826 SampSetUserInternal2(PSAM_DB_OBJECT UserObject,
7827                      PSAMPR_USER_INFO_BUFFER Buffer)
7828 {
7829     SAM_USER_FIXED_DATA FixedData;
7830     ULONG Length = 0;
7831     NTSTATUS Status = STATUS_SUCCESS;
7832 
7833     /* Get the fixed user attributes */
7834     Length = sizeof(SAM_USER_FIXED_DATA);
7835     Status = SampGetObjectAttribute(UserObject,
7836                                     L"F",
7837                                     NULL,
7838                                     (PVOID)&FixedData,
7839                                     &Length);
7840     if (!NT_SUCCESS(Status))
7841         goto done;
7842 
7843     if ((Buffer->Internal2.Flags & USER_LOGON_SUCCESS) &&
7844         ((Buffer->Internal2.Flags & ~USER_LOGON_SUCCESS) == 0))
7845     {
7846         /* Update the LastLogon time */
7847         Status = NtQuerySystemTime(&FixedData.LastLogon);
7848         if (!NT_SUCCESS(Status))
7849             goto done;
7850 
7851         FixedData.LogonCount++;
7852         FixedData.BadPasswordCount = 0;
7853     }
7854 
7855     if ((Buffer->Internal2.Flags & USER_LOGON_BAD_PASSWORD) &&
7856         ((Buffer->Internal2.Flags & ~USER_LOGON_BAD_PASSWORD) == 0))
7857     {
7858         /* Update the LastBadPasswordTime */
7859         Status = NtQuerySystemTime(&FixedData.LastBadPasswordTime);
7860         if (!NT_SUCCESS(Status))
7861             goto done;
7862 
7863         FixedData.BadPasswordCount++;
7864     }
7865 
7866     /* Set the fixed user attributes */
7867     Status = SampSetObjectAttribute(UserObject,
7868                                     L"F",
7869                                     REG_BINARY,
7870                                     &FixedData,
7871                                     Length);
7872 
7873 done:
7874     return Status;
7875 }
7876 
7877 
7878 static NTSTATUS
7879 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7880                PSAMPR_USER_INFO_BUFFER Buffer)
7881 {
7882     SAM_USER_FIXED_DATA FixedData;
7883     ULONG Length = 0;
7884     ULONG WhichFields;
7885     PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7886     PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7887     BOOLEAN NtPasswordPresent = FALSE;
7888     BOOLEAN LmPasswordPresent = FALSE;
7889     BOOLEAN WriteFixedData = FALSE;
7890     NTSTATUS Status = STATUS_SUCCESS;
7891 
7892     WhichFields = Buffer->All.WhichFields;
7893 
7894     /* Get the fixed size attributes */
7895     Length = sizeof(SAM_USER_FIXED_DATA);
7896     Status = SampGetObjectAttribute(UserObject,
7897                                     L"F",
7898                                     NULL,
7899                                     (PVOID)&FixedData,
7900                                     &Length);
7901     if (!NT_SUCCESS(Status))
7902         goto done;
7903 
7904     if (WhichFields & USER_ALL_USERNAME)
7905     {
7906         Status = SampSetUserName(UserObject,
7907                                  &Buffer->All.UserName);
7908         if (!NT_SUCCESS(Status))
7909             goto done;
7910     }
7911 
7912     if (WhichFields & USER_ALL_FULLNAME)
7913     {
7914         Status = SampSetObjectAttributeString(UserObject,
7915                                               L"FullName",
7916                                               &Buffer->All.FullName);
7917         if (!NT_SUCCESS(Status))
7918             goto done;
7919     }
7920 
7921     if (WhichFields & USER_ALL_ADMINCOMMENT)
7922     {
7923         Status = SampSetObjectAttributeString(UserObject,
7924                                               L"AdminComment",
7925                                               &Buffer->All.AdminComment);
7926         if (!NT_SUCCESS(Status))
7927             goto done;
7928     }
7929 
7930     if (WhichFields & USER_ALL_USERCOMMENT)
7931     {
7932         Status = SampSetObjectAttributeString(UserObject,
7933                                               L"UserComment",
7934                                               &Buffer->All.UserComment);
7935         if (!NT_SUCCESS(Status))
7936             goto done;
7937     }
7938 
7939     if (WhichFields & USER_ALL_HOMEDIRECTORY)
7940     {
7941         Status = SampSetObjectAttributeString(UserObject,
7942                                               L"HomeDirectory",
7943                                               &Buffer->All.HomeDirectory);
7944         if (!NT_SUCCESS(Status))
7945             goto done;
7946     }
7947 
7948     if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7949     {
7950         Status = SampSetObjectAttributeString(UserObject,
7951                                               L"HomeDirectoryDrive",
7952                                               &Buffer->All.HomeDirectoryDrive);
7953         if (!NT_SUCCESS(Status))
7954             goto done;
7955     }
7956 
7957     if (WhichFields & USER_ALL_SCRIPTPATH)
7958     {
7959         Status = SampSetObjectAttributeString(UserObject,
7960                                               L"ScriptPath",
7961                                               &Buffer->All.ScriptPath);
7962         if (!NT_SUCCESS(Status))
7963             goto done;
7964     }
7965 
7966     if (WhichFields & USER_ALL_PROFILEPATH)
7967     {
7968         Status = SampSetObjectAttributeString(UserObject,
7969                                               L"ProfilePath",
7970                                               &Buffer->All.ProfilePath);
7971         if (!NT_SUCCESS(Status))
7972             goto done;
7973     }
7974 
7975     if (WhichFields & USER_ALL_WORKSTATIONS)
7976     {
7977         Status = SampSetObjectAttributeString(UserObject,
7978                                               L"WorkStations",
7979                                               &Buffer->All.WorkStations);
7980         if (!NT_SUCCESS(Status))
7981             goto done;
7982     }
7983 
7984     if (WhichFields & USER_ALL_PARAMETERS)
7985     {
7986         Status = SampSetObjectAttributeString(UserObject,
7987                                               L"Parameters",
7988                                               &Buffer->All.Parameters);
7989         if (!NT_SUCCESS(Status))
7990             goto done;
7991     }
7992 
7993     if (WhichFields & USER_ALL_LOGONHOURS)
7994     {
7995         Status = SampSetLogonHoursAttribute(UserObject,
7996                                            &Buffer->All.LogonHours);
7997         if (!NT_SUCCESS(Status))
7998             goto done;
7999     }
8000 
8001     if (WhichFields & USER_ALL_PRIMARYGROUPID)
8002     {
8003         FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
8004         WriteFixedData = TRUE;
8005     }
8006 
8007     if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
8008     {
8009         FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
8010         FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
8011         WriteFixedData = TRUE;
8012     }
8013 
8014     if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
8015     {
8016         FixedData.UserAccountControl = Buffer->All.UserAccountControl;
8017         WriteFixedData = TRUE;
8018     }
8019 
8020     if (WhichFields & USER_ALL_COUNTRYCODE)
8021     {
8022         FixedData.CountryCode = Buffer->All.CountryCode;
8023         WriteFixedData = TRUE;
8024     }
8025 
8026     if (WhichFields & USER_ALL_CODEPAGE)
8027     {
8028         FixedData.CodePage = Buffer->All.CodePage;
8029         WriteFixedData = TRUE;
8030     }
8031 
8032     if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
8033                        USER_ALL_LMPASSWORDPRESENT))
8034     {
8035         if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
8036         {
8037             NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
8038             NtPasswordPresent = Buffer->All.NtPasswordPresent;
8039         }
8040 
8041         if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
8042         {
8043             LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
8044             LmPasswordPresent = Buffer->All.LmPasswordPresent;
8045         }
8046 
8047         Status = SampSetUserPassword(UserObject,
8048                                      NtPassword,
8049                                      NtPasswordPresent,
8050                                      LmPassword,
8051                                      LmPasswordPresent);
8052         if (!NT_SUCCESS(Status))
8053             goto done;
8054 
8055         /* The password has just been set */
8056         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8057         if (!NT_SUCCESS(Status))
8058             goto done;
8059 
8060         WriteFixedData = TRUE;
8061     }
8062 
8063     if (WhichFields & USER_ALL_PRIVATEDATA)
8064     {
8065         Status = SampSetObjectAttributeString(UserObject,
8066                                               L"PrivateData",
8067                                               &Buffer->All.PrivateData);
8068         if (!NT_SUCCESS(Status))
8069             goto done;
8070     }
8071 
8072     if (WhichFields & USER_ALL_PASSWORDEXPIRED)
8073     {
8074         if (Buffer->All.PasswordExpired)
8075         {
8076             /* The password was last set ages ago */
8077             FixedData.PasswordLastSet.LowPart = 0;
8078             FixedData.PasswordLastSet.HighPart = 0;
8079         }
8080         else
8081         {
8082             /* The password was last set right now */
8083             Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
8084             if (!NT_SUCCESS(Status))
8085                 goto done;
8086         }
8087 
8088         WriteFixedData = TRUE;
8089     }
8090 
8091     if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
8092     {
8093         Status = SampSetObjectAttribute(UserObject,
8094                                         L"SecDesc",
8095                                         REG_BINARY,
8096                                         Buffer->All.SecurityDescriptor.SecurityDescriptor,
8097                                         Buffer->All.SecurityDescriptor.Length);
8098     }
8099 
8100     if (WriteFixedData != FALSE)
8101     {
8102         Status = SampSetObjectAttribute(UserObject,
8103                                         L"F",
8104                                         REG_BINARY,
8105                                         &FixedData,
8106                                         Length);
8107         if (!NT_SUCCESS(Status))
8108             goto done;
8109     }
8110 
8111 done:
8112     return Status;
8113 }
8114 
8115 
8116 /* Function 37 */
8117 NTSTATUS
8118 NTAPI
8119 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
8120                        IN USER_INFORMATION_CLASS UserInformationClass,
8121                        IN PSAMPR_USER_INFO_BUFFER Buffer)
8122 {
8123     PSAM_DB_OBJECT UserObject;
8124     ACCESS_MASK DesiredAccess;
8125     NTSTATUS Status;
8126 
8127     TRACE("SamrSetInformationUser(%p %lu %p)\n",
8128           UserHandle, UserInformationClass, Buffer);
8129 
8130     switch (UserInformationClass)
8131     {
8132         case UserLogonHoursInformation:
8133         case UserNameInformation:
8134         case UserAccountNameInformation:
8135         case UserFullNameInformation:
8136         case UserPrimaryGroupInformation:
8137         case UserHomeInformation:
8138         case UserScriptInformation:
8139         case UserProfileInformation:
8140         case UserAdminCommentInformation:
8141         case UserWorkStationsInformation:
8142         case UserControlInformation:
8143         case UserExpiresInformation:
8144         case UserParametersInformation:
8145             DesiredAccess = USER_WRITE_ACCOUNT;
8146             break;
8147 
8148         case UserGeneralInformation:
8149             DesiredAccess = USER_WRITE_ACCOUNT |
8150                             USER_WRITE_PREFERENCES;
8151             break;
8152 
8153         case UserPreferencesInformation:
8154             DesiredAccess = USER_WRITE_PREFERENCES;
8155             break;
8156 
8157         case UserSetPasswordInformation:
8158         case UserInternal1Information:
8159             DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
8160             break;
8161 
8162         case UserAllInformation:
8163         case UserInternal2Information:
8164             DesiredAccess = 0; /* FIXME */
8165             break;
8166 
8167         default:
8168             return STATUS_INVALID_INFO_CLASS;
8169     }
8170 
8171     RtlAcquireResourceExclusive(&SampResource,
8172                                 TRUE);
8173 
8174     /* Validate the domain handle */
8175     Status = SampValidateDbObject(UserHandle,
8176                                   SamDbUserObject,
8177                                   DesiredAccess,
8178                                   &UserObject);
8179     if (!NT_SUCCESS(Status))
8180     {
8181         TRACE("failed with status 0x%08lx\n", Status);
8182         goto done;
8183     }
8184 
8185     switch (UserInformationClass)
8186     {
8187         case UserGeneralInformation:
8188             Status = SampSetUserGeneral(UserObject,
8189                                         Buffer);
8190             break;
8191 
8192         case UserPreferencesInformation:
8193             Status = SampSetUserPreferences(UserObject,
8194                                             Buffer);
8195             break;
8196 
8197         case UserLogonHoursInformation:
8198             Status = SampSetLogonHoursAttribute(UserObject,
8199                                                &Buffer->LogonHours.LogonHours);
8200             break;
8201 
8202         case UserNameInformation:
8203             Status = SampSetUserName(UserObject,
8204                                      &Buffer->Name.UserName);
8205             if (!NT_SUCCESS(Status))
8206                 break;
8207 
8208             Status = SampSetObjectAttributeString(UserObject,
8209                                                   L"FullName",
8210                                                   &Buffer->Name.FullName);
8211             break;
8212 
8213         case UserAccountNameInformation:
8214             Status = SampSetUserName(UserObject,
8215                                      &Buffer->AccountName.UserName);
8216             break;
8217 
8218         case UserFullNameInformation:
8219             Status = SampSetObjectAttributeString(UserObject,
8220                                                   L"FullName",
8221                                                   &Buffer->FullName.FullName);
8222             break;
8223 
8224         case UserPrimaryGroupInformation:
8225             Status = SampSetUserPrimaryGroup(UserObject,
8226                                              Buffer);
8227             break;
8228 
8229         case UserHomeInformation:
8230             Status = SampSetObjectAttributeString(UserObject,
8231                                                   L"HomeDirectory",
8232                                                   &Buffer->Home.HomeDirectory);
8233             if (!NT_SUCCESS(Status))
8234                 break;
8235 
8236             Status = SampSetObjectAttributeString(UserObject,
8237                                                   L"HomeDirectoryDrive",
8238                                                   &Buffer->Home.HomeDirectoryDrive);
8239             break;
8240 
8241         case UserScriptInformation:
8242             Status = SampSetObjectAttributeString(UserObject,
8243                                                   L"ScriptPath",
8244                                                   &Buffer->Script.ScriptPath);
8245             break;
8246 
8247         case UserProfileInformation:
8248             Status = SampSetObjectAttributeString(UserObject,
8249                                                   L"ProfilePath",
8250                                                   &Buffer->Profile.ProfilePath);
8251             break;
8252 
8253         case UserAdminCommentInformation:
8254             Status = SampSetObjectAttributeString(UserObject,
8255                                                   L"AdminComment",
8256                                                   &Buffer->AdminComment.AdminComment);
8257             break;
8258 
8259         case UserWorkStationsInformation:
8260             Status = SampSetObjectAttributeString(UserObject,
8261                                                   L"WorkStations",
8262                                                   &Buffer->WorkStations.WorkStations);
8263             break;
8264 
8265         case UserSetPasswordInformation:
8266             TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
8267             TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
8268 
8269             Status = SampSetObjectAttributeString(UserObject,
8270                                                   L"Password",
8271                                                   &Buffer->SetPassword.Password);
8272             break;
8273 
8274         case UserControlInformation:
8275             Status = SampSetUserControl(UserObject,
8276                                         Buffer);
8277             break;
8278 
8279         case UserExpiresInformation:
8280             Status = SampSetUserExpires(UserObject,
8281                                         Buffer);
8282             break;
8283 
8284         case UserInternal1Information:
8285             Status = SampSetUserInternal1(UserObject,
8286                                           Buffer);
8287             break;
8288 
8289         case UserInternal2Information:
8290             Status = SampSetUserInternal2(UserObject,
8291                                           Buffer);
8292             break;
8293 
8294         case UserParametersInformation:
8295             Status = SampSetObjectAttributeString(UserObject,
8296                                                   L"Parameters",
8297                                                   &Buffer->Parameters.Parameters);
8298             break;
8299 
8300         case UserAllInformation:
8301             Status = SampSetUserAll(UserObject,
8302                                     Buffer);
8303             break;
8304 
8305 //        case UserInternal4Information:
8306 //        case UserInternal5Information:
8307 //        case UserInternal4InformationNew:
8308 //        case UserInternal5InformationNew:
8309 
8310         default:
8311             Status = STATUS_INVALID_INFO_CLASS;
8312     }
8313 
8314 done:
8315     RtlReleaseResource(&SampResource);
8316 
8317     return Status;
8318 }
8319 
8320 
8321 /* Function 38 */
8322 NTSTATUS
8323 NTAPI
8324 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
8325                        IN unsigned char LmPresent,
8326                        IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
8327                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
8328                        IN unsigned char NtPresent,
8329                        IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
8330                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
8331                        IN unsigned char NtCrossEncryptionPresent,
8332                        IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
8333                        IN unsigned char LmCrossEncryptionPresent,
8334                        IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
8335 {
8336     ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
8337     ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
8338     LM_OWF_PASSWORD OldLmPassword;
8339     LM_OWF_PASSWORD NewLmPassword;
8340     NT_OWF_PASSWORD OldNtPassword;
8341     NT_OWF_PASSWORD NewNtPassword;
8342     BOOLEAN StoredLmPresent = FALSE;
8343     BOOLEAN StoredNtPresent = FALSE;
8344     BOOLEAN StoredLmEmpty = TRUE;
8345     BOOLEAN StoredNtEmpty = TRUE;
8346     PSAM_DB_OBJECT UserObject;
8347     ULONG Length;
8348     SAM_USER_FIXED_DATA UserFixedData;
8349     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8350     LARGE_INTEGER SystemTime;
8351     NTSTATUS Status;
8352 
8353     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
8354     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
8355     DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
8356 
8357     TRACE("SamrChangePasswordUser(%p %u %p %p %u %p %p %u %p %u %p)\n",
8358           UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
8359           NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
8360           NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
8361 
8362     RtlAcquireResourceExclusive(&SampResource,
8363                                 TRUE);
8364 
8365     /* Validate the user handle */
8366     Status = SampValidateDbObject(UserHandle,
8367                                   SamDbUserObject,
8368                                   USER_CHANGE_PASSWORD,
8369                                   &UserObject);
8370     if (!NT_SUCCESS(Status))
8371     {
8372         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8373         goto done;
8374     }
8375 
8376     /* Get the current time */
8377     Status = NtQuerySystemTime(&SystemTime);
8378     if (!NT_SUCCESS(Status))
8379     {
8380         TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
8381         goto done;
8382     }
8383 
8384     /* Retrieve the LM password */
8385     Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
8386     Status = SampGetObjectAttribute(UserObject,
8387                                     L"LMPwd",
8388                                     NULL,
8389                                     &StoredLmPassword,
8390                                     &Length);
8391     if (NT_SUCCESS(Status))
8392     {
8393         if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
8394         {
8395             StoredLmPresent = TRUE;
8396             if (!RtlEqualMemory(&StoredLmPassword,
8397                                 &EmptyLmHash,
8398                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8399                 StoredLmEmpty = FALSE;
8400         }
8401     }
8402 
8403     /* Retrieve the NT password */
8404     Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
8405     Status = SampGetObjectAttribute(UserObject,
8406                                     L"NTPwd",
8407                                     NULL,
8408                                     &StoredNtPassword,
8409                                     &Length);
8410     if (NT_SUCCESS(Status))
8411     {
8412         if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
8413         {
8414             StoredNtPresent = TRUE;
8415             if (!RtlEqualMemory(&StoredNtPassword,
8416                                 &EmptyNtHash,
8417                                 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
8418                 StoredNtEmpty = FALSE;
8419         }
8420     }
8421 
8422     /* Retrieve the fixed size user data */
8423     Length = sizeof(SAM_USER_FIXED_DATA);
8424     Status = SampGetObjectAttribute(UserObject,
8425                                     L"F",
8426                                     NULL,
8427                                     &UserFixedData,
8428                                     &Length);
8429     if (!NT_SUCCESS(Status))
8430     {
8431         TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
8432         goto done;
8433     }
8434 
8435     /* Check if we can change the password at this time */
8436     if ((StoredLmEmpty == FALSE) || (StoredNtEmpty == FALSE))
8437     {
8438         /* Get fixed domain data */
8439         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8440         Status = SampGetObjectAttribute(UserObject->ParentObject,
8441                                         L"F",
8442                                         NULL,
8443                                         &DomainFixedData,
8444                                         &Length);
8445         if (!NT_SUCCESS(Status))
8446         {
8447             TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
8448             goto done;
8449         }
8450 
8451         if (DomainFixedData.MinPasswordAge.QuadPart > 0)
8452         {
8453             if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
8454             {
8455                 Status = STATUS_ACCOUNT_RESTRICTION;
8456                 goto done;
8457             }
8458         }
8459     }
8460 
8461     /* Decrypt the LM passwords, if present */
8462     if (LmPresent)
8463     {
8464         Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
8465                                    (const BYTE *)&StoredLmPassword,
8466                                    (LPBYTE)&NewLmPassword);
8467         if (!NT_SUCCESS(Status))
8468         {
8469             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8470             goto done;
8471         }
8472 
8473         Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
8474                                    (const BYTE *)&NewLmPassword,
8475                                    (LPBYTE)&OldLmPassword);
8476         if (!NT_SUCCESS(Status))
8477         {
8478             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8479             goto done;
8480         }
8481     }
8482 
8483     /* Decrypt the NT passwords, if present */
8484     if (NtPresent)
8485     {
8486         Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
8487                                    (const BYTE *)&StoredNtPassword,
8488                                    (LPBYTE)&NewNtPassword);
8489         if (!NT_SUCCESS(Status))
8490         {
8491             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8492             goto done;
8493         }
8494 
8495         Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
8496                                    (const BYTE *)&NewNtPassword,
8497                                    (LPBYTE)&OldNtPassword);
8498         if (!NT_SUCCESS(Status))
8499         {
8500             TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8501             goto done;
8502         }
8503     }
8504 
8505     /* Check if the old passwords match the stored ones */
8506     if (NtPresent)
8507     {
8508         if (LmPresent)
8509         {
8510             if (!RtlEqualMemory(&StoredLmPassword,
8511                                 &OldLmPassword,
8512                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8513             {
8514                 TRACE("Old LM Password does not match!\n");
8515                 Status = STATUS_WRONG_PASSWORD;
8516             }
8517             else
8518             {
8519                 if (!RtlEqualMemory(&StoredNtPassword,
8520                                     &OldNtPassword,
8521                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8522                 {
8523                     TRACE("Old NT Password does not match!\n");
8524                     Status = STATUS_WRONG_PASSWORD;
8525                 }
8526             }
8527         }
8528         else
8529         {
8530             if (!RtlEqualMemory(&StoredNtPassword,
8531                                 &OldNtPassword,
8532                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8533             {
8534                 TRACE("Old NT Password does not match!\n");
8535                 Status = STATUS_WRONG_PASSWORD;
8536             }
8537         }
8538     }
8539     else
8540     {
8541         if (LmPresent)
8542         {
8543             if (!RtlEqualMemory(&StoredLmPassword,
8544                                 &OldLmPassword,
8545                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8546             {
8547                 TRACE("Old LM Password does not match!\n");
8548                 Status = STATUS_WRONG_PASSWORD;
8549             }
8550         }
8551         else
8552         {
8553             Status = STATUS_INVALID_PARAMETER;
8554         }
8555     }
8556 
8557     /* Store the new password hashes */
8558     if (NT_SUCCESS(Status))
8559     {
8560         Status = SampSetUserPassword(UserObject,
8561                                      &NewNtPassword,
8562                                      NtPresent,
8563                                      &NewLmPassword,
8564                                      LmPresent);
8565         if (NT_SUCCESS(Status))
8566         {
8567             /* Update PasswordLastSet */
8568             UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
8569 
8570             /* Set the fixed size user data */
8571             Length = sizeof(SAM_USER_FIXED_DATA);
8572             Status = SampSetObjectAttribute(UserObject,
8573                                             L"F",
8574                                             REG_BINARY,
8575                                             &UserFixedData,
8576                                             Length);
8577         }
8578     }
8579 
8580     if (Status == STATUS_WRONG_PASSWORD)
8581     {
8582         /* Update BadPasswordCount and LastBadPasswordTime */
8583         UserFixedData.BadPasswordCount++;
8584         UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
8585 
8586         /* Set the fixed size user data */
8587         Length = sizeof(SAM_USER_FIXED_DATA);
8588         Status = SampSetObjectAttribute(UserObject,
8589                                         L"F",
8590                                         REG_BINARY,
8591                                         &UserFixedData,
8592                                         Length);
8593     }
8594 
8595 done:
8596     RtlReleaseResource(&SampResource);
8597 
8598     return Status;
8599 }
8600 
8601 
8602 /* Function 39 */
8603 NTSTATUS
8604 NTAPI
8605 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
8606                      OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
8607 {
8608     PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
8609     PSAM_DB_OBJECT UserObject;
8610     ULONG Length = 0;
8611     NTSTATUS Status;
8612 
8613     TRACE("SamrGetGroupsForUser(%p %p)\n",
8614           UserHandle, Groups);
8615 
8616     RtlAcquireResourceShared(&SampResource,
8617                              TRUE);
8618 
8619     /* Validate the user handle */
8620     Status = SampValidateDbObject(UserHandle,
8621                                   SamDbUserObject,
8622                                   USER_LIST_GROUPS,
8623                                   &UserObject);
8624     if (!NT_SUCCESS(Status))
8625     {
8626         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8627         goto done;
8628     }
8629 
8630     /* Allocate the groups buffer */
8631     GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
8632     if (GroupsBuffer == NULL)
8633     {
8634         Status = STATUS_INSUFFICIENT_RESOURCES;
8635         goto done;
8636     }
8637 
8638     /*
8639      * Get the size of the Groups attribute.
8640      * Do not check the status code because in case of an error
8641      * Length will be 0. And that is all we need.
8642      */
8643     SampGetObjectAttribute(UserObject,
8644                            L"Groups",
8645                            NULL,
8646                            NULL,
8647                            &Length);
8648 
8649     /* If there is no Groups attribute, return a groups buffer without an array */
8650     if (Length == 0)
8651     {
8652         GroupsBuffer->MembershipCount = 0;
8653         GroupsBuffer->Groups = NULL;
8654 
8655         *Groups = GroupsBuffer;
8656 
8657         Status = STATUS_SUCCESS;
8658         goto done;
8659     }
8660 
8661     /* Allocate a buffer for the Groups attribute */
8662     GroupsBuffer->Groups = midl_user_allocate(Length);
8663     if (GroupsBuffer->Groups == NULL)
8664     {
8665         Status = STATUS_INSUFFICIENT_RESOURCES;
8666         goto done;
8667     }
8668 
8669     /* Retrieve the Grous attribute */
8670     Status = SampGetObjectAttribute(UserObject,
8671                                     L"Groups",
8672                                     NULL,
8673                                     GroupsBuffer->Groups,
8674                                     &Length);
8675     if (!NT_SUCCESS(Status))
8676     {
8677         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8678         goto done;
8679     }
8680 
8681     /* Calculate the membership count */
8682     GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8683 
8684     /* Return the groups buffer to the caller */
8685     *Groups = GroupsBuffer;
8686 
8687 done:
8688     if (!NT_SUCCESS(Status))
8689     {
8690         if (GroupsBuffer != NULL)
8691         {
8692             if (GroupsBuffer->Groups != NULL)
8693                 midl_user_free(GroupsBuffer->Groups);
8694 
8695             midl_user_free(GroupsBuffer);
8696         }
8697     }
8698 
8699     RtlReleaseResource(&SampResource);
8700 
8701     return Status;
8702 }
8703 
8704 
8705 /* Function 40 */
8706 NTSTATUS
8707 NTAPI
8708 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8709                             IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8710                             IN unsigned long Index,
8711                             IN unsigned long EntryCount,
8712                             IN unsigned long PreferredMaximumLength,
8713                             OUT unsigned long *TotalAvailable,
8714                             OUT unsigned long *TotalReturned,
8715                             OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8716 {
8717     UNIMPLEMENTED;
8718     return STATUS_NOT_IMPLEMENTED;
8719 }
8720 
8721 /* Function 41 */
8722 NTSTATUS
8723 NTAPI
8724 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8725                                IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8726                                IN PRPC_UNICODE_STRING Prefix,
8727                                OUT unsigned long *Index)
8728 {
8729     UNIMPLEMENTED;
8730     return STATUS_NOT_IMPLEMENTED;
8731 }
8732 
8733 /* Function 42 */
8734 NTSTATUS
8735 NTAPI
8736 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8737 {
8738     UNIMPLEMENTED;
8739     return STATUS_NOT_IMPLEMENTED;
8740 }
8741 
8742 /* Function 43 */
8743 NTSTATUS
8744 NTAPI
8745 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8746 {
8747     UNIMPLEMENTED;
8748     return STATUS_NOT_IMPLEMENTED;
8749 }
8750 
8751 
8752 /* Function 44 */
8753 NTSTATUS
8754 NTAPI
8755 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8756                                      OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8757 {
8758     SAM_DOMAIN_FIXED_DATA DomainFixedData;
8759     SAM_USER_FIXED_DATA UserFixedData;
8760     PSAM_DB_OBJECT DomainObject;
8761     PSAM_DB_OBJECT UserObject;
8762     ULONG Length = 0;
8763     NTSTATUS Status;
8764 
8765     TRACE("SamrGetUserDomainPasswordInformation(%p %p)\n",
8766           UserHandle, PasswordInformation);
8767 
8768     RtlAcquireResourceShared(&SampResource,
8769                              TRUE);
8770 
8771     /* Validate the user handle */
8772     Status = SampValidateDbObject(UserHandle,
8773                                   SamDbUserObject,
8774                                   0,
8775                                   &UserObject);
8776     if (!NT_SUCCESS(Status))
8777     {
8778         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8779         goto done;
8780     }
8781 
8782     /* Validate the domain object */
8783     Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8784                                   SamDbDomainObject,
8785                                   DOMAIN_READ_PASSWORD_PARAMETERS,
8786                                   &DomainObject);
8787     if (!NT_SUCCESS(Status))
8788     {
8789         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8790         goto done;
8791     }
8792 
8793     /* Get fixed user data */
8794     Length = sizeof(SAM_USER_FIXED_DATA);
8795     Status = SampGetObjectAttribute(UserObject,
8796                                     L"F",
8797                                     NULL,
8798                                     (PVOID)&UserFixedData,
8799                                     &Length);
8800     if (!NT_SUCCESS(Status))
8801     {
8802         TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8803         goto done;
8804     }
8805 
8806     if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8807         (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8808                                              USER_WORKSTATION_TRUST_ACCOUNT |
8809                                              USER_SERVER_TRUST_ACCOUNT)))
8810     {
8811         PasswordInformation->MinPasswordLength = 0;
8812         PasswordInformation->PasswordProperties = 0;
8813     }
8814     else
8815     {
8816         /* Get fixed domain data */
8817         Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8818         Status = SampGetObjectAttribute(DomainObject,
8819                                         L"F",
8820                                         NULL,
8821                                         (PVOID)&DomainFixedData,
8822                                         &Length);
8823         if (!NT_SUCCESS(Status))
8824         {
8825             TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8826             goto done;
8827         }
8828 
8829         PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8830         PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8831     }
8832 
8833 done:
8834     RtlReleaseResource(&SampResource);
8835 
8836     return STATUS_SUCCESS;
8837 }
8838 
8839 
8840 /* Function 45 */
8841 NTSTATUS
8842 NTAPI
8843 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8844                                   IN PRPC_SID MemberSid)
8845 {
8846     PSAM_DB_OBJECT DomainObject;
8847     ULONG Rid = 0;
8848     NTSTATUS Status;
8849 
8850     TRACE("SamrRemoveMemberFromForeignDomain(%p %p)\n",
8851           DomainHandle, MemberSid);
8852 
8853     RtlAcquireResourceExclusive(&SampResource,
8854                                 TRUE);
8855 
8856     /* Validate the domain object */
8857     Status = SampValidateDbObject(DomainHandle,
8858                                   SamDbDomainObject,
8859                                   DOMAIN_LOOKUP,
8860                                   &DomainObject);
8861     if (!NT_SUCCESS(Status))
8862     {
8863         TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8864         goto done;
8865     }
8866 
8867     /* Retrieve the RID from the MemberSID */
8868     Status = SampGetRidFromSid((PSID)MemberSid,
8869                                &Rid);
8870     if (!NT_SUCCESS(Status))
8871     {
8872         TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8873         goto done;
8874     }
8875 
8876     /* Fail, if the RID represents a special account */
8877     if (Rid < 1000)
8878     {
8879         TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8880         Status = STATUS_SPECIAL_ACCOUNT;
8881         goto done;
8882     }
8883 
8884     /* Remove the member from all aliases in the domain */
8885     Status = SampRemoveMemberFromAllAliases(DomainObject,
8886                                             MemberSid);
8887     if (!NT_SUCCESS(Status))
8888     {
8889         TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8890     }
8891 
8892 done:
8893     RtlReleaseResource(&SampResource);
8894 
8895     return Status;
8896 }
8897 
8898 
8899 /* Function 46 */
8900 NTSTATUS
8901 NTAPI
8902 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8903                             IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8904                             OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8905 {
8906     TRACE("SamrQueryInformationDomain2(%p %lu %p)\n",
8907           DomainHandle, DomainInformationClass, Buffer);
8908 
8909     return SamrQueryInformationDomain(DomainHandle,
8910                                       DomainInformationClass,
8911                                       Buffer);
8912 }
8913 
8914 
8915 /* Function 47 */
8916 NTSTATUS
8917 NTAPI
8918 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8919                           IN USER_INFORMATION_CLASS UserInformationClass,
8920                           OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8921 {
8922     TRACE("SamrQueryInformationUser2(%p %lu %p)\n",
8923           UserHandle, UserInformationClass, Buffer);
8924 
8925     return SamrQueryInformationUser(UserHandle,
8926                                     UserInformationClass,
8927                                     Buffer);
8928 }
8929 
8930 
8931 /* Function 48 */
8932 NTSTATUS
8933 NTAPI
8934 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8935                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8936                              IN unsigned long Index,
8937                              IN unsigned long EntryCount,
8938                              IN unsigned long PreferredMaximumLength,
8939                              OUT unsigned long *TotalAvailable,
8940                              OUT unsigned long *TotalReturned,
8941                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8942 {
8943     TRACE("SamrQueryDisplayInformation2(%p %lu %lu %lu %lu %p %p %p)\n",
8944           DomainHandle, DisplayInformationClass, Index,
8945           EntryCount, PreferredMaximumLength, TotalAvailable,
8946           TotalReturned, Buffer);
8947 
8948     return SamrQueryDisplayInformation(DomainHandle,
8949                                        DisplayInformationClass,
8950                                        Index,
8951                                        EntryCount,
8952                                        PreferredMaximumLength,
8953                                        TotalAvailable,
8954                                        TotalReturned,
8955                                        Buffer);
8956 }
8957 
8958 
8959 /* Function 49 */
8960 NTSTATUS
8961 NTAPI
8962 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8963                                 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8964                                 IN PRPC_UNICODE_STRING Prefix,
8965                                 OUT unsigned long *Index)
8966 {
8967     TRACE("SamrGetDisplayEnumerationIndex2(%p %lu %p %p)\n",
8968           DomainHandle, DisplayInformationClass, Prefix, Index);
8969 
8970     return SamrGetDisplayEnumerationIndex(DomainHandle,
8971                                           DisplayInformationClass,
8972                                           Prefix,
8973                                           Index);
8974 }
8975 
8976 
8977 /* Function 50 */
8978 NTSTATUS
8979 NTAPI
8980 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8981                         IN PRPC_UNICODE_STRING Name,
8982                         IN unsigned long AccountType,
8983                         IN ACCESS_MASK DesiredAccess,
8984                         OUT SAMPR_HANDLE *UserHandle,
8985                         OUT unsigned long *GrantedAccess,
8986                         OUT unsigned long *RelativeId)
8987 {
8988     SAM_DOMAIN_FIXED_DATA FixedDomainData;
8989     SAM_USER_FIXED_DATA FixedUserData;
8990     PSAM_DB_OBJECT DomainObject;
8991     PSAM_DB_OBJECT UserObject;
8992     GROUP_MEMBERSHIP GroupMembership;
8993     UCHAR LogonHours[23];
8994     ULONG ulSize;
8995     ULONG ulRid;
8996     WCHAR szRid[9];
8997     PSECURITY_DESCRIPTOR Sd = NULL;
8998     ULONG SdSize = 0;
8999     PSID UserSid = NULL;
9000     NTSTATUS Status;
9001 
9002     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
9003           DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
9004 
9005     if (Name == NULL ||
9006         Name->Length == 0 ||
9007         Name->Buffer == NULL ||
9008         UserHandle == NULL ||
9009         RelativeId == NULL)
9010         return STATUS_INVALID_PARAMETER;
9011 
9012     /* Check for valid account type */
9013     if (AccountType != USER_NORMAL_ACCOUNT &&
9014         AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
9015         AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
9016         AccountType != USER_SERVER_TRUST_ACCOUNT &&
9017         AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
9018         return STATUS_INVALID_PARAMETER;
9019 
9020     /* Map generic access rights */
9021     RtlMapGenericMask(&DesiredAccess,
9022                       &UserMapping);
9023 
9024     RtlAcquireResourceExclusive(&SampResource,
9025                                 TRUE);
9026 
9027     /* Validate the domain handle */
9028     Status = SampValidateDbObject(DomainHandle,
9029                                   SamDbDomainObject,
9030                                   DOMAIN_CREATE_USER,
9031                                   &DomainObject);
9032     if (!NT_SUCCESS(Status))
9033     {
9034         TRACE("failed with status 0x%08lx\n", Status);
9035         goto done;
9036     }
9037 
9038     /* Check the user account name */
9039     Status = SampCheckAccountName(Name, 20);
9040     if (!NT_SUCCESS(Status))
9041     {
9042         TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
9043         goto done;
9044     }
9045 
9046     /* Check if the user name already exists in the domain */
9047     Status = SampCheckAccountNameInDomain(DomainObject,
9048                                           Name->Buffer);
9049     if (!NT_SUCCESS(Status))
9050     {
9051         TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
9052               Name->Buffer, Status);
9053         goto done;
9054     }
9055 
9056     /* Get the fixed domain attributes */
9057     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
9058     Status = SampGetObjectAttribute(DomainObject,
9059                                     L"F",
9060                                     NULL,
9061                                     (PVOID)&FixedDomainData,
9062                                     &ulSize);
9063     if (!NT_SUCCESS(Status))
9064     {
9065         TRACE("failed with status 0x%08lx\n", Status);
9066         goto done;
9067     }
9068 
9069     /* Increment the NextRid attribute */
9070     ulRid = FixedDomainData.NextRid;
9071     FixedDomainData.NextRid++;
9072 
9073     TRACE("RID: %lx\n", ulRid);
9074 
9075     /* Create the user SID */
9076     Status = SampCreateAccountSid(DomainObject,
9077                                   ulRid,
9078                                   &UserSid);
9079     if (!NT_SUCCESS(Status))
9080     {
9081         TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
9082         goto done;
9083     }
9084 
9085     /* Create the security descriptor */
9086     Status = SampCreateUserSD(UserSid,
9087                               &Sd,
9088                               &SdSize);
9089     if (!NT_SUCCESS(Status))
9090     {
9091         TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
9092         goto done;
9093     }
9094 
9095     /* Store the fixed domain attributes */
9096     Status = SampSetObjectAttribute(DomainObject,
9097                                     L"F",
9098                                     REG_BINARY,
9099                                     &FixedDomainData,
9100                                     ulSize);
9101     if (!NT_SUCCESS(Status))
9102     {
9103         TRACE("failed with status 0x%08lx\n", Status);
9104         goto done;
9105     }
9106 
9107     /* Convert the RID into a string (hex) */
9108     swprintf(szRid, L"%08lX", ulRid);
9109 
9110     /* Create the user object */
9111     Status = SampCreateDbObject(DomainObject,
9112                                 L"Users",
9113                                 szRid,
9114                                 ulRid,
9115                                 SamDbUserObject,
9116                                 DesiredAccess,
9117                                 &UserObject);
9118     if (!NT_SUCCESS(Status))
9119     {
9120         TRACE("failed with status 0x%08lx\n", Status);
9121         goto done;
9122     }
9123 
9124     /* Add the account name for the user object */
9125     Status = SampSetAccountNameInDomain(DomainObject,
9126                                         L"Users",
9127                                         Name->Buffer,
9128                                         ulRid);
9129     if (!NT_SUCCESS(Status))
9130     {
9131         TRACE("failed with status 0x%08lx\n", Status);
9132         goto done;
9133     }
9134 
9135     /* Initialize fixed user data */
9136     FixedUserData.Version = 1;
9137     FixedUserData.Reserved = 0;
9138     FixedUserData.LastLogon.QuadPart = 0;
9139     FixedUserData.LastLogoff.QuadPart = 0;
9140     FixedUserData.PasswordLastSet.QuadPart = 0;
9141     FixedUserData.AccountExpires.LowPart = MAXULONG;
9142     FixedUserData.AccountExpires.HighPart = MAXLONG;
9143     FixedUserData.LastBadPasswordTime.QuadPart = 0;
9144     FixedUserData.UserId = ulRid;
9145     FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
9146     FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
9147                                        USER_PASSWORD_NOT_REQUIRED |
9148                                        AccountType;
9149     FixedUserData.CountryCode = 0;
9150     FixedUserData.CodePage = 0;
9151     FixedUserData.BadPasswordCount = 0;
9152     FixedUserData.LogonCount = 0;
9153     FixedUserData.AdminCount = 0;
9154     FixedUserData.OperatorCount = 0;
9155 
9156     /* Set fixed user data attribute */
9157     Status = SampSetObjectAttribute(UserObject,
9158                                     L"F",
9159                                     REG_BINARY,
9160                                     (LPVOID)&FixedUserData,
9161                                     sizeof(SAM_USER_FIXED_DATA));
9162     if (!NT_SUCCESS(Status))
9163     {
9164         TRACE("failed with status 0x%08lx\n", Status);
9165         goto done;
9166     }
9167 
9168     /* Set the Name attribute */
9169     Status = SampSetObjectAttributeString(UserObject,
9170                                           L"Name",
9171                                           Name);
9172     if (!NT_SUCCESS(Status))
9173     {
9174         TRACE("failed with status 0x%08lx\n", Status);
9175         goto done;
9176     }
9177 
9178     /* Set the FullName attribute */
9179     Status = SampSetObjectAttributeString(UserObject,
9180                                           L"FullName",
9181                                           NULL);
9182     if (!NT_SUCCESS(Status))
9183     {
9184         TRACE("failed with status 0x%08lx\n", Status);
9185         goto done;
9186     }
9187 
9188     /* Set the HomeDirectory attribute */
9189     Status = SampSetObjectAttributeString(UserObject,
9190                                           L"HomeDirectory",
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 HomeDirectoryDrive attribute */
9199     Status = SampSetObjectAttributeString(UserObject,
9200                                           L"HomeDirectoryDrive",
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 ScriptPath attribute */
9209     Status = SampSetObjectAttributeString(UserObject,
9210                                           L"ScriptPath",
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 ProfilePath attribute */
9219     Status = SampSetObjectAttributeString(UserObject,
9220                                           L"ProfilePath",
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 AdminComment attribute */
9229     Status = SampSetObjectAttributeString(UserObject,
9230                                           L"AdminComment",
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 UserComment attribute */
9239     Status = SampSetObjectAttributeString(UserObject,
9240                                           L"UserComment",
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 WorkStations attribute */
9249     Status = SampSetObjectAttributeString(UserObject,
9250                                           L"WorkStations",
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 Parameters attribute */
9259     Status = SampSetObjectAttributeString(UserObject,
9260                                           L"Parameters",
9261                                           NULL);
9262     if (!NT_SUCCESS(Status))
9263     {
9264         TRACE("failed with status 0x%08lx\n", Status);
9265         goto done;
9266     }
9267 
9268     /* Set LogonHours attribute*/
9269     *((PUSHORT)LogonHours) = 168;
9270     memset(&(LogonHours[2]), 0xff, 21);
9271 
9272     Status = SampSetObjectAttribute(UserObject,
9273                                     L"LogonHours",
9274                                     REG_BINARY,
9275                                     &LogonHours,
9276                                     sizeof(LogonHours));
9277     if (!NT_SUCCESS(Status))
9278     {
9279         TRACE("failed with status 0x%08lx\n", Status);
9280         goto done;
9281     }
9282 
9283     /* Set Groups attribute*/
9284     GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
9285     GroupMembership.Attributes = SE_GROUP_MANDATORY |
9286                                  SE_GROUP_ENABLED |
9287                                  SE_GROUP_ENABLED_BY_DEFAULT;
9288 
9289     Status = SampSetObjectAttribute(UserObject,
9290                                     L"Groups",
9291                                     REG_BINARY,
9292                                     &GroupMembership,
9293                                     sizeof(GROUP_MEMBERSHIP));
9294     if (!NT_SUCCESS(Status))
9295     {
9296         TRACE("failed with status 0x%08lx\n", Status);
9297         goto done;
9298     }
9299 
9300     /* Set LMPwd attribute*/
9301     Status = SampSetObjectAttribute(UserObject,
9302                                     L"LMPwd",
9303                                     REG_BINARY,
9304                                     NULL,
9305                                     0);
9306     if (!NT_SUCCESS(Status))
9307     {
9308         TRACE("failed with status 0x%08lx\n", Status);
9309         goto done;
9310     }
9311 
9312     /* Set NTPwd attribute*/
9313     Status = SampSetObjectAttribute(UserObject,
9314                                     L"NTPwd",
9315                                     REG_BINARY,
9316                                     NULL,
9317                                     0);
9318     if (!NT_SUCCESS(Status))
9319     {
9320         TRACE("failed with status 0x%08lx\n", Status);
9321         goto done;
9322     }
9323 
9324     /* Set LMPwdHistory attribute*/
9325     Status = SampSetObjectAttribute(UserObject,
9326                                     L"LMPwdHistory",
9327                                     REG_BINARY,
9328                                     NULL,
9329                                     0);
9330     if (!NT_SUCCESS(Status))
9331     {
9332         TRACE("failed with status 0x%08lx\n", Status);
9333         goto done;
9334     }
9335 
9336     /* Set NTPwdHistory attribute*/
9337     Status = SampSetObjectAttribute(UserObject,
9338                                     L"NTPwdHistory",
9339                                     REG_BINARY,
9340                                     NULL,
9341                                     0);
9342     if (!NT_SUCCESS(Status))
9343     {
9344         TRACE("failed with status 0x%08lx\n", Status);
9345         goto done;
9346     }
9347 
9348     /* Set the PrivateData attribute */
9349     Status = SampSetObjectAttributeString(UserObject,
9350                                           L"PrivateData",
9351                                           NULL);
9352     if (!NT_SUCCESS(Status))
9353     {
9354         TRACE("failed with status 0x%08lx\n", Status);
9355         goto done;
9356     }
9357 
9358     /* Set the SecDesc attribute*/
9359     Status = SampSetObjectAttribute(UserObject,
9360                                     L"SecDesc",
9361                                     REG_BINARY,
9362                                     Sd,
9363                                     SdSize);
9364     if (!NT_SUCCESS(Status))
9365     {
9366         TRACE("failed with status 0x%08lx\n", Status);
9367         goto done;
9368     }
9369 
9370     if (NT_SUCCESS(Status))
9371     {
9372         *UserHandle = (SAMPR_HANDLE)UserObject;
9373         *RelativeId = ulRid;
9374         *GrantedAccess = UserObject->Access;
9375     }
9376 
9377 done:
9378     if (Sd != NULL)
9379         RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
9380 
9381     if (UserSid != NULL)
9382         RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
9383 
9384     RtlReleaseResource(&SampResource);
9385 
9386     TRACE("returns with status 0x%08lx\n", Status);
9387 
9388     return Status;
9389 }
9390 
9391 
9392 /* Function 51 */
9393 NTSTATUS
9394 NTAPI
9395 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
9396                              IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
9397                              IN unsigned long Index,
9398                              IN unsigned long EntryCount,
9399                              IN unsigned long PreferredMaximumLength,
9400                              OUT unsigned long *TotalAvailable,
9401                              OUT unsigned long *TotalReturned,
9402                              OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
9403 {
9404     TRACE("SamrQueryDisplayInformation3(%p %lu %lu %lu %lu %p %p %p)\n",
9405           DomainHandle, DisplayInformationClass, Index,
9406           EntryCount, PreferredMaximumLength, TotalAvailable,
9407           TotalReturned, Buffer);
9408 
9409     return SamrQueryDisplayInformation(DomainHandle,
9410                                        DisplayInformationClass,
9411                                        Index,
9412                                        EntryCount,
9413                                        PreferredMaximumLength,
9414                                        TotalAvailable,
9415                                        TotalReturned,
9416                                        Buffer);
9417 }
9418 
9419 
9420 /* Function 52 */
9421 NTSTATUS
9422 NTAPI
9423 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
9424                               IN PSAMPR_PSID_ARRAY MembersBuffer)
9425 {
9426     ULONG i;
9427     NTSTATUS Status = STATUS_SUCCESS;
9428 
9429     TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
9430           AliasHandle, MembersBuffer);
9431 
9432     for (i = 0; i < MembersBuffer->Count; i++)
9433     {
9434         Status = SamrAddMemberToAlias(AliasHandle,
9435                                       ((PSID *)MembersBuffer->Sids)[i]);
9436 
9437         if (Status == STATUS_MEMBER_IN_ALIAS)
9438             Status = STATUS_SUCCESS;
9439 
9440         if (!NT_SUCCESS(Status))
9441             break;
9442     }
9443 
9444     return Status;
9445 }
9446 
9447 
9448 /* Function 53 */
9449 NTSTATUS
9450 NTAPI
9451 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
9452                                    IN PSAMPR_PSID_ARRAY MembersBuffer)
9453 {
9454     ULONG i;
9455     NTSTATUS Status = STATUS_SUCCESS;
9456 
9457     TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
9458           AliasHandle, MembersBuffer);
9459 
9460     for (i = 0; i < MembersBuffer->Count; i++)
9461     {
9462         Status = SamrRemoveMemberFromAlias(AliasHandle,
9463                                            ((PSID *)MembersBuffer->Sids)[i]);
9464 
9465         if (Status == STATUS_MEMBER_IN_ALIAS)
9466             Status = STATUS_SUCCESS;
9467 
9468         if (!NT_SUCCESS(Status))
9469             break;
9470     }
9471 
9472     return Status;
9473 }
9474 
9475 
9476 /* Function 54 */
9477 NTSTATUS
9478 NTAPI
9479 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
9480                            IN PRPC_STRING ServerName,
9481                            IN PRPC_STRING UserName,
9482                            IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9483                            IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
9484 {
9485     UNIMPLEMENTED;
9486     return STATUS_NOT_IMPLEMENTED;
9487 }
9488 
9489 /* Function 55 */
9490 NTSTATUS
9491 NTAPI
9492 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
9493                                IN PRPC_UNICODE_STRING ServerName,
9494                                IN PRPC_UNICODE_STRING UserName,
9495                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
9496                                IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
9497                                IN unsigned char LmPresent,
9498                                IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9499                                IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
9500 {
9501     UNIMPLEMENTED;
9502     return STATUS_NOT_IMPLEMENTED;
9503 }
9504 
9505 
9506 /* Function 56 */
9507 NTSTATUS
9508 NTAPI
9509 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
9510                                  IN PRPC_UNICODE_STRING Unused,
9511                                  OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
9512 {
9513     SAMPR_HANDLE ServerHandle = NULL;
9514     PSAM_DB_OBJECT DomainObject = NULL;
9515     SAM_DOMAIN_FIXED_DATA FixedData;
9516     ULONG Length;
9517     NTSTATUS Status;
9518 
9519     TRACE("SamrGetDomainPasswordInformation(%p %p %p)\n",
9520           BindingHandle, Unused, PasswordInformation);
9521 
9522     Status = SamrConnect(NULL,
9523                          &ServerHandle,
9524                          SAM_SERVER_LOOKUP_DOMAIN);
9525     if (!NT_SUCCESS(Status))
9526     {
9527         TRACE("SamrConnect() failed (Status 0x%08lx)\n", Status);
9528         goto done;
9529     }
9530 
9531     Status = SampOpenDbObject((PSAM_DB_OBJECT)ServerHandle,
9532                               L"Domains",
9533                               L"Account",
9534                               0,
9535                               SamDbDomainObject,
9536                               DOMAIN_READ_PASSWORD_PARAMETERS,
9537                               &DomainObject);
9538     if (!NT_SUCCESS(Status))
9539     {
9540         TRACE("SampOpenDbObject() failed (Status 0x%08lx)\n", Status);
9541         goto done;
9542     }
9543 
9544     Length = sizeof(SAM_DOMAIN_FIXED_DATA);
9545     Status = SampGetObjectAttribute(DomainObject,
9546                                     L"F",
9547                                     NULL,
9548                                     &FixedData,
9549                                     &Length);
9550     if (!NT_SUCCESS(Status))
9551     {
9552         TRACE("SampGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
9553         goto done;
9554     }
9555 
9556     PasswordInformation->MinPasswordLength = FixedData.MinPasswordLength;
9557     PasswordInformation->PasswordProperties = FixedData.PasswordProperties;
9558 
9559 done:
9560     if (DomainObject != NULL)
9561         SampCloseDbObject(DomainObject);
9562 
9563     if (ServerHandle != NULL)
9564         SamrCloseHandle(ServerHandle);
9565 
9566     return Status;
9567 }
9568 
9569 
9570 /* Function 57 */
9571 NTSTATUS
9572 NTAPI
9573 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
9574              OUT SAMPR_HANDLE *ServerHandle,
9575              IN ACCESS_MASK DesiredAccess)
9576 {
9577     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9578     ULONG OutVersion;
9579 
9580     TRACE("SamrConnect2(%p %p %lx)\n",
9581           ServerName, ServerHandle, DesiredAccess);
9582 
9583     InRevisionInfo.V1.Revision = 1;
9584     InRevisionInfo.V1.SupportedFeatures = 0;
9585 
9586     return SamrConnect5(ServerName,
9587                         DesiredAccess,
9588                         1,
9589                         &InRevisionInfo,
9590                         &OutVersion,
9591                         &OutRevisionInfo,
9592                         ServerHandle);
9593 }
9594 
9595 
9596 /* Function 58 */
9597 NTSTATUS
9598 NTAPI
9599 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
9600                         IN USER_INFORMATION_CLASS UserInformationClass,
9601                         IN PSAMPR_USER_INFO_BUFFER Buffer)
9602 {
9603     TRACE("SamrSetInformationUser2(%p %lu %p)\n",
9604           UserHandle, UserInformationClass, Buffer);
9605 
9606     return SamrSetInformationUser(UserHandle,
9607                                   UserInformationClass,
9608                                   Buffer);
9609 }
9610 
9611 
9612 /* Function 59 */
9613 NTSTATUS
9614 NTAPI
9615 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9616 {
9617     UNIMPLEMENTED;
9618     return STATUS_NOT_IMPLEMENTED;
9619 }
9620 
9621 /* Function 60 */
9622 NTSTATUS
9623 NTAPI
9624 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9625 {
9626     UNIMPLEMENTED;
9627     return STATUS_NOT_IMPLEMENTED;
9628 }
9629 
9630 /* Function 61 */
9631 NTSTATUS
9632 NTAPI
9633 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
9634 {
9635     UNIMPLEMENTED;
9636     return STATUS_NOT_IMPLEMENTED;
9637 }
9638 
9639 
9640 /* Function 62 */
9641 NTSTATUS
9642 NTAPI
9643 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
9644              OUT SAMPR_HANDLE *ServerHandle,
9645              IN unsigned long ClientRevision,
9646              IN ACCESS_MASK DesiredAccess)
9647 {
9648     SAMPR_REVISION_INFO InRevisionInfo, OutRevisionInfo;
9649     ULONG OutVersion;
9650 
9651     TRACE("SamrConnect4(%p %p %lu 0x%lx)\n",
9652           ServerName, ServerHandle, ClientRevision, DesiredAccess);
9653 
9654     InRevisionInfo.V1.Revision = 2;
9655     InRevisionInfo.V1.SupportedFeatures = 0;
9656 
9657     return SamrConnect5(ServerName,
9658                         DesiredAccess,
9659                         1,
9660                         &InRevisionInfo,
9661                         &OutVersion,
9662                         &OutRevisionInfo,
9663                         ServerHandle);
9664 }
9665 
9666 
9667 /* Function 63 */
9668 NTSTATUS
9669 NTAPI
9670 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
9671 {
9672     UNIMPLEMENTED;
9673     return STATUS_NOT_IMPLEMENTED;
9674 }
9675 
9676 
9677 /* Function 64 */
9678 NTSTATUS
9679 NTAPI
9680 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
9681              IN ACCESS_MASK DesiredAccess,
9682              IN unsigned long InVersion,
9683              IN SAMPR_REVISION_INFO *InRevisionInfo,
9684              OUT unsigned long *OutVersion,
9685              OUT SAMPR_REVISION_INFO *OutRevisionInfo,
9686              OUT SAMPR_HANDLE *ServerHandle)
9687 {
9688     PSAM_DB_OBJECT ServerObject;
9689     NTSTATUS Status;
9690 
9691     TRACE("SamrConnect5(%p 0x%lx %lu %p %p %p %p)\n",
9692           ServerName, DesiredAccess, InVersion, InRevisionInfo,
9693           OutVersion, OutRevisionInfo, ServerHandle);
9694 
9695     if (InVersion != 1)
9696         return STATUS_NOT_SUPPORTED;
9697 
9698     RtlAcquireResourceShared(&SampResource,
9699                              TRUE);
9700 
9701     /* Map generic access rights */
9702     RtlMapGenericMask(&DesiredAccess,
9703                       &ServerMapping);
9704 
9705     /* Open the Server Object */
9706     Status = SampOpenDbObject(NULL,
9707                               NULL,
9708                               L"SAM",
9709                               0,
9710                               SamDbServerObject,
9711                               DesiredAccess,
9712                               &ServerObject);
9713     if (NT_SUCCESS(Status))
9714     {
9715         *OutVersion = 1;
9716 
9717         OutRevisionInfo->V1.Revision = 3;
9718         OutRevisionInfo->V1.SupportedFeatures = 0;
9719 
9720         *ServerHandle = (SAMPR_HANDLE)ServerObject;
9721     }
9722 
9723     RtlReleaseResource(&SampResource);
9724 
9725     TRACE("SamrConnect5 done (Status 0x%08lx)\n", Status);
9726 
9727     return Status;
9728 }
9729 
9730 
9731 /* Function 65 */
9732 NTSTATUS
9733 NTAPI
9734 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
9735              IN unsigned long Rid,
9736              OUT PRPC_SID *Sid)
9737 {
9738     UNIMPLEMENTED;
9739     return STATUS_NOT_IMPLEMENTED;
9740 }
9741 
9742 /* Function 66 */
9743 NTSTATUS
9744 NTAPI
9745 SamrSetDSRMPassword(IN handle_t BindingHandle,
9746                     IN PRPC_UNICODE_STRING Unused,
9747                     IN unsigned long UserId,
9748                     IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
9749 {
9750     UNIMPLEMENTED;
9751     return STATUS_NOT_IMPLEMENTED;
9752 }
9753 
9754 /* Function 67 */
9755 NTSTATUS
9756 NTAPI
9757 SamrValidatePassword(IN handle_t Handle,
9758                      IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
9759                      IN PSAM_VALIDATE_INPUT_ARG InputArg,
9760                      OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
9761 {
9762     UNIMPLEMENTED;
9763     return STATUS_NOT_IMPLEMENTED;
9764 }
9765 
9766 /* EOF */
9767