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