2 * Copyright 2002 Andriy Palamarchuk
4 * netapi32 user functions
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.
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.
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
24 #define WIN32_NO_STATUS
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "wine/list.h"
38 #define NTOS_MODE_USER
39 #include <ndk/rtlfuncs.h>
43 WINE_DEFAULT_DEBUG_CHANNEL(netapi32
);
46 typedef struct _ENUM_CONTEXT
48 SAM_HANDLE ServerHandle
;
49 SAM_HANDLE BuiltinDomainHandle
;
50 SAM_HANDLE AccountDomainHandle
;
52 SAM_ENUMERATE_HANDLE EnumerationContext
;
53 PSAM_RID_ENUMERATION Buffer
;
58 } ENUM_CONTEXT
, *PENUM_CONTEXT
;
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.
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.
72 WCHAR user_name
[LM20_UNLEN
+1];
73 WCHAR user_password
[PWLEN
+ 1];
74 DWORD sec_since_passwd_change
;
79 LPWSTR user_logon_script_path
;
82 static struct list user_list
= LIST_INIT( user_list
);
84 BOOL
NETAPI_IsLocalComputer(LPCWSTR ServerName
);
86 /************************************************************
87 * NETAPI_ValidateServername
89 * Validates server name
91 static NET_API_STATUS
NETAPI_ValidateServername(LPCWSTR ServerName
)
95 if (ServerName
[0] == 0)
96 return ERROR_BAD_NETPATH
;
98 ((ServerName
[0] == '\\') &&
99 (ServerName
[1] != '\\'))
101 ((ServerName
[0] == '\\') &&
102 (ServerName
[1] == '\\') &&
103 (ServerName
[2] == 0))
105 return ERROR_INVALID_NAME
;
110 /************************************************************
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.
117 static struct sam_user
* NETAPI_FindUser(LPCWSTR UserName
)
119 struct sam_user
*user
;
121 LIST_FOR_EACH_ENTRY(user
, &user_list
, struct sam_user
, entry
)
123 if(lstrcmpW(user
->user_name
, UserName
) == 0)
132 BuildUserInfoBuffer(PUSER_ACCOUNT_INFORMATION UserInfo
,
137 LPVOID LocalBuffer
= NULL
;
138 PUSER_INFO_0 UserInfo0
;
139 PUSER_INFO_1 UserInfo1
;
140 PUSER_INFO_10 UserInfo10
;
141 PUSER_INFO_20 UserInfo20
;
144 NET_API_STATUS ApiStatus
= NERR_Success
;
151 Size
= sizeof(USER_INFO_0
) +
152 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
156 Size
= sizeof(USER_INFO_1
) +
157 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
159 if (UserInfo
->HomeDirectory
.Length
> 0)
160 Size
+= UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
);
162 if (UserInfo
->AdminComment
.Length
> 0)
163 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
165 if (UserInfo
->ScriptPath
.Length
> 0)
166 Size
= UserInfo
->ScriptPath
.Length
+ sizeof(WCHAR
);
174 Size
= sizeof(USER_INFO_10
) +
175 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
177 if (UserInfo
->AdminComment
.Length
> 0)
178 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
180 /* FIXME: Add user comment here */
182 if (UserInfo
->FullName
.Length
> 0)
183 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
189 Size
= sizeof(USER_INFO_20
) +
190 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
192 if (UserInfo
->FullName
.Length
> 0)
193 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
195 if (UserInfo
->AdminComment
.Length
> 0)
196 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
202 ApiStatus
= ERROR_INVALID_LEVEL
;
206 ApiStatus
= NetApiBufferAllocate(Size
, &LocalBuffer
);
207 if (ApiStatus
!= NERR_Success
)
210 ZeroMemory(LocalBuffer
, Size
);
215 UserInfo0
= (PUSER_INFO_0
)LocalBuffer
;
217 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo0
+ sizeof(USER_INFO_0
));
218 UserInfo0
->usri0_name
= Ptr
;
220 memcpy(UserInfo0
->usri0_name
,
221 UserInfo
->UserName
.Buffer
,
222 UserInfo
->UserName
.Length
);
223 UserInfo0
->usri0_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
227 UserInfo1
= (PUSER_INFO_1
)LocalBuffer
;
229 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo1
+ sizeof(USER_INFO_1
));
231 UserInfo1
->usri1_name
= Ptr
;
233 memcpy(UserInfo1
->usri1_name
,
234 UserInfo
->UserName
.Buffer
,
235 UserInfo
->UserName
.Length
);
236 UserInfo1
->usri1_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
238 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
240 UserInfo1
->usri1_password
= NULL
;
242 UserInfo1
->usri1_password_age
= 0; /* FIXME */
244 UserInfo1
->usri1_priv
= 0; /* FIXME */
246 if (UserInfo
->HomeDirectory
.Length
> 0)
248 UserInfo1
->usri1_home_dir
= Ptr
;
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
;
255 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
));
258 if (UserInfo
->AdminComment
.Length
> 0)
260 UserInfo1
->usri1_comment
= Ptr
;
262 memcpy(UserInfo1
->usri1_comment
,
263 UserInfo
->AdminComment
.Buffer
,
264 UserInfo
->AdminComment
.Length
);
265 UserInfo1
->usri1_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
267 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
270 UserInfo1
->usri1_flags
= UserInfo
->UserAccountControl
;
272 if (UserInfo
->ScriptPath
.Length
> 0)
274 UserInfo1
->usri1_script_path
= Ptr
;
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
;
288 UserInfo10
= (PUSER_INFO_10
)LocalBuffer
;
290 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo10
+ sizeof(USER_INFO_10
));
292 UserInfo10
->usri10_name
= Ptr
;
294 memcpy(UserInfo10
->usri10_name
,
295 UserInfo
->UserName
.Buffer
,
296 UserInfo
->UserName
.Length
);
297 UserInfo10
->usri10_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
299 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
301 if (UserInfo
->AdminComment
.Length
> 0)
303 UserInfo10
->usri10_comment
= Ptr
;
305 memcpy(UserInfo10
->usri10_comment
,
306 UserInfo
->AdminComment
.Buffer
,
307 UserInfo
->AdminComment
.Length
);
308 UserInfo10
->usri10_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
310 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
313 /* FIXME: Add user comment here */
315 if (UserInfo
->FullName
.Length
> 0)
317 UserInfo10
->usri10_full_name
= Ptr
;
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
;
330 UserInfo20
= (PUSER_INFO_20
)LocalBuffer
;
332 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo20
+ sizeof(USER_INFO_20
));
334 UserInfo20
->usri20_name
= Ptr
;
336 memcpy(UserInfo20
->usri20_name
,
337 UserInfo
->UserName
.Buffer
,
338 UserInfo
->UserName
.Length
);
339 UserInfo20
->usri20_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
341 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
343 if (UserInfo
->FullName
.Length
> 0)
345 UserInfo20
->usri20_full_name
= Ptr
;
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
;
352 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->FullName
.Length
+ sizeof(WCHAR
));
355 if (UserInfo
->AdminComment
.Length
> 0)
357 UserInfo20
->usri20_comment
= Ptr
;
359 memcpy(UserInfo20
->usri20_comment
,
360 UserInfo
->AdminComment
.Buffer
,
361 UserInfo
->AdminComment
.Length
);
362 UserInfo20
->usri20_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
364 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
367 UserInfo20
->usri20_flags
= UserInfo
->UserAccountControl
;
368 UserInfo20
->usri20_user_id
= RelativeId
;
375 if (ApiStatus
== NERR_Success
)
377 *Buffer
= LocalBuffer
;
381 if (LocalBuffer
!= NULL
)
382 NetApiBufferFree(LocalBuffer
);
391 FreeUserInfo(PUSER_ACCOUNT_INFORMATION UserInfo
)
393 if (UserInfo
->UserName
.Buffer
!= NULL
)
394 SamFreeMemory(UserInfo
->UserName
.Buffer
);
396 if (UserInfo
->FullName
.Buffer
!= NULL
)
397 SamFreeMemory(UserInfo
->FullName
.Buffer
);
399 if (UserInfo
->HomeDirectory
.Buffer
!= NULL
)
400 SamFreeMemory(UserInfo
->HomeDirectory
.Buffer
);
402 if (UserInfo
->HomeDirectoryDrive
.Buffer
!= NULL
)
403 SamFreeMemory(UserInfo
->HomeDirectoryDrive
.Buffer
);
405 if (UserInfo
->ScriptPath
.Buffer
!= NULL
)
406 SamFreeMemory(UserInfo
->ScriptPath
.Buffer
);
408 if (UserInfo
->ProfilePath
.Buffer
!= NULL
)
409 SamFreeMemory(UserInfo
->ProfilePath
.Buffer
);
411 if (UserInfo
->AdminComment
.Buffer
!= NULL
)
412 SamFreeMemory(UserInfo
->AdminComment
.Buffer
);
414 if (UserInfo
->WorkStations
.Buffer
!= NULL
)
415 SamFreeMemory(UserInfo
->WorkStations
.Buffer
);
417 if (UserInfo
->LogonHours
.LogonHours
!= NULL
)
418 SamFreeMemory(UserInfo
->LogonHours
.LogonHours
);
420 SamFreeMemory(UserInfo
);
424 /************************************************************
425 * NetUserAdd (NETAPI32.@)
429 NetUserAdd(LPCWSTR servername
,
434 NET_API_STATUS status
;
435 struct sam_user
* su
= NULL
;
437 FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername
), level
, bufptr
, parm_err
);
439 if((status
= NETAPI_ValidateServername(servername
)) != NERR_Success
)
444 /* Level 3 and 4 are identical for the purposes of NetUserAdd */
447 FIXME("Level 3 and 4 not implemented.\n");
450 FIXME("Level 2 not implemented.\n");
454 PUSER_INFO_1 ui
= (PUSER_INFO_1
) bufptr
;
455 su
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user
));
458 status
= NERR_InternalError
;
462 if(lstrlenW(ui
->usri1_name
) > LM20_UNLEN
)
464 status
= NERR_BadUsername
;
468 /*FIXME: do other checks for a valid username */
469 lstrcpyW(su
->user_name
, ui
->usri1_name
);
471 if(lstrlenW(ui
->usri1_password
) > PWLEN
)
473 /* Always return PasswordTooShort on invalid passwords. */
474 status
= NERR_PasswordTooShort
;
477 lstrcpyW(su
->user_password
, ui
->usri1_password
);
479 su
->sec_since_passwd_change
= ui
->usri1_password_age
;
480 su
->user_priv
= ui
->usri1_priv
;
481 su
->user_flags
= ui
->usri1_flags
;
483 /*FIXME: set the other LPWSTRs to NULL for now */
485 su
->user_comment
= NULL
;
486 su
->user_logon_script_path
= NULL
;
488 list_add_head(&user_list
, &su
->entry
);
492 TRACE("Invalid level %d specified.\n", level
);
493 status
= ERROR_INVALID_LEVEL
;
497 HeapFree(GetProcessHeap(), 0, su
);
503 /******************************************************************************
504 * NetUserChangePassword (NETAPI32.@)
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.
514 * Success: NERR_Success.
515 * Failure: NERR_* failure code or win error code.
520 NetUserChangePassword(LPCWSTR domainname
,
525 struct sam_user
*user
;
527 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname
), debugstr_w(username
));
530 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname
));
532 if((user
= NETAPI_FindUser(username
)) == NULL
)
533 return NERR_UserNotFound
;
535 if(lstrcmpW(user
->user_password
, oldpassword
) != 0)
536 return ERROR_INVALID_PASSWORD
;
538 if(lstrlenW(newpassword
) > PWLEN
)
539 return ERROR_PASSWORD_RESTRICTION
;
541 lstrcpyW(user
->user_password
, newpassword
);
547 /************************************************************
548 * NetUserDel (NETAPI32.@)
552 NetUserDel(LPCWSTR servername
,
555 NET_API_STATUS status
;
556 struct sam_user
*user
;
558 TRACE("(%s, %s)\n", debugstr_w(servername
), debugstr_w(username
));
560 if((status
= NETAPI_ValidateServername(servername
))!= NERR_Success
)
563 if ((user
= NETAPI_FindUser(username
)) == NULL
)
564 return NERR_UserNotFound
;
566 list_remove(&user
->entry
);
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
);
577 /************************************************************
578 * NetUserEnum (NETAPI32.@)
582 NetUserEnum(LPCWSTR servername
,
588 LPDWORD totalentries
,
589 LPDWORD resume_handle
)
591 UNICODE_STRING ServerName
;
592 PSAM_RID_ENUMERATION CurrentUser
;
593 PENUM_CONTEXT EnumContext
= NULL
;
594 LPVOID Buffer
= NULL
;
595 PSID DomainSid
= NULL
;
599 SAM_HANDLE UserHandle
= NULL
;
600 PUSER_ACCOUNT_INFORMATION UserInfo
= NULL
;
602 NET_API_STATUS ApiStatus
= NERR_Success
;
603 NTSTATUS Status
= STATUS_SUCCESS
;
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
);
612 if (servername
!= NULL
)
613 RtlInitUnicodeString(&ServerName
, servername
);
615 if (resume_handle
!= NULL
&& *resume_handle
!= 0)
617 EnumContext
= (PENUM_CONTEXT
)*resume_handle
;
621 ApiStatus
= NetApiBufferAllocate(sizeof(ENUM_CONTEXT
), (PVOID
*)&EnumContext
);
622 if (ApiStatus
!= NERR_Success
)
625 EnumContext
->EnumerationContext
= 0;
626 EnumContext
->Buffer
= NULL
;
627 EnumContext
->Returned
= 0;
628 EnumContext
->Index
= 0;
629 EnumContext
->BuiltinDone
= FALSE
;
631 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
632 &EnumContext
->ServerHandle
,
633 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
635 if (!NT_SUCCESS(Status
))
637 ERR("SamConnect failed (Status %08lx)\n", Status
);
638 ApiStatus
= NetpNtStatusToApiStatus(Status
);
642 Status
= GetAccountDomainSid((servername
!= NULL
) ? &ServerName
: NULL
,
644 if (!NT_SUCCESS(Status
))
646 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
647 ApiStatus
= NetpNtStatusToApiStatus(Status
);
651 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
652 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
654 &EnumContext
->AccountDomainHandle
);
656 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
658 if (!NT_SUCCESS(Status
))
660 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
661 ApiStatus
= NetpNtStatusToApiStatus(Status
);
665 Status
= GetBuiltinDomainSid(&DomainSid
);
666 if (!NT_SUCCESS(Status
))
668 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
669 ApiStatus
= NetpNtStatusToApiStatus(Status
);
673 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
674 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
676 &EnumContext
->BuiltinDomainHandle
);
678 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
680 if (!NT_SUCCESS(Status
))
682 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
683 ApiStatus
= NetpNtStatusToApiStatus(Status
);
690 TRACE("EnumContext->Index: %lu\n", EnumContext
->Index
);
691 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
693 if (EnumContext
->Index
>= EnumContext
->Returned
)
695 // if (EnumContext->BuiltinDone == TRUE)
697 // ApiStatus = NERR_Success;
701 TRACE("Calling SamEnumerateUsersInDomain\n");
702 Status
= SamEnumerateUsersInDomain(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
703 &EnumContext
->EnumerationContext
,
705 (PVOID
*)&EnumContext
->Buffer
,
707 &EnumContext
->Returned
);
709 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status
);
710 if (!NT_SUCCESS(Status
))
712 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status
);
713 ApiStatus
= NetpNtStatusToApiStatus(Status
);
717 if (Status
== STATUS_MORE_ENTRIES
)
719 ApiStatus
= NERR_BufTooSmall
;
724 EnumContext
->BuiltinDone
= TRUE
;
728 TRACE("EnumContext: %lu\n", EnumContext
);
729 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
730 TRACE("EnumContext->Buffer: %p\n", EnumContext
->Buffer
);
732 /* Get a pointer to the current user */
733 CurrentUser
= &EnumContext
->Buffer
[EnumContext
->Index
];
735 TRACE("RID: %lu\n", CurrentUser
->RelativeId
);
737 Status
= SamOpenUser(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
738 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
739 CurrentUser
->RelativeId
,
741 if (!NT_SUCCESS(Status
))
743 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
744 ApiStatus
= NetpNtStatusToApiStatus(Status
);
748 Status
= SamQueryInformationUser(UserHandle
,
749 UserAccountInformation
,
751 if (!NT_SUCCESS(Status
))
753 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
754 ApiStatus
= NetpNtStatusToApiStatus(Status
);
758 SamCloseHandle(UserHandle
);
761 ApiStatus
= BuildUserInfoBuffer(UserInfo
,
763 CurrentUser
->RelativeId
,
765 if (ApiStatus
!= NERR_Success
)
767 ERR("BuildUserInfoBuffer failed (ApiStatus %lu)\n", ApiStatus
);
771 if (UserInfo
!= NULL
)
773 FreeUserInfo(UserInfo
);
777 EnumContext
->Index
++;
783 if (ApiStatus
== NERR_Success
&& EnumContext
->Index
< EnumContext
->Returned
)
784 ApiStatus
= ERROR_MORE_DATA
;
786 if (EnumContext
!= NULL
)
787 *totalentries
= EnumContext
->Returned
;
789 if (resume_handle
== NULL
|| ApiStatus
!= ERROR_MORE_DATA
)
791 if (EnumContext
!= NULL
)
793 if (EnumContext
->BuiltinDomainHandle
!= NULL
)
794 SamCloseHandle(EnumContext
->BuiltinDomainHandle
);
796 if (EnumContext
->AccountDomainHandle
!= NULL
)
797 SamCloseHandle(EnumContext
->AccountDomainHandle
);
799 if (EnumContext
->ServerHandle
!= NULL
)
800 SamCloseHandle(EnumContext
->ServerHandle
);
802 if (EnumContext
->Buffer
!= NULL
)
804 for (i
= 0; i
< EnumContext
->Returned
; i
++)
806 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
809 SamFreeMemory(EnumContext
->Buffer
);
812 NetApiBufferFree(EnumContext
);
817 if (UserHandle
!= NULL
)
818 SamCloseHandle(UserHandle
);
820 if (UserInfo
!= NULL
)
821 FreeUserInfo(UserInfo
);
823 if (resume_handle
!= NULL
)
824 *resume_handle
= (DWORD_PTR
)EnumContext
;
826 *bufptr
= (LPBYTE
)Buffer
;
828 TRACE("return %lu\n", ApiStatus
);
834 /************************************************************
835 * NetUserGetGroups (NETAPI32.@)
839 NetUserGetGroups(LPCWSTR servername
,
845 LPDWORD totalentries
)
847 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername
),
848 debugstr_w(username
), level
, bufptr
, prefixmaxlen
, entriesread
,
855 return ERROR_INVALID_LEVEL
;
859 /************************************************************
860 * NetUserGetInfo (NETAPI32.@)
864 NetUserGetInfo(LPCWSTR servername
,
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
;
882 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername
),
883 debugstr_w(username
), level
, bufptr
);
885 if (servername
!= NULL
)
886 RtlInitUnicodeString(&ServerName
, servername
);
888 RtlInitUnicodeString(&UserName
, username
);
890 /* Connect to the SAM Server */
891 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
893 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
895 if (!NT_SUCCESS(Status
))
897 ERR("SamConnect failed (Status %08lx)\n", Status
);
898 ApiStatus
= NetpNtStatusToApiStatus(Status
);
902 /* Get the Account Domain SID */
903 Status
= GetAccountDomainSid((servername
!= NULL
) ? &ServerName
: NULL
,
905 if (!NT_SUCCESS(Status
))
907 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
908 ApiStatus
= NetpNtStatusToApiStatus(Status
);
912 /* Open the Account Domain */
913 Status
= SamOpenDomain(ServerHandle
,
914 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
916 &AccountDomainHandle
);
917 if (!NT_SUCCESS(Status
))
919 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
920 ApiStatus
= NetpNtStatusToApiStatus(Status
);
924 /* Get the RID for the given user name */
925 Status
= SamLookupNamesInDomain(AccountDomainHandle
,
930 if (!NT_SUCCESS(Status
))
932 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
933 ApiStatus
= NetpNtStatusToApiStatus(Status
);
937 /* Check if the account is a user account */
938 if (Use
[0] != SidTypeUser
)
940 ERR("No user found!\n");
941 ApiStatus
= NERR_UserNotFound
;
945 TRACE("RID: %lu\n", RelativeIds
[0]);
947 /* Open the user object */
948 Status
= SamOpenUser(AccountDomainHandle
,
949 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
952 if (!NT_SUCCESS(Status
))
954 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
955 ApiStatus
= NetpNtStatusToApiStatus(Status
);
959 Status
= SamQueryInformationUser(UserHandle
,
960 UserAccountInformation
,
962 if (!NT_SUCCESS(Status
))
964 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
965 ApiStatus
= NetpNtStatusToApiStatus(Status
);
969 ApiStatus
= BuildUserInfoBuffer(UserInfo
,
973 if (ApiStatus
!= NERR_Success
)
975 ERR("BuildUserInfoBuffer failed (ApiStatus %08lu)\n", ApiStatus
);
980 if (UserInfo
!= NULL
)
981 FreeUserInfo(UserInfo
);
983 if (UserHandle
!= NULL
)
984 SamCloseHandle(UserHandle
);
986 if (RelativeIds
!= NULL
)
987 SamFreeMemory(RelativeIds
);
992 if (DomainSid
!= NULL
)
993 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
995 if (AccountDomainHandle
!= NULL
)
996 SamCloseHandle(AccountDomainHandle
);
998 if (ServerHandle
!= NULL
)
999 SamCloseHandle(ServerHandle
);
1001 *bufptr
= (LPBYTE
)Buffer
;
1007 /************************************************************
1008 * NetUserGetLocalGroups (NETAPI32.@)
1012 NetUserGetLocalGroups(LPCWSTR servername
,
1018 LPDWORD entriesread
,
1019 LPDWORD totalentries
)
1021 NET_API_STATUS status
;
1022 const WCHAR admins
[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0};
1024 LOCALGROUP_USERS_INFO_0
* info
;
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
);
1031 status
= NETAPI_ValidateServername(servername
);
1032 if (status
!= NERR_Success
)
1036 NetApiBufferAllocate(size
* sizeof(WCHAR
), (LPVOID
*)¤tuser
);
1037 GetUserNameW(currentuser
, &size
);
1039 if (lstrcmpiW(username
, currentuser
) && NETAPI_FindUser(username
))
1041 NetApiBufferFree(currentuser
);
1042 return NERR_UserNotFound
;
1045 NetApiBufferFree(currentuser
);
1047 size
= sizeof(*info
) + sizeof(admins
);
1049 if(prefmaxlen
< size
)
1050 status
= ERROR_MORE_DATA
;
1052 status
= NetApiBufferAllocate(size
, (LPVOID
*)&info
);
1054 if(status
!= NERR_Success
)
1061 info
->lgrui0_name
= (LPWSTR
)((LPBYTE
)info
+ sizeof(*info
));
1062 lstrcpyW(info
->lgrui0_name
, admins
);
1064 *bufptr
= (LPBYTE
)info
;
1067 return NERR_Success
;
1071 /******************************************************************************
1072 * NetUserSetGroups (NETAPI32.@)
1076 NetUserSetGroups(LPCWSTR servername
,
1082 FIXME("(%s %s %lu %p %lu)\n",
1083 debugstr_w(servername
), debugstr_w(username
), level
, buf
, num_entries
);
1084 return ERROR_ACCESS_DENIED
;
1088 /******************************************************************************
1089 * NetUserSetInfo (NETAPI32.@)
1093 NetUserSetInfo(LPCWSTR servername
,
1099 FIXME("(%s %s %lu %p %p)\n",
1100 debugstr_w(servername
), debugstr_w(username
), level
, buf
, parm_err
);
1101 return ERROR_ACCESS_DENIED
;