xref: /reactos/dll/win32/netapi32/user.c (revision da7cd270)
1 /*
2  * Copyright 2002 Andriy Palamarchuk
3  *
4  * netapi32 user functions
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 /*
22  *  TODO:
23  *    Implement NetUserGetGroups (WIP)
24  *    Implement NetUserSetGroups
25  *    NetUserGetLocalGroups does not support LG_INCLUDE_INDIRECT yet.
26  *    Add missing information levels.
27  *    ...
28  */
29 
30 #include "netapi32.h"
31 
32 #include <ndk/kefuncs.h>
33 #include <ndk/obfuncs.h>
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
36 
37 typedef struct _ENUM_CONTEXT
38 {
39     LIST_ENTRY ListLink;
40     ULONG EnumHandle;
41 
42     SAM_HANDLE ServerHandle;
43     SAM_HANDLE BuiltinDomainHandle;
44     SAM_HANDLE AccountDomainHandle;
45     PSID BuiltinDomainSid;
46     PSID AccountDomainSid;
47 
48     SAM_ENUMERATE_HANDLE EnumerationContext;
49     PSAM_RID_ENUMERATION Buffer;
50     ULONG Count;
51     ULONG Index;
52     BOOLEAN BuiltinDone;
53 
54 } ENUM_CONTEXT, *PENUM_CONTEXT;
55 
56 LIST_ENTRY g_EnumContextListHead;
57 CRITICAL_SECTION g_EnumContextListLock;
58 LONG g_EnumContextHandle = 0;
59 
60 static
61 ULONG
DeltaTimeToSeconds(LARGE_INTEGER DeltaTime)62 DeltaTimeToSeconds(LARGE_INTEGER DeltaTime)
63 {
64     LARGE_INTEGER Seconds;
65 
66     if (DeltaTime.QuadPart == 0)
67         return 0;
68 
69     Seconds.QuadPart = -DeltaTime.QuadPart / 10000000;
70 
71     if (Seconds.HighPart != 0)
72         return TIMEQ_FOREVER;
73 
74     return Seconds.LowPart;
75 }
76 
77 
78 static
79 NTSTATUS
GetAllowedWorldAce(IN PACL Acl,OUT PACCESS_ALLOWED_ACE * Ace)80 GetAllowedWorldAce(IN PACL Acl,
81                    OUT PACCESS_ALLOWED_ACE *Ace)
82 {
83     SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
84     ULONG WorldSid[sizeof(SID) / sizeof(ULONG) + SID_MAX_SUB_AUTHORITIES];
85     ACL_SIZE_INFORMATION AclSize;
86     PVOID LocalAce = NULL;
87     ULONG i;
88     NTSTATUS Status;
89 
90     *Ace = NULL;
91 
92     RtlInitializeSid((PSID)WorldSid,
93                      &WorldAuthority,
94                      1);
95     *(RtlSubAuthoritySid((PSID)WorldSid, 0)) = SECURITY_WORLD_RID;
96 
97     Status = RtlQueryInformationAcl(Acl,
98                                     &AclSize,
99                                     sizeof(AclSize),
100                                     AclSizeInformation);
101     if (!NT_SUCCESS(Status))
102         return Status;
103 
104     for (i = 0; i < AclSize.AceCount; i++)
105     {
106         Status = RtlGetAce(Acl, i, &LocalAce);
107         if (!NT_SUCCESS(Status))
108             return Status;
109 
110         if (((PACE_HEADER)LocalAce)->AceType != ACCESS_ALLOWED_ACE_TYPE)
111             continue;
112 
113         if (RtlEqualSid((PSID)WorldSid,
114                         (PSID)&((PACCESS_ALLOWED_ACE)LocalAce)->SidStart))
115         {
116             *Ace = (PACCESS_ALLOWED_ACE)LocalAce;
117             return STATUS_SUCCESS;
118         }
119     }
120 
121     return STATUS_SUCCESS;
122 }
123 
124 
125 static
126 ULONG
GetAccountFlags(ULONG AccountControl,PACL Dacl)127 GetAccountFlags(ULONG AccountControl,
128                 PACL Dacl)
129 {
130     PACCESS_ALLOWED_ACE Ace = NULL;
131     ULONG Flags = UF_SCRIPT;
132     NTSTATUS Status;
133 
134     if (Dacl != NULL)
135     {
136         Status = GetAllowedWorldAce(Dacl, &Ace);
137         if (NT_SUCCESS(Status))
138         {
139             if (Ace == NULL)
140             {
141                 Flags |= UF_PASSWD_CANT_CHANGE;
142             }
143             else if ((Ace->Mask & USER_CHANGE_PASSWORD) == 0)
144             {
145                 Flags |= UF_PASSWD_CANT_CHANGE;
146             }
147         }
148     }
149 
150     if (AccountControl & USER_ACCOUNT_DISABLED)
151         Flags |= UF_ACCOUNTDISABLE;
152 
153     if (AccountControl & USER_HOME_DIRECTORY_REQUIRED)
154         Flags |= UF_HOMEDIR_REQUIRED;
155 
156     if (AccountControl & USER_PASSWORD_NOT_REQUIRED)
157         Flags |= UF_PASSWD_NOTREQD;
158 
159     if (AccountControl & USER_ACCOUNT_AUTO_LOCKED)
160         Flags |= UF_LOCKOUT;
161 
162     if (AccountControl & USER_DONT_EXPIRE_PASSWORD)
163         Flags |= UF_DONT_EXPIRE_PASSWD;
164 
165 /*
166     if (AccountControl & USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED)
167         Flags |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
168 
169     if (AccountControl & USER_SMARTCARD_REQUIRED)
170         Flags |= UF_SMARTCARD_REQUIRED;
171 
172     if (AccountControl & USER_TRUSTED_FOR_DELEGATION)
173         Flags |= UF_TRUSTED_FOR_DELEGATION;
174 
175     if (AccountControl & USER_NOT_DELEGATED)
176         Flags |= UF_NOT_DELEGATED;
177 
178     if (AccountControl & USER_USE_DES_KEY_ONLY)
179         Flags |= UF_USE_DES_KEY_ONLY;
180 
181     if (AccountControl & USER_DONT_REQUIRE_PREAUTH)
182         Flags |= UF_DONT_REQUIRE_PREAUTH;
183 
184     if (AccountControl & USER_PASSWORD_EXPIRED)
185         Flags |= UF_PASSWORD_EXPIRED;
186 */
187 
188     /* Set account type flags */
189     if (AccountControl & USER_TEMP_DUPLICATE_ACCOUNT)
190         Flags |= UF_TEMP_DUPLICATE_ACCOUNT;
191     else if (AccountControl & USER_NORMAL_ACCOUNT)
192         Flags |= UF_NORMAL_ACCOUNT;
193     else if (AccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT)
194         Flags |= UF_INTERDOMAIN_TRUST_ACCOUNT;
195     else if (AccountControl & USER_WORKSTATION_TRUST_ACCOUNT)
196         Flags |= UF_WORKSTATION_TRUST_ACCOUNT;
197     else if (AccountControl & USER_SERVER_TRUST_ACCOUNT)
198         Flags |= UF_SERVER_TRUST_ACCOUNT;
199 
200     return Flags;
201 }
202 
203 
204 static
205 ULONG
GetAccountControl(ULONG Flags)206 GetAccountControl(ULONG Flags)
207 {
208     ULONG AccountControl = 0;
209 
210     if (Flags & UF_ACCOUNTDISABLE)
211         AccountControl |= USER_ACCOUNT_DISABLED;
212 
213     if (Flags & UF_HOMEDIR_REQUIRED)
214         AccountControl |= USER_HOME_DIRECTORY_REQUIRED;
215 
216     if (Flags & UF_PASSWD_NOTREQD)
217         AccountControl |= USER_PASSWORD_NOT_REQUIRED;
218 
219     if (Flags & UF_LOCKOUT)
220         AccountControl |= USER_ACCOUNT_AUTO_LOCKED;
221 
222     if (Flags & UF_DONT_EXPIRE_PASSWD)
223         AccountControl |= USER_DONT_EXPIRE_PASSWORD;
224 
225     /* Set account type flags */
226     if (Flags & UF_TEMP_DUPLICATE_ACCOUNT)
227         AccountControl |= USER_TEMP_DUPLICATE_ACCOUNT;
228     else if (Flags & UF_NORMAL_ACCOUNT)
229         AccountControl |= USER_NORMAL_ACCOUNT;
230     else if (Flags & UF_INTERDOMAIN_TRUST_ACCOUNT)
231         AccountControl |= USER_INTERDOMAIN_TRUST_ACCOUNT;
232     else if (Flags & UF_WORKSTATION_TRUST_ACCOUNT)
233         AccountControl |= USER_WORKSTATION_TRUST_ACCOUNT;
234     else if (Flags & UF_SERVER_TRUST_ACCOUNT)
235         AccountControl |= USER_SERVER_TRUST_ACCOUNT;
236 
237     return AccountControl;
238 }
239 
240 
241 static
242 DWORD
GetPasswordAge(IN PLARGE_INTEGER PasswordLastSet)243 GetPasswordAge(IN PLARGE_INTEGER PasswordLastSet)
244 {
245     LARGE_INTEGER SystemTime;
246     ULONG SystemSecondsSince1970;
247     ULONG PasswordSecondsSince1970;
248     NTSTATUS Status;
249 
250     Status = NtQuerySystemTime(&SystemTime);
251     if (!NT_SUCCESS(Status))
252         return 0;
253 
254     RtlTimeToSecondsSince1970(&SystemTime, &SystemSecondsSince1970);
255     RtlTimeToSecondsSince1970(PasswordLastSet, &PasswordSecondsSince1970);
256 
257     return SystemSecondsSince1970 - PasswordSecondsSince1970;
258 }
259 
260 
261 static
262 VOID
ChangeUserDacl(IN PACL Dacl,IN ULONG Flags)263 ChangeUserDacl(IN PACL Dacl,
264                IN ULONG Flags)
265 {
266     PACCESS_ALLOWED_ACE Ace = NULL;
267     NTSTATUS Status;
268 
269     if (Dacl == NULL)
270         return;
271 
272     Status = GetAllowedWorldAce(Dacl, &Ace);
273     if (!NT_SUCCESS(Status))
274         return;
275 
276     if (Flags & UF_PASSWD_CANT_CHANGE)
277         Ace->Mask &= ~USER_CHANGE_PASSWORD;
278     else
279         Ace->Mask |= USER_CHANGE_PASSWORD;
280 }
281 
282 
283 static
284 NET_API_STATUS
GetUserDacl(IN SAM_HANDLE UserHandle,OUT PACL * Dacl)285 GetUserDacl(IN SAM_HANDLE UserHandle,
286             OUT PACL *Dacl)
287 {
288     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
289     PACL SamDacl;
290     PACL LocalDacl;
291     BOOLEAN Defaulted;
292     BOOLEAN Present;
293     ACL_SIZE_INFORMATION AclSize;
294     NET_API_STATUS ApiStatus;
295     NTSTATUS Status;
296 
297     TRACE("(%p %p)\n", UserHandle, Dacl);
298 
299     *Dacl = NULL;
300 
301     Status = SamQuerySecurityObject(UserHandle,
302                                     DACL_SECURITY_INFORMATION,
303                                     &SecurityDescriptor);
304     if (!NT_SUCCESS(Status))
305     {
306         TRACE("SamQuerySecurityObject() failed (Status 0x%08lx)\n", Status);
307         ApiStatus = NetpNtStatusToApiStatus(Status);
308         goto done;
309     }
310 
311     Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
312                                           &Present,
313                                           &SamDacl,
314                                           &Defaulted);
315     if (!NT_SUCCESS(Status))
316     {
317         TRACE("RtlGetDaclSecurityDescriptor() failed (Status 0x%08lx)\n", Status);
318         ApiStatus = NERR_InternalError;
319         goto done;
320     }
321 
322     if (Present == FALSE)
323     {
324         TRACE("No DACL present\n");
325         ApiStatus = NERR_Success;
326         goto done;
327     }
328 
329     Status = RtlQueryInformationAcl(SamDacl,
330                                     &AclSize,
331                                     sizeof(AclSize),
332                                     AclSizeInformation);
333     if (!NT_SUCCESS(Status))
334     {
335         TRACE("RtlQueryInformationAcl() failed (Status 0x%08lx)\n", Status);
336         ApiStatus = NERR_InternalError;
337         goto done;
338     }
339 
340     LocalDacl = HeapAlloc(GetProcessHeap(), 0, AclSize.AclBytesInUse);
341     if (LocalDacl == NULL)
342     {
343         TRACE("Memory allocation failed\n");
344         ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
345         goto done;
346     }
347 
348     RtlCopyMemory(LocalDacl, SamDacl, AclSize.AclBytesInUse);
349 
350     *Dacl = LocalDacl;
351 
352     ApiStatus = NERR_Success;
353 
354 done:
355     if (SecurityDescriptor != NULL)
356         SamFreeMemory(SecurityDescriptor);
357 
358     TRACE("done (ApiStatus: 0x%08lx)\n", ApiStatus);
359 
360     return ApiStatus;
361 }
362 
363 
364 static
365 VOID
FreeUserInfo(PUSER_ALL_INFORMATION UserInfo)366 FreeUserInfo(PUSER_ALL_INFORMATION UserInfo)
367 {
368     if (UserInfo->UserName.Buffer != NULL)
369         SamFreeMemory(UserInfo->UserName.Buffer);
370 
371     if (UserInfo->FullName.Buffer != NULL)
372         SamFreeMemory(UserInfo->FullName.Buffer);
373 
374     if (UserInfo->HomeDirectory.Buffer != NULL)
375         SamFreeMemory(UserInfo->HomeDirectory.Buffer);
376 
377     if (UserInfo->HomeDirectoryDrive.Buffer != NULL)
378         SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer);
379 
380     if (UserInfo->ScriptPath.Buffer != NULL)
381         SamFreeMemory(UserInfo->ScriptPath.Buffer);
382 
383     if (UserInfo->ProfilePath.Buffer != NULL)
384         SamFreeMemory(UserInfo->ProfilePath.Buffer);
385 
386     if (UserInfo->AdminComment.Buffer != NULL)
387         SamFreeMemory(UserInfo->AdminComment.Buffer);
388 
389     if (UserInfo->WorkStations.Buffer != NULL)
390         SamFreeMemory(UserInfo->WorkStations.Buffer);
391 
392     if (UserInfo->UserComment.Buffer != NULL)
393         SamFreeMemory(UserInfo->UserComment.Buffer);
394 
395     if (UserInfo->Parameters.Buffer != NULL)
396         SamFreeMemory(UserInfo->Parameters.Buffer);
397 
398     if (UserInfo->PrivateData.Buffer != NULL)
399         SamFreeMemory(UserInfo->PrivateData.Buffer);
400 
401     if (UserInfo->LogonHours.LogonHours != NULL)
402         SamFreeMemory(UserInfo->LogonHours.LogonHours);
403 
404     SamFreeMemory(UserInfo);
405 }
406 
407 
408 static
409 NET_API_STATUS
GetUserPrivileges(_In_ SAM_HANDLE BuiltinDomainHandle,_In_ SAM_HANDLE UserHandle,_In_ PSID AccountDomainSid,_In_ ULONG RelativeId,_Out_ PDWORD Priv,_Out_ PDWORD AuthFlags)410 GetUserPrivileges(
411     _In_ SAM_HANDLE BuiltinDomainHandle,
412     _In_ SAM_HANDLE UserHandle,
413     _In_ PSID AccountDomainSid,
414     _In_ ULONG RelativeId,
415     _Out_ PDWORD Priv,
416     _Out_ PDWORD AuthFlags)
417 {
418     PGROUP_MEMBERSHIP GroupMembership = NULL;
419     ULONG GroupCount, SidCount, AliasCount, i;
420     PSID *SidArray = NULL;
421     PULONG AliasArray = NULL;
422     BOOL bAdmin = FALSE, bUser = FALSE;
423     NET_API_STATUS ApiStatus = NERR_Success;
424     NTSTATUS Status;
425 
426     FIXME("GetUserPrivileges(%p)\n", UserHandle);
427 
428     /* Get the users group memberships */
429     Status = SamGetGroupsForUser(UserHandle,
430                                  &GroupMembership,
431                                  &GroupCount);
432     if (!NT_SUCCESS(Status))
433     {
434         ERR("SamGetGroupsForUser() failed (Status 0x%08lx)\n", Status);
435         ApiStatus = NetpNtStatusToApiStatus(Status);
436         goto done;
437     }
438 
439     /* Allocate the SID array */
440     ApiStatus = NetApiBufferAllocate((GroupCount + 1) * sizeof(PSID),
441                                      (PVOID*)&SidArray);
442     if (ApiStatus != NERR_Success)
443     {
444         goto done;
445     }
446 
447     /* Add the user to the SID array */
448     SidCount = 0;
449     ApiStatus = BuildSidFromSidAndRid(AccountDomainSid,
450                                       RelativeId,
451                                       &SidArray[0]);
452     if (ApiStatus != NERR_Success)
453     {
454         goto done;
455     }
456 
457     SidCount++;
458 
459     /* Add the groups to the SID array */
460     for (i = 0; i < GroupCount; i++)
461     {
462         ApiStatus = BuildSidFromSidAndRid(AccountDomainSid,
463                                           GroupMembership[i].RelativeId,
464                                           &SidArray[i + 1]);
465         if (ApiStatus != NERR_Success)
466         {
467             goto done;
468         }
469 
470         SidCount++;
471     }
472 
473     /* Get aliases for the user and his groups */
474     Status = SamGetAliasMembership(BuiltinDomainHandle,
475                                    SidCount,
476                                    SidArray,
477                                    &AliasCount,
478                                    &AliasArray);
479     if (!NT_SUCCESS(Status))
480     {
481         ERR("SamGetAliasMembership() failed (Status 0x%08lx)\n", Status);
482         ApiStatus = NetpNtStatusToApiStatus(Status);
483         goto done;
484     }
485 
486     *AuthFlags = 0;
487 
488     /* Set the AuthFlags */
489     for (i = 0; i < AliasCount; i++)
490     {
491         switch (AliasArray[i])
492         {
493             case DOMAIN_ALIAS_RID_ADMINS:
494                 bAdmin = TRUE;
495                 break;
496 
497             case DOMAIN_ALIAS_RID_USERS:
498                 bUser = TRUE;
499                 break;
500 
501             case DOMAIN_ALIAS_RID_ACCOUNT_OPS:
502                 *AuthFlags |= AF_OP_ACCOUNTS;
503                 break;
504 
505             case DOMAIN_ALIAS_RID_SYSTEM_OPS:
506                 *AuthFlags |= AF_OP_SERVER;
507                 break;
508 
509             case DOMAIN_ALIAS_RID_PRINT_OPS:
510                 *AuthFlags |= AF_OP_PRINT;
511                 break;
512         }
513     }
514 
515     /* Set the prvileges */
516     if (bAdmin)
517     {
518         *Priv = USER_PRIV_ADMIN;
519     }
520     else if (bUser)
521     {
522         *Priv = USER_PRIV_USER;
523     }
524     else
525     {
526         *Priv = USER_PRIV_GUEST;
527     }
528 
529 done:
530     if (AliasArray != NULL)
531         SamFreeMemory(AliasArray);
532 
533     if (SidArray != NULL)
534     {
535         for (i = 0; i < SidCount; i++)
536             NetApiBufferFree(SidArray[i]);
537 
538         NetApiBufferFree(SidArray);
539     }
540 
541     if (GroupMembership != NULL)
542         SamFreeMemory(GroupMembership);
543 
544     return ApiStatus;
545 }
546 
547 
548 static
549 NET_API_STATUS
BuildUserInfoBuffer(_In_ SAM_HANDLE BuiltinDomainHandle,_In_ SAM_HANDLE UserHandle,_In_ PSID AccountDomainSid,_In_ ULONG RelativeId,_In_ DWORD level,_Out_ LPVOID * Buffer)550 BuildUserInfoBuffer(
551     _In_ SAM_HANDLE BuiltinDomainHandle,
552     _In_ SAM_HANDLE UserHandle,
553     _In_ PSID AccountDomainSid,
554     _In_ ULONG RelativeId,
555     _In_ DWORD level,
556     _Out_ LPVOID *Buffer)
557 {
558     UNICODE_STRING LogonServer = RTL_CONSTANT_STRING(L"\\\\*");
559     PUSER_ALL_INFORMATION UserInfo = NULL;
560     LPVOID LocalBuffer = NULL;
561     PACL Dacl = NULL;
562     DWORD Priv = 0, AuthFlags = 0;
563     PUSER_INFO_0 UserInfo0;
564     PUSER_INFO_1 UserInfo1;
565     PUSER_INFO_2 UserInfo2;
566     PUSER_INFO_3 UserInfo3;
567     PUSER_INFO_4 UserInfo4;
568     PUSER_INFO_10 UserInfo10;
569     PUSER_INFO_11 UserInfo11;
570     PUSER_INFO_20 UserInfo20;
571     PUSER_INFO_23 UserInfo23;
572     LPWSTR Ptr;
573     ULONG Size = 0;
574     NTSTATUS Status;
575     NET_API_STATUS ApiStatus = NERR_Success;
576 
577     *Buffer = NULL;
578 
579     Status = SamQueryInformationUser(UserHandle,
580                                      UserAllInformation,
581                                      (PVOID *)&UserInfo);
582     if (!NT_SUCCESS(Status))
583     {
584         ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
585         ApiStatus = NetpNtStatusToApiStatus(Status);
586         goto done;
587     }
588 
589     if ((level == 1) || (level == 2) || (level == 3) ||
590         (level == 4) || (level == 20) || (level == 23))
591     {
592         ApiStatus = GetUserDacl(UserHandle, &Dacl);
593         if (ApiStatus != NERR_Success)
594             goto done;
595     }
596 
597     if ((level == 1) || (level == 2) || (level == 3) ||
598         (level == 4) || (level == 11))
599     {
600         ApiStatus = GetUserPrivileges(BuiltinDomainHandle,
601                                       UserHandle,
602                                       AccountDomainSid,
603                                       RelativeId,
604                                       &Priv,
605                                       &AuthFlags);
606         if (ApiStatus != NERR_Success)
607             goto done;
608     }
609 
610     switch (level)
611     {
612         case 0:
613             Size = sizeof(USER_INFO_0) +
614                    UserInfo->UserName.Length + sizeof(WCHAR);
615             break;
616 
617         case 1:
618             Size = sizeof(USER_INFO_1) +
619                    UserInfo->UserName.Length + sizeof(WCHAR) +
620                    UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
621                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
622                    UserInfo->ScriptPath.Length + sizeof(WCHAR);
623             break;
624 
625         case 2:
626             Size = sizeof(USER_INFO_2) +
627                    UserInfo->UserName.Length + sizeof(WCHAR) +
628                    UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
629                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
630                    UserInfo->ScriptPath.Length + sizeof(WCHAR) +
631                    UserInfo->FullName.Length + sizeof(WCHAR) +
632                    UserInfo->UserComment.Length + sizeof(WCHAR) +
633                    UserInfo->Parameters.Length + sizeof(WCHAR) +
634                    UserInfo->WorkStations.Length + sizeof(WCHAR) +
635                    LogonServer.Length + sizeof(WCHAR);
636 
637             if (UserInfo->LogonHours.UnitsPerWeek > 0)
638                 Size += (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8;
639             break;
640 
641         case 3:
642             Size = sizeof(USER_INFO_3) +
643                    UserInfo->UserName.Length + sizeof(WCHAR) +
644                    UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
645                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
646                    UserInfo->ScriptPath.Length + sizeof(WCHAR) +
647                    UserInfo->FullName.Length + sizeof(WCHAR) +
648                    UserInfo->UserComment.Length + sizeof(WCHAR) +
649                    UserInfo->Parameters.Length + sizeof(WCHAR) +
650                    UserInfo->WorkStations.Length + sizeof(WCHAR) +
651                    LogonServer.Length + sizeof(WCHAR) +
652                    UserInfo->ProfilePath.Length + sizeof(WCHAR) +
653                    UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR);
654 
655             if (UserInfo->LogonHours.UnitsPerWeek > 0)
656                 Size += (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8;
657             break;
658 
659         case 4:
660             Size = sizeof(USER_INFO_4) +
661                    UserInfo->UserName.Length + sizeof(WCHAR) +
662                    UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
663                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
664                    UserInfo->ScriptPath.Length + sizeof(WCHAR) +
665                    UserInfo->FullName.Length + sizeof(WCHAR) +
666                    UserInfo->UserComment.Length + sizeof(WCHAR) +
667                    UserInfo->Parameters.Length + sizeof(WCHAR) +
668                    UserInfo->WorkStations.Length + sizeof(WCHAR) +
669                    LogonServer.Length + sizeof(WCHAR) +
670                    UserInfo->ProfilePath.Length + sizeof(WCHAR) +
671                    UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR);
672 
673             if (UserInfo->LogonHours.UnitsPerWeek > 0)
674                 Size += (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8;
675 
676             Size += RtlLengthSid(AccountDomainSid) + sizeof(ULONG);
677             break;
678 
679         case 10:
680             Size = sizeof(USER_INFO_10) +
681                    UserInfo->UserName.Length + sizeof(WCHAR) +
682                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
683                    UserInfo->UserComment.Length + sizeof(WCHAR) +
684                    UserInfo->FullName.Length + sizeof(WCHAR);
685             break;
686 
687         case 11:
688             Size = sizeof(USER_INFO_11) +
689                    UserInfo->UserName.Length + sizeof(WCHAR) +
690                    UserInfo->AdminComment.Length + sizeof(WCHAR) +
691                    UserInfo->UserComment.Length + sizeof(WCHAR) +
692                    UserInfo->FullName.Length + sizeof(WCHAR) +
693                    UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
694                    UserInfo->Parameters.Length + sizeof(WCHAR) +
695                    LogonServer.Length + sizeof(WCHAR) +
696                    UserInfo->WorkStations.Length + sizeof(WCHAR);
697 
698             if (UserInfo->LogonHours.UnitsPerWeek > 0)
699                 Size += (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8;
700             break;
701 
702         case 20:
703             Size = sizeof(USER_INFO_20) +
704                    UserInfo->UserName.Length + sizeof(WCHAR) +
705                    UserInfo->FullName.Length + sizeof(WCHAR) +
706                    UserInfo->AdminComment.Length + sizeof(WCHAR);
707             break;
708 
709         case 23:
710             Size = sizeof(USER_INFO_23) +
711                    UserInfo->UserName.Length + sizeof(WCHAR) +
712                    UserInfo->FullName.Length + sizeof(WCHAR) +
713                    UserInfo->AdminComment.Length + sizeof(WCHAR);
714 
715             Size += RtlLengthSid(AccountDomainSid) + sizeof(ULONG);
716             break;
717 
718         default:
719             ApiStatus = ERROR_INVALID_LEVEL;
720             goto done;
721     }
722 
723     ApiStatus = NetApiBufferAllocate(Size, &LocalBuffer);
724     if (ApiStatus != NERR_Success)
725         goto done;
726 
727     ZeroMemory(LocalBuffer, Size);
728 
729     switch (level)
730     {
731         case 0:
732             UserInfo0 = (PUSER_INFO_0)LocalBuffer;
733 
734             Ptr = (LPWSTR)((ULONG_PTR)UserInfo0 + sizeof(USER_INFO_0));
735 
736             UserInfo0->usri0_name = Ptr;
737 
738             memcpy(UserInfo0->usri0_name,
739                    UserInfo->UserName.Buffer,
740                    UserInfo->UserName.Length);
741             UserInfo0->usri0_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
742             break;
743 
744         case 1:
745             UserInfo1 = (PUSER_INFO_1)LocalBuffer;
746 
747             Ptr = (LPWSTR)((ULONG_PTR)UserInfo1 + sizeof(USER_INFO_1));
748 
749             UserInfo1->usri1_name = Ptr;
750 
751             memcpy(UserInfo1->usri1_name,
752                    UserInfo->UserName.Buffer,
753                    UserInfo->UserName.Length);
754             UserInfo1->usri1_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
755 
756             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
757 
758             UserInfo1->usri1_password = NULL;
759             UserInfo1->usri1_password_age = GetPasswordAge(&UserInfo->PasswordLastSet);
760 
761             UserInfo1->usri1_priv = Priv;
762 
763             UserInfo1->usri1_home_dir = Ptr;
764             memcpy(UserInfo1->usri1_home_dir,
765                    UserInfo->HomeDirectory.Buffer,
766                    UserInfo->HomeDirectory.Length);
767             UserInfo1->usri1_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
768             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
769 
770             UserInfo1->usri1_comment = Ptr;
771             memcpy(UserInfo1->usri1_comment,
772                    UserInfo->AdminComment.Buffer,
773                    UserInfo->AdminComment.Length);
774             UserInfo1->usri1_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
775             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
776 
777             UserInfo1->usri1_flags = GetAccountFlags(UserInfo->UserAccountControl,
778                                                      Dacl);
779 
780             UserInfo1->usri1_script_path = Ptr;
781             memcpy(UserInfo1->usri1_script_path,
782                    UserInfo->ScriptPath.Buffer,
783                    UserInfo->ScriptPath.Length);
784             UserInfo1->usri1_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
785             break;
786 
787         case 2:
788             UserInfo2 = (PUSER_INFO_2)LocalBuffer;
789 
790             Ptr = (LPWSTR)((ULONG_PTR)UserInfo2 + sizeof(USER_INFO_2));
791 
792             UserInfo2->usri2_name = Ptr;
793 
794             memcpy(UserInfo2->usri2_name,
795                    UserInfo->UserName.Buffer,
796                    UserInfo->UserName.Length);
797             UserInfo2->usri2_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
798 
799             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
800 
801             UserInfo2->usri2_password = NULL;
802             UserInfo2->usri2_password_age = GetPasswordAge(&UserInfo->PasswordLastSet);
803 
804             UserInfo2->usri2_priv = Priv;
805 
806             UserInfo2->usri2_home_dir = Ptr;
807             memcpy(UserInfo2->usri2_home_dir,
808                    UserInfo->HomeDirectory.Buffer,
809                    UserInfo->HomeDirectory.Length);
810             UserInfo2->usri2_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
811             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
812 
813             UserInfo2->usri2_comment = Ptr;
814             memcpy(UserInfo2->usri2_comment,
815                    UserInfo->AdminComment.Buffer,
816                    UserInfo->AdminComment.Length);
817             UserInfo2->usri2_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
818             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
819 
820             UserInfo2->usri2_flags = GetAccountFlags(UserInfo->UserAccountControl,
821                                                      Dacl);
822 
823             UserInfo2->usri2_script_path = Ptr;
824             memcpy(UserInfo2->usri2_script_path,
825                    UserInfo->ScriptPath.Buffer,
826                    UserInfo->ScriptPath.Length);
827             UserInfo2->usri2_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
828             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ScriptPath.Length + sizeof(WCHAR));
829 
830             UserInfo2->usri2_auth_flags = AuthFlags;
831 
832             UserInfo2->usri2_full_name = Ptr;
833             memcpy(UserInfo2->usri2_full_name,
834                    UserInfo->FullName.Buffer,
835                    UserInfo->FullName.Length);
836             UserInfo2->usri2_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
837             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
838 
839             UserInfo2->usri2_usr_comment = Ptr;
840             memcpy(UserInfo2->usri2_usr_comment,
841                    UserInfo->UserComment.Buffer,
842                    UserInfo->UserComment.Length);
843             UserInfo2->usri2_usr_comment[UserInfo->UserComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
844             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserComment.Length + sizeof(WCHAR));
845 
846             UserInfo2->usri2_parms = Ptr;
847             memcpy(UserInfo2->usri2_parms,
848                    UserInfo->Parameters.Buffer,
849                    UserInfo->Parameters.Length);
850             UserInfo2->usri2_parms[UserInfo->Parameters.Length / sizeof(WCHAR)] = UNICODE_NULL;
851             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->Parameters.Length + sizeof(WCHAR));
852 
853             UserInfo2->usri2_workstations = Ptr;
854             memcpy(UserInfo2->usri2_workstations,
855                    UserInfo->WorkStations.Buffer,
856                    UserInfo->WorkStations.Length);
857             UserInfo2->usri2_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
858             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
859 
860             if (UserInfo->LastLogon.QuadPart == 0)
861                 UserInfo2->usri2_last_logon = 0;
862             else
863                 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
864                                           &UserInfo2->usri2_last_logon);
865 
866             if (UserInfo->LastLogoff.QuadPart == 0)
867                 UserInfo2->usri2_last_logoff = 0;
868             else
869                 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
870                                           &UserInfo2->usri2_last_logoff);
871 
872             if (UserInfo->AccountExpires.QuadPart == MAXLONGLONG)
873                 UserInfo2->usri2_acct_expires = TIMEQ_FOREVER;
874             else
875                 RtlTimeToSecondsSince1970(&UserInfo->AccountExpires,
876                                           &UserInfo2->usri2_acct_expires);
877 
878             UserInfo2->usri2_max_storage = USER_MAXSTORAGE_UNLIMITED;
879             UserInfo2->usri2_units_per_week = UserInfo->LogonHours.UnitsPerWeek;
880 
881             if (UserInfo->LogonHours.UnitsPerWeek > 0)
882             {
883                 UserInfo2->usri2_logon_hours = (PVOID)Ptr;
884 
885                 memcpy(UserInfo2->usri2_logon_hours,
886                        UserInfo->LogonHours.LogonHours,
887                        (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
888 
889                 Ptr = (LPWSTR)((ULONG_PTR)Ptr + (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
890             }
891 
892             UserInfo2->usri2_bad_pw_count = UserInfo->BadPasswordCount;
893             UserInfo2->usri2_num_logons = UserInfo->LogonCount;
894 
895             UserInfo2->usri2_logon_server = Ptr;
896             memcpy(UserInfo2->usri2_logon_server,
897                    LogonServer.Buffer,
898                    LogonServer.Length);
899             UserInfo2->usri2_logon_server[LogonServer.Length / sizeof(WCHAR)] = UNICODE_NULL;
900             Ptr = (LPWSTR)((ULONG_PTR)Ptr + LogonServer.Length + sizeof(WCHAR));
901 
902             UserInfo2->usri2_country_code = UserInfo->CountryCode;
903             UserInfo2->usri2_code_page = UserInfo->CodePage;
904             break;
905 
906         case 3:
907             UserInfo3 = (PUSER_INFO_3)LocalBuffer;
908 
909             Ptr = (LPWSTR)((ULONG_PTR)UserInfo3 + sizeof(USER_INFO_3));
910 
911             UserInfo3->usri3_name = Ptr;
912 
913             memcpy(UserInfo3->usri3_name,
914                    UserInfo->UserName.Buffer,
915                    UserInfo->UserName.Length);
916             UserInfo3->usri3_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
917 
918             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
919 
920             UserInfo3->usri3_password = NULL;
921             UserInfo3->usri3_password_age = GetPasswordAge(&UserInfo->PasswordLastSet);
922 
923             UserInfo3->usri3_priv = Priv;
924 
925             UserInfo3->usri3_home_dir = Ptr;
926             memcpy(UserInfo3->usri3_home_dir,
927                    UserInfo->HomeDirectory.Buffer,
928                    UserInfo->HomeDirectory.Length);
929             UserInfo3->usri3_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
930             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
931 
932             UserInfo3->usri3_comment = Ptr;
933             memcpy(UserInfo3->usri3_comment,
934                    UserInfo->AdminComment.Buffer,
935                    UserInfo->AdminComment.Length);
936             UserInfo3->usri3_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
937             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
938 
939             UserInfo3->usri3_flags = GetAccountFlags(UserInfo->UserAccountControl,
940                                                      Dacl);
941 
942             UserInfo3->usri3_script_path = Ptr;
943             memcpy(UserInfo3->usri3_script_path,
944                    UserInfo->ScriptPath.Buffer,
945                    UserInfo->ScriptPath.Length);
946             UserInfo3->usri3_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
947             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ScriptPath.Length + sizeof(WCHAR));
948 
949             UserInfo3->usri3_auth_flags = AuthFlags;
950 
951             UserInfo3->usri3_full_name = Ptr;
952             memcpy(UserInfo3->usri3_full_name,
953                    UserInfo->FullName.Buffer,
954                    UserInfo->FullName.Length);
955             UserInfo3->usri3_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
956             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
957 
958             UserInfo3->usri3_usr_comment = Ptr;
959             memcpy(UserInfo3->usri3_usr_comment,
960                    UserInfo->UserComment.Buffer,
961                    UserInfo->UserComment.Length);
962             UserInfo3->usri3_usr_comment[UserInfo->UserComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
963             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserComment.Length + sizeof(WCHAR));
964 
965             UserInfo3->usri3_parms = Ptr;
966             memcpy(UserInfo3->usri3_parms,
967                    UserInfo->Parameters.Buffer,
968                    UserInfo->Parameters.Length);
969             UserInfo3->usri3_parms[UserInfo->Parameters.Length / sizeof(WCHAR)] = UNICODE_NULL;
970             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->Parameters.Length + sizeof(WCHAR));
971 
972             UserInfo3->usri3_workstations = Ptr;
973             memcpy(UserInfo3->usri3_workstations,
974                    UserInfo->WorkStations.Buffer,
975                    UserInfo->WorkStations.Length);
976             UserInfo3->usri3_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
977             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
978 
979             if (UserInfo->LastLogon.QuadPart == 0)
980                 UserInfo3->usri3_last_logon = 0;
981             else
982                 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
983                                           &UserInfo3->usri3_last_logon);
984 
985             if (UserInfo->LastLogoff.QuadPart == 0)
986                 UserInfo3->usri3_last_logoff = 0;
987             else
988                 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
989                                           &UserInfo3->usri3_last_logoff);
990 
991             if (UserInfo->AccountExpires.QuadPart == MAXLONGLONG)
992                 UserInfo3->usri3_acct_expires = TIMEQ_FOREVER;
993             else
994                 RtlTimeToSecondsSince1970(&UserInfo->AccountExpires,
995                                           &UserInfo3->usri3_acct_expires);
996 
997             UserInfo3->usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
998             UserInfo3->usri3_units_per_week = UserInfo->LogonHours.UnitsPerWeek;
999 
1000             if (UserInfo->LogonHours.UnitsPerWeek > 0)
1001             {
1002                 UserInfo3->usri3_logon_hours = (PVOID)Ptr;
1003 
1004                 memcpy(UserInfo3->usri3_logon_hours,
1005                        UserInfo->LogonHours.LogonHours,
1006                        (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1007 
1008                 Ptr = (LPWSTR)((ULONG_PTR)Ptr + (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1009             }
1010 
1011             UserInfo3->usri3_bad_pw_count = UserInfo->BadPasswordCount;
1012             UserInfo3->usri3_num_logons = UserInfo->LogonCount;
1013 
1014             UserInfo3->usri3_logon_server = Ptr;
1015             memcpy(UserInfo3->usri3_logon_server,
1016                    LogonServer.Buffer,
1017                    LogonServer.Length);
1018             UserInfo3->usri3_logon_server[LogonServer.Length / sizeof(WCHAR)] = UNICODE_NULL;
1019             Ptr = (LPWSTR)((ULONG_PTR)Ptr + LogonServer.Length + sizeof(WCHAR));
1020 
1021             UserInfo3->usri3_country_code = UserInfo->CountryCode;
1022             UserInfo3->usri3_code_page = UserInfo->CodePage;
1023             UserInfo3->usri3_user_id = RelativeId;
1024             UserInfo3->usri3_primary_group_id = UserInfo->PrimaryGroupId;
1025 
1026             UserInfo3->usri3_profile = Ptr;
1027             memcpy(UserInfo3->usri3_profile,
1028                    UserInfo->ProfilePath.Buffer,
1029                    UserInfo->ProfilePath.Length);
1030             UserInfo3->usri3_profile[UserInfo->ProfilePath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1031             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ProfilePath.Length + sizeof(WCHAR));
1032 
1033             UserInfo3->usri3_home_dir_drive = Ptr;
1034             memcpy(UserInfo3->usri3_home_dir_drive,
1035                    UserInfo->HomeDirectoryDrive.Buffer,
1036                    UserInfo->HomeDirectoryDrive.Length);
1037             UserInfo3->usri3_home_dir_drive[UserInfo->HomeDirectoryDrive.Length / sizeof(WCHAR)] = UNICODE_NULL;
1038             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR));
1039 
1040             UserInfo3->usri3_password_expired = (UserInfo->UserAccountControl & USER_PASSWORD_EXPIRED);
1041             break;
1042 
1043         case 4:
1044             UserInfo4 = (PUSER_INFO_4)LocalBuffer;
1045 
1046             Ptr = (LPWSTR)((ULONG_PTR)UserInfo4 + sizeof(USER_INFO_4));
1047 
1048             UserInfo4->usri4_name = Ptr;
1049 
1050             memcpy(UserInfo4->usri4_name,
1051                    UserInfo->UserName.Buffer,
1052                    UserInfo->UserName.Length);
1053             UserInfo4->usri4_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1054 
1055             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
1056 
1057             UserInfo4->usri4_password = NULL;
1058             UserInfo4->usri4_password_age = GetPasswordAge(&UserInfo->PasswordLastSet);
1059 
1060             UserInfo4->usri4_priv = Priv;
1061 
1062             UserInfo4->usri4_home_dir = Ptr;
1063             memcpy(UserInfo4->usri4_home_dir,
1064                    UserInfo->HomeDirectory.Buffer,
1065                    UserInfo->HomeDirectory.Length);
1066             UserInfo4->usri4_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
1067             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
1068 
1069             UserInfo4->usri4_comment = Ptr;
1070             memcpy(UserInfo4->usri4_comment,
1071                    UserInfo->AdminComment.Buffer,
1072                    UserInfo->AdminComment.Length);
1073             UserInfo4->usri4_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1074             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
1075 
1076             UserInfo4->usri4_flags = GetAccountFlags(UserInfo->UserAccountControl,
1077                                                      Dacl);
1078 
1079             UserInfo4->usri4_script_path = Ptr;
1080             memcpy(UserInfo4->usri4_script_path,
1081                    UserInfo->ScriptPath.Buffer,
1082                    UserInfo->ScriptPath.Length);
1083             UserInfo4->usri4_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1084             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ScriptPath.Length + sizeof(WCHAR));
1085 
1086             UserInfo4->usri4_auth_flags = AuthFlags;
1087 
1088             UserInfo4->usri4_full_name = Ptr;
1089             memcpy(UserInfo4->usri4_full_name,
1090                    UserInfo->FullName.Buffer,
1091                    UserInfo->FullName.Length);
1092             UserInfo4->usri4_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1093             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
1094 
1095             UserInfo4->usri4_usr_comment = Ptr;
1096             memcpy(UserInfo4->usri4_usr_comment,
1097                    UserInfo->UserComment.Buffer,
1098                    UserInfo->UserComment.Length);
1099             UserInfo4->usri4_usr_comment[UserInfo->UserComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1100             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserComment.Length + sizeof(WCHAR));
1101 
1102             UserInfo4->usri4_parms = Ptr;
1103             memcpy(UserInfo4->usri4_parms,
1104                    UserInfo->Parameters.Buffer,
1105                    UserInfo->Parameters.Length);
1106             UserInfo4->usri4_parms[UserInfo->Parameters.Length / sizeof(WCHAR)] = UNICODE_NULL;
1107             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->Parameters.Length + sizeof(WCHAR));
1108 
1109             UserInfo4->usri4_workstations = Ptr;
1110             memcpy(UserInfo4->usri4_workstations,
1111                    UserInfo->WorkStations.Buffer,
1112                    UserInfo->WorkStations.Length);
1113             UserInfo4->usri4_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
1114             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
1115 
1116             if (UserInfo->LastLogon.QuadPart == 0)
1117                 UserInfo4->usri4_last_logon = 0;
1118             else
1119                 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
1120                                           &UserInfo4->usri4_last_logon);
1121 
1122             if (UserInfo->LastLogoff.QuadPart == 0)
1123                 UserInfo4->usri4_last_logoff = 0;
1124             else
1125                 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
1126                                           &UserInfo4->usri4_last_logoff);
1127 
1128             if (UserInfo->AccountExpires.QuadPart == MAXLONGLONG)
1129                 UserInfo4->usri4_acct_expires = TIMEQ_FOREVER;
1130             else
1131                 RtlTimeToSecondsSince1970(&UserInfo->AccountExpires,
1132                                           &UserInfo4->usri4_acct_expires);
1133 
1134             UserInfo4->usri4_max_storage = USER_MAXSTORAGE_UNLIMITED;
1135             UserInfo4->usri4_units_per_week = UserInfo->LogonHours.UnitsPerWeek;
1136 
1137             if (UserInfo->LogonHours.UnitsPerWeek > 0)
1138             {
1139                 UserInfo4->usri4_logon_hours = (PVOID)Ptr;
1140 
1141                 memcpy(UserInfo4->usri4_logon_hours,
1142                        UserInfo->LogonHours.LogonHours,
1143                        (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1144 
1145                 Ptr = (LPWSTR)((ULONG_PTR)Ptr + (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1146             }
1147 
1148             UserInfo4->usri4_bad_pw_count = UserInfo->BadPasswordCount;
1149             UserInfo4->usri4_num_logons = UserInfo->LogonCount;
1150 
1151             UserInfo4->usri4_logon_server = Ptr;
1152             memcpy(UserInfo4->usri4_logon_server,
1153                    LogonServer.Buffer,
1154                    LogonServer.Length);
1155             UserInfo4->usri4_logon_server[LogonServer.Length / sizeof(WCHAR)] = UNICODE_NULL;
1156             Ptr = (LPWSTR)((ULONG_PTR)Ptr + LogonServer.Length + sizeof(WCHAR));
1157 
1158             UserInfo4->usri4_country_code = UserInfo->CountryCode;
1159             UserInfo4->usri4_code_page = UserInfo->CodePage;
1160 
1161             UserInfo4->usri4_user_sid = (PVOID)Ptr;
1162             CopySidFromSidAndRid(UserInfo4->usri4_user_sid, AccountDomainSid, RelativeId);
1163             Ptr = (LPWSTR)((ULONG_PTR)Ptr + RtlLengthSid(AccountDomainSid) + sizeof(ULONG));
1164 
1165             UserInfo4->usri4_primary_group_id = UserInfo->PrimaryGroupId;
1166 
1167             UserInfo4->usri4_profile = Ptr;
1168             memcpy(UserInfo4->usri4_profile,
1169                    UserInfo->ProfilePath.Buffer,
1170                    UserInfo->ProfilePath.Length);
1171             UserInfo4->usri4_profile[UserInfo->ProfilePath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1172             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ProfilePath.Length + sizeof(WCHAR));
1173 
1174             UserInfo4->usri4_home_dir_drive = Ptr;
1175             memcpy(UserInfo4->usri4_home_dir_drive,
1176                    UserInfo->HomeDirectoryDrive.Buffer,
1177                    UserInfo->HomeDirectoryDrive.Length);
1178             UserInfo4->usri4_home_dir_drive[UserInfo->HomeDirectoryDrive.Length / sizeof(WCHAR)] = UNICODE_NULL;
1179             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR));
1180 
1181             UserInfo4->usri4_password_expired = (UserInfo->UserAccountControl & USER_PASSWORD_EXPIRED);
1182             break;
1183 
1184         case 10:
1185             UserInfo10 = (PUSER_INFO_10)LocalBuffer;
1186 
1187             Ptr = (LPWSTR)((ULONG_PTR)UserInfo10 + sizeof(USER_INFO_10));
1188 
1189             UserInfo10->usri10_name = Ptr;
1190 
1191             memcpy(UserInfo10->usri10_name,
1192                    UserInfo->UserName.Buffer,
1193                    UserInfo->UserName.Length);
1194             UserInfo10->usri10_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1195 
1196             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
1197 
1198             UserInfo10->usri10_comment = Ptr;
1199             memcpy(UserInfo10->usri10_comment,
1200                    UserInfo->AdminComment.Buffer,
1201                    UserInfo->AdminComment.Length);
1202             UserInfo10->usri10_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1203             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
1204 
1205             UserInfo10->usri10_usr_comment = Ptr;
1206             memcpy(UserInfo10->usri10_usr_comment,
1207                    UserInfo->UserComment.Buffer,
1208                    UserInfo->UserComment.Length);
1209             UserInfo10->usri10_usr_comment[UserInfo->UserComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1210             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserComment.Length + sizeof(WCHAR));
1211 
1212             UserInfo10->usri10_full_name = Ptr;
1213             memcpy(UserInfo10->usri10_full_name,
1214                    UserInfo->FullName.Buffer,
1215                    UserInfo->FullName.Length);
1216             UserInfo10->usri10_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1217             break;
1218 
1219         case 11:
1220             UserInfo11 = (PUSER_INFO_11)LocalBuffer;
1221 
1222             Ptr = (LPWSTR)((ULONG_PTR)UserInfo11 + sizeof(USER_INFO_11));
1223 
1224             UserInfo11->usri11_name = Ptr;
1225 
1226             memcpy(UserInfo11->usri11_name,
1227                    UserInfo->UserName.Buffer,
1228                    UserInfo->UserName.Length);
1229             UserInfo11->usri11_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1230 
1231             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
1232 
1233             UserInfo11->usri11_comment = Ptr;
1234             memcpy(UserInfo11->usri11_comment,
1235                    UserInfo->AdminComment.Buffer,
1236                    UserInfo->AdminComment.Length);
1237             UserInfo11->usri11_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1238             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
1239 
1240             UserInfo11->usri11_usr_comment = Ptr;
1241             memcpy(UserInfo11->usri11_usr_comment,
1242                    UserInfo->UserComment.Buffer,
1243                    UserInfo->UserComment.Length);
1244             UserInfo11->usri11_usr_comment[UserInfo->UserComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1245             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserComment.Length + sizeof(WCHAR));
1246 
1247             UserInfo11->usri11_full_name = Ptr;
1248             memcpy(UserInfo11->usri11_full_name,
1249                    UserInfo->FullName.Buffer,
1250                    UserInfo->FullName.Length);
1251             UserInfo11->usri11_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1252             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
1253 
1254             UserInfo11->usri11_priv = Priv;
1255             UserInfo11->usri11_auth_flags = AuthFlags;
1256 
1257             UserInfo11->usri11_password_age = GetPasswordAge(&UserInfo->PasswordLastSet);
1258 
1259             UserInfo11->usri11_home_dir = Ptr;
1260             memcpy(UserInfo11->usri11_home_dir,
1261                    UserInfo->HomeDirectory.Buffer,
1262                    UserInfo->HomeDirectory.Length);
1263             UserInfo11->usri11_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
1264             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
1265 
1266             UserInfo11->usri11_parms = Ptr;
1267             memcpy(UserInfo11->usri11_parms,
1268                    UserInfo->Parameters.Buffer,
1269                    UserInfo->Parameters.Length);
1270             UserInfo11->usri11_parms[UserInfo->Parameters.Length / sizeof(WCHAR)] = UNICODE_NULL;
1271             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->Parameters.Length + sizeof(WCHAR));
1272 
1273             if (UserInfo->LastLogon.QuadPart == 0)
1274                 UserInfo11->usri11_last_logon = 0;
1275             else
1276                 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
1277                                           &UserInfo11->usri11_last_logon);
1278 
1279             if (UserInfo->LastLogoff.QuadPart == 0)
1280                 UserInfo11->usri11_last_logoff = 0;
1281             else
1282                 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
1283                                           &UserInfo11->usri11_last_logoff);
1284 
1285             UserInfo11->usri11_bad_pw_count = UserInfo->BadPasswordCount;
1286             UserInfo11->usri11_num_logons = UserInfo->LogonCount;
1287 
1288             UserInfo11->usri11_logon_server = Ptr;
1289             memcpy(UserInfo11->usri11_logon_server,
1290                    LogonServer.Buffer,
1291                    LogonServer.Length);
1292             UserInfo11->usri11_logon_server[LogonServer.Length / sizeof(WCHAR)] = UNICODE_NULL;
1293             Ptr = (LPWSTR)((ULONG_PTR)Ptr + LogonServer.Length + sizeof(WCHAR));
1294 
1295             UserInfo11->usri11_country_code = UserInfo->CountryCode;
1296 
1297             UserInfo11->usri11_workstations = Ptr;
1298             memcpy(UserInfo11->usri11_workstations,
1299                    UserInfo->WorkStations.Buffer,
1300                    UserInfo->WorkStations.Length);
1301             UserInfo11->usri11_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
1302             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
1303 
1304             UserInfo11->usri11_max_storage = USER_MAXSTORAGE_UNLIMITED;
1305             UserInfo11->usri11_units_per_week = UserInfo->LogonHours.UnitsPerWeek;
1306 
1307             if (UserInfo->LogonHours.UnitsPerWeek > 0)
1308             {
1309                 UserInfo11->usri11_logon_hours = (PVOID)Ptr;
1310 
1311                 memcpy(UserInfo11->usri11_logon_hours,
1312                        UserInfo->LogonHours.LogonHours,
1313                        (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1314 
1315                 Ptr = (LPWSTR)((ULONG_PTR)Ptr + (((ULONG)UserInfo->LogonHours.UnitsPerWeek) + 7) / 8);
1316             }
1317 
1318             UserInfo11->usri11_code_page = UserInfo->CodePage;
1319             break;
1320 
1321         case 20:
1322             UserInfo20 = (PUSER_INFO_20)LocalBuffer;
1323 
1324             Ptr = (LPWSTR)((ULONG_PTR)UserInfo20 + sizeof(USER_INFO_20));
1325 
1326             UserInfo20->usri20_name = Ptr;
1327 
1328             memcpy(UserInfo20->usri20_name,
1329                    UserInfo->UserName.Buffer,
1330                    UserInfo->UserName.Length);
1331             UserInfo20->usri20_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1332 
1333             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
1334 
1335             UserInfo20->usri20_full_name = Ptr;
1336             memcpy(UserInfo20->usri20_full_name,
1337                    UserInfo->FullName.Buffer,
1338                    UserInfo->FullName.Length);
1339             UserInfo20->usri20_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1340             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
1341 
1342             UserInfo20->usri20_comment = Ptr;
1343             memcpy(UserInfo20->usri20_comment,
1344                    UserInfo->AdminComment.Buffer,
1345                    UserInfo->AdminComment.Length);
1346             UserInfo20->usri20_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1347             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
1348 
1349             UserInfo20->usri20_flags = GetAccountFlags(UserInfo->UserAccountControl,
1350                                                        Dacl);
1351 
1352             UserInfo20->usri20_user_id = RelativeId;
1353             break;
1354 
1355         case 23:
1356             UserInfo23 = (PUSER_INFO_23)LocalBuffer;
1357 
1358             Ptr = (LPWSTR)((ULONG_PTR)UserInfo23 + sizeof(USER_INFO_23));
1359 
1360             UserInfo23->usri23_name = Ptr;
1361 
1362             memcpy(UserInfo23->usri23_name,
1363                    UserInfo->UserName.Buffer,
1364                    UserInfo->UserName.Length);
1365             UserInfo23->usri23_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1366 
1367             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
1368 
1369             UserInfo23->usri23_full_name = Ptr;
1370             memcpy(UserInfo23->usri23_full_name,
1371                    UserInfo->FullName.Buffer,
1372                    UserInfo->FullName.Length);
1373             UserInfo23->usri23_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1374             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
1375 
1376             UserInfo23->usri23_comment = Ptr;
1377             memcpy(UserInfo23->usri23_comment,
1378                    UserInfo->AdminComment.Buffer,
1379                    UserInfo->AdminComment.Length);
1380             UserInfo23->usri23_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
1381             Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
1382 
1383             UserInfo23->usri23_flags = GetAccountFlags(UserInfo->UserAccountControl,
1384                                                        Dacl);
1385 
1386             UserInfo23->usri23_user_sid = (PVOID)Ptr;
1387             CopySidFromSidAndRid(UserInfo23->usri23_user_sid, AccountDomainSid, RelativeId);
1388             Ptr = (LPWSTR)((ULONG_PTR)Ptr + RtlLengthSid(AccountDomainSid) + sizeof(ULONG));
1389             break;
1390     }
1391 
1392 done:
1393     if (UserInfo != NULL)
1394         FreeUserInfo(UserInfo);
1395 
1396     if (Dacl != NULL)
1397         HeapFree(GetProcessHeap(), 0, Dacl);
1398 
1399     if (ApiStatus == NERR_Success)
1400     {
1401         *Buffer = LocalBuffer;
1402     }
1403     else
1404     {
1405         if (LocalBuffer != NULL)
1406             NetApiBufferFree(LocalBuffer);
1407     }
1408 
1409     return ApiStatus;
1410 }
1411 
1412 
1413 static
1414 NET_API_STATUS
SetUserInfo(SAM_HANDLE UserHandle,LPBYTE UserInfo,DWORD Level,PDWORD parm_err)1415 SetUserInfo(SAM_HANDLE UserHandle,
1416             LPBYTE UserInfo,
1417             DWORD Level,
1418             PDWORD parm_err)
1419 {
1420     USER_ALL_INFORMATION UserAllInfo;
1421     PUSER_INFO_0 UserInfo0;
1422     PUSER_INFO_1 UserInfo1;
1423     PUSER_INFO_2 UserInfo2;
1424     PUSER_INFO_3 UserInfo3;
1425     PUSER_INFO_4 UserInfo4;
1426     PUSER_INFO_22 UserInfo22;
1427     PUSER_INFO_1003 UserInfo1003;
1428     PUSER_INFO_1006 UserInfo1006;
1429     PUSER_INFO_1007 UserInfo1007;
1430     PUSER_INFO_1008 UserInfo1008;
1431     PUSER_INFO_1009 UserInfo1009;
1432     PUSER_INFO_1011 UserInfo1011;
1433     PUSER_INFO_1012 UserInfo1012;
1434     PUSER_INFO_1013 UserInfo1013;
1435     PUSER_INFO_1014 UserInfo1014;
1436     PUSER_INFO_1017 UserInfo1017;
1437     PUSER_INFO_1020 UserInfo1020;
1438     PUSER_INFO_1024 UserInfo1024;
1439     PUSER_INFO_1025 UserInfo1025;
1440     PUSER_INFO_1051 UserInfo1051;
1441     PUSER_INFO_1052 UserInfo1052;
1442     PUSER_INFO_1053 UserInfo1053;
1443     PACL Dacl = NULL;
1444     NET_API_STATUS ApiStatus = NERR_Success;
1445     NTSTATUS Status = STATUS_SUCCESS;
1446 
1447     ZeroMemory(&UserAllInfo, sizeof(USER_ALL_INFORMATION));
1448 
1449     if ((Level == 1) || (Level == 2) || (Level == 3) ||
1450         (Level == 4) || (Level == 22) || (Level == 1008))
1451     {
1452         ApiStatus = GetUserDacl(UserHandle, &Dacl);
1453         if (ApiStatus != NERR_Success)
1454             goto done;
1455     }
1456 
1457     switch (Level)
1458     {
1459         case 0:
1460             UserInfo0 = (PUSER_INFO_0)UserInfo;
1461 
1462             RtlInitUnicodeString(&UserAllInfo.UserName,
1463                                  UserInfo0->usri0_name);
1464 
1465             UserAllInfo.WhichFields |= USER_ALL_USERNAME;
1466             break;
1467 
1468         case 1:
1469             UserInfo1 = (PUSER_INFO_1)UserInfo;
1470 
1471             // usri1_name ignored
1472 
1473             if (UserInfo1->usri1_password != NULL)
1474             {
1475                 RtlInitUnicodeString(&UserAllInfo.NtPassword,
1476                                      UserInfo1->usri1_password);
1477                 UserAllInfo.NtPasswordPresent = TRUE;
1478                 UserAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;
1479             }
1480 
1481             // usri1_password_age ignored
1482 
1483 //          UserInfo1->usri1_priv
1484 
1485             if (UserInfo1->usri1_home_dir != NULL)
1486             {
1487                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
1488                                      UserInfo1->usri1_home_dir);
1489                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
1490             }
1491 
1492             if (UserInfo1->usri1_comment != NULL)
1493             {
1494                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
1495                                      UserInfo1->usri1_comment);
1496                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
1497             }
1498 
1499             ChangeUserDacl(Dacl, UserInfo1->usri1_flags);
1500             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo1->usri1_flags);
1501             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
1502 
1503             if (UserInfo1->usri1_script_path != NULL)
1504             {
1505                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
1506                                      UserInfo1->usri1_script_path);
1507                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
1508             }
1509             break;
1510 
1511         case 2:
1512             UserInfo2 = (PUSER_INFO_2)UserInfo;
1513 
1514             // usri2_name ignored
1515 
1516             if (UserInfo2->usri2_password != NULL)
1517             {
1518                 RtlInitUnicodeString(&UserAllInfo.NtPassword,
1519                                      UserInfo2->usri2_password);
1520                 UserAllInfo.NtPasswordPresent = TRUE;
1521                 UserAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;
1522             }
1523 
1524             // usri2_password_age ignored
1525 
1526 //          UserInfo2->usri2_priv;
1527 
1528             if (UserInfo2->usri2_home_dir != NULL)
1529             {
1530                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
1531                                      UserInfo2->usri2_home_dir);
1532                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
1533             }
1534 
1535             if (UserInfo2->usri2_comment != NULL)
1536             {
1537                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
1538                                      UserInfo2->usri2_comment);
1539                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
1540             }
1541 
1542             ChangeUserDacl(Dacl, UserInfo2->usri2_flags);
1543             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo2->usri2_flags);
1544             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
1545 
1546             if (UserInfo2->usri2_script_path != NULL)
1547             {
1548                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
1549                                      UserInfo2->usri2_script_path);
1550                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
1551             }
1552 
1553 //          UserInfo2->usri2_auth_flags;
1554 
1555             if (UserInfo2->usri2_full_name != NULL)
1556             {
1557                 RtlInitUnicodeString(&UserAllInfo.FullName,
1558                                      UserInfo2->usri2_full_name);
1559                 UserAllInfo.WhichFields |= USER_ALL_FULLNAME;
1560             }
1561 
1562             if (UserInfo2->usri2_usr_comment != NULL)
1563             {
1564                 RtlInitUnicodeString(&UserAllInfo.UserComment,
1565                                      UserInfo2->usri2_usr_comment);
1566                 UserAllInfo.WhichFields |= USER_ALL_USERCOMMENT;
1567             }
1568 
1569             if (UserInfo2->usri2_parms != NULL)
1570             {
1571                 RtlInitUnicodeString(&UserAllInfo.Parameters,
1572                                      UserInfo2->usri2_parms);
1573                 UserAllInfo.WhichFields |= USER_ALL_PARAMETERS;
1574             }
1575 
1576             if (UserInfo2->usri2_workstations != NULL)
1577             {
1578                 RtlInitUnicodeString(&UserAllInfo.WorkStations,
1579                                      UserInfo2->usri2_workstations);
1580                 UserAllInfo.WhichFields |= USER_ALL_WORKSTATIONS;
1581             }
1582 
1583             // usri2_last_logon ignored
1584             // usri2_last_logoff ignored
1585 
1586             if (UserInfo2->usri2_acct_expires == TIMEQ_FOREVER)
1587             {
1588                 UserAllInfo.AccountExpires.QuadPart = MAXLONGLONG;
1589             }
1590             else
1591             {
1592                 RtlSecondsSince1970ToTime(UserInfo2->usri2_acct_expires,
1593                                           &UserAllInfo.AccountExpires);
1594             }
1595             UserAllInfo.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
1596 
1597             // usri2_max_storage ignored
1598 
1599             if (UserInfo2->usri2_logon_hours != NULL)
1600             {
1601                 if (UserInfo2->usri2_units_per_week > USHRT_MAX)
1602                 {
1603                     if (parm_err != NULL)
1604                         *parm_err = USER_UNITS_PER_WEEK_PARMNUM;
1605                     ApiStatus = ERROR_INVALID_PARAMETER;
1606                     break;
1607                 }
1608 
1609                 UserAllInfo.LogonHours.UnitsPerWeek = UserInfo2->usri2_units_per_week;
1610                 UserAllInfo.LogonHours.LogonHours = UserInfo2->usri2_logon_hours;
1611                 UserAllInfo.WhichFields |= USER_ALL_LOGONHOURS;
1612             }
1613 
1614             // usri2_bad_pw_count ignored
1615             // usri2_num_logons ignored
1616             // usri2_logon_server ignored
1617 
1618             UserAllInfo.CountryCode = UserInfo2->usri2_country_code;
1619             UserAllInfo.WhichFields |= USER_ALL_COUNTRYCODE;
1620 
1621             UserAllInfo.CodePage = UserInfo2->usri2_code_page;
1622             UserAllInfo.WhichFields |= USER_ALL_CODEPAGE;
1623             break;
1624 
1625         case 3:
1626             UserInfo3 = (PUSER_INFO_3)UserInfo;
1627 
1628             // usri3_name ignored
1629 
1630             if (UserInfo3->usri3_password != NULL)
1631             {
1632                 RtlInitUnicodeString(&UserAllInfo.NtPassword,
1633                                      UserInfo3->usri3_password);
1634                 UserAllInfo.NtPasswordPresent = TRUE;
1635                 UserAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;
1636             }
1637 
1638             // usri3_password_age ignored
1639 
1640 //          UserInfo3->usri3_priv;
1641 
1642             if (UserInfo3->usri3_home_dir != NULL)
1643             {
1644                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
1645                                      UserInfo3->usri3_home_dir);
1646                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
1647             }
1648 
1649             if (UserInfo3->usri3_comment != NULL)
1650             {
1651                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
1652                                      UserInfo3->usri3_comment);
1653                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
1654             }
1655 
1656             ChangeUserDacl(Dacl, UserInfo3->usri3_flags);
1657             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo3->usri3_flags);
1658             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
1659 
1660             if (UserInfo3->usri3_script_path != NULL)
1661             {
1662                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
1663                                      UserInfo3->usri3_script_path);
1664                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
1665             }
1666 
1667 //          UserInfo3->usri3_auth_flags;
1668 
1669             if (UserInfo3->usri3_full_name != NULL)
1670             {
1671                 RtlInitUnicodeString(&UserAllInfo.FullName,
1672                                      UserInfo3->usri3_full_name);
1673                 UserAllInfo.WhichFields |= USER_ALL_FULLNAME;
1674             }
1675 
1676             if (UserInfo3->usri3_usr_comment != NULL)
1677             {
1678                 RtlInitUnicodeString(&UserAllInfo.UserComment,
1679                                      UserInfo3->usri3_usr_comment);
1680                 UserAllInfo.WhichFields |= USER_ALL_USERCOMMENT;
1681             }
1682 
1683             if (UserInfo3->usri3_parms != NULL)
1684             {
1685                 RtlInitUnicodeString(&UserAllInfo.Parameters,
1686                                      UserInfo3->usri3_parms);
1687                 UserAllInfo.WhichFields |= USER_ALL_PARAMETERS;
1688             }
1689 
1690             if (UserInfo3->usri3_workstations != NULL)
1691             {
1692                 RtlInitUnicodeString(&UserAllInfo.WorkStations,
1693                                      UserInfo3->usri3_workstations);
1694                 UserAllInfo.WhichFields |= USER_ALL_WORKSTATIONS;
1695             }
1696 
1697             // usri3_last_logon ignored
1698             // usri3_last_logoff ignored
1699 
1700             if (UserInfo3->usri3_acct_expires == TIMEQ_FOREVER)
1701             {
1702                 UserAllInfo.AccountExpires.QuadPart = MAXLONGLONG;
1703             }
1704             else
1705             {
1706                 RtlSecondsSince1970ToTime(UserInfo3->usri3_acct_expires,
1707                                           &UserAllInfo.AccountExpires);
1708             }
1709             UserAllInfo.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
1710 
1711             // usri3_max_storage ignored
1712 
1713             if (UserInfo3->usri3_logon_hours != NULL)
1714             {
1715                 if (UserInfo3->usri3_units_per_week > USHRT_MAX)
1716                 {
1717                     if (parm_err != NULL)
1718                         *parm_err = USER_UNITS_PER_WEEK_PARMNUM;
1719                     ApiStatus = ERROR_INVALID_PARAMETER;
1720                     break;
1721                 }
1722 
1723                 UserAllInfo.LogonHours.UnitsPerWeek = UserInfo3->usri3_units_per_week;
1724                 UserAllInfo.LogonHours.LogonHours = UserInfo3->usri3_logon_hours;
1725                 UserAllInfo.WhichFields |= USER_ALL_LOGONHOURS;
1726             }
1727 
1728             // usri3_bad_pw_count ignored
1729             // usri3_num_logons ignored
1730             // usri3_logon_server ignored
1731 
1732             UserAllInfo.CountryCode = UserInfo3->usri3_country_code;
1733             UserAllInfo.WhichFields |= USER_ALL_COUNTRYCODE;
1734 
1735             UserAllInfo.CodePage = UserInfo3->usri3_code_page;
1736             UserAllInfo.WhichFields |= USER_ALL_CODEPAGE;
1737 
1738             // usri3_user_id ignored
1739 
1740             UserAllInfo.PrimaryGroupId = UserInfo3->usri3_primary_group_id;
1741             UserAllInfo.WhichFields |= USER_ALL_PRIMARYGROUPID;
1742 
1743             if (UserInfo3->usri3_profile != NULL)
1744             {
1745                 RtlInitUnicodeString(&UserAllInfo.ProfilePath,
1746                                      UserInfo3->usri3_profile);
1747                 UserAllInfo.WhichFields |= USER_ALL_PROFILEPATH;
1748             }
1749 
1750             if (UserInfo3->usri3_home_dir_drive != NULL)
1751             {
1752                 RtlInitUnicodeString(&UserAllInfo.HomeDirectoryDrive,
1753                                      UserInfo3->usri3_home_dir_drive);
1754                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORYDRIVE;
1755             }
1756 
1757             UserAllInfo.PasswordExpired = (UserInfo3->usri3_password_expired != 0);
1758             UserAllInfo.WhichFields |= USER_ALL_PASSWORDEXPIRED;
1759             break;
1760 
1761         case 4:
1762             UserInfo4 = (PUSER_INFO_4)UserInfo;
1763 
1764             // usri4_name ignored
1765 
1766             if (UserInfo4->usri4_password != NULL)
1767             {
1768                 RtlInitUnicodeString(&UserAllInfo.NtPassword,
1769                                      UserInfo4->usri4_password);
1770                 UserAllInfo.NtPasswordPresent = TRUE;
1771                 UserAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;
1772             }
1773 
1774             // usri4_password_age ignored
1775 
1776 //          UserInfo3->usri4_priv;
1777 
1778             if (UserInfo4->usri4_home_dir != NULL)
1779             {
1780                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
1781                                      UserInfo4->usri4_home_dir);
1782                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
1783             }
1784 
1785             if (UserInfo4->usri4_comment != NULL)
1786             {
1787                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
1788                                      UserInfo4->usri4_comment);
1789                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
1790             }
1791 
1792             ChangeUserDacl(Dacl, UserInfo4->usri4_flags);
1793             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo4->usri4_flags);
1794             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
1795 
1796             if (UserInfo4->usri4_script_path != NULL)
1797             {
1798                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
1799                                      UserInfo4->usri4_script_path);
1800                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
1801             }
1802 
1803 //          UserInfo4->usri4_auth_flags;
1804 
1805             if (UserInfo4->usri4_full_name != NULL)
1806             {
1807                 RtlInitUnicodeString(&UserAllInfo.FullName,
1808                                      UserInfo4->usri4_full_name);
1809                 UserAllInfo.WhichFields |= USER_ALL_FULLNAME;
1810             }
1811 
1812             if (UserInfo4->usri4_usr_comment != NULL)
1813             {
1814                 RtlInitUnicodeString(&UserAllInfo.UserComment,
1815                                      UserInfo4->usri4_usr_comment);
1816                 UserAllInfo.WhichFields |= USER_ALL_USERCOMMENT;
1817             }
1818 
1819             if (UserInfo4->usri4_parms != NULL)
1820             {
1821                 RtlInitUnicodeString(&UserAllInfo.Parameters,
1822                                      UserInfo4->usri4_parms);
1823                 UserAllInfo.WhichFields |= USER_ALL_PARAMETERS;
1824             }
1825 
1826             if (UserInfo4->usri4_workstations != NULL)
1827             {
1828                 RtlInitUnicodeString(&UserAllInfo.WorkStations,
1829                                      UserInfo4->usri4_workstations);
1830                 UserAllInfo.WhichFields |= USER_ALL_WORKSTATIONS;
1831             }
1832 
1833             // usri4_last_logon ignored
1834             // usri4_last_logoff ignored
1835 
1836             if (UserInfo4->usri4_acct_expires == TIMEQ_FOREVER)
1837             {
1838                 UserAllInfo.AccountExpires.QuadPart = MAXLONGLONG;
1839             }
1840             else
1841             {
1842                 RtlSecondsSince1970ToTime(UserInfo4->usri4_acct_expires,
1843                                           &UserAllInfo.AccountExpires);
1844             }
1845             UserAllInfo.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
1846 
1847             // usri4_max_storage ignored
1848 
1849             if (UserInfo4->usri4_logon_hours != NULL)
1850             {
1851                 if (UserInfo4->usri4_units_per_week > USHRT_MAX)
1852                 {
1853                     if (parm_err != NULL)
1854                         *parm_err = USER_UNITS_PER_WEEK_PARMNUM;
1855                     ApiStatus = ERROR_INVALID_PARAMETER;
1856                     break;
1857                 }
1858 
1859                 UserAllInfo.LogonHours.UnitsPerWeek = UserInfo4->usri4_units_per_week;
1860                 UserAllInfo.LogonHours.LogonHours = UserInfo4->usri4_logon_hours;
1861                 UserAllInfo.WhichFields |= USER_ALL_LOGONHOURS;
1862             }
1863 
1864             // usri4_bad_pw_count ignored
1865             // usri4_num_logons ignored
1866             // usri4_logon_server ignored
1867 
1868             UserAllInfo.CountryCode = UserInfo4->usri4_country_code;
1869             UserAllInfo.WhichFields |= USER_ALL_COUNTRYCODE;
1870 
1871             UserAllInfo.CodePage = UserInfo4->usri4_code_page;
1872             UserAllInfo.WhichFields |= USER_ALL_CODEPAGE;
1873 
1874             // usri4_user_sid ignored
1875 
1876             UserAllInfo.PrimaryGroupId = UserInfo4->usri4_primary_group_id;
1877             UserAllInfo.WhichFields |= USER_ALL_PRIMARYGROUPID;
1878 
1879             if (UserInfo4->usri4_profile != NULL)
1880             {
1881                 RtlInitUnicodeString(&UserAllInfo.ProfilePath,
1882                                      UserInfo4->usri4_profile);
1883                 UserAllInfo.WhichFields |= USER_ALL_PROFILEPATH;
1884             }
1885 
1886             if (UserInfo4->usri4_home_dir_drive != NULL)
1887             {
1888                 RtlInitUnicodeString(&UserAllInfo.HomeDirectoryDrive,
1889                                      UserInfo4->usri4_home_dir_drive);
1890                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORYDRIVE;
1891             }
1892 
1893             UserAllInfo.PasswordExpired = (UserInfo4->usri4_password_expired != 0);
1894             UserAllInfo.WhichFields |= USER_ALL_PASSWORDEXPIRED;
1895             break;
1896 
1897 //        case 21:
1898 //            break;
1899 
1900         case 22:
1901             UserInfo22 = (PUSER_INFO_22)UserInfo;
1902 
1903             // usri22_name ignored
1904 
1905 //          UserInfo22->usri22_password[ENCRYPTED_PWLEN];
1906 
1907             // usri22_password_age ignored
1908 
1909 //          UserInfo3->usri3_priv;
1910 
1911             if (UserInfo22->usri22_home_dir != NULL)
1912             {
1913                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
1914                                      UserInfo22->usri22_home_dir);
1915                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
1916             }
1917 
1918             if (UserInfo22->usri22_comment != NULL)
1919             {
1920                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
1921                                      UserInfo22->usri22_comment);
1922                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
1923             }
1924 
1925             ChangeUserDacl(Dacl, UserInfo22->usri22_flags);
1926             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo22->usri22_flags);
1927             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
1928 
1929             if (UserInfo22->usri22_script_path != NULL)
1930             {
1931                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
1932                                      UserInfo22->usri22_script_path);
1933                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
1934             }
1935 
1936 //          UserInfo22->usri22_auth_flags;
1937 
1938             if (UserInfo22->usri22_full_name != NULL)
1939             {
1940                 RtlInitUnicodeString(&UserAllInfo.FullName,
1941                                      UserInfo22->usri22_full_name);
1942                 UserAllInfo.WhichFields |= USER_ALL_FULLNAME;
1943             }
1944 
1945             if (UserInfo22->usri22_usr_comment != NULL)
1946             {
1947                 RtlInitUnicodeString(&UserAllInfo.UserComment,
1948                                      UserInfo22->usri22_usr_comment);
1949                 UserAllInfo.WhichFields |= USER_ALL_USERCOMMENT;
1950             }
1951 
1952             if (UserInfo22->usri22_parms != NULL)
1953             {
1954                 RtlInitUnicodeString(&UserAllInfo.Parameters,
1955                                      UserInfo22->usri22_parms);
1956                 UserAllInfo.WhichFields |= USER_ALL_PARAMETERS;
1957             }
1958 
1959             if (UserInfo22->usri22_workstations != NULL)
1960             {
1961                 RtlInitUnicodeString(&UserAllInfo.WorkStations,
1962                                      UserInfo22->usri22_workstations);
1963                 UserAllInfo.WhichFields |= USER_ALL_WORKSTATIONS;
1964             }
1965 
1966             // usri22_last_logon ignored
1967             // usri22_last_logoff ignored
1968 
1969             if (UserInfo22->usri22_acct_expires == TIMEQ_FOREVER)
1970             {
1971                 UserAllInfo.AccountExpires.QuadPart = MAXLONGLONG;
1972             }
1973             else
1974             {
1975                 RtlSecondsSince1970ToTime(UserInfo22->usri22_acct_expires,
1976                                           &UserAllInfo.AccountExpires);
1977             }
1978             UserAllInfo.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
1979 
1980             // usri22_max_storage ignored
1981 
1982             if (UserInfo22->usri22_logon_hours != NULL)
1983             {
1984                 if (UserInfo22->usri22_units_per_week > USHRT_MAX)
1985                 {
1986                     if (parm_err != NULL)
1987                         *parm_err = USER_UNITS_PER_WEEK_PARMNUM;
1988                     ApiStatus = ERROR_INVALID_PARAMETER;
1989                     break;
1990                 }
1991 
1992                 UserAllInfo.LogonHours.UnitsPerWeek = UserInfo22->usri22_units_per_week;
1993                 UserAllInfo.LogonHours.LogonHours = UserInfo22->usri22_logon_hours;
1994                 UserAllInfo.WhichFields |= USER_ALL_LOGONHOURS;
1995             }
1996 
1997             // usri22_bad_pw_count ignored
1998             // usri22_num_logons ignored
1999             // usri22_logon_server ignored
2000 
2001             UserAllInfo.CountryCode = UserInfo22->usri22_country_code;
2002             UserAllInfo.WhichFields |= USER_ALL_COUNTRYCODE;
2003 
2004             UserAllInfo.CodePage = UserInfo22->usri22_code_page;
2005             UserAllInfo.WhichFields |= USER_ALL_CODEPAGE;
2006             break;
2007 
2008         case 1003:
2009             UserInfo1003 = (PUSER_INFO_1003)UserInfo;
2010 
2011             if (UserInfo1003->usri1003_password != NULL)
2012             {
2013                 RtlInitUnicodeString(&UserAllInfo.NtPassword,
2014                                      UserInfo1003->usri1003_password);
2015                 UserAllInfo.NtPasswordPresent = TRUE;
2016                 UserAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;
2017             }
2018             break;
2019 
2020 //        case 1005:
2021 //            break;
2022 
2023         case 1006:
2024             UserInfo1006 = (PUSER_INFO_1006)UserInfo;
2025 
2026             if (UserInfo1006->usri1006_home_dir != NULL)
2027             {
2028                 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
2029                                      UserInfo1006->usri1006_home_dir);
2030                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORY;
2031             }
2032             break;
2033 
2034         case 1007:
2035             UserInfo1007 = (PUSER_INFO_1007)UserInfo;
2036 
2037             if (UserInfo1007->usri1007_comment != NULL)
2038             {
2039                 RtlInitUnicodeString(&UserAllInfo.AdminComment,
2040                                      UserInfo1007->usri1007_comment);
2041                 UserAllInfo.WhichFields |= USER_ALL_ADMINCOMMENT;
2042             }
2043             break;
2044 
2045         case 1008:
2046             UserInfo1008 = (PUSER_INFO_1008)UserInfo;
2047             ChangeUserDacl(Dacl, UserInfo1008->usri1008_flags);
2048             UserAllInfo.UserAccountControl = GetAccountControl(UserInfo1008->usri1008_flags);
2049             UserAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
2050             break;
2051 
2052         case 1009:
2053             UserInfo1009 = (PUSER_INFO_1009)UserInfo;
2054 
2055             if (UserInfo1009->usri1009_script_path != NULL)
2056             {
2057                 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
2058                                      UserInfo1009->usri1009_script_path);
2059                 UserAllInfo.WhichFields |= USER_ALL_SCRIPTPATH;
2060             }
2061             break;
2062 
2063 //        case 1010:
2064 //            break;
2065 
2066         case 1011:
2067             UserInfo1011 = (PUSER_INFO_1011)UserInfo;
2068 
2069             if (UserInfo1011->usri1011_full_name != NULL)
2070             {
2071                 RtlInitUnicodeString(&UserAllInfo.FullName,
2072                                      UserInfo1011->usri1011_full_name);
2073                 UserAllInfo.WhichFields |= USER_ALL_FULLNAME;
2074             }
2075             break;
2076 
2077         case 1012:
2078             UserInfo1012 = (PUSER_INFO_1012)UserInfo;
2079 
2080             if (UserInfo1012->usri1012_usr_comment != NULL)
2081             {
2082                 RtlInitUnicodeString(&UserAllInfo.UserComment,
2083                                      UserInfo1012->usri1012_usr_comment);
2084                 UserAllInfo.WhichFields |= USER_ALL_USERCOMMENT;
2085             }
2086             break;
2087 
2088         case 1013:
2089             UserInfo1013 = (PUSER_INFO_1013)UserInfo;
2090 
2091             if (UserInfo1013->usri1013_parms != NULL)
2092             {
2093                 RtlInitUnicodeString(&UserAllInfo.Parameters,
2094                                      UserInfo1013->usri1013_parms);
2095                 UserAllInfo.WhichFields |= USER_ALL_PARAMETERS;
2096             }
2097             break;
2098 
2099         case 1014:
2100             UserInfo1014 = (PUSER_INFO_1014)UserInfo;
2101 
2102             if (UserInfo1014->usri1014_workstations != NULL)
2103             {
2104                 RtlInitUnicodeString(&UserAllInfo.WorkStations,
2105                                      UserInfo1014->usri1014_workstations);
2106                 UserAllInfo.WhichFields |= USER_ALL_WORKSTATIONS;
2107             }
2108             break;
2109 
2110         case 1017:
2111             UserInfo1017 = (PUSER_INFO_1017)UserInfo;
2112 
2113             if (UserInfo1017->usri1017_acct_expires == TIMEQ_FOREVER)
2114             {
2115                 UserAllInfo.AccountExpires.QuadPart = MAXLONGLONG;
2116             }
2117             else
2118             {
2119                 RtlSecondsSince1970ToTime(UserInfo1017->usri1017_acct_expires,
2120                                           &UserAllInfo.AccountExpires);
2121             }
2122             UserAllInfo.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
2123             break;
2124 
2125         case 1018:
2126             // usri1018_max_storage ignored
2127             break;
2128 
2129         case 1020:
2130             UserInfo1020 = (PUSER_INFO_1020)UserInfo;
2131 
2132             if (UserInfo1020->usri1020_logon_hours != NULL)
2133             {
2134                 if (UserInfo1020->usri1020_units_per_week > USHRT_MAX)
2135                 {
2136                     if (parm_err != NULL)
2137                         *parm_err = USER_UNITS_PER_WEEK_PARMNUM;
2138                     ApiStatus = ERROR_INVALID_PARAMETER;
2139                     break;
2140                 }
2141 
2142                 UserAllInfo.LogonHours.UnitsPerWeek = UserInfo1020->usri1020_units_per_week;
2143                 UserAllInfo.LogonHours.LogonHours = UserInfo1020->usri1020_logon_hours;
2144                 UserAllInfo.WhichFields |= USER_ALL_LOGONHOURS;
2145             }
2146             break;
2147 
2148         case 1024:
2149             UserInfo1024 = (PUSER_INFO_1024)UserInfo;
2150 
2151             UserAllInfo.CountryCode = UserInfo1024->usri1024_country_code;
2152             UserAllInfo.WhichFields |= USER_ALL_COUNTRYCODE;
2153             break;
2154 
2155         case 1025:
2156             UserInfo1025 = (PUSER_INFO_1025)UserInfo;
2157 
2158             UserAllInfo.CodePage = UserInfo1025->usri1025_code_page;
2159             UserAllInfo.WhichFields |= USER_ALL_CODEPAGE;
2160             break;
2161 
2162         case 1051:
2163             UserInfo1051 = (PUSER_INFO_1051)UserInfo;
2164 
2165             UserAllInfo.PrimaryGroupId = UserInfo1051->usri1051_primary_group_id;
2166             UserAllInfo.WhichFields |= USER_ALL_PRIMARYGROUPID;
2167             break;
2168 
2169         case 1052:
2170             UserInfo1052 = (PUSER_INFO_1052)UserInfo;
2171 
2172             if (UserInfo1052->usri1052_profile != NULL)
2173             {
2174                 RtlInitUnicodeString(&UserAllInfo.ProfilePath,
2175                                      UserInfo1052->usri1052_profile);
2176                 UserAllInfo.WhichFields |= USER_ALL_PROFILEPATH;
2177             }
2178             break;
2179 
2180         case 1053:
2181             UserInfo1053 = (PUSER_INFO_1053)UserInfo;
2182 
2183             if (UserInfo1053->usri1053_home_dir_drive != NULL)
2184             {
2185                 RtlInitUnicodeString(&UserAllInfo.HomeDirectoryDrive,
2186                                      UserInfo1053->usri1053_home_dir_drive);
2187                 UserAllInfo.WhichFields |= USER_ALL_HOMEDIRECTORYDRIVE;
2188             }
2189             break;
2190     }
2191 
2192     if (ApiStatus != NERR_Success)
2193         goto done;
2194 
2195     Status = SamSetInformationUser(UserHandle,
2196                                    UserAllInformation,
2197                                    &UserAllInfo);
2198     if (!NT_SUCCESS(Status))
2199     {
2200         ERR("SamSetInformationUser failed (Status %08lx)\n", Status);
2201         ApiStatus = NetpNtStatusToApiStatus(Status);
2202         goto done;
2203     }
2204 
2205 done:
2206     if (Dacl != NULL)
2207         HeapFree(GetProcessHeap(), 0, Dacl);
2208 
2209     return ApiStatus;
2210 }
2211 
2212 
2213 static
2214 NET_API_STATUS
OpenUserByName(SAM_HANDLE DomainHandle,PUNICODE_STRING UserName,ULONG DesiredAccess,PSAM_HANDLE UserHandle)2215 OpenUserByName(SAM_HANDLE DomainHandle,
2216                PUNICODE_STRING UserName,
2217                ULONG DesiredAccess,
2218                PSAM_HANDLE UserHandle)
2219 {
2220     PULONG RelativeIds = NULL;
2221     PSID_NAME_USE Use = NULL;
2222     NET_API_STATUS ApiStatus = NERR_Success;
2223     NTSTATUS Status = STATUS_SUCCESS;
2224 
2225     /* Get the RID for the given user name */
2226     Status = SamLookupNamesInDomain(DomainHandle,
2227                                     1,
2228                                     UserName,
2229                                     &RelativeIds,
2230                                     &Use);
2231     if (!NT_SUCCESS(Status))
2232     {
2233         ERR("SamLookupNamesInDomain(%wZ) failed (Status %08lx)\n", UserName, Status);
2234         return NetpNtStatusToApiStatus(Status);
2235     }
2236 
2237     /* Fail, if it is not an alias account */
2238     if (Use[0] != SidTypeUser)
2239     {
2240         ERR("Object is not a user!\n");
2241         ApiStatus = NERR_GroupNotFound;
2242         goto done;
2243     }
2244 
2245     /* Open the alias account */
2246     Status = SamOpenUser(DomainHandle,
2247                          DesiredAccess,
2248                          RelativeIds[0],
2249                          UserHandle);
2250     if (!NT_SUCCESS(Status))
2251     {
2252         ERR("SamOpenUser failed (Status %08lx)\n", Status);
2253         ApiStatus = NetpNtStatusToApiStatus(Status);
2254         goto done;
2255     }
2256 
2257 done:
2258     if (RelativeIds != NULL)
2259         SamFreeMemory(RelativeIds);
2260 
2261     if (Use != NULL)
2262         SamFreeMemory(Use);
2263 
2264     return ApiStatus;
2265 }
2266 
2267 
2268 /************************************************************
2269  * NetUserAdd (NETAPI32.@)
2270  */
2271 NET_API_STATUS
2272 WINAPI
NetUserAdd(LPCWSTR servername,DWORD level,LPBYTE bufptr,LPDWORD parm_err)2273 NetUserAdd(LPCWSTR servername,
2274            DWORD level,
2275            LPBYTE bufptr,
2276            LPDWORD parm_err)
2277 {
2278     UNICODE_STRING ServerName;
2279     UNICODE_STRING UserName;
2280     SAM_HANDLE ServerHandle = NULL;
2281     SAM_HANDLE DomainHandle = NULL;
2282     SAM_HANDLE UserHandle = NULL;
2283     ULONG GrantedAccess;
2284     ULONG RelativeId;
2285     NET_API_STATUS ApiStatus = NERR_Success;
2286     NTSTATUS Status = STATUS_SUCCESS;
2287 
2288     TRACE("(%s, %d, %p, %p)\n", debugstr_w(servername), level, bufptr, parm_err);
2289 
2290     if (parm_err != NULL)
2291         *parm_err = PARM_ERROR_NONE;
2292 
2293     /* Check the info level */
2294     switch (level)
2295     {
2296         case 1:
2297         case 2:
2298         case 3:
2299         case 4:
2300             break;
2301 
2302         default:
2303             return ERROR_INVALID_LEVEL;
2304     }
2305 
2306     if (servername != NULL)
2307         RtlInitUnicodeString(&ServerName, servername);
2308 
2309     /* Connect to the SAM Server */
2310     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
2311                         &ServerHandle,
2312                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
2313                         NULL);
2314     if (!NT_SUCCESS(Status))
2315     {
2316         ERR("SamConnect failed (Status %08lx)\n", Status);
2317         ApiStatus = NetpNtStatusToApiStatus(Status);
2318         goto done;
2319     }
2320 
2321     /* Open the Account Domain */
2322     Status = OpenAccountDomain(ServerHandle,
2323                                (servername != NULL) ? &ServerName : NULL,
2324                                DOMAIN_CREATE_USER | DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS,
2325                                &DomainHandle);
2326     if (!NT_SUCCESS(Status))
2327     {
2328         ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
2329         ApiStatus = NetpNtStatusToApiStatus(Status);
2330         goto done;
2331     }
2332 
2333     /* Initialize the user name string */
2334     RtlInitUnicodeString(&UserName,
2335                          ((PUSER_INFO_1)bufptr)->usri1_name);
2336 
2337     /* Create the user account */
2338     Status = SamCreateUser2InDomain(DomainHandle,
2339                                     &UserName,
2340                                     USER_NORMAL_ACCOUNT,
2341                                     USER_ALL_ACCESS | DELETE | WRITE_DAC,
2342                                     &UserHandle,
2343                                     &GrantedAccess,
2344                                     &RelativeId);
2345     if (!NT_SUCCESS(Status))
2346     {
2347         ERR("SamCreateUser2InDomain failed (Status %08lx)\n", Status);
2348         ApiStatus = NetpNtStatusToApiStatus(Status);
2349         goto done;
2350     }
2351 
2352     /* Set user information */
2353     ApiStatus = SetUserInfo(UserHandle,
2354                             bufptr,
2355                             level,
2356                             parm_err);
2357     if (ApiStatus != NERR_Success)
2358     {
2359         ERR("SetUserInfo failed (Status %lu)\n", ApiStatus);
2360         goto done;
2361     }
2362 
2363 done:
2364     if (UserHandle != NULL)
2365     {
2366         if (ApiStatus != NERR_Success)
2367             SamDeleteUser(UserHandle);
2368         else
2369             SamCloseHandle(UserHandle);
2370     }
2371 
2372     if (DomainHandle != NULL)
2373         SamCloseHandle(DomainHandle);
2374 
2375     if (ServerHandle != NULL)
2376         SamCloseHandle(ServerHandle);
2377 
2378     return ApiStatus;
2379 }
2380 
2381 
2382 /******************************************************************************
2383  *                NetUserChangePassword  (NETAPI32.@)
2384  * PARAMS
2385  *  domainname  [I] Optional. Domain on which the user resides or the logon
2386  *                  domain of the current user if NULL.
2387  *  username    [I] Optional. Username to change the password for or the name
2388  *                  of the current user if NULL.
2389  *  oldpassword [I] The user's current password.
2390  *  newpassword [I] The password that the user will be changed to using.
2391  *
2392  * RETURNS
2393  *  Success: NERR_Success.
2394  *  Failure: NERR_* failure code or win error code.
2395  *
2396  */
2397 NET_API_STATUS
2398 WINAPI
NetUserChangePassword(LPCWSTR domainname,LPCWSTR username,LPCWSTR oldpassword,LPCWSTR newpassword)2399 NetUserChangePassword(LPCWSTR domainname,
2400                       LPCWSTR username,
2401                       LPCWSTR oldpassword,
2402                       LPCWSTR newpassword)
2403 {
2404     PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer = NULL;
2405     PMSV1_0_CHANGEPASSWORD_RESPONSE ResponseBuffer = NULL;
2406     ULONG RequestBufferSize;
2407     ULONG ResponseBufferSize = 0;
2408     LPWSTR Ptr;
2409     ANSI_STRING PackageName;
2410     ULONG AuthenticationPackage = 0;
2411     HANDLE LsaHandle = NULL;
2412     NET_API_STATUS ApiStatus = NERR_Success;
2413     NTSTATUS Status = STATUS_SUCCESS;
2414     NTSTATUS ProtocolStatus;
2415 
2416     TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname), debugstr_w(username));
2417 
2418     /* FIXME: handle null domain or user name */
2419 
2420     /* Check the parameters */
2421     if ((oldpassword == NULL) ||
2422         (newpassword == NULL))
2423         return ERROR_INVALID_PARAMETER;
2424 
2425     /* Connect to the LSA server */
2426     Status = LsaConnectUntrusted(&LsaHandle);
2427     if (!NT_SUCCESS(Status))
2428         return NetpNtStatusToApiStatus(Status);
2429 
2430     /* Get the authentication package ID */
2431     RtlInitAnsiString(&PackageName,
2432                       MSV1_0_PACKAGE_NAME);
2433 
2434     Status = LsaLookupAuthenticationPackage(LsaHandle,
2435                                             &PackageName,
2436                                             &AuthenticationPackage);
2437     if (!NT_SUCCESS(Status))
2438     {
2439         ApiStatus = NetpNtStatusToApiStatus(Status);
2440         goto done;
2441     }
2442 
2443     /* Calculate the request buffer size */
2444     RequestBufferSize = sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) +
2445                         ((wcslen(domainname) + 1) * sizeof(WCHAR)) +
2446                         ((wcslen(username) + 1) * sizeof(WCHAR)) +
2447                         ((wcslen(oldpassword) + 1) * sizeof(WCHAR)) +
2448                         ((wcslen(newpassword) + 1) * sizeof(WCHAR));
2449 
2450     /* Allocate the request buffer */
2451     ApiStatus = NetApiBufferAllocate(RequestBufferSize,
2452                                      (PVOID*)&RequestBuffer);
2453     if (ApiStatus != NERR_Success)
2454         goto done;
2455 
2456     /* Initialize the request buffer */
2457     RequestBuffer->MessageType = MsV1_0ChangePassword;
2458     RequestBuffer->Impersonating = TRUE;
2459 
2460     Ptr = (LPWSTR)((ULONG_PTR)RequestBuffer + sizeof(MSV1_0_CHANGEPASSWORD_REQUEST));
2461 
2462     /* Pack the domain name */
2463     RequestBuffer->DomainName.Length = wcslen(domainname) * sizeof(WCHAR);
2464     RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length + sizeof(WCHAR);
2465     RequestBuffer->DomainName.Buffer = Ptr;
2466 
2467     RtlCopyMemory(RequestBuffer->DomainName.Buffer,
2468                   domainname,
2469                   RequestBuffer->DomainName.MaximumLength);
2470 
2471     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->DomainName.MaximumLength);
2472 
2473     /* Pack the user name */
2474     RequestBuffer->AccountName.Length = wcslen(username) * sizeof(WCHAR);
2475     RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length + sizeof(WCHAR);
2476     RequestBuffer->AccountName.Buffer = Ptr;
2477 
2478     RtlCopyMemory(RequestBuffer->AccountName.Buffer,
2479                   username,
2480                   RequestBuffer->AccountName.MaximumLength);
2481 
2482     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->AccountName.MaximumLength);
2483 
2484     /* Pack the old password */
2485     RequestBuffer->OldPassword.Length = wcslen(oldpassword) * sizeof(WCHAR);
2486     RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length + sizeof(WCHAR);
2487     RequestBuffer->OldPassword.Buffer = Ptr;
2488 
2489     RtlCopyMemory(RequestBuffer->OldPassword.Buffer,
2490                   oldpassword,
2491                   RequestBuffer->OldPassword.MaximumLength);
2492 
2493     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->OldPassword.MaximumLength);
2494 
2495     /* Pack the new password */
2496     RequestBuffer->NewPassword.Length = wcslen(newpassword) * sizeof(WCHAR);
2497     RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length + sizeof(WCHAR);
2498     RequestBuffer->NewPassword.Buffer = Ptr;
2499 
2500     RtlCopyMemory(RequestBuffer->NewPassword.Buffer,
2501                   newpassword,
2502                   RequestBuffer->NewPassword.MaximumLength);
2503 
2504     /* Call the authentication package */
2505     Status = LsaCallAuthenticationPackage(LsaHandle,
2506                                           AuthenticationPackage,
2507                                           RequestBuffer,
2508                                           RequestBufferSize,
2509                                           (PVOID*)&ResponseBuffer,
2510                                           &ResponseBufferSize,
2511                                           &ProtocolStatus);
2512     if (!NT_SUCCESS(Status))
2513     {
2514         ApiStatus = NetpNtStatusToApiStatus(Status);
2515         goto done;
2516     }
2517 
2518     if (!NT_SUCCESS(ProtocolStatus))
2519     {
2520         ApiStatus = NetpNtStatusToApiStatus(ProtocolStatus);
2521         goto done;
2522     }
2523 
2524 done:
2525     if (RequestBuffer != NULL)
2526         NetApiBufferFree(RequestBuffer);
2527 
2528     if (ResponseBuffer != NULL)
2529         LsaFreeReturnBuffer(ResponseBuffer);
2530 
2531     if (LsaHandle != NULL)
2532         NtClose(LsaHandle);
2533 
2534     return ApiStatus;
2535 }
2536 
2537 
2538 /************************************************************
2539  * NetUserDel  (NETAPI32.@)
2540  */
2541 NET_API_STATUS
2542 WINAPI
NetUserDel(LPCWSTR servername,LPCWSTR username)2543 NetUserDel(LPCWSTR servername,
2544            LPCWSTR username)
2545 {
2546     UNICODE_STRING ServerName;
2547     UNICODE_STRING UserName;
2548     SAM_HANDLE ServerHandle = NULL;
2549     SAM_HANDLE DomainHandle = NULL;
2550     SAM_HANDLE UserHandle = NULL;
2551     NET_API_STATUS ApiStatus = NERR_Success;
2552     NTSTATUS Status = STATUS_SUCCESS;
2553 
2554     TRACE("(%s, %s)\n", debugstr_w(servername), debugstr_w(username));
2555 
2556     if (servername != NULL)
2557         RtlInitUnicodeString(&ServerName, servername);
2558 
2559     RtlInitUnicodeString(&UserName, username);
2560 
2561     /* Connect to the SAM Server */
2562     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
2563                         &ServerHandle,
2564                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
2565                         NULL);
2566     if (!NT_SUCCESS(Status))
2567     {
2568         ERR("SamConnect failed (Status %08lx)\n", Status);
2569         ApiStatus = NetpNtStatusToApiStatus(Status);
2570         goto done;
2571     }
2572 
2573     /* Open the Builtin Domain */
2574     Status = OpenBuiltinDomain(ServerHandle,
2575                                DOMAIN_LOOKUP,
2576                                &DomainHandle);
2577     if (!NT_SUCCESS(Status))
2578     {
2579         ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
2580         ApiStatus = NetpNtStatusToApiStatus(Status);
2581         goto done;
2582     }
2583 
2584     /* Open the user account in the builtin domain */
2585     ApiStatus = OpenUserByName(DomainHandle,
2586                                &UserName,
2587                                DELETE,
2588                                &UserHandle);
2589     if (ApiStatus != NERR_Success && ApiStatus != ERROR_NONE_MAPPED)
2590     {
2591         TRACE("OpenUserByName(%wZ) failed (ApiStatus %lu)\n", &UserName, ApiStatus);
2592         goto done;
2593     }
2594 
2595     if (UserHandle == NULL)
2596     {
2597         if (DomainHandle != NULL)
2598         {
2599             SamCloseHandle(DomainHandle);
2600             DomainHandle = NULL;
2601         }
2602 
2603         /* Open the Acount Domain */
2604         Status = OpenAccountDomain(ServerHandle,
2605                                    (servername != NULL) ? &ServerName : NULL,
2606                                    DOMAIN_LOOKUP,
2607                                    &DomainHandle);
2608         if (!NT_SUCCESS(Status))
2609         {
2610             ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
2611             ApiStatus = NetpNtStatusToApiStatus(Status);
2612             goto done;
2613         }
2614 
2615         /* Open the user account in the account domain */
2616         ApiStatus = OpenUserByName(DomainHandle,
2617                                    &UserName,
2618                                    DELETE,
2619                                    &UserHandle);
2620         if (ApiStatus != NERR_Success)
2621         {
2622             ERR("OpenUserByName(%wZ) failed (ApiStatus %lu)\n", &UserName, ApiStatus);
2623             if (ApiStatus == ERROR_NONE_MAPPED)
2624                 ApiStatus = NERR_UserNotFound;
2625             goto done;
2626         }
2627     }
2628 
2629     /* Delete the user */
2630     Status = SamDeleteUser(UserHandle);
2631     if (!NT_SUCCESS(Status))
2632     {
2633         ERR("SamDeleteUser failed (Status %08lx)\n", Status);
2634         ApiStatus = NetpNtStatusToApiStatus(Status);
2635         goto done;
2636     }
2637 
2638     /* A successful delete invalidates the handle */
2639     UserHandle = NULL;
2640 
2641 done:
2642     if (UserHandle != NULL)
2643         SamCloseHandle(UserHandle);
2644 
2645     if (DomainHandle != NULL)
2646         SamCloseHandle(DomainHandle);
2647 
2648     if (ServerHandle != NULL)
2649         SamCloseHandle(ServerHandle);
2650 
2651     return ApiStatus;
2652 }
2653 
2654 static
2655 NET_API_STATUS
AllocateEnumContext(PENUM_CONTEXT * AllocatedEnumContext)2656 AllocateEnumContext(
2657     PENUM_CONTEXT *AllocatedEnumContext)
2658 {
2659     NET_API_STATUS ApiStatus;
2660     PENUM_CONTEXT EnumContext;
2661 
2662     /* Allocate the context structure */
2663     ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
2664     if (ApiStatus != NERR_Success)
2665         return ApiStatus;
2666 
2667     /* Initialize the fields */
2668     EnumContext->EnumerationContext = 0;
2669     EnumContext->Buffer = NULL;
2670     EnumContext->Count = 0;
2671     EnumContext->Index = 0;
2672     EnumContext->BuiltinDone = FALSE;
2673 
2674     /* Set a "unique" handle */
2675     EnumContext->EnumHandle = InterlockedIncrement(&g_EnumContextHandle);
2676     if (EnumContext->EnumHandle == 0)
2677     {
2678         EnumContext->EnumHandle = InterlockedIncrement(&g_EnumContextHandle);
2679     }
2680 
2681     /* Insert the context in the list */
2682     EnterCriticalSection(&g_EnumContextListLock);
2683     InsertTailList(&g_EnumContextListHead, &EnumContext->ListLink);
2684     LeaveCriticalSection(&g_EnumContextListLock);
2685 
2686     *AllocatedEnumContext = EnumContext;
2687     return NERR_Success;
2688 }
2689 
2690 static
2691 VOID
FreeEnumContext(PENUM_CONTEXT EnumContext)2692 FreeEnumContext(
2693     PENUM_CONTEXT EnumContext)
2694 
2695 {
2696     /* Remove the context from the list */
2697     EnterCriticalSection(&g_EnumContextListLock);
2698     RemoveEntryList(&EnumContext->ListLink);
2699     LeaveCriticalSection(&g_EnumContextListLock);
2700 
2701     /* Free it */
2702     NetApiBufferFree(EnumContext);
2703 }
2704 
2705 static
2706 PENUM_CONTEXT
LookupEnumContext(SAM_ENUMERATE_HANDLE EnumerationHandle)2707 LookupEnumContext(
2708     SAM_ENUMERATE_HANDLE EnumerationHandle)
2709 {
2710     PENUM_CONTEXT FoundEnumContext = NULL;
2711     PLIST_ENTRY ListEntry;
2712 
2713     /* Acquire the list lock */
2714     EnterCriticalSection(&g_EnumContextListLock);
2715 
2716     /* Search the list for the handle */
2717     for (ListEntry = g_EnumContextListHead.Flink;
2718          ListEntry != &g_EnumContextListHead;
2719          ListEntry = ListEntry->Flink)
2720     {
2721         PENUM_CONTEXT EnumContext = CONTAINING_RECORD(ListEntry, ENUM_CONTEXT, ListLink);
2722         if (EnumContext->EnumHandle == EnumerationHandle)
2723         {
2724             FoundEnumContext = EnumContext;
2725             break;
2726         }
2727     }
2728 
2729     /* Release the list lock */
2730     LeaveCriticalSection(&g_EnumContextListLock);
2731 
2732     return FoundEnumContext;
2733 }
2734 
2735 /************************************************************
2736  * NetUserEnum  (NETAPI32.@)
2737  */
2738 NET_API_STATUS
2739 WINAPI
NetUserEnum(LPCWSTR servername,DWORD level,DWORD filter,LPBYTE * bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries,LPDWORD resume_handle)2740 NetUserEnum(LPCWSTR servername,
2741             DWORD level,
2742             DWORD filter,
2743             LPBYTE* bufptr,
2744             DWORD prefmaxlen,
2745             LPDWORD entriesread,
2746             LPDWORD totalentries,
2747             LPDWORD resume_handle)
2748 {
2749     UNICODE_STRING ServerName;
2750     PSAM_RID_ENUMERATION CurrentUser;
2751     PENUM_CONTEXT EnumContext = NULL;
2752     LPVOID Buffer = NULL;
2753     ULONG i;
2754     SAM_HANDLE UserHandle = NULL;
2755     ACCESS_MASK DesiredAccess;
2756     NET_API_STATUS ApiStatus = NERR_Success;
2757     NTSTATUS Status = STATUS_SUCCESS;
2758 
2759     TRACE("(%s %d 0x%d %p %d %p %p %p)\n", debugstr_w(servername), level,
2760           filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
2761 
2762     *entriesread = 0;
2763     *totalentries = 0;
2764     *bufptr = NULL;
2765 
2766     if (servername != NULL)
2767         RtlInitUnicodeString(&ServerName, servername);
2768 
2769     if (resume_handle != NULL && *resume_handle != 0)
2770     {
2771         EnumContext = LookupEnumContext(*resume_handle);
2772     }
2773     else
2774     {
2775         ApiStatus = AllocateEnumContext(&EnumContext);
2776         if (ApiStatus != NERR_Success)
2777             goto done;
2778 
2779         Status = SamConnect((servername != NULL) ? &ServerName : NULL,
2780                             &EnumContext->ServerHandle,
2781                             SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
2782                             NULL);
2783         if (!NT_SUCCESS(Status))
2784         {
2785             ERR("SamConnect failed (Status %08lx)\n", Status);
2786             ApiStatus = NetpNtStatusToApiStatus(Status);
2787             goto done;
2788         }
2789 
2790         /* Get the Account Domain SID */
2791         Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
2792                                      &EnumContext->AccountDomainSid);
2793         if (!NT_SUCCESS(Status))
2794         {
2795             ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
2796             ApiStatus = NetpNtStatusToApiStatus(Status);
2797             goto done;
2798         }
2799 
2800         /* Open the Account Domain */
2801         Status = SamOpenDomain(EnumContext->ServerHandle,
2802                                DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
2803                                EnumContext->AccountDomainSid,
2804                                &EnumContext->AccountDomainHandle);
2805         if (!NT_SUCCESS(Status))
2806         {
2807             ERR("SamOpenDomain failed (Status %08lx)\n", Status);
2808             ApiStatus = NetpNtStatusToApiStatus(Status);
2809             goto done;
2810         }
2811 
2812         /* Get the Builtin Domain SID */
2813         Status = GetBuiltinDomainSid(&EnumContext->BuiltinDomainSid);
2814         if (!NT_SUCCESS(Status))
2815         {
2816             ERR("GetBuiltinDomainSid failed (Status %08lx)\n", Status);
2817             ApiStatus = NetpNtStatusToApiStatus(Status);
2818             goto done;
2819         }
2820 
2821         DesiredAccess = DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP;
2822         if ((level == 1) || (level == 2) || (level == 3) || (level == 4) || (level == 11))
2823             DesiredAccess |= DOMAIN_GET_ALIAS_MEMBERSHIP;
2824 
2825         /* Open the Builtin Domain */
2826         Status = SamOpenDomain(EnumContext->ServerHandle,
2827                                DesiredAccess,
2828                                EnumContext->BuiltinDomainSid,
2829                                &EnumContext->BuiltinDomainHandle);
2830         if (!NT_SUCCESS(Status))
2831         {
2832             ERR("SamOpenDomain failed (Status %08lx)\n", Status);
2833             ApiStatus = NetpNtStatusToApiStatus(Status);
2834             goto done;
2835         }
2836     }
2837 
2838 //    while (TRUE)
2839 //    {
2840         TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
2841         TRACE("EnumContext->Count: %lu\n", EnumContext->Count);
2842 
2843         if (EnumContext->Index >= EnumContext->Count)
2844         {
2845 //            if (EnumContext->BuiltinDone != FALSE)
2846 //            {
2847 //                ApiStatus = NERR_Success;
2848 //                goto done;
2849 //            }
2850 
2851             TRACE("Calling SamEnumerateUsersInDomain\n");
2852             Status = SamEnumerateUsersInDomain(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
2853                                                &EnumContext->EnumerationContext,
2854                                                0,
2855                                                (PVOID *)&EnumContext->Buffer,
2856                                                prefmaxlen,
2857                                                &EnumContext->Count);
2858 
2859             TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status);
2860             if (!NT_SUCCESS(Status))
2861             {
2862                 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status);
2863                 ApiStatus = NetpNtStatusToApiStatus(Status);
2864                 goto done;
2865             }
2866 
2867             if (Status == STATUS_MORE_ENTRIES)
2868             {
2869                 ApiStatus = NERR_BufTooSmall;
2870                 goto done;
2871             }
2872             else
2873             {
2874                 EnumContext->BuiltinDone = TRUE;
2875             }
2876         }
2877 
2878         TRACE("EnumContext: %lu\n", EnumContext);
2879         TRACE("EnumContext->Count: %lu\n", EnumContext->Count);
2880         TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
2881 
2882         /* Get a pointer to the current user */
2883         CurrentUser = &EnumContext->Buffer[EnumContext->Index];
2884 
2885         TRACE("RID: %lu\n", CurrentUser->RelativeId);
2886 
2887         DesiredAccess = READ_CONTROL | USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT;
2888         if ((level == 1) || (level == 2) || (level == 3) || (level == 4) || (level == 11))
2889             DesiredAccess |= USER_LIST_GROUPS;
2890 
2891         Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
2892                              DesiredAccess,
2893                              CurrentUser->RelativeId,
2894                              &UserHandle);
2895         if (!NT_SUCCESS(Status))
2896         {
2897             ERR("SamOpenUser failed (Status %08lx)\n", Status);
2898             ApiStatus = NetpNtStatusToApiStatus(Status);
2899             goto done;
2900         }
2901 
2902         ApiStatus = BuildUserInfoBuffer(EnumContext->BuiltinDomainHandle,
2903                                         UserHandle,
2904                                         EnumContext->AccountDomainSid,
2905                                         CurrentUser->RelativeId,
2906                                         level,
2907                                         &Buffer);
2908         if (ApiStatus != NERR_Success)
2909         {
2910             ERR("BuildUserInfoBuffer failed (ApiStatus %lu)\n", ApiStatus);
2911             goto done;
2912         }
2913 
2914         SamCloseHandle(UserHandle);
2915         UserHandle = NULL;
2916 
2917         EnumContext->Index++;
2918 
2919         (*entriesread)++;
2920 //    }
2921 
2922 done:
2923     if (ApiStatus == NERR_Success && EnumContext != NULL && EnumContext->Index < EnumContext->Count)
2924         ApiStatus = ERROR_MORE_DATA;
2925 
2926     if (EnumContext != NULL)
2927         *totalentries = EnumContext->Count;
2928 
2929     if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
2930     {
2931         if (EnumContext != NULL)
2932         {
2933             if (EnumContext->BuiltinDomainHandle != NULL)
2934                 SamCloseHandle(EnumContext->BuiltinDomainHandle);
2935 
2936             if (EnumContext->AccountDomainHandle != NULL)
2937                 SamCloseHandle(EnumContext->AccountDomainHandle);
2938 
2939             if (EnumContext->BuiltinDomainSid != NULL)
2940                 RtlFreeHeap(RtlGetProcessHeap(), 0, EnumContext->BuiltinDomainSid);
2941 
2942             if (EnumContext->AccountDomainSid != NULL)
2943                 RtlFreeHeap(RtlGetProcessHeap(), 0, EnumContext->AccountDomainSid);
2944 
2945             if (EnumContext->ServerHandle != NULL)
2946                 SamCloseHandle(EnumContext->ServerHandle);
2947 
2948             if (EnumContext->Buffer != NULL)
2949             {
2950                 for (i = 0; i < EnumContext->Count; i++)
2951                 {
2952                     SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
2953                 }
2954 
2955                 SamFreeMemory(EnumContext->Buffer);
2956             }
2957 
2958             FreeEnumContext(EnumContext);
2959             EnumContext = NULL;
2960         }
2961     }
2962 
2963     if (UserHandle != NULL)
2964         SamCloseHandle(UserHandle);
2965 
2966     if (resume_handle != NULL)
2967         *resume_handle = EnumContext ? EnumContext->EnumHandle : 0;
2968 
2969     *bufptr = (LPBYTE)Buffer;
2970 
2971     TRACE("return %lu\n", ApiStatus);
2972 
2973     return ApiStatus;
2974 }
2975 
2976 
2977 /************************************************************
2978  * NetUserGetGroups (NETAPI32.@)
2979  */
2980 NET_API_STATUS
2981 WINAPI
NetUserGetGroups(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE * bufptr,DWORD prefixmaxlen,LPDWORD entriesread,LPDWORD totalentries)2982 NetUserGetGroups(LPCWSTR servername,
2983                  LPCWSTR username,
2984                  DWORD level,
2985                  LPBYTE *bufptr,
2986                  DWORD prefixmaxlen,
2987                  LPDWORD entriesread,
2988                  LPDWORD totalentries)
2989 {
2990     UNICODE_STRING ServerName;
2991     UNICODE_STRING UserName;
2992     SAM_HANDLE ServerHandle = NULL;
2993     SAM_HANDLE AccountDomainHandle = NULL;
2994     SAM_HANDLE UserHandle = NULL;
2995     PSID AccountDomainSid = NULL;
2996     PULONG RelativeIds = NULL;
2997     PSID_NAME_USE Use = NULL;
2998     PGROUP_MEMBERSHIP GroupMembership = NULL;
2999     ULONG GroupCount;
3000 
3001     NET_API_STATUS ApiStatus = NERR_Success;
3002     NTSTATUS Status = STATUS_SUCCESS;
3003 
3004     TRACE("%s %s %d %p %d %p %p stub\n", debugstr_w(servername),
3005           debugstr_w(username), level, bufptr, prefixmaxlen, entriesread,
3006           totalentries);
3007 
3008     if (servername != NULL)
3009         RtlInitUnicodeString(&ServerName, servername);
3010 
3011     RtlInitUnicodeString(&UserName, username);
3012 
3013     /* Connect to the SAM Server */
3014     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
3015                         &ServerHandle,
3016                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
3017                         NULL);
3018     if (!NT_SUCCESS(Status))
3019     {
3020         ERR("SamConnect failed (Status %08lx)\n", Status);
3021         ApiStatus = NetpNtStatusToApiStatus(Status);
3022         goto done;
3023     }
3024 
3025     /* Get the Account Domain SID */
3026     Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
3027                                  &AccountDomainSid);
3028     if (!NT_SUCCESS(Status))
3029     {
3030         ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
3031         ApiStatus = NetpNtStatusToApiStatus(Status);
3032         goto done;
3033     }
3034 
3035     /* Open the Account Domain */
3036     Status = SamOpenDomain(ServerHandle,
3037                            DOMAIN_LOOKUP | DOMAIN_GET_ALIAS_MEMBERSHIP,
3038                            AccountDomainSid,
3039                            &AccountDomainHandle);
3040     if (!NT_SUCCESS(Status))
3041     {
3042         ERR("SamOpenDomain failed (Status %08lx)\n", Status);
3043         ApiStatus = NetpNtStatusToApiStatus(Status);
3044         goto done;
3045     }
3046 
3047     /* Get the RID for the given user name */
3048     Status = SamLookupNamesInDomain(AccountDomainHandle,
3049                                     1,
3050                                     &UserName,
3051                                     &RelativeIds,
3052                                     &Use);
3053     if (!NT_SUCCESS(Status))
3054     {
3055         ERR("SamLookupNamesInDomain(%wZ) failed (Status %08lx)\n", &UserName, Status);
3056         if (Status == STATUS_NONE_MAPPED)
3057             ApiStatus = NERR_UserNotFound;
3058         else
3059             ApiStatus = NetpNtStatusToApiStatus(Status);
3060         goto done;
3061     }
3062 
3063     /* Fail, if it is not a user account */
3064     if (Use[0] != SidTypeUser)
3065     {
3066         ERR("Account is not a User!\n");
3067         ApiStatus = NERR_UserNotFound;
3068         goto done;
3069     }
3070 
3071     /* Open the user object */
3072     Status = SamOpenUser(AccountDomainHandle,
3073                          USER_LIST_GROUPS,
3074                          RelativeIds[0],
3075                          &UserHandle);
3076     if (!NT_SUCCESS(Status))
3077     {
3078         ERR("SamOpenUser failed (Status %08lx)\n", Status);
3079         ApiStatus = NetpNtStatusToApiStatus(Status);
3080         goto done;
3081     }
3082 
3083     /* Get the group memberships of this user */
3084     Status = SamGetGroupsForUser(UserHandle,
3085                                  &GroupMembership,
3086                                  &GroupCount);
3087     if (!NT_SUCCESS(Status))
3088     {
3089         ERR("SamGetGroupsForUser failed (Status %08lx)\n", Status);
3090         ApiStatus = NetpNtStatusToApiStatus(Status);
3091         goto done;
3092     }
3093 
3094     /* If there is no group membership, we're done */
3095     if (GroupCount == 0)
3096     {
3097         ApiStatus = NERR_Success;
3098         goto done;
3099     }
3100 
3101 
3102 done:
3103 
3104     if (GroupMembership != NULL)
3105         SamFreeMemory(GroupMembership);
3106 
3107     if (UserHandle != NULL)
3108         SamCloseHandle(UserHandle);
3109 
3110     if (RelativeIds != NULL)
3111         SamFreeMemory(RelativeIds);
3112 
3113     if (Use != NULL)
3114         SamFreeMemory(Use);
3115 
3116     if (AccountDomainSid != NULL)
3117         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
3118 
3119     if (AccountDomainHandle != NULL)
3120         SamCloseHandle(AccountDomainHandle);
3121 
3122     if (ServerHandle != NULL)
3123         SamCloseHandle(ServerHandle);
3124 
3125     if (ApiStatus != NERR_Success && ApiStatus != ERROR_MORE_DATA)
3126     {
3127         *entriesread = 0;
3128         *totalentries = 0;
3129     }
3130     else
3131     {
3132 //        *entriesread = Count;
3133 //        *totalentries = Count;
3134     }
3135 
3136 //    *bufptr = (LPBYTE)Buffer;
3137 
3138     return ApiStatus;
3139 }
3140 
3141 
3142 /************************************************************
3143  * NetUserGetInfo  (NETAPI32.@)
3144  */
3145 NET_API_STATUS
3146 WINAPI
NetUserGetInfo(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE * bufptr)3147 NetUserGetInfo(LPCWSTR servername,
3148                LPCWSTR username,
3149                DWORD level,
3150                LPBYTE* bufptr)
3151 {
3152     UNICODE_STRING ServerName;
3153     UNICODE_STRING UserName;
3154     SAM_HANDLE ServerHandle = NULL;
3155     SAM_HANDLE AccountDomainHandle = NULL;
3156     SAM_HANDLE BuiltinDomainHandle = NULL;
3157     SAM_HANDLE UserHandle = NULL;
3158     PULONG RelativeIds = NULL;
3159     PSID_NAME_USE Use = NULL;
3160     LPVOID Buffer = NULL;
3161     PSID AccountDomainSid = NULL;
3162     PSID BuiltinDomainSid = NULL;
3163     ACCESS_MASK DesiredAccess;
3164     NET_API_STATUS ApiStatus = NERR_Success;
3165     NTSTATUS Status = STATUS_SUCCESS;
3166 
3167     TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername),
3168           debugstr_w(username), level, bufptr);
3169 
3170     if (servername != NULL)
3171         RtlInitUnicodeString(&ServerName, servername);
3172 
3173     RtlInitUnicodeString(&UserName, username);
3174 
3175     /* Connect to the SAM Server */
3176     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
3177                         &ServerHandle,
3178                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
3179                         NULL);
3180     if (!NT_SUCCESS(Status))
3181     {
3182         ERR("SamConnect failed (Status %08lx)\n", Status);
3183         ApiStatus = NetpNtStatusToApiStatus(Status);
3184         goto done;
3185     }
3186 
3187     /* Get the Builtin Domain SID */
3188     Status = GetBuiltinDomainSid(&BuiltinDomainSid);
3189     if (!NT_SUCCESS(Status))
3190     {
3191         ERR("GetBuiltinDomainSid failed (Status %08lx)\n", Status);
3192         ApiStatus = NetpNtStatusToApiStatus(Status);
3193         goto done;
3194     }
3195 
3196     DesiredAccess = DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP;
3197     if ((level == 1) || (level == 2) || (level == 3) || (level == 4) || (level == 11))
3198         DesiredAccess |= DOMAIN_GET_ALIAS_MEMBERSHIP;
3199 
3200     /* Open the Builtin Domain */
3201     Status = SamOpenDomain(ServerHandle,
3202                            DesiredAccess,
3203                            BuiltinDomainSid,
3204                            &BuiltinDomainHandle);
3205     if (!NT_SUCCESS(Status))
3206     {
3207         ERR("SamOpenDomain failed (Status %08lx)\n", Status);
3208         ApiStatus = NetpNtStatusToApiStatus(Status);
3209         goto done;
3210     }
3211 
3212     /* Get the Account Domain SID */
3213     Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
3214                                  &AccountDomainSid);
3215     if (!NT_SUCCESS(Status))
3216     {
3217         ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
3218         ApiStatus = NetpNtStatusToApiStatus(Status);
3219         goto done;
3220     }
3221 
3222     /* Open the Account Domain */
3223     Status = SamOpenDomain(ServerHandle,
3224                            DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
3225                            AccountDomainSid,
3226                            &AccountDomainHandle);
3227     if (!NT_SUCCESS(Status))
3228     {
3229         ERR("SamOpenDomain failed (Status %08lx)\n", Status);
3230         ApiStatus = NetpNtStatusToApiStatus(Status);
3231         goto done;
3232     }
3233 
3234     /* Get the RID for the given user name */
3235     Status = SamLookupNamesInDomain(AccountDomainHandle,
3236                                     1,
3237                                     &UserName,
3238                                     &RelativeIds,
3239                                     &Use);
3240     if (!NT_SUCCESS(Status))
3241     {
3242         ERR("SamLookupNamesInDomain(%wZ) failed (Status %08lx)\n", &UserName, Status);
3243         if (Status == STATUS_NONE_MAPPED)
3244             ApiStatus = NERR_UserNotFound;
3245         else
3246             ApiStatus = NetpNtStatusToApiStatus(Status);
3247         goto done;
3248     }
3249 
3250     /* Check if the account is a user account */
3251     if (Use[0] != SidTypeUser)
3252     {
3253         ERR("No user found!\n");
3254         ApiStatus = NERR_UserNotFound;
3255         goto done;
3256     }
3257 
3258     TRACE("RID: %lu\n", RelativeIds[0]);
3259 
3260     DesiredAccess = READ_CONTROL | USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT;
3261     if ((level == 1) || (level == 2) || (level == 3) || (level == 4) || (level == 11))
3262         DesiredAccess |= USER_LIST_GROUPS;
3263 
3264     /* Open the user object */
3265     Status = SamOpenUser(AccountDomainHandle,
3266                          DesiredAccess,
3267                          RelativeIds[0],
3268                          &UserHandle);
3269     if (!NT_SUCCESS(Status))
3270     {
3271         ERR("SamOpenUser failed (Status %08lx)\n", Status);
3272         ApiStatus = NetpNtStatusToApiStatus(Status);
3273         goto done;
3274     }
3275 
3276     ApiStatus = BuildUserInfoBuffer(BuiltinDomainHandle,
3277                                     UserHandle,
3278                                     AccountDomainSid,
3279                                     RelativeIds[0],
3280                                     level,
3281                                     &Buffer);
3282     if (ApiStatus != NERR_Success)
3283     {
3284         ERR("BuildUserInfoBuffer failed (ApiStatus %08lu)\n", ApiStatus);
3285         goto done;
3286     }
3287 
3288 done:
3289     if (UserHandle != NULL)
3290         SamCloseHandle(UserHandle);
3291 
3292     if (RelativeIds != NULL)
3293         SamFreeMemory(RelativeIds);
3294 
3295     if (Use != NULL)
3296         SamFreeMemory(Use);
3297 
3298     if (AccountDomainHandle != NULL)
3299         SamCloseHandle(AccountDomainHandle);
3300 
3301     if (AccountDomainSid != NULL)
3302         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
3303 
3304     if (BuiltinDomainHandle != NULL)
3305         SamCloseHandle(BuiltinDomainHandle);
3306 
3307     if (BuiltinDomainSid != NULL)
3308         RtlFreeHeap(RtlGetProcessHeap(), 0, BuiltinDomainSid);
3309 
3310     if (ServerHandle != NULL)
3311         SamCloseHandle(ServerHandle);
3312 
3313     *bufptr = (LPBYTE)Buffer;
3314 
3315     return ApiStatus;
3316 }
3317 
3318 
3319 /************************************************************
3320  * NetUserGetLocalGroups  (NETAPI32.@)
3321  */
3322 NET_API_STATUS
3323 WINAPI
NetUserGetLocalGroups(LPCWSTR servername,LPCWSTR username,DWORD level,DWORD flags,LPBYTE * bufptr,DWORD prefmaxlen,LPDWORD entriesread,LPDWORD totalentries)3324 NetUserGetLocalGroups(LPCWSTR servername,
3325                       LPCWSTR username,
3326                       DWORD level,
3327                       DWORD flags,
3328                       LPBYTE* bufptr,
3329                       DWORD prefmaxlen,
3330                       LPDWORD entriesread,
3331                       LPDWORD totalentries)
3332 {
3333     UNICODE_STRING ServerName;
3334     UNICODE_STRING UserName;
3335     SAM_HANDLE ServerHandle = NULL;
3336     SAM_HANDLE BuiltinDomainHandle = NULL;
3337     SAM_HANDLE AccountDomainHandle = NULL;
3338     PSID AccountDomainSid = NULL;
3339     PSID UserSid = NULL;
3340     PULONG RelativeIds = NULL;
3341     PSID_NAME_USE Use = NULL;
3342     ULONG BuiltinMemberCount = 0;
3343     ULONG AccountMemberCount = 0;
3344     PULONG BuiltinAliases = NULL;
3345     PULONG AccountAliases = NULL;
3346     PUNICODE_STRING BuiltinNames = NULL;
3347     PUNICODE_STRING AccountNames = NULL;
3348     PLOCALGROUP_USERS_INFO_0 Buffer = NULL;
3349     ULONG Size;
3350     ULONG Count = 0;
3351     ULONG Index;
3352     ULONG i;
3353     LPWSTR StrPtr;
3354     NET_API_STATUS ApiStatus = NERR_Success;
3355     NTSTATUS Status = STATUS_SUCCESS;
3356 
3357     TRACE("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
3358           debugstr_w(servername), debugstr_w(username), level, flags, bufptr,
3359           prefmaxlen, entriesread, totalentries);
3360 
3361     if (level != 0)
3362         return ERROR_INVALID_LEVEL;
3363 
3364     if (flags & ~LG_INCLUDE_INDIRECT)
3365         return ERROR_INVALID_PARAMETER;
3366 
3367     if (flags & LG_INCLUDE_INDIRECT)
3368     {
3369         WARN("The flag LG_INCLUDE_INDIRECT is not supported yet!\n");
3370     }
3371 
3372     if (servername != NULL)
3373         RtlInitUnicodeString(&ServerName, servername);
3374 
3375     RtlInitUnicodeString(&UserName, username);
3376 
3377     /* Connect to the SAM Server */
3378     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
3379                         &ServerHandle,
3380                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
3381                         NULL);
3382     if (!NT_SUCCESS(Status))
3383     {
3384         ERR("SamConnect failed (Status %08lx)\n", Status);
3385         ApiStatus = NetpNtStatusToApiStatus(Status);
3386         goto done;
3387     }
3388 
3389     /* Open the Builtin Domain */
3390     Status = OpenBuiltinDomain(ServerHandle,
3391                                DOMAIN_LOOKUP | DOMAIN_GET_ALIAS_MEMBERSHIP,
3392                                &BuiltinDomainHandle);
3393     if (!NT_SUCCESS(Status))
3394     {
3395         ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
3396         ApiStatus = NetpNtStatusToApiStatus(Status);
3397         goto done;
3398     }
3399 
3400     /* Get the Account Domain SID */
3401     Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
3402                                  &AccountDomainSid);
3403     if (!NT_SUCCESS(Status))
3404     {
3405         ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
3406         ApiStatus = NetpNtStatusToApiStatus(Status);
3407         goto done;
3408     }
3409 
3410     /* Open the Account Domain */
3411     Status = SamOpenDomain(ServerHandle,
3412                            DOMAIN_LOOKUP | DOMAIN_GET_ALIAS_MEMBERSHIP,
3413                            AccountDomainSid,
3414                            &AccountDomainHandle);
3415     if (!NT_SUCCESS(Status))
3416     {
3417         ERR("SamOpenDomain failed (Status %08lx)\n", Status);
3418         ApiStatus = NetpNtStatusToApiStatus(Status);
3419         goto done;
3420     }
3421 
3422     /* Get the RID for the given user name */
3423     Status = SamLookupNamesInDomain(AccountDomainHandle,
3424                                     1,
3425                                     &UserName,
3426                                     &RelativeIds,
3427                                     &Use);
3428     if (!NT_SUCCESS(Status))
3429     {
3430         ERR("SamLookupNamesInDomain(%wZ) failed (Status %08lx)\n", &UserName, Status);
3431         if (Status == STATUS_NONE_MAPPED)
3432             ApiStatus = NERR_UserNotFound;
3433         else
3434             ApiStatus = NetpNtStatusToApiStatus(Status);
3435         goto done;
3436     }
3437 
3438     /* Fail, if it is not a user account */
3439     if (Use[0] != SidTypeUser)
3440     {
3441         ERR("Account is not a User!\n");
3442         ApiStatus = NERR_UserNotFound;
3443         goto done;
3444     }
3445 
3446     /* Build the User SID from the Account Domain SID and the users RID */
3447     ApiStatus = BuildSidFromSidAndRid(AccountDomainSid,
3448                                       RelativeIds[0],
3449                                       &UserSid);
3450     if (ApiStatus != NERR_Success)
3451     {
3452         ERR("BuildSidFromSidAndRid failed!\n");
3453         goto done;
3454     }
3455 
3456     /* Get alias memberships in the Builtin Domain */
3457     Status = SamGetAliasMembership(BuiltinDomainHandle,
3458                                    1,
3459                                    &UserSid,
3460                                    &BuiltinMemberCount,
3461                                    &BuiltinAliases);
3462     if (!NT_SUCCESS(Status))
3463     {
3464         ERR("SamGetAliasMembership failed (Status %08lx)\n", Status);
3465         ApiStatus = NetpNtStatusToApiStatus(Status);
3466         goto done;
3467     }
3468 
3469     if (BuiltinMemberCount > 0)
3470     {
3471         /* Get the Names of the builtin alias members */
3472         Status = SamLookupIdsInDomain(BuiltinDomainHandle,
3473                                       BuiltinMemberCount,
3474                                       BuiltinAliases,
3475                                       &BuiltinNames,
3476                                       NULL);
3477         if (!NT_SUCCESS(Status))
3478         {
3479             ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
3480             ApiStatus = NetpNtStatusToApiStatus(Status);
3481             goto done;
3482         }
3483     }
3484 
3485     /* Get alias memberships in the Account Domain */
3486     Status = SamGetAliasMembership(AccountDomainHandle,
3487                                    1,
3488                                    &UserSid,
3489                                    &AccountMemberCount,
3490                                    &AccountAliases);
3491     if (!NT_SUCCESS(Status))
3492     {
3493         ERR("SamGetAliasMembership failed (Status %08lx)\n", Status);
3494         ApiStatus = NetpNtStatusToApiStatus(Status);
3495         goto done;
3496     }
3497 
3498     if (AccountMemberCount > 0)
3499     {
3500         /* Get the Names of the builtin alias members */
3501         Status = SamLookupIdsInDomain(AccountDomainHandle,
3502                                       AccountMemberCount,
3503                                       AccountAliases,
3504                                       &AccountNames,
3505                                       NULL);
3506         if (!NT_SUCCESS(Status))
3507         {
3508             ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
3509             ApiStatus = NetpNtStatusToApiStatus(Status);
3510             goto done;
3511         }
3512     }
3513 
3514     /* Calculate the required buffer size */
3515     Size = 0;
3516 
3517     for (i = 0; i < BuiltinMemberCount; i++)
3518     {
3519         if (BuiltinNames[i].Length > 0)
3520         {
3521             Size += (sizeof(LOCALGROUP_USERS_INFO_0) + BuiltinNames[i].Length + sizeof(UNICODE_NULL));
3522             Count++;
3523         }
3524     }
3525 
3526     for (i = 0; i < AccountMemberCount; i++)
3527     {
3528         if (AccountNames[i].Length > 0)
3529         {
3530             Size += (sizeof(LOCALGROUP_USERS_INFO_0) + AccountNames[i].Length + sizeof(UNICODE_NULL));
3531             Count++;
3532         }
3533     }
3534 
3535     if (Size == 0)
3536     {
3537         ApiStatus = NERR_Success;
3538         goto done;
3539     }
3540 
3541     /* Allocate buffer */
3542     ApiStatus = NetApiBufferAllocate(Size, (LPVOID*)&Buffer);
3543     if (ApiStatus != NERR_Success)
3544         goto done;
3545 
3546     ZeroMemory(Buffer, Size);
3547 
3548     StrPtr = (LPWSTR)((INT_PTR)Buffer + Count * sizeof(LOCALGROUP_USERS_INFO_0));
3549 
3550     /* Copy data to the allocated buffer */
3551     Index = 0;
3552     for (i = 0; i < BuiltinMemberCount; i++)
3553     {
3554         if (BuiltinNames[i].Length > 0)
3555         {
3556             CopyMemory(StrPtr,
3557                        BuiltinNames[i].Buffer,
3558                        BuiltinNames[i].Length);
3559             Buffer[Index].lgrui0_name = StrPtr;
3560 
3561             StrPtr = (LPWSTR)((INT_PTR)StrPtr + BuiltinNames[i].Length + sizeof(UNICODE_NULL));
3562             Index++;
3563         }
3564     }
3565 
3566     for (i = 0; i < AccountMemberCount; i++)
3567     {
3568         if (AccountNames[i].Length > 0)
3569         {
3570             CopyMemory(StrPtr,
3571                        AccountNames[i].Buffer,
3572                        AccountNames[i].Length);
3573             Buffer[Index].lgrui0_name = StrPtr;
3574 
3575             StrPtr = (LPWSTR)((INT_PTR)StrPtr + AccountNames[i].Length + sizeof(UNICODE_NULL));
3576             Index++;
3577         }
3578     }
3579 
3580 done:
3581     if (AccountNames != NULL)
3582         SamFreeMemory(AccountNames);
3583 
3584     if (BuiltinNames != NULL)
3585         SamFreeMemory(BuiltinNames);
3586 
3587     if (AccountAliases != NULL)
3588         SamFreeMemory(AccountAliases);
3589 
3590     if (BuiltinAliases != NULL)
3591         SamFreeMemory(BuiltinAliases);
3592 
3593     if (RelativeIds != NULL)
3594         SamFreeMemory(RelativeIds);
3595 
3596     if (Use != NULL)
3597         SamFreeMemory(Use);
3598 
3599     if (UserSid != NULL)
3600         NetApiBufferFree(UserSid);
3601 
3602     if (AccountDomainSid != NULL)
3603         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
3604 
3605     if (AccountDomainHandle != NULL)
3606         SamCloseHandle(AccountDomainHandle);
3607 
3608     if (BuiltinDomainHandle != NULL)
3609         SamCloseHandle(BuiltinDomainHandle);
3610 
3611     if (ServerHandle != NULL)
3612         SamCloseHandle(ServerHandle);
3613 
3614     if (ApiStatus != NERR_Success && ApiStatus != ERROR_MORE_DATA)
3615     {
3616         *entriesread = 0;
3617         *totalentries = 0;
3618     }
3619     else
3620     {
3621         *entriesread = Count;
3622         *totalentries = Count;
3623     }
3624 
3625     *bufptr = (LPBYTE)Buffer;
3626 
3627     return ApiStatus;
3628 }
3629 
3630 
3631 /******************************************************************************
3632  * NetUserModalsGet  (NETAPI32.@)
3633  *
3634  * Retrieves global information for all users and global groups in the security
3635  * database.
3636  *
3637  * PARAMS
3638  *  servername [I] Specifies the DNS or the NetBIOS name of the remote server
3639  *                 on which the function is to execute.
3640  *  level      [I] Information level of the data.
3641  *     0   Return global passwords parameters. bufptr points to a
3642  *         USER_MODALS_INFO_0 struct.
3643  *     1   Return logon server and domain controller information. bufptr
3644  *         points to a USER_MODALS_INFO_1 struct.
3645  *     2   Return domain name and identifier. bufptr points to a
3646  *         USER_MODALS_INFO_2 struct.
3647  *     3   Return lockout information. bufptr points to a USER_MODALS_INFO_3
3648  *         struct.
3649  *  bufptr     [O] Buffer that receives the data.
3650  *
3651  * RETURNS
3652  *  Success: NERR_Success.
3653  *  Failure:
3654  *     ERROR_ACCESS_DENIED - the user does not have access to the info.
3655  *     NERR_InvalidComputer - computer name is invalid.
3656  */
3657 NET_API_STATUS
3658 WINAPI
NetUserModalsGet(LPCWSTR servername,DWORD level,LPBYTE * bufptr)3659 NetUserModalsGet(LPCWSTR servername,
3660                  DWORD level,
3661                  LPBYTE *bufptr)
3662 {
3663     UNICODE_STRING ServerName;
3664     SAM_HANDLE ServerHandle = NULL;
3665     SAM_HANDLE DomainHandle = NULL;
3666     PSID DomainSid = NULL;
3667     PDOMAIN_PASSWORD_INFORMATION PasswordInfo = NULL;
3668     PDOMAIN_LOGOFF_INFORMATION LogoffInfo = NULL;
3669     PDOMAIN_SERVER_ROLE_INFORMATION ServerRoleInfo = NULL;
3670     PDOMAIN_REPLICATION_INFORMATION ReplicationInfo = NULL;
3671     PDOMAIN_NAME_INFORMATION NameInfo = NULL;
3672     PDOMAIN_LOCKOUT_INFORMATION LockoutInfo = NULL;
3673     ULONG DesiredAccess;
3674     ULONG BufferSize;
3675     PUSER_MODALS_INFO_0 umi0;
3676     PUSER_MODALS_INFO_1 umi1;
3677     PUSER_MODALS_INFO_2 umi2;
3678     PUSER_MODALS_INFO_3 umi3;
3679     NET_API_STATUS ApiStatus = NERR_Success;
3680     NTSTATUS Status = STATUS_SUCCESS;
3681 
3682     TRACE("(%s %d %p)\n", debugstr_w(servername), level, bufptr);
3683 
3684     *bufptr = NULL;
3685 
3686     if (servername != NULL)
3687         RtlInitUnicodeString(&ServerName, servername);
3688 
3689     /* Connect to the SAM Server */
3690     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
3691                         &ServerHandle,
3692                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
3693                         NULL);
3694     if (!NT_SUCCESS(Status))
3695     {
3696         ERR("SamConnect failed (Status %08lx)\n", Status);
3697         ApiStatus = NetpNtStatusToApiStatus(Status);
3698         goto done;
3699     }
3700 
3701     /* Get the Account Domain SID */
3702     Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
3703                                  &DomainSid);
3704     if (!NT_SUCCESS(Status))
3705     {
3706         ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
3707         ApiStatus = NetpNtStatusToApiStatus(Status);
3708         goto done;
3709     }
3710 
3711     switch (level)
3712     {
3713         case 0:
3714             DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS | DOMAIN_READ_PASSWORD_PARAMETERS;
3715             break;
3716 
3717         case 1:
3718             DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
3719             break;
3720 
3721         case 2:
3722             DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
3723             break;
3724 
3725         case 3:
3726             DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
3727             break;
3728 
3729         default:
3730             ApiStatus = ERROR_INVALID_LEVEL;
3731             goto done;
3732     }
3733 
3734     /* Open the Account Domain */
3735     Status = SamOpenDomain(ServerHandle,
3736                            DesiredAccess,
3737                            DomainSid,
3738                            &DomainHandle);
3739     if (!NT_SUCCESS(Status))
3740     {
3741         ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
3742         ApiStatus = NetpNtStatusToApiStatus(Status);
3743         goto done;
3744     }
3745 
3746     switch (level)
3747     {
3748         case 0:
3749             /* return global passwords parameters */
3750             Status = SamQueryInformationDomain(DomainHandle,
3751                                                DomainPasswordInformation,
3752                                                (PVOID*)&PasswordInfo);
3753             if (!NT_SUCCESS(Status))
3754             {
3755                 ApiStatus = NetpNtStatusToApiStatus(Status);
3756                 goto done;
3757             }
3758 
3759             Status = SamQueryInformationDomain(DomainHandle,
3760                                                DomainLogoffInformation,
3761                                                (PVOID*)&LogoffInfo);
3762             if (!NT_SUCCESS(Status))
3763             {
3764                 ApiStatus = NetpNtStatusToApiStatus(Status);
3765                 goto done;
3766             }
3767 
3768             BufferSize = sizeof(USER_MODALS_INFO_0);
3769             break;
3770 
3771         case 1:
3772             /* return logon server and domain controller info */
3773             Status = SamQueryInformationDomain(DomainHandle,
3774                                                DomainServerRoleInformation,
3775                                                (PVOID*)&ServerRoleInfo);
3776             if (!NT_SUCCESS(Status))
3777             {
3778                 ApiStatus = NetpNtStatusToApiStatus(Status);
3779                 goto done;
3780             }
3781 
3782             Status = SamQueryInformationDomain(DomainHandle,
3783                                                DomainReplicationInformation,
3784                                                (PVOID*)&ReplicationInfo);
3785             if (!NT_SUCCESS(Status))
3786             {
3787                 ApiStatus = NetpNtStatusToApiStatus(Status);
3788                 goto done;
3789             }
3790 
3791             BufferSize = sizeof(USER_MODALS_INFO_1) +
3792                          ReplicationInfo->ReplicaSourceNodeName.Length + sizeof(WCHAR);
3793             break;
3794 
3795         case 2:
3796             /* return domain name and identifier */
3797             Status = SamQueryInformationDomain(DomainHandle,
3798                                                DomainNameInformation,
3799                                                (PVOID*)&NameInfo);
3800             if (!NT_SUCCESS(Status))
3801             {
3802                 ApiStatus = NetpNtStatusToApiStatus(Status);
3803                 goto done;
3804             }
3805 
3806             BufferSize = sizeof( USER_MODALS_INFO_2 ) +
3807                          NameInfo->DomainName.Length + sizeof(WCHAR) +
3808                          RtlLengthSid(DomainSid);
3809             break;
3810 
3811         case 3:
3812             /* return lockout information */
3813             Status = SamQueryInformationDomain(DomainHandle,
3814                                                DomainLockoutInformation,
3815                                                (PVOID*)&LockoutInfo);
3816             if (!NT_SUCCESS(Status))
3817             {
3818                 ApiStatus = NetpNtStatusToApiStatus(Status);
3819                 goto done;
3820             }
3821 
3822             BufferSize = sizeof(USER_MODALS_INFO_3);
3823             break;
3824 
3825         default:
3826             TRACE("Invalid level %d is specified\n", level);
3827             ApiStatus = ERROR_INVALID_LEVEL;
3828             goto done;
3829     }
3830 
3831 
3832     ApiStatus = NetApiBufferAllocate(BufferSize,
3833                                      (LPVOID *)bufptr);
3834     if (ApiStatus != NERR_Success)
3835     {
3836         WARN("NetApiBufferAllocate() failed\n");
3837         goto done;
3838     }
3839 
3840     switch (level)
3841     {
3842         case 0:
3843             umi0 = (PUSER_MODALS_INFO_0)*bufptr;
3844 
3845             umi0->usrmod0_min_passwd_len = PasswordInfo->MinPasswordLength;
3846             umi0->usrmod0_max_passwd_age = (ULONG)(-PasswordInfo->MaxPasswordAge.QuadPart / 10000000);
3847             umi0->usrmod0_min_passwd_age =
3848                 DeltaTimeToSeconds(PasswordInfo->MinPasswordAge);
3849             umi0->usrmod0_force_logoff =
3850                 DeltaTimeToSeconds(LogoffInfo->ForceLogoff);
3851             umi0->usrmod0_password_hist_len = PasswordInfo->PasswordHistoryLength;
3852             break;
3853 
3854         case 1:
3855             umi1 = (PUSER_MODALS_INFO_1)*bufptr;
3856 
3857             switch (ServerRoleInfo->DomainServerRole)
3858             {
3859                 case DomainServerRolePrimary:
3860                     umi1->usrmod1_role = UAS_ROLE_PRIMARY;
3861                     break;
3862 
3863                 case DomainServerRoleBackup:
3864                     umi1->usrmod1_role = UAS_ROLE_BACKUP;
3865                     break;
3866 
3867                 default:
3868                     ApiStatus = NERR_InternalError;
3869                     goto done;
3870             }
3871 
3872             umi1->usrmod1_primary = (LPWSTR)(*bufptr + sizeof(USER_MODALS_INFO_1));
3873             RtlCopyMemory(umi1->usrmod1_primary,
3874                           ReplicationInfo->ReplicaSourceNodeName.Buffer,
3875                           ReplicationInfo->ReplicaSourceNodeName.Length);
3876             umi1->usrmod1_primary[ReplicationInfo->ReplicaSourceNodeName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3877             break;
3878 
3879         case 2:
3880             umi2 = (PUSER_MODALS_INFO_2)*bufptr;
3881 
3882             umi2->usrmod2_domain_name = (LPWSTR)(*bufptr + sizeof(USER_MODALS_INFO_2));
3883             RtlCopyMemory(umi2->usrmod2_domain_name,
3884                           NameInfo->DomainName.Buffer,
3885                           NameInfo->DomainName.Length);
3886             umi2->usrmod2_domain_name[NameInfo->DomainName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3887 
3888             umi2->usrmod2_domain_id = *bufptr +
3889                                       sizeof(USER_MODALS_INFO_2) +
3890                                       NameInfo->DomainName.Length + sizeof(WCHAR);
3891             RtlCopyMemory(umi2->usrmod2_domain_id,
3892                           DomainSid,
3893                           RtlLengthSid(DomainSid));
3894             break;
3895 
3896         case 3:
3897             umi3 = (PUSER_MODALS_INFO_3)*bufptr;
3898             umi3->usrmod3_lockout_duration =
3899                 DeltaTimeToSeconds(LockoutInfo->LockoutDuration);
3900             umi3->usrmod3_lockout_observation_window =
3901                 DeltaTimeToSeconds(LockoutInfo->LockoutObservationWindow );
3902             umi3->usrmod3_lockout_threshold = LockoutInfo->LockoutThreshold;
3903             break;
3904     }
3905 
3906 done:
3907     if (LockoutInfo != NULL)
3908         SamFreeMemory(LockoutInfo);
3909 
3910     if (NameInfo != NULL)
3911         SamFreeMemory(NameInfo);
3912 
3913     if (ReplicationInfo != NULL)
3914         SamFreeMemory(ReplicationInfo);
3915 
3916     if (ServerRoleInfo != NULL)
3917         SamFreeMemory(ServerRoleInfo);
3918 
3919     if (LogoffInfo != NULL)
3920         SamFreeMemory(LogoffInfo);
3921 
3922     if (PasswordInfo != NULL)
3923         SamFreeMemory(PasswordInfo);
3924 
3925     if (DomainSid != NULL)
3926         RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
3927 
3928     if (DomainHandle != NULL)
3929         SamCloseHandle(DomainHandle);
3930 
3931     if (ServerHandle != NULL)
3932         SamCloseHandle(ServerHandle);
3933 
3934     return ApiStatus;
3935 }
3936 
3937 
3938 /******************************************************************************
3939  * NetUserModalsSet  (NETAPI32.@)
3940  */
3941 NET_API_STATUS
3942 WINAPI
NetUserModalsSet(IN LPCWSTR servername,IN DWORD level,IN LPBYTE buf,OUT LPDWORD parm_err)3943 NetUserModalsSet(IN LPCWSTR servername,
3944                  IN DWORD level,
3945                  IN LPBYTE buf,
3946                  OUT LPDWORD parm_err)
3947 {
3948     FIXME("(%s %d %p %p)\n", debugstr_w(servername), level, buf, parm_err);
3949     return ERROR_ACCESS_DENIED;
3950 }
3951 
3952 
3953 /******************************************************************************
3954  * NetUserSetGroups  (NETAPI32.@)
3955  */
3956 NET_API_STATUS
3957 WINAPI
NetUserSetGroups(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE buf,DWORD num_entries)3958 NetUserSetGroups(LPCWSTR servername,
3959                  LPCWSTR username,
3960                  DWORD level,
3961                  LPBYTE buf,
3962                  DWORD num_entries)
3963 {
3964     FIXME("(%s %s %lu %p %lu)\n",
3965           debugstr_w(servername), debugstr_w(username), level, buf, num_entries);
3966     return ERROR_ACCESS_DENIED;
3967 }
3968 
3969 
3970 /******************************************************************************
3971  * NetUserSetInfo  (NETAPI32.@)
3972  */
3973 NET_API_STATUS
3974 WINAPI
NetUserSetInfo(LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE buf,LPDWORD parm_err)3975 NetUserSetInfo(LPCWSTR servername,
3976                LPCWSTR username,
3977                DWORD level,
3978                LPBYTE buf,
3979                LPDWORD parm_err)
3980 {
3981     UNICODE_STRING ServerName;
3982     UNICODE_STRING UserName;
3983     SAM_HANDLE ServerHandle = NULL;
3984     SAM_HANDLE AccountDomainHandle = NULL;
3985     SAM_HANDLE UserHandle = NULL;
3986     NET_API_STATUS ApiStatus = NERR_Success;
3987     NTSTATUS Status = STATUS_SUCCESS;
3988 
3989     TRACE("(%s %s %lu %p %p)\n",
3990           debugstr_w(servername), debugstr_w(username), level, buf, parm_err);
3991 
3992     if (parm_err != NULL)
3993         *parm_err = PARM_ERROR_NONE;
3994 
3995     /* Check the info level */
3996     switch (level)
3997     {
3998         case 0:
3999         case 1:
4000         case 2:
4001         case 3:
4002         case 4:
4003 //        case 21:
4004         case 22:
4005         case 1003:
4006 //        case 1005:
4007         case 1006:
4008         case 1007:
4009         case 1008:
4010         case 1009:
4011 //        case 1010:
4012         case 1011:
4013         case 1012:
4014         case 1013:
4015         case 1014:
4016         case 1017:
4017         case 1018:
4018         case 1020:
4019         case 1024:
4020         case 1025:
4021         case 1051:
4022         case 1052:
4023         case 1053:
4024             break;
4025 
4026         default:
4027             return ERROR_INVALID_LEVEL;
4028     }
4029 
4030     if (servername != NULL)
4031         RtlInitUnicodeString(&ServerName, servername);
4032 
4033     RtlInitUnicodeString(&UserName, username);
4034 
4035     /* Connect to the SAM Server */
4036     Status = SamConnect((servername != NULL) ? &ServerName : NULL,
4037                         &ServerHandle,
4038                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
4039                         NULL);
4040     if (!NT_SUCCESS(Status))
4041     {
4042         ERR("SamConnect failed (Status %08lx)\n", Status);
4043         ApiStatus = NetpNtStatusToApiStatus(Status);
4044         goto done;
4045     }
4046 
4047     /* Open the Account Domain */
4048     Status = OpenAccountDomain(ServerHandle,
4049                                (servername != NULL) ? &ServerName : NULL,
4050                                DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS,
4051                                &AccountDomainHandle);
4052     if (!NT_SUCCESS(Status))
4053     {
4054         ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
4055         ApiStatus = NetpNtStatusToApiStatus(Status);
4056         goto done;
4057     }
4058 
4059     /* Open the User Account */
4060     ApiStatus = OpenUserByName(AccountDomainHandle,
4061                                &UserName,
4062                                USER_ALL_ACCESS,
4063                                &UserHandle);
4064     if (ApiStatus != NERR_Success)
4065     {
4066         ERR("OpenUserByName(%wZ) failed (ApiStatus %lu)\n", &UserName, ApiStatus);
4067         goto done;
4068     }
4069 
4070     /* Set user information */
4071     ApiStatus = SetUserInfo(UserHandle,
4072                             buf,
4073                             level,
4074                             parm_err);
4075     if (ApiStatus != NERR_Success)
4076     {
4077         ERR("SetUserInfo failed (Status %lu)\n", ApiStatus);
4078     }
4079 
4080 done:
4081     if (UserHandle != NULL)
4082         SamCloseHandle(UserHandle);
4083 
4084     if (AccountDomainHandle != NULL)
4085         SamCloseHandle(AccountDomainHandle);
4086 
4087     if (ServerHandle != NULL)
4088         SamCloseHandle(ServerHandle);
4089 
4090     return ApiStatus;
4091 }
4092 
4093 /* EOF */
4094