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)
129 static BOOL
NETAPI_IsCurrentUser(LPCWSTR username
)
131 LPWSTR curr_user
= NULL
;
135 dwSize
= LM20_UNLEN
+1;
136 curr_user
= HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(WCHAR
));
139 ERR("Failed to allocate memory for user name.\n");
142 if(!GetUserNameW(curr_user
, &dwSize
))
144 ERR("Failed to get current user's user name.\n");
147 if (!lstrcmpW(curr_user
, username
))
153 HeapFree(GetProcessHeap(), 0, curr_user
);
160 BuildInfoBuffer(PUSER_ACCOUNT_INFORMATION UserInfo
,
165 LPVOID LocalBuffer
= NULL
;
166 PUSER_INFO_0 UserInfo0
;
167 PUSER_INFO_1 UserInfo1
;
168 PUSER_INFO_20 UserInfo20
;
171 NET_API_STATUS ApiStatus
= NERR_Success
;
178 Size
= sizeof(USER_INFO_0
) +
179 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
183 Size
= sizeof(USER_INFO_1
) +
184 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
186 if (UserInfo
->HomeDirectory
.Length
> 0)
187 Size
+= UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
);
189 if (UserInfo
->AdminComment
.Length
> 0)
190 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
192 if (UserInfo
->ScriptPath
.Length
> 0)
193 Size
= UserInfo
->ScriptPath
.Length
+ sizeof(WCHAR
);
203 Size
= sizeof(USER_INFO_20
) +
204 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
206 if (UserInfo
->FullName
.Length
> 0)
207 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
209 if (UserInfo
->AdminComment
.Length
> 0)
210 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
216 ApiStatus
= ERROR_INVALID_LEVEL
;
220 ApiStatus
= NetApiBufferAllocate(Size
, &LocalBuffer
);
221 if (ApiStatus
!= NERR_Success
)
227 UserInfo0
= (PUSER_INFO_0
)LocalBuffer
;
229 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo0
+ sizeof(USER_INFO_0
));
230 UserInfo0
->usri0_name
= Ptr
;
232 memcpy(UserInfo0
->usri0_name
,
233 UserInfo
->UserName
.Buffer
,
234 UserInfo
->UserName
.Length
);
235 UserInfo0
->usri0_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
239 UserInfo1
= (PUSER_INFO_1
)LocalBuffer
;
241 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo1
+ sizeof(USER_INFO_1
));
243 UserInfo1
->usri1_name
= Ptr
;
245 memcpy(UserInfo1
->usri1_name
,
246 UserInfo
->UserName
.Buffer
,
247 UserInfo
->UserName
.Length
);
248 UserInfo1
->usri1_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
250 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
252 UserInfo1
->usri1_password
= NULL
;
254 UserInfo1
->usri1_password_age
= 0; /* FIXME */
256 UserInfo1
->usri1_priv
= 0; /* FIXME */
258 if (UserInfo
->HomeDirectory
.Length
> 0)
260 UserInfo1
->usri1_home_dir
= Ptr
;
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
;
267 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
));
270 if (UserInfo
->AdminComment
.Length
> 0)
272 UserInfo1
->usri1_comment
= Ptr
;
274 memcpy(UserInfo1
->usri1_comment
,
275 UserInfo
->AdminComment
.Buffer
,
276 UserInfo
->AdminComment
.Length
);
277 UserInfo1
->usri1_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
279 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
282 UserInfo1
->usri1_flags
= UserInfo
->UserAccountControl
;
284 if (UserInfo
->ScriptPath
.Length
> 0)
286 UserInfo1
->usri1_script_path
= Ptr
;
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
;
301 UserInfo20
= (PUSER_INFO_20
)LocalBuffer
;
303 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo20
+ sizeof(USER_INFO_20
));
305 UserInfo20
->usri20_name
= Ptr
;
307 memcpy(UserInfo20
->usri20_name
,
308 UserInfo
->UserName
.Buffer
,
309 UserInfo
->UserName
.Length
);
310 UserInfo20
->usri20_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
312 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
314 if (UserInfo
->FullName
.Length
> 0)
316 UserInfo20
->usri20_full_name
= Ptr
;
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
;
323 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->FullName
.Length
+ sizeof(WCHAR
));
326 if (UserInfo
->AdminComment
.Length
> 0)
328 UserInfo20
->usri20_comment
= Ptr
;
330 memcpy(UserInfo20
->usri20_comment
,
331 UserInfo
->AdminComment
.Buffer
,
332 UserInfo
->AdminComment
.Length
);
333 UserInfo20
->usri20_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
335 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
338 UserInfo20
->usri20_flags
= UserInfo
->UserAccountControl
;
339 UserInfo20
->usri20_user_id
= RelativeId
;
346 if (ApiStatus
== NERR_Success
)
348 *Buffer
= LocalBuffer
;
352 if (LocalBuffer
!= NULL
)
353 NetApiBufferFree(LocalBuffer
);
362 FreeUserInfo(PUSER_ACCOUNT_INFORMATION UserInfo
)
364 if (UserInfo
->UserName
.Buffer
!= NULL
)
365 SamFreeMemory(UserInfo
->UserName
.Buffer
);
367 if (UserInfo
->FullName
.Buffer
!= NULL
)
368 SamFreeMemory(UserInfo
->FullName
.Buffer
);
370 if (UserInfo
->HomeDirectory
.Buffer
!= NULL
)
371 SamFreeMemory(UserInfo
->HomeDirectory
.Buffer
);
373 if (UserInfo
->HomeDirectoryDrive
.Buffer
!= NULL
)
374 SamFreeMemory(UserInfo
->HomeDirectoryDrive
.Buffer
);
376 if (UserInfo
->ScriptPath
.Buffer
!= NULL
)
377 SamFreeMemory(UserInfo
->ScriptPath
.Buffer
);
379 if (UserInfo
->ProfilePath
.Buffer
!= NULL
)
380 SamFreeMemory(UserInfo
->ProfilePath
.Buffer
);
382 if (UserInfo
->AdminComment
.Buffer
!= NULL
)
383 SamFreeMemory(UserInfo
->AdminComment
.Buffer
);
385 if (UserInfo
->WorkStations
.Buffer
!= NULL
)
386 SamFreeMemory(UserInfo
->WorkStations
.Buffer
);
388 if (UserInfo
->LogonHours
.LogonHours
!= NULL
)
389 SamFreeMemory(UserInfo
->LogonHours
.LogonHours
);
391 SamFreeMemory(UserInfo
);
395 /************************************************************
396 * NetUserAdd (NETAPI32.@)
400 NetUserAdd(LPCWSTR servername
,
405 NET_API_STATUS status
;
406 struct sam_user
* su
= NULL
;
408 FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername
), level
, bufptr
, parm_err
);
410 if((status
= NETAPI_ValidateServername(servername
)) != NERR_Success
)
415 /* Level 3 and 4 are identical for the purposes of NetUserAdd */
418 FIXME("Level 3 and 4 not implemented.\n");
421 FIXME("Level 2 not implemented.\n");
425 PUSER_INFO_1 ui
= (PUSER_INFO_1
) bufptr
;
426 su
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user
));
429 status
= NERR_InternalError
;
433 if(lstrlenW(ui
->usri1_name
) > LM20_UNLEN
)
435 status
= NERR_BadUsername
;
439 /*FIXME: do other checks for a valid username */
440 lstrcpyW(su
->user_name
, ui
->usri1_name
);
442 if(lstrlenW(ui
->usri1_password
) > PWLEN
)
444 /* Always return PasswordTooShort on invalid passwords. */
445 status
= NERR_PasswordTooShort
;
448 lstrcpyW(su
->user_password
, ui
->usri1_password
);
450 su
->sec_since_passwd_change
= ui
->usri1_password_age
;
451 su
->user_priv
= ui
->usri1_priv
;
452 su
->user_flags
= ui
->usri1_flags
;
454 /*FIXME: set the other LPWSTRs to NULL for now */
456 su
->user_comment
= NULL
;
457 su
->user_logon_script_path
= NULL
;
459 list_add_head(&user_list
, &su
->entry
);
463 TRACE("Invalid level %d specified.\n", level
);
464 status
= ERROR_INVALID_LEVEL
;
468 HeapFree(GetProcessHeap(), 0, su
);
474 /******************************************************************************
475 * NetUserChangePassword (NETAPI32.@)
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.
485 * Success: NERR_Success.
486 * Failure: NERR_* failure code or win error code.
491 NetUserChangePassword(LPCWSTR domainname
,
496 struct sam_user
*user
;
498 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname
), debugstr_w(username
));
501 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname
));
503 if((user
= NETAPI_FindUser(username
)) == NULL
)
504 return NERR_UserNotFound
;
506 if(lstrcmpW(user
->user_password
, oldpassword
) != 0)
507 return ERROR_INVALID_PASSWORD
;
509 if(lstrlenW(newpassword
) > PWLEN
)
510 return ERROR_PASSWORD_RESTRICTION
;
512 lstrcpyW(user
->user_password
, newpassword
);
518 /************************************************************
519 * NetUserDel (NETAPI32.@)
523 NetUserDel(LPCWSTR servername
,
526 NET_API_STATUS status
;
527 struct sam_user
*user
;
529 TRACE("(%s, %s)\n", debugstr_w(servername
), debugstr_w(username
));
531 if((status
= NETAPI_ValidateServername(servername
))!= NERR_Success
)
534 if ((user
= NETAPI_FindUser(username
)) == NULL
)
535 return NERR_UserNotFound
;
537 list_remove(&user
->entry
);
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
);
548 /************************************************************
549 * NetUserEnum (NETAPI32.@)
553 NetUserEnum(LPCWSTR servername
,
559 LPDWORD totalentries
,
560 LPDWORD resume_handle
)
562 UNICODE_STRING ServerName
;
563 PSAM_RID_ENUMERATION CurrentUser
;
564 PENUM_CONTEXT EnumContext
= NULL
;
565 LPVOID Buffer
= NULL
;
566 PSID DomainSid
= NULL
;
570 SAM_HANDLE UserHandle
= NULL
;
571 PUSER_ACCOUNT_INFORMATION UserInfo
= NULL
;
573 NET_API_STATUS ApiStatus
= NERR_Success
;
574 NTSTATUS Status
= STATUS_SUCCESS
;
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
);
583 if (servername
!= NULL
)
584 RtlInitUnicodeString(&ServerName
, servername
);
586 if (resume_handle
!= NULL
&& *resume_handle
!= 0)
588 EnumContext
= (PENUM_CONTEXT
)*resume_handle
;
592 ApiStatus
= NetApiBufferAllocate(sizeof(ENUM_CONTEXT
), (PVOID
*)&EnumContext
);
593 if (ApiStatus
!= NERR_Success
)
596 EnumContext
->EnumerationContext
= 0;
597 EnumContext
->Buffer
= NULL
;
598 EnumContext
->Returned
= 0;
599 EnumContext
->Index
= 0;
600 EnumContext
->BuiltinDone
= FALSE
;
602 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
603 &EnumContext
->ServerHandle
,
604 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
606 if (!NT_SUCCESS(Status
))
608 ERR("SamConnect failed (Status %08lx)\n", Status
);
609 ApiStatus
= NetpNtStatusToApiStatus(Status
);
613 Status
= GetAccountDomainSid((servername
!= NULL
) ? &ServerName
: NULL
,
615 if (!NT_SUCCESS(Status
))
617 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
618 ApiStatus
= NetpNtStatusToApiStatus(Status
);
622 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
623 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
625 &EnumContext
->AccountDomainHandle
);
627 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
629 if (!NT_SUCCESS(Status
))
631 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
632 ApiStatus
= NetpNtStatusToApiStatus(Status
);
636 Status
= GetBuiltinDomainSid(&DomainSid
);
637 if (!NT_SUCCESS(Status
))
639 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
640 ApiStatus
= NetpNtStatusToApiStatus(Status
);
644 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
645 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
647 &EnumContext
->BuiltinDomainHandle
);
649 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
651 if (!NT_SUCCESS(Status
))
653 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
654 ApiStatus
= NetpNtStatusToApiStatus(Status
);
661 TRACE("EnumContext->Index: %lu\n", EnumContext
->Index
);
662 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
664 if (EnumContext
->Index
>= EnumContext
->Returned
)
666 // if (EnumContext->BuiltinDone == TRUE)
668 // ApiStatus = NERR_Success;
672 TRACE("Calling SamEnumerateUsersInDomain\n");
673 Status
= SamEnumerateUsersInDomain(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
674 &EnumContext
->EnumerationContext
,
676 (PVOID
*)&EnumContext
->Buffer
,
678 &EnumContext
->Returned
);
680 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status
);
681 if (!NT_SUCCESS(Status
))
683 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status
);
684 ApiStatus
= NetpNtStatusToApiStatus(Status
);
688 if (Status
== STATUS_MORE_ENTRIES
)
690 ApiStatus
= NERR_BufTooSmall
;
695 EnumContext
->BuiltinDone
= TRUE
;
699 TRACE("EnumContext: %lu\n", EnumContext
);
700 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
701 TRACE("EnumContext->Buffer: %p\n", EnumContext
->Buffer
);
703 /* Get a pointer to the current user */
704 CurrentUser
= &EnumContext
->Buffer
[EnumContext
->Index
];
706 TRACE("RID: %lu\n", CurrentUser
->RelativeId
);
708 Status
= SamOpenUser(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
709 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
710 CurrentUser
->RelativeId
,
712 if (!NT_SUCCESS(Status
))
714 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
715 ApiStatus
= NetpNtStatusToApiStatus(Status
);
719 Status
= SamQueryInformationUser(UserHandle
,
720 UserAccountInformation
,
722 if (!NT_SUCCESS(Status
))
724 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
725 ApiStatus
= NetpNtStatusToApiStatus(Status
);
729 SamCloseHandle(UserHandle
);
732 ApiStatus
= BuildInfoBuffer(UserInfo
,
734 CurrentUser
->RelativeId
,
736 if (ApiStatus
!= NERR_Success
)
738 ERR("BuildInfoBuffer failed (ApiStatus %lu)\n", ApiStatus
);
742 if (UserInfo
!= NULL
)
744 FreeUserInfo(UserInfo
);
748 EnumContext
->Index
++;
754 if (ApiStatus
== NERR_Success
&& EnumContext
->Index
< EnumContext
->Returned
)
755 ApiStatus
= ERROR_MORE_DATA
;
757 if (EnumContext
!= NULL
)
758 *totalentries
= EnumContext
->Returned
;
760 if (resume_handle
== NULL
|| ApiStatus
!= ERROR_MORE_DATA
)
762 if (EnumContext
!= NULL
)
764 if (EnumContext
->BuiltinDomainHandle
!= NULL
)
765 SamCloseHandle(EnumContext
->BuiltinDomainHandle
);
767 if (EnumContext
->AccountDomainHandle
!= NULL
)
768 SamCloseHandle(EnumContext
->AccountDomainHandle
);
770 if (EnumContext
->ServerHandle
!= NULL
)
771 SamCloseHandle(EnumContext
->ServerHandle
);
773 if (EnumContext
->Buffer
!= NULL
)
775 for (i
= 0; i
< EnumContext
->Returned
; i
++)
777 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
780 SamFreeMemory(EnumContext
->Buffer
);
783 NetApiBufferFree(EnumContext
);
788 if (UserHandle
!= NULL
)
789 SamCloseHandle(UserHandle
);
791 if (UserInfo
!= NULL
)
792 FreeUserInfo(UserInfo
);
794 if (resume_handle
!= NULL
)
795 *resume_handle
= (DWORD_PTR
)EnumContext
;
797 *bufptr
= (LPBYTE
)Buffer
;
799 TRACE("return %lu\n", ApiStatus
);
805 /************************************************************
806 * NetUserGetGroups (NETAPI32.@)
810 NetUserGetGroups(LPCWSTR servername
,
816 LPDWORD totalentries
)
818 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername
),
819 debugstr_w(username
), level
, bufptr
, prefixmaxlen
, entriesread
,
826 return ERROR_INVALID_LEVEL
;
830 /************************************************************
831 * NetUserGetInfo (NETAPI32.@)
835 NetUserGetInfo(LPCWSTR servername
,
840 NET_API_STATUS status
;
841 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername
), debugstr_w(username
),
843 status
= NETAPI_ValidateServername(servername
);
844 if (status
!= NERR_Success
)
847 if(!NETAPI_IsLocalComputer(servername
))
849 FIXME("Only implemented for local computer, but remote server"
850 "%s was requested.\n", debugstr_w(servername
));
851 return NERR_InvalidComputer
;
854 if(!NETAPI_FindUser(username
) && !NETAPI_IsCurrentUser(username
))
856 TRACE("User %s is unknown.\n", debugstr_w(username
));
857 return NERR_UserNotFound
;
867 name_sz
= lstrlenW(username
) + 1;
870 NetApiBufferAllocate(sizeof(USER_INFO_0
) + name_sz
* sizeof(WCHAR
),
873 ui
= (PUSER_INFO_0
) *bufptr
;
874 ui
->usri0_name
= (LPWSTR
) (*bufptr
+ sizeof(USER_INFO_0
));
877 lstrcpyW(ui
->usri0_name
, username
);
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
;
894 status
= NetUserGetInfo(servername
, username
, 0, (LPBYTE
*) &ui0
);
895 if (status
!= NERR_Success
)
897 NetApiBufferFree(ui0
);
900 name_sz
= lstrlenW(ui0
->usri0_name
) + 1;
903 NetApiBufferAllocate(sizeof(USER_INFO_10
) +
904 (name_sz
+ comment_sz
+ usr_comment_sz
+
905 full_name_sz
) * sizeof(WCHAR
),
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
));
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;
927 static const WCHAR homedirW
[] = {'H','O','M','E',0};
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
;
934 password_sz
= 1; /* not filled out for security reasons for NetUserGetInfo*/
939 status
= NetUserGetInfo(servername
, username
, 0, (LPBYTE
*) &ui0
);
940 if (status
!= NERR_Success
)
942 NetApiBufferFree(ui0
);
945 name_sz
= lstrlenW(ui0
->usri0_name
) + 1;
946 home_dir_sz
= GetEnvironmentVariableW(homedirW
, NULL
,0);
948 NetApiBufferAllocate(sizeof(USER_INFO_1
) +
949 (name_sz
+ password_sz
+ home_dir_sz
+
950 comment_sz
+ script_path_sz
) * sizeof(WCHAR
),
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
;
960 lstrcpyW(ui
->usri1_name
, ui0
->usri0_name
);
961 NetApiBufferFree(ui0
);
962 ui
->usri1_password
[0] = 0;
963 ui
->usri1_password_age
= 0;
965 GetEnvironmentVariableW(homedirW
, ui
->usri1_home_dir
,home_dir_sz
);
966 ui
->usri1_comment
[0] = 0;
968 ui
->usri1_script_path
[0] = 0;
998 FIXME("Level %d is not implemented\n", level
);
999 return NERR_InternalError
;
1002 TRACE("Invalid level %d is specified\n", level
);
1003 return ERROR_INVALID_LEVEL
;
1005 return NERR_Success
;
1009 /************************************************************
1010 * NetUserGetLocalGroups (NETAPI32.@)
1014 NetUserGetLocalGroups(LPCWSTR servername
,
1020 LPDWORD entriesread
,
1021 LPDWORD totalentries
)
1023 NET_API_STATUS status
;
1024 const WCHAR admins
[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0};
1026 LOCALGROUP_USERS_INFO_0
* info
;
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
);
1033 status
= NETAPI_ValidateServername(servername
);
1034 if (status
!= NERR_Success
)
1038 NetApiBufferAllocate(size
* sizeof(WCHAR
), (LPVOID
*)¤tuser
);
1039 GetUserNameW(currentuser
, &size
);
1041 if (lstrcmpiW(username
, currentuser
) && NETAPI_FindUser(username
))
1043 NetApiBufferFree(currentuser
);
1044 return NERR_UserNotFound
;
1047 NetApiBufferFree(currentuser
);
1049 size
= sizeof(*info
) + sizeof(admins
);
1051 if(prefmaxlen
< size
)
1052 status
= ERROR_MORE_DATA
;
1054 status
= NetApiBufferAllocate(size
, (LPVOID
*)&info
);
1056 if(status
!= NERR_Success
)
1063 info
->lgrui0_name
= (LPWSTR
)((LPBYTE
)info
+ sizeof(*info
));
1064 lstrcpyW(info
->lgrui0_name
, admins
);
1066 *bufptr
= (LPBYTE
)info
;
1069 return NERR_Success
;
1073 /******************************************************************************
1074 * NetUserSetGroups (NETAPI32.@)
1078 NetUserSetGroups(LPCWSTR servername
,
1084 FIXME("(%s %s %lu %p %lu)\n",
1085 debugstr_w(servername
), debugstr_w(username
), level
, buf
, num_entries
);
1086 return ERROR_ACCESS_DENIED
;
1090 /******************************************************************************
1091 * NetUserSetInfo (NETAPI32.@)
1095 NetUserSetInfo(LPCWSTR servername
,
1101 FIXME("(%s %s %lu %p %p)\n",
1102 debugstr_w(servername
), debugstr_w(username
), level
, buf
, parm_err
);
1103 return ERROR_ACCESS_DENIED
;