Sync with trunk r58033.
[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 #include "netapi32.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
24
25
26 typedef struct _ENUM_CONTEXT
27 {
28 SAM_HANDLE ServerHandle;
29 SAM_HANDLE BuiltinDomainHandle;
30 SAM_HANDLE AccountDomainHandle;
31
32 SAM_ENUMERATE_HANDLE EnumerationContext;
33 PSAM_RID_ENUMERATION Buffer;
34 ULONG Returned;
35 ULONG Index;
36 BOOLEAN BuiltinDone;
37
38 } ENUM_CONTEXT, *PENUM_CONTEXT;
39
40
41 /* NOTE: So far, this is implemented to support tests that require user logins,
42 * but not designed to handle real user databases. Those should probably
43 * be synced with either the host's user database or with Samba.
44 *
45 * FIXME: The user database should hold all the information the USER_INFO_4 struct
46 * needs, but for the first try, I will just implement the USER_INFO_1 fields.
47 */
48
49 struct sam_user
50 {
51 struct list entry;
52 WCHAR user_name[LM20_UNLEN+1];
53 WCHAR user_password[PWLEN + 1];
54 DWORD sec_since_passwd_change;
55 DWORD user_priv;
56 LPWSTR home_dir;
57 LPWSTR user_comment;
58 DWORD user_flags;
59 LPWSTR user_logon_script_path;
60 };
61
62 static struct list user_list = LIST_INIT( user_list );
63
64 BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName);
65
66 /************************************************************
67 * NETAPI_ValidateServername
68 *
69 * Validates server name
70 */
71 static NET_API_STATUS NETAPI_ValidateServername(LPCWSTR ServerName)
72 {
73 if (ServerName)
74 {
75 if (ServerName[0] == 0)
76 return ERROR_BAD_NETPATH;
77 else if (
78 ((ServerName[0] == '\\') &&
79 (ServerName[1] != '\\'))
80 ||
81 ((ServerName[0] == '\\') &&
82 (ServerName[1] == '\\') &&
83 (ServerName[2] == 0))
84 )
85 return ERROR_INVALID_NAME;
86 }
87 return NERR_Success;
88 }
89
90 /************************************************************
91 * NETAPI_FindUser
92 *
93 * Looks for a user in the user database.
94 * Returns a pointer to the entry in the user list when the user
95 * is found, NULL otherwise.
96 */
97 static struct sam_user* NETAPI_FindUser(LPCWSTR UserName)
98 {
99 struct sam_user *user;
100
101 LIST_FOR_EACH_ENTRY(user, &user_list, struct sam_user, entry)
102 {
103 if(lstrcmpW(user->user_name, UserName) == 0)
104 return user;
105 }
106 return NULL;
107 }
108
109
110 static
111 NET_API_STATUS
112 BuildUserInfoBuffer(PUSER_ACCOUNT_INFORMATION UserInfo,
113 DWORD level,
114 ULONG RelativeId,
115 LPVOID *Buffer)
116 {
117 LPVOID LocalBuffer = NULL;
118 PUSER_INFO_0 UserInfo0;
119 PUSER_INFO_1 UserInfo1;
120 PUSER_INFO_10 UserInfo10;
121 PUSER_INFO_20 UserInfo20;
122 LPWSTR Ptr;
123 ULONG Size = 0;
124 NET_API_STATUS ApiStatus = NERR_Success;
125
126 *Buffer = NULL;
127
128 switch (level)
129 {
130 case 0:
131 Size = sizeof(USER_INFO_0) +
132 UserInfo->UserName.Length + sizeof(WCHAR);
133 break;
134
135 case 1:
136 Size = sizeof(USER_INFO_1) +
137 UserInfo->UserName.Length + sizeof(WCHAR);
138
139 if (UserInfo->HomeDirectory.Length > 0)
140 Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR);
141
142 if (UserInfo->AdminComment.Length > 0)
143 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
144
145 if (UserInfo->ScriptPath.Length > 0)
146 Size = UserInfo->ScriptPath.Length + sizeof(WCHAR);
147 break;
148
149 // case 2:
150 // case 3:
151 // case 4:
152
153 case 10:
154 Size = sizeof(USER_INFO_10) +
155 UserInfo->UserName.Length + sizeof(WCHAR);
156
157 if (UserInfo->AdminComment.Length > 0)
158 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
159
160 /* FIXME: usri10_usr_comment */
161
162 if (UserInfo->FullName.Length > 0)
163 Size += UserInfo->FullName.Length + sizeof(WCHAR);
164 break;
165
166 // case 11:
167
168 case 20:
169 Size = sizeof(USER_INFO_20) +
170 UserInfo->UserName.Length + sizeof(WCHAR);
171
172 if (UserInfo->FullName.Length > 0)
173 Size += UserInfo->FullName.Length + sizeof(WCHAR);
174
175 if (UserInfo->AdminComment.Length > 0)
176 Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
177 break;
178
179 // case 23:
180
181 default:
182 ApiStatus = ERROR_INVALID_LEVEL;
183 goto done;
184 }
185
186 ApiStatus = NetApiBufferAllocate(Size, &LocalBuffer);
187 if (ApiStatus != NERR_Success)
188 goto done;
189
190 ZeroMemory(LocalBuffer, Size);
191
192 switch (level)
193 {
194 case 0:
195 UserInfo0 = (PUSER_INFO_0)LocalBuffer;
196
197 Ptr = (LPWSTR)((ULONG_PTR)UserInfo0 + sizeof(USER_INFO_0));
198 UserInfo0->usri0_name = Ptr;
199
200 memcpy(UserInfo0->usri0_name,
201 UserInfo->UserName.Buffer,
202 UserInfo->UserName.Length);
203 UserInfo0->usri0_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
204 break;
205
206 case 1:
207 UserInfo1 = (PUSER_INFO_1)LocalBuffer;
208
209 Ptr = (LPWSTR)((ULONG_PTR)UserInfo1 + sizeof(USER_INFO_1));
210
211 UserInfo1->usri1_name = Ptr;
212
213 memcpy(UserInfo1->usri1_name,
214 UserInfo->UserName.Buffer,
215 UserInfo->UserName.Length);
216 UserInfo1->usri1_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
217
218 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
219
220 UserInfo1->usri1_password = NULL;
221
222 /* FIXME: UserInfo1->usri1_password_age */
223 /* FIXME: UserInfo1->usri1_priv */
224
225 if (UserInfo->HomeDirectory.Length > 0)
226 {
227 UserInfo1->usri1_home_dir = Ptr;
228
229 memcpy(UserInfo1->usri1_home_dir,
230 UserInfo->HomeDirectory.Buffer,
231 UserInfo->HomeDirectory.Length);
232 UserInfo1->usri1_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
233
234 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
235 }
236
237 if (UserInfo->AdminComment.Length > 0)
238 {
239 UserInfo1->usri1_comment = Ptr;
240
241 memcpy(UserInfo1->usri1_comment,
242 UserInfo->AdminComment.Buffer,
243 UserInfo->AdminComment.Length);
244 UserInfo1->usri1_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
245
246 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
247 }
248
249 UserInfo1->usri1_flags = UserInfo->UserAccountControl;
250
251 if (UserInfo->ScriptPath.Length > 0)
252 {
253 UserInfo1->usri1_script_path = Ptr;
254
255 memcpy(UserInfo1->usri1_script_path,
256 UserInfo->ScriptPath.Buffer,
257 UserInfo->ScriptPath.Length);
258 UserInfo1->usri1_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
259 }
260 break;
261
262 // case 2:
263 // case 3:
264 // case 4:
265
266 case 10:
267 UserInfo10 = (PUSER_INFO_10)LocalBuffer;
268
269 Ptr = (LPWSTR)((ULONG_PTR)UserInfo10 + sizeof(USER_INFO_10));
270
271 UserInfo10->usri10_name = Ptr;
272
273 memcpy(UserInfo10->usri10_name,
274 UserInfo->UserName.Buffer,
275 UserInfo->UserName.Length);
276 UserInfo10->usri10_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
277
278 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
279
280 if (UserInfo->AdminComment.Length > 0)
281 {
282 UserInfo10->usri10_comment = Ptr;
283
284 memcpy(UserInfo10->usri10_comment,
285 UserInfo->AdminComment.Buffer,
286 UserInfo->AdminComment.Length);
287 UserInfo10->usri10_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
288
289 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
290 }
291
292 /* FIXME: UserInfo10->usri10_usr_comment */
293
294 if (UserInfo->FullName.Length > 0)
295 {
296 UserInfo10->usri10_full_name = Ptr;
297
298 memcpy(UserInfo10->usri10_full_name,
299 UserInfo->FullName.Buffer,
300 UserInfo->FullName.Length);
301 UserInfo10->usri10_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
302 }
303 break;
304
305 // case 11:
306
307 case 20:
308 UserInfo20 = (PUSER_INFO_20)LocalBuffer;
309
310 Ptr = (LPWSTR)((ULONG_PTR)UserInfo20 + sizeof(USER_INFO_20));
311
312 UserInfo20->usri20_name = Ptr;
313
314 memcpy(UserInfo20->usri20_name,
315 UserInfo->UserName.Buffer,
316 UserInfo->UserName.Length);
317 UserInfo20->usri20_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
318
319 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
320
321 if (UserInfo->FullName.Length > 0)
322 {
323 UserInfo20->usri20_full_name = Ptr;
324
325 memcpy(UserInfo20->usri20_full_name,
326 UserInfo->FullName.Buffer,
327 UserInfo->FullName.Length);
328 UserInfo20->usri20_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
329
330 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
331 }
332
333 if (UserInfo->AdminComment.Length > 0)
334 {
335 UserInfo20->usri20_comment = Ptr;
336
337 memcpy(UserInfo20->usri20_comment,
338 UserInfo->AdminComment.Buffer,
339 UserInfo->AdminComment.Length);
340 UserInfo20->usri20_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
341
342 Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
343 }
344
345 UserInfo20->usri20_flags = UserInfo->UserAccountControl;
346 UserInfo20->usri20_user_id = RelativeId;
347 break;
348
349 // case 23:
350 }
351
352 done:
353 if (ApiStatus == NERR_Success)
354 {
355 *Buffer = LocalBuffer;
356 }
357 else
358 {
359 if (LocalBuffer != NULL)
360 NetApiBufferFree(LocalBuffer);
361 }
362
363 return ApiStatus;
364 }
365
366
367 static
368 VOID
369 FreeUserInfo(PUSER_ACCOUNT_INFORMATION UserInfo)
370 {
371 if (UserInfo->UserName.Buffer != NULL)
372 SamFreeMemory(UserInfo->UserName.Buffer);
373
374 if (UserInfo->FullName.Buffer != NULL)
375 SamFreeMemory(UserInfo->FullName.Buffer);
376
377 if (UserInfo->HomeDirectory.Buffer != NULL)
378 SamFreeMemory(UserInfo->HomeDirectory.Buffer);
379
380 if (UserInfo->HomeDirectoryDrive.Buffer != NULL)
381 SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer);
382
383 if (UserInfo->ScriptPath.Buffer != NULL)
384 SamFreeMemory(UserInfo->ScriptPath.Buffer);
385
386 if (UserInfo->ProfilePath.Buffer != NULL)
387 SamFreeMemory(UserInfo->ProfilePath.Buffer);
388
389 if (UserInfo->AdminComment.Buffer != NULL)
390 SamFreeMemory(UserInfo->AdminComment.Buffer);
391
392 if (UserInfo->WorkStations.Buffer != NULL)
393 SamFreeMemory(UserInfo->WorkStations.Buffer);
394
395 if (UserInfo->LogonHours.LogonHours != NULL)
396 SamFreeMemory(UserInfo->LogonHours.LogonHours);
397
398 SamFreeMemory(UserInfo);
399 }
400
401
402 /************************************************************
403 * NetUserAdd (NETAPI32.@)
404 */
405 NET_API_STATUS
406 WINAPI
407 NetUserAdd(LPCWSTR servername,
408 DWORD level,
409 LPBYTE bufptr,
410 LPDWORD parm_err)
411 {
412 NET_API_STATUS status;
413 struct sam_user * su = NULL;
414
415 FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername), level, bufptr, parm_err);
416
417 if((status = NETAPI_ValidateServername(servername)) != NERR_Success)
418 return status;
419
420 switch(level)
421 {
422 /* Level 3 and 4 are identical for the purposes of NetUserAdd */
423 case 4:
424 case 3:
425 FIXME("Level 3 and 4 not implemented.\n");
426 /* Fall through */
427 case 2:
428 FIXME("Level 2 not implemented.\n");
429 /* Fall through */
430 case 1:
431 {
432 PUSER_INFO_1 ui = (PUSER_INFO_1) bufptr;
433 su = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user));
434 if(!su)
435 {
436 status = NERR_InternalError;
437 break;
438 }
439
440 if(lstrlenW(ui->usri1_name) > LM20_UNLEN)
441 {
442 status = NERR_BadUsername;
443 break;
444 }
445
446 /*FIXME: do other checks for a valid username */
447 lstrcpyW(su->user_name, ui->usri1_name);
448
449 if(lstrlenW(ui->usri1_password) > PWLEN)
450 {
451 /* Always return PasswordTooShort on invalid passwords. */
452 status = NERR_PasswordTooShort;
453 break;
454 }
455 lstrcpyW(su->user_password, ui->usri1_password);
456
457 su->sec_since_passwd_change = ui->usri1_password_age;
458 su->user_priv = ui->usri1_priv;
459 su->user_flags = ui->usri1_flags;
460
461 /*FIXME: set the other LPWSTRs to NULL for now */
462 su->home_dir = NULL;
463 su->user_comment = NULL;
464 su->user_logon_script_path = NULL;
465
466 list_add_head(&user_list, &su->entry);
467 return NERR_Success;
468 }
469 default:
470 TRACE("Invalid level %d specified.\n", level);
471 status = ERROR_INVALID_LEVEL;
472 break;
473 }
474
475 HeapFree(GetProcessHeap(), 0, su);
476
477 return status;
478 }
479
480
481 /******************************************************************************
482 * NetUserChangePassword (NETAPI32.@)
483 * PARAMS
484 * domainname [I] Optional. Domain on which the user resides or the logon
485 * domain of the current user if NULL.
486 * username [I] Optional. Username to change the password for or the name
487 * of the current user if NULL.
488 * oldpassword [I] The user's current password.
489 * newpassword [I] The password that the user will be changed to using.
490 *
491 * RETURNS
492 * Success: NERR_Success.
493 * Failure: NERR_* failure code or win error code.
494 *
495 */
496 NET_API_STATUS
497 WINAPI
498 NetUserChangePassword(LPCWSTR domainname,
499 LPCWSTR username,
500 LPCWSTR oldpassword,
501 LPCWSTR newpassword)
502 {
503 struct sam_user *user;
504
505 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname), debugstr_w(username));
506
507 if(domainname)
508 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname));
509
510 if((user = NETAPI_FindUser(username)) == NULL)
511 return NERR_UserNotFound;
512
513 if(lstrcmpW(user->user_password, oldpassword) != 0)
514 return ERROR_INVALID_PASSWORD;
515
516 if(lstrlenW(newpassword) > PWLEN)
517 return ERROR_PASSWORD_RESTRICTION;
518
519 lstrcpyW(user->user_password, newpassword);
520
521 return NERR_Success;
522 }
523
524
525 /************************************************************
526 * NetUserDel (NETAPI32.@)
527 */
528 NET_API_STATUS
529 WINAPI
530 NetUserDel(LPCWSTR servername,
531 LPCWSTR username)
532 {
533 NET_API_STATUS status;
534 struct sam_user *user;
535
536 TRACE("(%s, %s)\n", debugstr_w(servername), debugstr_w(username));
537
538 if((status = NETAPI_ValidateServername(servername))!= NERR_Success)
539 return status;
540
541 if ((user = NETAPI_FindUser(username)) == NULL)
542 return NERR_UserNotFound;
543
544 list_remove(&user->entry);
545
546 HeapFree(GetProcessHeap(), 0, user->home_dir);
547 HeapFree(GetProcessHeap(), 0, user->user_comment);
548 HeapFree(GetProcessHeap(), 0, user->user_logon_script_path);
549 HeapFree(GetProcessHeap(), 0, user);
550
551 return NERR_Success;
552 }
553
554
555 /************************************************************
556 * NetUserEnum (NETAPI32.@)
557 */
558 NET_API_STATUS
559 WINAPI
560 NetUserEnum(LPCWSTR servername,
561 DWORD level,
562 DWORD filter,
563 LPBYTE* bufptr,
564 DWORD prefmaxlen,
565 LPDWORD entriesread,
566 LPDWORD totalentries,
567 LPDWORD resume_handle)
568 {
569 UNICODE_STRING ServerName;
570 PSAM_RID_ENUMERATION CurrentUser;
571 PENUM_CONTEXT EnumContext = NULL;
572 LPVOID Buffer = NULL;
573 ULONG i;
574 SAM_HANDLE UserHandle = NULL;
575 PUSER_ACCOUNT_INFORMATION UserInfo = NULL;
576
577 NET_API_STATUS ApiStatus = NERR_Success;
578 NTSTATUS Status = STATUS_SUCCESS;
579
580 FIXME("(%s %d 0x%d %p %d %p %p %p) stub!\n", debugstr_w(servername), level,
581 filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
582
583 *entriesread = 0;
584 *totalentries = 0;
585 *bufptr = NULL;
586
587 if (servername != NULL)
588 RtlInitUnicodeString(&ServerName, servername);
589
590 if (resume_handle != NULL && *resume_handle != 0)
591 {
592 EnumContext = (PENUM_CONTEXT)*resume_handle;
593 }
594 else
595 {
596 ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
597 if (ApiStatus != NERR_Success)
598 goto done;
599
600 EnumContext->EnumerationContext = 0;
601 EnumContext->Buffer = NULL;
602 EnumContext->Returned = 0;
603 EnumContext->Index = 0;
604 EnumContext->BuiltinDone = FALSE;
605
606 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
607 &EnumContext->ServerHandle,
608 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
609 NULL);
610 if (!NT_SUCCESS(Status))
611 {
612 ERR("SamConnect failed (Status %08lx)\n", Status);
613 ApiStatus = NetpNtStatusToApiStatus(Status);
614 goto done;
615 }
616
617 Status = OpenAccountDomain(EnumContext->ServerHandle,
618 (servername != NULL) ? &ServerName : NULL,
619 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
620 &EnumContext->AccountDomainHandle);
621 if (!NT_SUCCESS(Status))
622 {
623 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
624 ApiStatus = NetpNtStatusToApiStatus(Status);
625 goto done;
626 }
627
628 Status = OpenBuiltinDomain(EnumContext->ServerHandle,
629 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
630 &EnumContext->BuiltinDomainHandle);
631 if (!NT_SUCCESS(Status))
632 {
633 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
634 ApiStatus = NetpNtStatusToApiStatus(Status);
635 goto done;
636 }
637 }
638
639 // while (TRUE)
640 // {
641 TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
642 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
643
644 if (EnumContext->Index >= EnumContext->Returned)
645 {
646 // if (EnumContext->BuiltinDone == TRUE)
647 // {
648 // ApiStatus = NERR_Success;
649 // goto done;
650 // }
651
652 TRACE("Calling SamEnumerateUsersInDomain\n");
653 Status = SamEnumerateUsersInDomain(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
654 &EnumContext->EnumerationContext,
655 0,
656 (PVOID *)&EnumContext->Buffer,
657 prefmaxlen,
658 &EnumContext->Returned);
659
660 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status);
661 if (!NT_SUCCESS(Status))
662 {
663 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status);
664 ApiStatus = NetpNtStatusToApiStatus(Status);
665 goto done;
666 }
667
668 if (Status == STATUS_MORE_ENTRIES)
669 {
670 ApiStatus = NERR_BufTooSmall;
671 goto done;
672 }
673 else
674 {
675 EnumContext->BuiltinDone = TRUE;
676 }
677 }
678
679 TRACE("EnumContext: %lu\n", EnumContext);
680 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
681 TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
682
683 /* Get a pointer to the current user */
684 CurrentUser = &EnumContext->Buffer[EnumContext->Index];
685
686 TRACE("RID: %lu\n", CurrentUser->RelativeId);
687
688 Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
689 USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT,
690 CurrentUser->RelativeId,
691 &UserHandle);
692 if (!NT_SUCCESS(Status))
693 {
694 ERR("SamOpenUser failed (Status %08lx)\n", Status);
695 ApiStatus = NetpNtStatusToApiStatus(Status);
696 goto done;
697 }
698
699 Status = SamQueryInformationUser(UserHandle,
700 UserAccountInformation,
701 (PVOID *)&UserInfo);
702 if (!NT_SUCCESS(Status))
703 {
704 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
705 ApiStatus = NetpNtStatusToApiStatus(Status);
706 goto done;
707 }
708
709 SamCloseHandle(UserHandle);
710 UserHandle = NULL;
711
712 ApiStatus = BuildUserInfoBuffer(UserInfo,
713 level,
714 CurrentUser->RelativeId,
715 &Buffer);
716 if (ApiStatus != NERR_Success)
717 {
718 ERR("BuildUserInfoBuffer failed (ApiStatus %lu)\n", ApiStatus);
719 goto done;
720 }
721
722 if (UserInfo != NULL)
723 {
724 FreeUserInfo(UserInfo);
725 UserInfo = NULL;
726 }
727
728 EnumContext->Index++;
729
730 (*entriesread)++;
731 // }
732
733 done:
734 if (ApiStatus == NERR_Success && EnumContext->Index < EnumContext->Returned)
735 ApiStatus = ERROR_MORE_DATA;
736
737 if (EnumContext != NULL)
738 *totalentries = EnumContext->Returned;
739
740 if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
741 {
742 if (EnumContext != NULL)
743 {
744 if (EnumContext->BuiltinDomainHandle != NULL)
745 SamCloseHandle(EnumContext->BuiltinDomainHandle);
746
747 if (EnumContext->AccountDomainHandle != NULL)
748 SamCloseHandle(EnumContext->AccountDomainHandle);
749
750 if (EnumContext->ServerHandle != NULL)
751 SamCloseHandle(EnumContext->ServerHandle);
752
753 if (EnumContext->Buffer != NULL)
754 {
755 for (i = 0; i < EnumContext->Returned; i++)
756 {
757 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
758 }
759
760 SamFreeMemory(EnumContext->Buffer);
761 }
762
763 NetApiBufferFree(EnumContext);
764 EnumContext = NULL;
765 }
766 }
767
768 if (UserHandle != NULL)
769 SamCloseHandle(UserHandle);
770
771 if (UserInfo != NULL)
772 FreeUserInfo(UserInfo);
773
774 if (resume_handle != NULL)
775 *resume_handle = (DWORD_PTR)EnumContext;
776
777 *bufptr = (LPBYTE)Buffer;
778
779 TRACE("return %lu\n", ApiStatus);
780
781 return ApiStatus;
782 }
783
784
785 /************************************************************
786 * NetUserGetGroups (NETAPI32.@)
787 */
788 NET_API_STATUS
789 WINAPI
790 NetUserGetGroups(LPCWSTR servername,
791 LPCWSTR username,
792 DWORD level,
793 LPBYTE *bufptr,
794 DWORD prefixmaxlen,
795 LPDWORD entriesread,
796 LPDWORD totalentries)
797 {
798 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername),
799 debugstr_w(username), level, bufptr, prefixmaxlen, entriesread,
800 totalentries);
801
802 *bufptr = NULL;
803 *entriesread = 0;
804 *totalentries = 0;
805
806 return ERROR_INVALID_LEVEL;
807 }
808
809
810 /************************************************************
811 * NetUserGetInfo (NETAPI32.@)
812 */
813 NET_API_STATUS
814 WINAPI
815 NetUserGetInfo(LPCWSTR servername,
816 LPCWSTR username,
817 DWORD level,
818 LPBYTE* bufptr)
819 {
820 UNICODE_STRING ServerName;
821 UNICODE_STRING UserName;
822 SAM_HANDLE ServerHandle = NULL;
823 SAM_HANDLE AccountDomainHandle = NULL;
824 SAM_HANDLE UserHandle = NULL;
825 PULONG RelativeIds = NULL;
826 PSID_NAME_USE Use = NULL;
827 PUSER_ACCOUNT_INFORMATION UserInfo = NULL;
828 LPVOID Buffer = NULL;
829 NET_API_STATUS ApiStatus = NERR_Success;
830 NTSTATUS Status = STATUS_SUCCESS;
831
832 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername),
833 debugstr_w(username), level, bufptr);
834
835 if (servername != NULL)
836 RtlInitUnicodeString(&ServerName, servername);
837
838 RtlInitUnicodeString(&UserName, username);
839
840 /* Connect to the SAM Server */
841 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
842 &ServerHandle,
843 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
844 NULL);
845 if (!NT_SUCCESS(Status))
846 {
847 ERR("SamConnect failed (Status %08lx)\n", Status);
848 ApiStatus = NetpNtStatusToApiStatus(Status);
849 goto done;
850 }
851
852 /* Open the Account Domain */
853 Status = OpenAccountDomain(ServerHandle,
854 (servername != NULL) ? &ServerName : NULL,
855 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
856 &AccountDomainHandle);
857 if (!NT_SUCCESS(Status))
858 {
859 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
860 ApiStatus = NetpNtStatusToApiStatus(Status);
861 goto done;
862 }
863
864 /* Get the RID for the given user name */
865 Status = SamLookupNamesInDomain(AccountDomainHandle,
866 1,
867 &UserName,
868 &RelativeIds,
869 &Use);
870 if (!NT_SUCCESS(Status))
871 {
872 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
873 ApiStatus = NetpNtStatusToApiStatus(Status);
874 goto done;
875 }
876
877 /* Check if the account is a user account */
878 if (Use[0] != SidTypeUser)
879 {
880 ERR("No user found!\n");
881 ApiStatus = NERR_UserNotFound;
882 goto done;
883 }
884
885 TRACE("RID: %lu\n", RelativeIds[0]);
886
887 /* Open the user object */
888 Status = SamOpenUser(AccountDomainHandle,
889 USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT,
890 RelativeIds[0],
891 &UserHandle);
892 if (!NT_SUCCESS(Status))
893 {
894 ERR("SamOpenUser failed (Status %08lx)\n", Status);
895 ApiStatus = NetpNtStatusToApiStatus(Status);
896 goto done;
897 }
898
899 Status = SamQueryInformationUser(UserHandle,
900 UserAccountInformation,
901 (PVOID *)&UserInfo);
902 if (!NT_SUCCESS(Status))
903 {
904 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
905 ApiStatus = NetpNtStatusToApiStatus(Status);
906 goto done;
907 }
908
909 ApiStatus = BuildUserInfoBuffer(UserInfo,
910 level,
911 RelativeIds[0],
912 &Buffer);
913 if (ApiStatus != NERR_Success)
914 {
915 ERR("BuildUserInfoBuffer failed (ApiStatus %08lu)\n", ApiStatus);
916 goto done;
917 }
918
919 done:
920 if (UserInfo != NULL)
921 FreeUserInfo(UserInfo);
922
923 if (UserHandle != NULL)
924 SamCloseHandle(UserHandle);
925
926 if (RelativeIds != NULL)
927 SamFreeMemory(RelativeIds);
928
929 if (Use != NULL)
930 SamFreeMemory(Use);
931
932 if (AccountDomainHandle != NULL)
933 SamCloseHandle(AccountDomainHandle);
934
935 if (ServerHandle != NULL)
936 SamCloseHandle(ServerHandle);
937
938 *bufptr = (LPBYTE)Buffer;
939
940 return ApiStatus;
941 }
942
943
944 /************************************************************
945 * NetUserGetLocalGroups (NETAPI32.@)
946 */
947 NET_API_STATUS
948 WINAPI
949 NetUserGetLocalGroups(LPCWSTR servername,
950 LPCWSTR username,
951 DWORD level,
952 DWORD flags,
953 LPBYTE* bufptr,
954 DWORD prefmaxlen,
955 LPDWORD entriesread,
956 LPDWORD totalentries)
957 {
958 NET_API_STATUS status;
959 const WCHAR admins[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0};
960 LPWSTR currentuser;
961 LOCALGROUP_USERS_INFO_0* info;
962 DWORD size;
963
964 FIXME("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
965 debugstr_w(servername), debugstr_w(username), level, flags, bufptr,
966 prefmaxlen, entriesread, totalentries);
967
968 status = NETAPI_ValidateServername(servername);
969 if (status != NERR_Success)
970 return status;
971
972 size = UNLEN + 1;
973 NetApiBufferAllocate(size * sizeof(WCHAR), (LPVOID*)&currentuser);
974 GetUserNameW(currentuser, &size);
975
976 if (lstrcmpiW(username, currentuser) && NETAPI_FindUser(username))
977 {
978 NetApiBufferFree(currentuser);
979 return NERR_UserNotFound;
980 }
981
982 NetApiBufferFree(currentuser);
983 *totalentries = 1;
984 size = sizeof(*info) + sizeof(admins);
985
986 if(prefmaxlen < size)
987 status = ERROR_MORE_DATA;
988 else
989 status = NetApiBufferAllocate(size, (LPVOID*)&info);
990
991 if(status != NERR_Success)
992 {
993 *bufptr = NULL;
994 *entriesread = 0;
995 return status;
996 }
997
998 info->lgrui0_name = (LPWSTR)((LPBYTE)info + sizeof(*info));
999 lstrcpyW(info->lgrui0_name, admins);
1000
1001 *bufptr = (LPBYTE)info;
1002 *entriesread = 1;
1003
1004 return NERR_Success;
1005 }
1006
1007
1008 /******************************************************************************
1009 * NetUserSetGroups (NETAPI32.@)
1010 */
1011 NET_API_STATUS
1012 WINAPI
1013 NetUserSetGroups(LPCWSTR servername,
1014 LPCWSTR username,
1015 DWORD level,
1016 LPBYTE buf,
1017 DWORD num_entries)
1018 {
1019 FIXME("(%s %s %lu %p %lu)\n",
1020 debugstr_w(servername), debugstr_w(username), level, buf, num_entries);
1021 return ERROR_ACCESS_DENIED;
1022 }
1023
1024
1025 /******************************************************************************
1026 * NetUserSetInfo (NETAPI32.@)
1027 */
1028 NET_API_STATUS
1029 WINAPI
1030 NetUserSetInfo(LPCWSTR servername,
1031 LPCWSTR username,
1032 DWORD level,
1033 LPBYTE buf,
1034 LPDWORD parm_err)
1035 {
1036 FIXME("(%s %s %lu %p %p)\n",
1037 debugstr_w(servername), debugstr_w(username), level, buf, parm_err);
1038 return ERROR_ACCESS_DENIED;
1039 }
1040
1041 /* EOF */