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