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