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