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