Synchronize with trunk r58528.
[reactos.git] / dll / win32 / netapi32 / user.c
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 NetUserChangePassword
24 * Implement NetUserDel
25 * Implement NetUserGetGroups
26 * Implement NetUserSetGroups
27 * Implement NetUserSetInfo
28 * NetUserGetLocalGroups does not support LG_INCLUDE_INDIRECT yet.
29 * Add missing information levels.
30 * ...
31 */
32
33 #include "netapi32.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
36
37
38 typedef struct _ENUM_CONTEXT
39 {
40 SAM_HANDLE ServerHandle;
41 SAM_HANDLE BuiltinDomainHandle;
42 SAM_HANDLE AccountDomainHandle;
43
44 SAM_ENUMERATE_HANDLE EnumerationContext;
45 PSAM_RID_ENUMERATION Buffer;
46 ULONG Count;
47 ULONG Index;
48 BOOLEAN BuiltinDone;
49
50 } ENUM_CONTEXT, *PENUM_CONTEXT;
51
52
53 /* NOTE: So far, this is implemented to support tests that require user logins,
54 * but not designed to handle real user databases. Those should probably
55 * be synced with either the host's user database or with Samba.
56 *
57 * FIXME: The user database should hold all the information the USER_INFO_4 struct
58 * needs, but for the first try, I will just implement the USER_INFO_1 fields.
59 */
60
61 struct sam_user
62 {
63 struct list entry;
64 WCHAR user_name[LM20_UNLEN+1];
65 WCHAR user_password[PWLEN + 1];
66 DWORD sec_since_passwd_change;
67 DWORD user_priv;
68 LPWSTR home_dir;
69 LPWSTR user_comment;
70 DWORD user_flags;
71 LPWSTR user_logon_script_path;
72 };
73
74 static struct list user_list = LIST_INIT( user_list );
75
76 BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName);
77
78 /************************************************************
79 * NETAPI_ValidateServername
80 *
81 * Validates server name
82 */
83 static NET_API_STATUS NETAPI_ValidateServername(LPCWSTR ServerName)
84 {
85 if (ServerName)
86 {
87 if (ServerName[0] == 0)
88 return ERROR_BAD_NETPATH;
89 else if (
90 ((ServerName[0] == '\\') &&
91 (ServerName[1] != '\\'))
92 ||
93 ((ServerName[0] == '\\') &&
94 (ServerName[1] == '\\') &&
95 (ServerName[2] == 0))
96 )
97 return ERROR_INVALID_NAME;
98 }
99 return NERR_Success;
100 }
101
102 /************************************************************
103 * NETAPI_FindUser
104 *
105 * Looks for a user in the user database.
106 * Returns a pointer to the entry in the user list when the user
107 * is found, NULL otherwise.
108 */
109 static struct sam_user* NETAPI_FindUser(LPCWSTR UserName)
110 {
111 struct sam_user *user;
112
113 LIST_FOR_EACH_ENTRY(user, &user_list, struct sam_user, entry)
114 {
115 if(lstrcmpW(user->user_name, UserName) == 0)
116 return user;
117 }
118 return NULL;
119 }
120
121
122 static PSID
123 CreateSidFromSidAndRid(PSID SrcSid,
124 ULONG RelativeId)
125 {
126 UCHAR RidCount;
127 PSID DstSid;
128 ULONG i;
129 ULONG DstSidSize;
130 PULONG p, q;
131
132 RidCount = *RtlSubAuthorityCountSid(SrcSid);
133 if (RidCount >= 8)
134 return NULL;
135
136 DstSidSize = RtlLengthRequiredSid(RidCount + 1);
137
138 DstSid = RtlAllocateHeap(RtlGetProcessHeap(),
139 0,
140 DstSidSize);
141 if (DstSid == NULL)
142 return NULL;
143
144 RtlInitializeSid(DstSid,
145 RtlIdentifierAuthoritySid(SrcSid),
146 RidCount + 1);
147
148 for (i = 0; i < (ULONG)RidCount; i++)
149 {
150 p = RtlSubAuthoritySid(SrcSid, i);
151 q = RtlSubAuthoritySid(DstSid, i);
152 *q = *p;
153 }
154
155 q = RtlSubAuthoritySid(DstSid, (ULONG)RidCount);
156 *q = RelativeId;
157
158 return DstSid;
159 }
160
161
162 static
163 ULONG
164 GetAccountFlags(ULONG AccountControl)
165 {
166 ULONG Flags = UF_SCRIPT;
167
168 if (AccountControl & USER_ACCOUNT_DISABLED)
169 Flags |= UF_ACCOUNTDISABLE;
170
171 if (AccountControl & USER_HOME_DIRECTORY_REQUIRED)
172 Flags |= UF_HOMEDIR_REQUIRED;
173
174 if (AccountControl & USER_PASSWORD_NOT_REQUIRED)
175 Flags |= UF_PASSWD_NOTREQD;
176
177 // UF_PASSWD_CANT_CHANGE
178
179 if (AccountControl & USER_ACCOUNT_AUTO_LOCKED)
180 Flags |= UF_LOCKOUT;
181
182 if (AccountControl & USER_DONT_EXPIRE_PASSWORD)
183 Flags |= UF_DONT_EXPIRE_PASSWD;
184
185 /*
186 if (AccountControl & USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED)
187 Flags |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
188
189 if (AccountControl & USER_SMARTCARD_REQUIRED)
190 Flags |= UF_SMARTCARD_REQUIRED;
191
192 if (AccountControl & USER_TRUSTED_FOR_DELEGATION)
193 Flags |= UF_TRUSTED_FOR_DELEGATION;
194
195 if (AccountControl & USER_NOT_DELEGATED)
196 Flags |= UF_NOT_DELEGATED;
197
198 if (AccountControl & USER_USE_DES_KEY_ONLY)
199 Flags |= UF_USE_DES_KEY_ONLY;
200
201 if (AccountControl & USER_DONT_REQUIRE_PREAUTH)
202 Flags |= UF_DONT_REQUIRE_PREAUTH;
203
204 if (AccountControl & USER_PASSWORD_EXPIRED)
205 Flags |= UF_PASSWORD_EXPIRED;
206 */
207
208 /* Set account type flags */
209 if (AccountControl & USER_TEMP_DUPLICATE_ACCOUNT)
210 Flags |= UF_TEMP_DUPLICATE_ACCOUNT;
211 else if (AccountControl & USER_NORMAL_ACCOUNT)
212 Flags |= UF_NORMAL_ACCOUNT;
213 else if (AccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT)
214 Flags |= UF_INTERDOMAIN_TRUST_ACCOUNT;
215 else if (AccountControl & USER_WORKSTATION_TRUST_ACCOUNT)
216 Flags |= UF_WORKSTATION_TRUST_ACCOUNT;
217 else if (AccountControl & USER_SERVER_TRUST_ACCOUNT)
218 Flags |= UF_SERVER_TRUST_ACCOUNT;
219
220 return Flags;
221 }
222
223
224 static
225 NET_API_STATUS
226 BuildUserInfoBuffer(PUSER_ACCOUNT_INFORMATION UserInfo,
227 DWORD level,
228 ULONG RelativeId,
229 LPVOID *Buffer)
230 {
231 LPVOID LocalBuffer = NULL;
232 PUSER_INFO_0 UserInfo0;
233 PUSER_INFO_1 UserInfo1;
234 PUSER_INFO_2 UserInfo2;
235 PUSER_INFO_3 UserInfo3;
236 PUSER_INFO_10 UserInfo10;
237 PUSER_INFO_20 UserInfo20;
238 PUSER_INFO_23 UserInfo23;
239 LPWSTR Ptr;
240 ULONG Size = 0;
241 NET_API_STATUS ApiStatus = NERR_Success;
242
243 *Buffer = NULL;
244
245 switch (level)
246 {
247 case 0:
248 Size = sizeof(USER_INFO_0) +
249 UserInfo->UserName.Length + sizeof(WCHAR);
250 break;
251
252 case 1:
253 Size = sizeof(USER_INFO_1) +
254 UserInfo->UserName.Length + sizeof(WCHAR);
255
256 if (UserInfo->HomeDirectory.Length > 0)
257 Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR);
258
259 if (UserInfo->AdminComment.Length > 0)
260 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
261
262 if (UserInfo->ScriptPath.Length > 0)
263 Size += UserInfo->ScriptPath.Length + sizeof(WCHAR);
264 break;
265
266 case 2:
267 Size = sizeof(USER_INFO_2) +
268 UserInfo->UserName.Length + sizeof(WCHAR);
269
270 if (UserInfo->HomeDirectory.Length > 0)
271 Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR);
272
273 if (UserInfo->AdminComment.Length > 0)
274 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
275
276 if (UserInfo->ScriptPath.Length > 0)
277 Size += UserInfo->ScriptPath.Length + sizeof(WCHAR);
278
279 if (UserInfo->FullName.Length > 0)
280 Size += UserInfo->FullName.Length + sizeof(WCHAR);
281
282 /* FIXME: usri2_usr_comment */
283 /* FIXME: usri2_parms */
284
285 if (UserInfo->WorkStations.Length > 0)
286 Size += UserInfo->WorkStations.Length + sizeof(WCHAR);
287
288 /* FIXME: usri2_logon_hours */
289 /* FIXME: usri2_logon_server */
290 break;
291
292 case 3:
293 Size = sizeof(USER_INFO_3) +
294 UserInfo->UserName.Length + sizeof(WCHAR);
295
296 if (UserInfo->HomeDirectory.Length > 0)
297 Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR);
298
299 if (UserInfo->AdminComment.Length > 0)
300 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
301
302 if (UserInfo->ScriptPath.Length > 0)
303 Size += UserInfo->ScriptPath.Length + sizeof(WCHAR);
304
305 if (UserInfo->FullName.Length > 0)
306 Size += UserInfo->FullName.Length + sizeof(WCHAR);
307
308 /* FIXME: usri3_usr_comment */
309 /* FIXME: usri3_parms */
310
311 if (UserInfo->WorkStations.Length > 0)
312 Size += UserInfo->WorkStations.Length + sizeof(WCHAR);
313
314 /* FIXME: usri3_logon_hours */
315 /* FIXME: usri3_logon_server */
316
317 if (UserInfo->ProfilePath.Length > 0)
318 Size += UserInfo->ProfilePath.Length + sizeof(WCHAR);
319
320 if (UserInfo->HomeDirectoryDrive.Length > 0)
321 Size += UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR);
322 break;
323
324 // case 4:
325
326 case 10:
327 Size = sizeof(USER_INFO_10) +
328 UserInfo->UserName.Length + sizeof(WCHAR);
329
330 if (UserInfo->AdminComment.Length > 0)
331 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
332
333 /* FIXME: usri10_usr_comment */
334
335 if (UserInfo->FullName.Length > 0)
336 Size += UserInfo->FullName.Length + sizeof(WCHAR);
337 break;
338
339 // case 11:
340
341 case 20:
342 Size = sizeof(USER_INFO_20) +
343 UserInfo->UserName.Length + sizeof(WCHAR);
344
345 if (UserInfo->FullName.Length > 0)
346 Size += UserInfo->FullName.Length + sizeof(WCHAR);
347
348 if (UserInfo->AdminComment.Length > 0)
349 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
350 break;
351
352 case 23:
353 Size = sizeof(USER_INFO_23) +
354 UserInfo->UserName.Length + sizeof(WCHAR);
355
356 if (UserInfo->FullName.Length > 0)
357 Size += UserInfo->FullName.Length + sizeof(WCHAR);
358
359 if (UserInfo->AdminComment.Length > 0)
360 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
361
362 /* FIXME: usri23_user_sid */
363 break;
364
365 default:
366 ApiStatus = ERROR_INVALID_LEVEL;
367 goto done;
368 }
369
370 ApiStatus = NetApiBufferAllocate(Size, &LocalBuffer);
371 if (ApiStatus != NERR_Success)
372 goto done;
373
374 ZeroMemory(LocalBuffer, Size);
375
376 switch (level)
377 {
378 case 0:
379 UserInfo0 = (PUSER_INFO_0)LocalBuffer;
380
381 Ptr = (LPWSTR)((ULONG_PTR)UserInfo0 + sizeof(USER_INFO_0));
382 UserInfo0->usri0_name = Ptr;
383
384 memcpy(UserInfo0->usri0_name,
385 UserInfo->UserName.Buffer,
386 UserInfo->UserName.Length);
387 UserInfo0->usri0_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
388 break;
389
390 case 1:
391 UserInfo1 = (PUSER_INFO_1)LocalBuffer;
392
393 Ptr = (LPWSTR)((ULONG_PTR)UserInfo1 + sizeof(USER_INFO_1));
394
395 UserInfo1->usri1_name = Ptr;
396
397 memcpy(UserInfo1->usri1_name,
398 UserInfo->UserName.Buffer,
399 UserInfo->UserName.Length);
400 UserInfo1->usri1_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
401
402 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
403
404 UserInfo1->usri1_password = NULL;
405
406 /* FIXME: UserInfo1->usri1_password_age */
407 /* FIXME: UserInfo1->usri1_priv */
408
409 if (UserInfo->HomeDirectory.Length > 0)
410 {
411 UserInfo1->usri1_home_dir = Ptr;
412
413 memcpy(UserInfo1->usri1_home_dir,
414 UserInfo->HomeDirectory.Buffer,
415 UserInfo->HomeDirectory.Length);
416 UserInfo1->usri1_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
417
418 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
419 }
420
421 if (UserInfo->AdminComment.Length > 0)
422 {
423 UserInfo1->usri1_comment = Ptr;
424
425 memcpy(UserInfo1->usri1_comment,
426 UserInfo->AdminComment.Buffer,
427 UserInfo->AdminComment.Length);
428 UserInfo1->usri1_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
429
430 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
431 }
432
433 UserInfo1->usri1_flags = GetAccountFlags(UserInfo->UserAccountControl);
434
435 if (UserInfo->ScriptPath.Length > 0)
436 {
437 UserInfo1->usri1_script_path = Ptr;
438
439 memcpy(UserInfo1->usri1_script_path,
440 UserInfo->ScriptPath.Buffer,
441 UserInfo->ScriptPath.Length);
442 UserInfo1->usri1_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
443 }
444 break;
445
446 case 2:
447 UserInfo2 = (PUSER_INFO_2)LocalBuffer;
448
449 Ptr = (LPWSTR)((ULONG_PTR)UserInfo2 + sizeof(USER_INFO_2));
450
451 UserInfo2->usri2_name = Ptr;
452
453 memcpy(UserInfo2->usri2_name,
454 UserInfo->UserName.Buffer,
455 UserInfo->UserName.Length);
456 UserInfo2->usri2_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
457
458 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
459
460 /* FIXME: usri2_password_age */
461 /* FIXME: usri2_priv */
462
463 if (UserInfo->HomeDirectory.Length > 0)
464 {
465 UserInfo2->usri2_home_dir = Ptr;
466
467 memcpy(UserInfo2->usri2_home_dir,
468 UserInfo->HomeDirectory.Buffer,
469 UserInfo->HomeDirectory.Length);
470 UserInfo2->usri2_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
471
472 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
473 }
474
475 if (UserInfo->AdminComment.Length > 0)
476 {
477 UserInfo2->usri2_comment = Ptr;
478
479 memcpy(UserInfo2->usri2_comment,
480 UserInfo->AdminComment.Buffer,
481 UserInfo->AdminComment.Length);
482 UserInfo2->usri2_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
483
484 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
485 }
486
487 UserInfo2->usri2_flags = GetAccountFlags(UserInfo->UserAccountControl);
488
489 if (UserInfo->ScriptPath.Length > 0)
490 {
491 UserInfo2->usri2_script_path = Ptr;
492
493 memcpy(UserInfo2->usri2_script_path,
494 UserInfo->ScriptPath.Buffer,
495 UserInfo->ScriptPath.Length);
496 UserInfo2->usri2_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
497
498 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ScriptPath.Length + sizeof(WCHAR));
499 }
500
501 /* FIXME: usri2_auth_flags */
502
503 if (UserInfo->FullName.Length > 0)
504 {
505 UserInfo2->usri2_full_name = Ptr;
506
507 memcpy(UserInfo2->usri2_full_name,
508 UserInfo->FullName.Buffer,
509 UserInfo->FullName.Length);
510 UserInfo2->usri2_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
511
512 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
513 }
514
515 /* FIXME: usri2_usr_comment */
516 /* FIXME: usri2_parms */
517
518 if (UserInfo->WorkStations.Length > 0)
519 {
520 UserInfo2->usri2_workstations = Ptr;
521
522 memcpy(UserInfo2->usri2_workstations,
523 UserInfo->WorkStations.Buffer,
524 UserInfo->WorkStations.Length);
525 UserInfo2->usri2_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
526
527 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
528 }
529
530 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
531 &UserInfo2->usri2_last_logon);
532
533 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
534 &UserInfo2->usri2_last_logoff);
535
536 RtlTimeToSecondsSince1970(&UserInfo->AccountExpires,
537 &UserInfo2->usri2_acct_expires);
538
539 UserInfo2->usri2_max_storage = USER_MAXSTORAGE_UNLIMITED;
540
541 /* FIXME: usri2_units_per_week */
542 /* FIXME: usri2_logon_hours */
543
544 UserInfo2->usri2_bad_pw_count = UserInfo->BadPasswordCount;
545 UserInfo2->usri2_num_logons = UserInfo->LogonCount;
546
547 /* FIXME: usri2_logon_server */
548 /* FIXME: usri2_country_code */
549 /* FIXME: usri2_code_page */
550
551 break;
552
553 case 3:
554 UserInfo3 = (PUSER_INFO_3)LocalBuffer;
555
556 Ptr = (LPWSTR)((ULONG_PTR)UserInfo3 + sizeof(USER_INFO_3));
557
558 UserInfo3->usri3_name = Ptr;
559
560 memcpy(UserInfo3->usri3_name,
561 UserInfo->UserName.Buffer,
562 UserInfo->UserName.Length);
563 UserInfo3->usri3_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
564
565 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
566
567 /* FIXME: usri3_password_age */
568 /* FIXME: usri3_priv */
569
570 if (UserInfo->HomeDirectory.Length > 0)
571 {
572 UserInfo3->usri3_home_dir = Ptr;
573
574 memcpy(UserInfo3->usri3_home_dir,
575 UserInfo->HomeDirectory.Buffer,
576 UserInfo->HomeDirectory.Length);
577 UserInfo3->usri3_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
578
579 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
580 }
581
582 if (UserInfo->AdminComment.Length > 0)
583 {
584 UserInfo3->usri3_comment = Ptr;
585
586 memcpy(UserInfo3->usri3_comment,
587 UserInfo->AdminComment.Buffer,
588 UserInfo->AdminComment.Length);
589 UserInfo3->usri3_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
590
591 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
592 }
593
594 UserInfo3->usri3_flags = GetAccountFlags(UserInfo->UserAccountControl);
595
596 if (UserInfo->ScriptPath.Length > 0)
597 {
598 UserInfo3->usri3_script_path = Ptr;
599
600 memcpy(UserInfo3->usri3_script_path,
601 UserInfo->ScriptPath.Buffer,
602 UserInfo->ScriptPath.Length);
603 UserInfo3->usri3_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
604
605 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ScriptPath.Length + sizeof(WCHAR));
606 }
607
608 /* FIXME: usri3_auth_flags */
609
610 if (UserInfo->FullName.Length > 0)
611 {
612 UserInfo3->usri3_full_name = Ptr;
613
614 memcpy(UserInfo3->usri3_full_name,
615 UserInfo->FullName.Buffer,
616 UserInfo->FullName.Length);
617 UserInfo3->usri3_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
618
619 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
620 }
621
622 /* FIXME: usri3_usr_comment */
623 /* FIXME: usri3_parms */
624
625 if (UserInfo->WorkStations.Length > 0)
626 {
627 UserInfo3->usri3_workstations = Ptr;
628
629 memcpy(UserInfo3->usri3_workstations,
630 UserInfo->WorkStations.Buffer,
631 UserInfo->WorkStations.Length);
632 UserInfo3->usri3_workstations[UserInfo->WorkStations.Length / sizeof(WCHAR)] = UNICODE_NULL;
633
634 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->WorkStations.Length + sizeof(WCHAR));
635 }
636
637 RtlTimeToSecondsSince1970(&UserInfo->LastLogon,
638 &UserInfo3->usri3_last_logon);
639
640 RtlTimeToSecondsSince1970(&UserInfo->LastLogoff,
641 &UserInfo3->usri3_last_logoff);
642
643 RtlTimeToSecondsSince1970(&UserInfo->AccountExpires,
644 &UserInfo3->usri3_acct_expires);
645
646 UserInfo3->usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
647
648 /* FIXME: usri3_units_per_week */
649 /* FIXME: usri3_logon_hours */
650
651 UserInfo3->usri3_bad_pw_count = UserInfo->BadPasswordCount;
652 UserInfo3->usri3_num_logons = UserInfo->LogonCount;
653
654 /* FIXME: usri3_logon_server */
655 /* FIXME: usri3_country_code */
656 /* FIXME: usri3_code_page */
657
658 UserInfo3->usri3_user_id = RelativeId;
659 UserInfo3->usri3_primary_group_id = UserInfo->PrimaryGroupId;
660
661 if (UserInfo->ProfilePath.Length > 0)
662 {
663 UserInfo3->usri3_profile = Ptr;
664
665 memcpy(UserInfo3->usri3_profile,
666 UserInfo->ProfilePath.Buffer,
667 UserInfo->ProfilePath.Length);
668 UserInfo3->usri3_profile[UserInfo->ProfilePath.Length / sizeof(WCHAR)] = UNICODE_NULL;
669
670 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->ProfilePath.Length + sizeof(WCHAR));
671 }
672
673 if (UserInfo->HomeDirectoryDrive.Length > 0)
674 {
675 UserInfo3->usri3_home_dir_drive = Ptr;
676
677 memcpy(UserInfo3->usri3_home_dir_drive,
678 UserInfo->HomeDirectoryDrive.Buffer,
679 UserInfo->HomeDirectoryDrive.Length);
680 UserInfo3->usri3_home_dir_drive[UserInfo->HomeDirectoryDrive.Length / sizeof(WCHAR)] = UNICODE_NULL;
681
682 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR));
683 }
684
685 UserInfo3->usri3_password_expired = (UserInfo->UserAccountControl & USER_PASSWORD_EXPIRED);
686 break;
687
688 // case 4:
689
690 case 10:
691 UserInfo10 = (PUSER_INFO_10)LocalBuffer;
692
693 Ptr = (LPWSTR)((ULONG_PTR)UserInfo10 + sizeof(USER_INFO_10));
694
695 UserInfo10->usri10_name = Ptr;
696
697 memcpy(UserInfo10->usri10_name,
698 UserInfo->UserName.Buffer,
699 UserInfo->UserName.Length);
700 UserInfo10->usri10_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
701
702 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
703
704 if (UserInfo->AdminComment.Length > 0)
705 {
706 UserInfo10->usri10_comment = Ptr;
707
708 memcpy(UserInfo10->usri10_comment,
709 UserInfo->AdminComment.Buffer,
710 UserInfo->AdminComment.Length);
711 UserInfo10->usri10_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
712
713 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
714 }
715
716 /* FIXME: usri10_usr_comment */
717
718 if (UserInfo->FullName.Length > 0)
719 {
720 UserInfo10->usri10_full_name = Ptr;
721
722 memcpy(UserInfo10->usri10_full_name,
723 UserInfo->FullName.Buffer,
724 UserInfo->FullName.Length);
725 UserInfo10->usri10_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
726
727 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
728 }
729 break;
730
731 // case 11:
732
733 case 20:
734 UserInfo20 = (PUSER_INFO_20)LocalBuffer;
735
736 Ptr = (LPWSTR)((ULONG_PTR)UserInfo20 + sizeof(USER_INFO_20));
737
738 UserInfo20->usri20_name = Ptr;
739
740 memcpy(UserInfo20->usri20_name,
741 UserInfo->UserName.Buffer,
742 UserInfo->UserName.Length);
743 UserInfo20->usri20_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
744
745 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
746
747 if (UserInfo->FullName.Length > 0)
748 {
749 UserInfo20->usri20_full_name = Ptr;
750
751 memcpy(UserInfo20->usri20_full_name,
752 UserInfo->FullName.Buffer,
753 UserInfo->FullName.Length);
754 UserInfo20->usri20_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
755
756 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
757 }
758
759 if (UserInfo->AdminComment.Length > 0)
760 {
761 UserInfo20->usri20_comment = Ptr;
762
763 memcpy(UserInfo20->usri20_comment,
764 UserInfo->AdminComment.Buffer,
765 UserInfo->AdminComment.Length);
766 UserInfo20->usri20_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
767
768 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
769 }
770
771 UserInfo20->usri20_flags = GetAccountFlags(UserInfo->UserAccountControl);
772
773 UserInfo20->usri20_user_id = RelativeId;
774 break;
775
776 case 23:
777 UserInfo23 = (PUSER_INFO_23)LocalBuffer;
778
779 Ptr = (LPWSTR)((ULONG_PTR)UserInfo23 + sizeof(USER_INFO_23));
780
781 UserInfo23->usri23_name = Ptr;
782
783 memcpy(UserInfo23->usri23_name,
784 UserInfo->UserName.Buffer,
785 UserInfo->UserName.Length);
786 UserInfo23->usri23_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
787
788 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
789
790 if (UserInfo->FullName.Length > 0)
791 {
792 UserInfo23->usri23_full_name = Ptr;
793
794 memcpy(UserInfo23->usri23_full_name,
795 UserInfo->FullName.Buffer,
796 UserInfo->FullName.Length);
797 UserInfo23->usri23_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
798
799 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
800 }
801
802 if (UserInfo->AdminComment.Length > 0)
803 {
804 UserInfo23->usri23_comment = Ptr;
805
806 memcpy(UserInfo23->usri23_comment,
807 UserInfo->AdminComment.Buffer,
808 UserInfo->AdminComment.Length);
809 UserInfo23->usri23_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
810
811 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
812 }
813
814 UserInfo23->usri23_flags = GetAccountFlags(UserInfo->UserAccountControl);
815
816 /* FIXME: usri23_user_sid */
817 break;
818 }
819
820 done:
821 if (ApiStatus == NERR_Success)
822 {
823 *Buffer = LocalBuffer;
824 }
825 else
826 {
827 if (LocalBuffer != NULL)
828 NetApiBufferFree(LocalBuffer);
829 }
830
831 return ApiStatus;
832 }
833
834
835 static
836 VOID
837 FreeUserInfo(PUSER_ACCOUNT_INFORMATION UserInfo)
838 {
839 if (UserInfo->UserName.Buffer != NULL)
840 SamFreeMemory(UserInfo->UserName.Buffer);
841
842 if (UserInfo->FullName.Buffer != NULL)
843 SamFreeMemory(UserInfo->FullName.Buffer);
844
845 if (UserInfo->HomeDirectory.Buffer != NULL)
846 SamFreeMemory(UserInfo->HomeDirectory.Buffer);
847
848 if (UserInfo->HomeDirectoryDrive.Buffer != NULL)
849 SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer);
850
851 if (UserInfo->ScriptPath.Buffer != NULL)
852 SamFreeMemory(UserInfo->ScriptPath.Buffer);
853
854 if (UserInfo->ProfilePath.Buffer != NULL)
855 SamFreeMemory(UserInfo->ProfilePath.Buffer);
856
857 if (UserInfo->AdminComment.Buffer != NULL)
858 SamFreeMemory(UserInfo->AdminComment.Buffer);
859
860 if (UserInfo->WorkStations.Buffer != NULL)
861 SamFreeMemory(UserInfo->WorkStations.Buffer);
862
863 if (UserInfo->LogonHours.LogonHours != NULL)
864 SamFreeMemory(UserInfo->LogonHours.LogonHours);
865
866 SamFreeMemory(UserInfo);
867 }
868
869
870 static
871 NET_API_STATUS
872 SetUserInfo(SAM_HANDLE UserHandle,
873 LPBYTE UserInfo,
874 DWORD Level)
875 {
876 USER_ALL_INFORMATION UserAllInfo;
877 PUSER_INFO_1 UserInfo1;
878 PUSER_INFO_3 UserInfo3;
879 NET_API_STATUS ApiStatus = NERR_Success;
880 NTSTATUS Status = STATUS_SUCCESS;
881
882 ZeroMemory(&UserAllInfo, sizeof(USER_ALL_INFORMATION));
883
884 switch (Level)
885 {
886 case 1:
887 UserInfo1 = (PUSER_INFO_1)UserInfo;
888 // RtlInitUnicodeString(&UserAllInfo.UserName,
889 // UserInfo1->usri1_name);
890
891 RtlInitUnicodeString(&UserAllInfo.AdminComment,
892 UserInfo1->usri1_comment);
893
894 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
895 UserInfo1->usri1_home_dir);
896
897 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
898 UserInfo1->usri1_script_path);
899
900 RtlInitUnicodeString(&UserAllInfo.NtPassword,
901 UserInfo1->usri1_password);
902 UserAllInfo.NtPasswordPresent = TRUE;
903
904 // UserInfo1->usri1_flags
905 // UserInfo1->usri1_priv
906
907 UserAllInfo.WhichFields =
908 USER_ALL_ADMINCOMMENT |
909 USER_ALL_HOMEDIRECTORY |
910 USER_ALL_SCRIPTPATH |
911 USER_ALL_NTPASSWORDPRESENT
912 // USER_ALL_USERACCOUNTCONTROL
913 ;
914 break;
915
916
917 case 3:
918 UserInfo3 = (PUSER_INFO_3)UserInfo;
919
920 // LPWSTR usri3_name;
921
922 RtlInitUnicodeString(&UserAllInfo.NtPassword,
923 UserInfo3->usri3_password);
924 UserAllInfo.NtPasswordPresent = TRUE;
925
926 // DWORD usri3_password_age; // ignored
927 // DWORD usri3_priv;
928
929 RtlInitUnicodeString(&UserAllInfo.HomeDirectory,
930 UserInfo3->usri3_home_dir);
931
932 RtlInitUnicodeString(&UserAllInfo.AdminComment,
933 UserInfo3->usri3_comment);
934
935 // DWORD usri3_flags;
936
937 RtlInitUnicodeString(&UserAllInfo.ScriptPath,
938 UserInfo3->usri3_script_path);
939
940 // DWORD usri3_auth_flags;
941
942 RtlInitUnicodeString(&UserAllInfo.FullName,
943 UserInfo3->usri3_full_name);
944
945 // LPWSTR usri3_usr_comment;
946 // LPWSTR usri3_parms;
947 // LPWSTR usri3_workstations;
948 // DWORD usri3_last_logon;
949 // DWORD usri3_last_logoff;
950 // DWORD usri3_acct_expires;
951 // DWORD usri3_max_storage;
952 // DWORD usri3_units_per_week;
953 // PBYTE usri3_logon_hours;
954 // DWORD usri3_bad_pw_count;
955 // DWORD usri3_num_logons;
956 // LPWSTR usri3_logon_server;
957 // DWORD usri3_country_code;
958 // DWORD usri3_code_page;
959 // DWORD usri3_user_id; // ignored
960 // DWORD usri3_primary_group_id;
961 // LPWSTR usri3_profile;
962 // LPWSTR usri3_home_dir_drive;
963 // DWORD usri3_password_expired;
964
965 UserAllInfo.WhichFields =
966 USER_ALL_NTPASSWORDPRESENT |
967 USER_ALL_HOMEDIRECTORY |
968 USER_ALL_ADMINCOMMENT |
969 USER_ALL_SCRIPTPATH |
970 USER_ALL_FULLNAME
971 // USER_ALL_USERACCOUNTCONTROL
972 ;
973 break;
974
975 default:
976 ERR("Unsupported level %lu!\n", Level);
977 return ERROR_INVALID_PARAMETER;
978 }
979
980 Status = SamSetInformationUser(UserHandle,
981 UserAllInformation,
982 &UserAllInfo);
983 if (!NT_SUCCESS(Status))
984 {
985 ERR("SamSetInformationUser failed (Status %08lx)\n", Status);
986 ApiStatus = NetpNtStatusToApiStatus(Status);
987 goto done;
988 }
989
990 done:
991 return ApiStatus;
992 }
993
994
995 /************************************************************
996 * NetUserAdd (NETAPI32.@)
997 */
998 NET_API_STATUS
999 WINAPI
1000 NetUserAdd(LPCWSTR servername,
1001 DWORD level,
1002 LPBYTE bufptr,
1003 LPDWORD parm_err)
1004 {
1005 UNICODE_STRING ServerName;
1006 UNICODE_STRING UserName;
1007 SAM_HANDLE ServerHandle = NULL;
1008 SAM_HANDLE DomainHandle = NULL;
1009 SAM_HANDLE UserHandle = NULL;
1010 ULONG GrantedAccess;
1011 ULONG RelativeId;
1012 NET_API_STATUS ApiStatus = NERR_Success;
1013 NTSTATUS Status = STATUS_SUCCESS;
1014
1015 TRACE("(%s, %d, %p, %p)\n", debugstr_w(servername), level, bufptr, parm_err);
1016
1017 /* Check the info level */
1018 if (level < 1 || level > 4)
1019 return ERROR_INVALID_LEVEL;
1020
1021 if (servername != NULL)
1022 RtlInitUnicodeString(&ServerName, servername);
1023
1024 /* Connect to the SAM Server */
1025 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1026 &ServerHandle,
1027 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1028 NULL);
1029 if (!NT_SUCCESS(Status))
1030 {
1031 ERR("SamConnect failed (Status %08lx)\n", Status);
1032 ApiStatus = NetpNtStatusToApiStatus(Status);
1033 goto done;
1034 }
1035
1036 /* Open the Account Domain */
1037 Status = OpenAccountDomain(ServerHandle,
1038 (servername != NULL) ? &ServerName : NULL,
1039 DOMAIN_CREATE_USER | DOMAIN_LOOKUP,
1040 &DomainHandle);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1044 ApiStatus = NetpNtStatusToApiStatus(Status);
1045 goto done;
1046 }
1047
1048 /* Initialize the user name string */
1049 RtlInitUnicodeString(&UserName,
1050 ((PUSER_INFO_1)bufptr)->usri1_name);
1051
1052 /* Create the user account */
1053 Status = SamCreateUser2InDomain(DomainHandle,
1054 &UserName,
1055 USER_NORMAL_ACCOUNT,
1056 USER_ALL_ACCESS | DELETE | WRITE_DAC,
1057 &UserHandle,
1058 &GrantedAccess,
1059 &RelativeId);
1060 if (!NT_SUCCESS(Status))
1061 {
1062 ERR("SamCreateUser2InDomain failed (Status %08lx)\n", Status);
1063 ApiStatus = NetpNtStatusToApiStatus(Status);
1064 goto done;
1065 }
1066
1067 /* Set user information */
1068 ApiStatus = SetUserInfo(UserHandle,
1069 bufptr,
1070 level);
1071 if (ApiStatus != NERR_Success)
1072 {
1073 ERR("SetUserInfo failed (Status %lu)\n", ApiStatus);
1074 goto done;
1075 }
1076
1077 done:
1078 if (UserHandle != NULL)
1079 SamCloseHandle(UserHandle);
1080
1081 if (DomainHandle != NULL)
1082 SamCloseHandle(DomainHandle);
1083
1084 if (ServerHandle != NULL)
1085 SamCloseHandle(ServerHandle);
1086
1087 return ApiStatus;
1088 }
1089
1090
1091 /******************************************************************************
1092 * NetUserChangePassword (NETAPI32.@)
1093 * PARAMS
1094 * domainname [I] Optional. Domain on which the user resides or the logon
1095 * domain of the current user if NULL.
1096 * username [I] Optional. Username to change the password for or the name
1097 * of the current user if NULL.
1098 * oldpassword [I] The user's current password.
1099 * newpassword [I] The password that the user will be changed to using.
1100 *
1101 * RETURNS
1102 * Success: NERR_Success.
1103 * Failure: NERR_* failure code or win error code.
1104 *
1105 */
1106 NET_API_STATUS
1107 WINAPI
1108 NetUserChangePassword(LPCWSTR domainname,
1109 LPCWSTR username,
1110 LPCWSTR oldpassword,
1111 LPCWSTR newpassword)
1112 {
1113 struct sam_user *user;
1114
1115 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname), debugstr_w(username));
1116
1117 if(domainname)
1118 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname));
1119
1120 if((user = NETAPI_FindUser(username)) == NULL)
1121 return NERR_UserNotFound;
1122
1123 if(lstrcmpW(user->user_password, oldpassword) != 0)
1124 return ERROR_INVALID_PASSWORD;
1125
1126 if(lstrlenW(newpassword) > PWLEN)
1127 return ERROR_PASSWORD_RESTRICTION;
1128
1129 lstrcpyW(user->user_password, newpassword);
1130
1131 return NERR_Success;
1132 }
1133
1134
1135 /************************************************************
1136 * NetUserDel (NETAPI32.@)
1137 */
1138 NET_API_STATUS
1139 WINAPI
1140 NetUserDel(LPCWSTR servername,
1141 LPCWSTR username)
1142 {
1143 NET_API_STATUS status;
1144 struct sam_user *user;
1145
1146 TRACE("(%s, %s)\n", debugstr_w(servername), debugstr_w(username));
1147
1148 if((status = NETAPI_ValidateServername(servername))!= NERR_Success)
1149 return status;
1150
1151 if ((user = NETAPI_FindUser(username)) == NULL)
1152 return NERR_UserNotFound;
1153
1154 list_remove(&user->entry);
1155
1156 HeapFree(GetProcessHeap(), 0, user->home_dir);
1157 HeapFree(GetProcessHeap(), 0, user->user_comment);
1158 HeapFree(GetProcessHeap(), 0, user->user_logon_script_path);
1159 HeapFree(GetProcessHeap(), 0, user);
1160
1161 return NERR_Success;
1162 }
1163
1164
1165 /************************************************************
1166 * NetUserEnum (NETAPI32.@)
1167 */
1168 NET_API_STATUS
1169 WINAPI
1170 NetUserEnum(LPCWSTR servername,
1171 DWORD level,
1172 DWORD filter,
1173 LPBYTE* bufptr,
1174 DWORD prefmaxlen,
1175 LPDWORD entriesread,
1176 LPDWORD totalentries,
1177 LPDWORD resume_handle)
1178 {
1179 UNICODE_STRING ServerName;
1180 PSAM_RID_ENUMERATION CurrentUser;
1181 PENUM_CONTEXT EnumContext = NULL;
1182 LPVOID Buffer = NULL;
1183 ULONG i;
1184 SAM_HANDLE UserHandle = NULL;
1185 PUSER_ACCOUNT_INFORMATION UserInfo = NULL;
1186
1187 NET_API_STATUS ApiStatus = NERR_Success;
1188 NTSTATUS Status = STATUS_SUCCESS;
1189
1190 FIXME("(%s %d 0x%d %p %d %p %p %p) stub!\n", debugstr_w(servername), level,
1191 filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
1192
1193 *entriesread = 0;
1194 *totalentries = 0;
1195 *bufptr = NULL;
1196
1197 if (servername != NULL)
1198 RtlInitUnicodeString(&ServerName, servername);
1199
1200 if (resume_handle != NULL && *resume_handle != 0)
1201 {
1202 EnumContext = (PENUM_CONTEXT)*resume_handle;
1203 }
1204 else
1205 {
1206 ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
1207 if (ApiStatus != NERR_Success)
1208 goto done;
1209
1210 EnumContext->EnumerationContext = 0;
1211 EnumContext->Buffer = NULL;
1212 EnumContext->Count = 0;
1213 EnumContext->Index = 0;
1214 EnumContext->BuiltinDone = FALSE;
1215
1216 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1217 &EnumContext->ServerHandle,
1218 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1219 NULL);
1220 if (!NT_SUCCESS(Status))
1221 {
1222 ERR("SamConnect failed (Status %08lx)\n", Status);
1223 ApiStatus = NetpNtStatusToApiStatus(Status);
1224 goto done;
1225 }
1226
1227 Status = OpenAccountDomain(EnumContext->ServerHandle,
1228 (servername != NULL) ? &ServerName : NULL,
1229 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
1230 &EnumContext->AccountDomainHandle);
1231 if (!NT_SUCCESS(Status))
1232 {
1233 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1234 ApiStatus = NetpNtStatusToApiStatus(Status);
1235 goto done;
1236 }
1237
1238 Status = OpenBuiltinDomain(EnumContext->ServerHandle,
1239 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
1240 &EnumContext->BuiltinDomainHandle);
1241 if (!NT_SUCCESS(Status))
1242 {
1243 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
1244 ApiStatus = NetpNtStatusToApiStatus(Status);
1245 goto done;
1246 }
1247 }
1248
1249 // while (TRUE)
1250 // {
1251 TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
1252 TRACE("EnumContext->Count: %lu\n", EnumContext->Count);
1253
1254 if (EnumContext->Index >= EnumContext->Count)
1255 {
1256 // if (EnumContext->BuiltinDone == TRUE)
1257 // {
1258 // ApiStatus = NERR_Success;
1259 // goto done;
1260 // }
1261
1262 TRACE("Calling SamEnumerateUsersInDomain\n");
1263 Status = SamEnumerateUsersInDomain(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
1264 &EnumContext->EnumerationContext,
1265 0,
1266 (PVOID *)&EnumContext->Buffer,
1267 prefmaxlen,
1268 &EnumContext->Count);
1269
1270 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status);
1271 if (!NT_SUCCESS(Status))
1272 {
1273 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status);
1274 ApiStatus = NetpNtStatusToApiStatus(Status);
1275 goto done;
1276 }
1277
1278 if (Status == STATUS_MORE_ENTRIES)
1279 {
1280 ApiStatus = NERR_BufTooSmall;
1281 goto done;
1282 }
1283 else
1284 {
1285 EnumContext->BuiltinDone = TRUE;
1286 }
1287 }
1288
1289 TRACE("EnumContext: %lu\n", EnumContext);
1290 TRACE("EnumContext->Count: %lu\n", EnumContext->Count);
1291 TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
1292
1293 /* Get a pointer to the current user */
1294 CurrentUser = &EnumContext->Buffer[EnumContext->Index];
1295
1296 TRACE("RID: %lu\n", CurrentUser->RelativeId);
1297
1298 Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
1299 USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT,
1300 CurrentUser->RelativeId,
1301 &UserHandle);
1302 if (!NT_SUCCESS(Status))
1303 {
1304 ERR("SamOpenUser failed (Status %08lx)\n", Status);
1305 ApiStatus = NetpNtStatusToApiStatus(Status);
1306 goto done;
1307 }
1308
1309 Status = SamQueryInformationUser(UserHandle,
1310 UserAccountInformation,
1311 (PVOID *)&UserInfo);
1312 if (!NT_SUCCESS(Status))
1313 {
1314 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
1315 ApiStatus = NetpNtStatusToApiStatus(Status);
1316 goto done;
1317 }
1318
1319 SamCloseHandle(UserHandle);
1320 UserHandle = NULL;
1321
1322 ApiStatus = BuildUserInfoBuffer(UserInfo,
1323 level,
1324 CurrentUser->RelativeId,
1325 &Buffer);
1326 if (ApiStatus != NERR_Success)
1327 {
1328 ERR("BuildUserInfoBuffer failed (ApiStatus %lu)\n", ApiStatus);
1329 goto done;
1330 }
1331
1332 if (UserInfo != NULL)
1333 {
1334 FreeUserInfo(UserInfo);
1335 UserInfo = NULL;
1336 }
1337
1338 EnumContext->Index++;
1339
1340 (*entriesread)++;
1341 // }
1342
1343 done:
1344 if (ApiStatus == NERR_Success && EnumContext->Index < EnumContext->Count)
1345 ApiStatus = ERROR_MORE_DATA;
1346
1347 if (EnumContext != NULL)
1348 *totalentries = EnumContext->Count;
1349
1350 if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
1351 {
1352 if (EnumContext != NULL)
1353 {
1354 if (EnumContext->BuiltinDomainHandle != NULL)
1355 SamCloseHandle(EnumContext->BuiltinDomainHandle);
1356
1357 if (EnumContext->AccountDomainHandle != NULL)
1358 SamCloseHandle(EnumContext->AccountDomainHandle);
1359
1360 if (EnumContext->ServerHandle != NULL)
1361 SamCloseHandle(EnumContext->ServerHandle);
1362
1363 if (EnumContext->Buffer != NULL)
1364 {
1365 for (i = 0; i < EnumContext->Count; i++)
1366 {
1367 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
1368 }
1369
1370 SamFreeMemory(EnumContext->Buffer);
1371 }
1372
1373 NetApiBufferFree(EnumContext);
1374 EnumContext = NULL;
1375 }
1376 }
1377
1378 if (UserHandle != NULL)
1379 SamCloseHandle(UserHandle);
1380
1381 if (UserInfo != NULL)
1382 FreeUserInfo(UserInfo);
1383
1384 if (resume_handle != NULL)
1385 *resume_handle = (DWORD_PTR)EnumContext;
1386
1387 *bufptr = (LPBYTE)Buffer;
1388
1389 TRACE("return %lu\n", ApiStatus);
1390
1391 return ApiStatus;
1392 }
1393
1394
1395 /************************************************************
1396 * NetUserGetGroups (NETAPI32.@)
1397 */
1398 NET_API_STATUS
1399 WINAPI
1400 NetUserGetGroups(LPCWSTR servername,
1401 LPCWSTR username,
1402 DWORD level,
1403 LPBYTE *bufptr,
1404 DWORD prefixmaxlen,
1405 LPDWORD entriesread,
1406 LPDWORD totalentries)
1407 {
1408 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername),
1409 debugstr_w(username), level, bufptr, prefixmaxlen, entriesread,
1410 totalentries);
1411
1412 *bufptr = NULL;
1413 *entriesread = 0;
1414 *totalentries = 0;
1415
1416 return ERROR_INVALID_LEVEL;
1417 }
1418
1419
1420 /************************************************************
1421 * NetUserGetInfo (NETAPI32.@)
1422 */
1423 NET_API_STATUS
1424 WINAPI
1425 NetUserGetInfo(LPCWSTR servername,
1426 LPCWSTR username,
1427 DWORD level,
1428 LPBYTE* bufptr)
1429 {
1430 UNICODE_STRING ServerName;
1431 UNICODE_STRING UserName;
1432 SAM_HANDLE ServerHandle = NULL;
1433 SAM_HANDLE AccountDomainHandle = NULL;
1434 SAM_HANDLE UserHandle = NULL;
1435 PULONG RelativeIds = NULL;
1436 PSID_NAME_USE Use = NULL;
1437 PUSER_ACCOUNT_INFORMATION UserInfo = NULL;
1438 LPVOID Buffer = NULL;
1439 NET_API_STATUS ApiStatus = NERR_Success;
1440 NTSTATUS Status = STATUS_SUCCESS;
1441
1442 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername),
1443 debugstr_w(username), level, bufptr);
1444
1445 if (servername != NULL)
1446 RtlInitUnicodeString(&ServerName, servername);
1447
1448 RtlInitUnicodeString(&UserName, username);
1449
1450 /* Connect to the SAM Server */
1451 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1452 &ServerHandle,
1453 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1454 NULL);
1455 if (!NT_SUCCESS(Status))
1456 {
1457 ERR("SamConnect failed (Status %08lx)\n", Status);
1458 ApiStatus = NetpNtStatusToApiStatus(Status);
1459 goto done;
1460 }
1461
1462 /* Open the Account Domain */
1463 Status = OpenAccountDomain(ServerHandle,
1464 (servername != NULL) ? &ServerName : NULL,
1465 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
1466 &AccountDomainHandle);
1467 if (!NT_SUCCESS(Status))
1468 {
1469 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1470 ApiStatus = NetpNtStatusToApiStatus(Status);
1471 goto done;
1472 }
1473
1474 /* Get the RID for the given user name */
1475 Status = SamLookupNamesInDomain(AccountDomainHandle,
1476 1,
1477 &UserName,
1478 &RelativeIds,
1479 &Use);
1480 if (!NT_SUCCESS(Status))
1481 {
1482 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
1483 ApiStatus = NetpNtStatusToApiStatus(Status);
1484 goto done;
1485 }
1486
1487 /* Check if the account is a user account */
1488 if (Use[0] != SidTypeUser)
1489 {
1490 ERR("No user found!\n");
1491 ApiStatus = NERR_UserNotFound;
1492 goto done;
1493 }
1494
1495 TRACE("RID: %lu\n", RelativeIds[0]);
1496
1497 /* Open the user object */
1498 Status = SamOpenUser(AccountDomainHandle,
1499 USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT,
1500 RelativeIds[0],
1501 &UserHandle);
1502 if (!NT_SUCCESS(Status))
1503 {
1504 ERR("SamOpenUser failed (Status %08lx)\n", Status);
1505 ApiStatus = NetpNtStatusToApiStatus(Status);
1506 goto done;
1507 }
1508
1509 Status = SamQueryInformationUser(UserHandle,
1510 UserAccountInformation,
1511 (PVOID *)&UserInfo);
1512 if (!NT_SUCCESS(Status))
1513 {
1514 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
1515 ApiStatus = NetpNtStatusToApiStatus(Status);
1516 goto done;
1517 }
1518
1519 ApiStatus = BuildUserInfoBuffer(UserInfo,
1520 level,
1521 RelativeIds[0],
1522 &Buffer);
1523 if (ApiStatus != NERR_Success)
1524 {
1525 ERR("BuildUserInfoBuffer failed (ApiStatus %08lu)\n", ApiStatus);
1526 goto done;
1527 }
1528
1529 done:
1530 if (UserInfo != NULL)
1531 FreeUserInfo(UserInfo);
1532
1533 if (UserHandle != NULL)
1534 SamCloseHandle(UserHandle);
1535
1536 if (RelativeIds != NULL)
1537 SamFreeMemory(RelativeIds);
1538
1539 if (Use != NULL)
1540 SamFreeMemory(Use);
1541
1542 if (AccountDomainHandle != NULL)
1543 SamCloseHandle(AccountDomainHandle);
1544
1545 if (ServerHandle != NULL)
1546 SamCloseHandle(ServerHandle);
1547
1548 *bufptr = (LPBYTE)Buffer;
1549
1550 return ApiStatus;
1551 }
1552
1553
1554 /************************************************************
1555 * NetUserGetLocalGroups (NETAPI32.@)
1556 */
1557 NET_API_STATUS
1558 WINAPI
1559 NetUserGetLocalGroups(LPCWSTR servername,
1560 LPCWSTR username,
1561 DWORD level,
1562 DWORD flags,
1563 LPBYTE* bufptr,
1564 DWORD prefmaxlen,
1565 LPDWORD entriesread,
1566 LPDWORD totalentries)
1567 {
1568 UNICODE_STRING ServerName;
1569 UNICODE_STRING UserName;
1570 SAM_HANDLE ServerHandle = NULL;
1571 SAM_HANDLE BuiltinDomainHandle = NULL;
1572 SAM_HANDLE AccountDomainHandle = NULL;
1573 PSID AccountDomainSid = NULL;
1574 PSID UserSid = NULL;
1575 PULONG RelativeIds = NULL;
1576 PSID_NAME_USE Use = NULL;
1577 ULONG BuiltinMemberCount = 0;
1578 ULONG AccountMemberCount = 0;
1579 PULONG BuiltinAliases = NULL;
1580 PULONG AccountAliases = NULL;
1581 PUNICODE_STRING BuiltinNames = NULL;
1582 PUNICODE_STRING AccountNames = NULL;
1583 PLOCALGROUP_USERS_INFO_0 Buffer = NULL;
1584 ULONG Size;
1585 ULONG Count = 0;
1586 ULONG Index;
1587 ULONG i;
1588 LPWSTR StrPtr;
1589 NET_API_STATUS ApiStatus = NERR_Success;
1590 NTSTATUS Status = STATUS_SUCCESS;
1591
1592 TRACE("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
1593 debugstr_w(servername), debugstr_w(username), level, flags, bufptr,
1594 prefmaxlen, entriesread, totalentries);
1595
1596 if (level != 0)
1597 return ERROR_INVALID_LEVEL;
1598
1599 if (flags & ~LG_INCLUDE_INDIRECT)
1600 return ERROR_INVALID_PARAMETER;
1601
1602 if (flags & LG_INCLUDE_INDIRECT)
1603 {
1604 WARN("The flag LG_INCLUDE_INDIRECT is not supported yet!\n");
1605 }
1606
1607 if (servername != NULL)
1608 RtlInitUnicodeString(&ServerName, servername);
1609
1610 RtlInitUnicodeString(&UserName, username);
1611
1612 /* Connect to the SAM Server */
1613 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1614 &ServerHandle,
1615 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1616 NULL);
1617 if (!NT_SUCCESS(Status))
1618 {
1619 ERR("SamConnect failed (Status %08lx)\n", Status);
1620 ApiStatus = NetpNtStatusToApiStatus(Status);
1621 goto done;
1622 }
1623
1624 /* Open the Builtin Domain */
1625 Status = OpenBuiltinDomain(ServerHandle,
1626 DOMAIN_LOOKUP | DOMAIN_GET_ALIAS_MEMBERSHIP,
1627 &BuiltinDomainHandle);
1628 if (!NT_SUCCESS(Status))
1629 {
1630 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
1631 ApiStatus = NetpNtStatusToApiStatus(Status);
1632 goto done;
1633 }
1634
1635 /* Get the Account Domain SID */
1636 Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
1637 &AccountDomainSid);
1638 if (!NT_SUCCESS(Status))
1639 {
1640 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
1641 ApiStatus = NetpNtStatusToApiStatus(Status);
1642 goto done;
1643 }
1644
1645 /* Open the Account Domain */
1646 Status = SamOpenDomain(ServerHandle,
1647 DOMAIN_LOOKUP | DOMAIN_GET_ALIAS_MEMBERSHIP,
1648 AccountDomainSid,
1649 &AccountDomainHandle);
1650 if (!NT_SUCCESS(Status))
1651 {
1652 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1653 ApiStatus = NetpNtStatusToApiStatus(Status);
1654 goto done;
1655 }
1656
1657 /* Get the RID for the given user name */
1658 Status = SamLookupNamesInDomain(AccountDomainHandle,
1659 1,
1660 &UserName,
1661 &RelativeIds,
1662 &Use);
1663 if (!NT_SUCCESS(Status))
1664 {
1665 ERR("SamLookupNamesInDomain failed (Status %08lx)\n", Status);
1666 ApiStatus = NetpNtStatusToApiStatus(Status);
1667 goto done;
1668 }
1669
1670 /* Fail, if it is not a user account */
1671 if (Use[0] != SidTypeUser)
1672 {
1673 ERR("Account is not a User!\n");
1674 ApiStatus = NERR_UserNotFound;
1675 goto done;
1676 }
1677
1678 /* Build the User SID from the Account Domain SID and the users RID */
1679 UserSid = CreateSidFromSidAndRid(AccountDomainSid,
1680 RelativeIds[0]);
1681 if (UserSid == NULL)
1682 {
1683 ERR("CreateSidFromSidAndRid failed!\n");
1684 ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
1685 goto done;
1686 }
1687
1688 /* Get alias memberships in the Builtin Domain */
1689 Status = SamGetAliasMembership(BuiltinDomainHandle,
1690 1,
1691 &UserSid,
1692 &BuiltinMemberCount,
1693 &BuiltinAliases);
1694 if (!NT_SUCCESS(Status))
1695 {
1696 ERR("SamGetAliasMembership failed (Status %08lx)\n", Status);
1697 ApiStatus = NetpNtStatusToApiStatus(Status);
1698 goto done;
1699 }
1700
1701 if (BuiltinMemberCount > 0)
1702 {
1703 /* Get the Names of the builtin alias members */
1704 Status = SamLookupIdsInDomain(BuiltinDomainHandle,
1705 BuiltinMemberCount,
1706 BuiltinAliases,
1707 &BuiltinNames,
1708 NULL);
1709 if (!NT_SUCCESS(Status))
1710 {
1711 ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
1712 ApiStatus = NetpNtStatusToApiStatus(Status);
1713 goto done;
1714 }
1715 }
1716
1717 /* Get alias memberships in the Account Domain */
1718 Status = SamGetAliasMembership(AccountDomainHandle,
1719 1,
1720 &UserSid,
1721 &AccountMemberCount,
1722 &AccountAliases);
1723 if (!NT_SUCCESS(Status))
1724 {
1725 ERR("SamGetAliasMembership failed (Status %08lx)\n", Status);
1726 ApiStatus = NetpNtStatusToApiStatus(Status);
1727 goto done;
1728 }
1729
1730 if (AccountMemberCount > 0)
1731 {
1732 /* Get the Names of the builtin alias members */
1733 Status = SamLookupIdsInDomain(AccountDomainHandle,
1734 AccountMemberCount,
1735 AccountAliases,
1736 &AccountNames,
1737 NULL);
1738 if (!NT_SUCCESS(Status))
1739 {
1740 ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
1741 ApiStatus = NetpNtStatusToApiStatus(Status);
1742 goto done;
1743 }
1744 }
1745
1746 /* Calculate the required buffer size */
1747 Size = 0;
1748
1749 for (i = 0; i < BuiltinMemberCount; i++)
1750 {
1751 if (BuiltinNames[i].Length > 0)
1752 {
1753 Size += (sizeof(LOCALGROUP_USERS_INFO_0) + BuiltinNames[i].Length + sizeof(UNICODE_NULL));
1754 Count++;
1755 }
1756 }
1757
1758 for (i = 0; i < AccountMemberCount; i++)
1759 {
1760 if (BuiltinNames[i].Length > 0)
1761 {
1762 Size += (sizeof(LOCALGROUP_USERS_INFO_0) + AccountNames[i].Length + sizeof(UNICODE_NULL));
1763 Count++;
1764 }
1765 }
1766
1767 if (Size == 0)
1768 {
1769 ApiStatus = NERR_Success;
1770 goto done;
1771 }
1772
1773 /* Allocate buffer */
1774 ApiStatus = NetApiBufferAllocate(Size, (LPVOID*)&Buffer);
1775 if (ApiStatus != NERR_Success)
1776 goto done;
1777
1778 ZeroMemory(Buffer, Size);
1779
1780 StrPtr = (LPWSTR)((INT_PTR)Buffer + Count * sizeof(LOCALGROUP_USERS_INFO_0));
1781
1782 /* Copy data to the allocated buffer */
1783 Index = 0;
1784 for (i = 0; i < BuiltinMemberCount; i++)
1785 {
1786 if (BuiltinNames[i].Length > 0)
1787 {
1788 CopyMemory(StrPtr,
1789 BuiltinNames[i].Buffer,
1790 BuiltinNames[i].Length);
1791 Buffer[Index].lgrui0_name = StrPtr;
1792
1793 StrPtr = (LPWSTR)((INT_PTR)StrPtr + BuiltinNames[i].Length + sizeof(UNICODE_NULL));
1794 Index++;
1795 }
1796 }
1797
1798 for (i = 0; i < AccountMemberCount; i++)
1799 {
1800 if (AccountNames[i].Length > 0)
1801 {
1802 CopyMemory(StrPtr,
1803 AccountNames[i].Buffer,
1804 AccountNames[i].Length);
1805 Buffer[Index].lgrui0_name = StrPtr;
1806
1807 StrPtr = (LPWSTR)((INT_PTR)StrPtr + AccountNames[i].Length + sizeof(UNICODE_NULL));
1808 Index++;
1809 }
1810 }
1811
1812 done:
1813 if (AccountNames != NULL)
1814 SamFreeMemory(AccountNames);
1815
1816 if (BuiltinNames != NULL)
1817 SamFreeMemory(BuiltinNames);
1818
1819 if (AccountAliases != NULL)
1820 SamFreeMemory(AccountAliases);
1821
1822 if (BuiltinAliases != NULL)
1823 SamFreeMemory(BuiltinAliases);
1824
1825 if (RelativeIds != NULL)
1826 SamFreeMemory(RelativeIds);
1827
1828 if (Use != NULL)
1829 SamFreeMemory(Use);
1830
1831 if (UserSid != NULL)
1832 RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
1833
1834 if (AccountDomainSid != NULL)
1835 RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
1836
1837 if (AccountDomainHandle != NULL)
1838 SamCloseHandle(AccountDomainHandle);
1839
1840 if (BuiltinDomainHandle != NULL)
1841 SamCloseHandle(BuiltinDomainHandle);
1842
1843 if (ServerHandle != NULL)
1844 SamCloseHandle(ServerHandle);
1845
1846 if (ApiStatus != NERR_Success && ApiStatus != ERROR_MORE_DATA)
1847 {
1848 *entriesread = 0;
1849 *totalentries = 0;
1850 }
1851 else
1852 {
1853 *entriesread = Count;
1854 *totalentries = Count;
1855 }
1856
1857 *bufptr = (LPBYTE)Buffer;
1858
1859 return ApiStatus;
1860 }
1861
1862
1863 /******************************************************************************
1864 * NetUserSetGroups (NETAPI32.@)
1865 */
1866 NET_API_STATUS
1867 WINAPI
1868 NetUserSetGroups(LPCWSTR servername,
1869 LPCWSTR username,
1870 DWORD level,
1871 LPBYTE buf,
1872 DWORD num_entries)
1873 {
1874 FIXME("(%s %s %lu %p %lu)\n",
1875 debugstr_w(servername), debugstr_w(username), level, buf, num_entries);
1876 return ERROR_ACCESS_DENIED;
1877 }
1878
1879
1880 /******************************************************************************
1881 * NetUserSetInfo (NETAPI32.@)
1882 */
1883 NET_API_STATUS
1884 WINAPI
1885 NetUserSetInfo(LPCWSTR servername,
1886 LPCWSTR username,
1887 DWORD level,
1888 LPBYTE buf,
1889 LPDWORD parm_err)
1890 {
1891 FIXME("(%s %s %lu %p %p)\n",
1892 debugstr_w(servername), debugstr_w(username), level, buf, parm_err);
1893 return ERROR_ACCESS_DENIED;
1894 }
1895
1896 /* EOF */