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
);
157 /************************************************************
158 * NetUserAdd (NETAPI32.@)
162 NetUserAdd(LPCWSTR servername
,
167 NET_API_STATUS status
;
168 struct sam_user
* su
= NULL
;
170 FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername
), level
, bufptr
, parm_err
);
172 if((status
= NETAPI_ValidateServername(servername
)) != NERR_Success
)
177 /* Level 3 and 4 are identical for the purposes of NetUserAdd */
180 FIXME("Level 3 and 4 not implemented.\n");
183 FIXME("Level 2 not implemented.\n");
187 PUSER_INFO_1 ui
= (PUSER_INFO_1
) bufptr
;
188 su
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user
));
191 status
= NERR_InternalError
;
195 if(lstrlenW(ui
->usri1_name
) > LM20_UNLEN
)
197 status
= NERR_BadUsername
;
201 /*FIXME: do other checks for a valid username */
202 lstrcpyW(su
->user_name
, ui
->usri1_name
);
204 if(lstrlenW(ui
->usri1_password
) > PWLEN
)
206 /* Always return PasswordTooShort on invalid passwords. */
207 status
= NERR_PasswordTooShort
;
210 lstrcpyW(su
->user_password
, ui
->usri1_password
);
212 su
->sec_since_passwd_change
= ui
->usri1_password_age
;
213 su
->user_priv
= ui
->usri1_priv
;
214 su
->user_flags
= ui
->usri1_flags
;
216 /*FIXME: set the other LPWSTRs to NULL for now */
218 su
->user_comment
= NULL
;
219 su
->user_logon_script_path
= NULL
;
221 list_add_head(&user_list
, &su
->entry
);
225 TRACE("Invalid level %d specified.\n", level
);
226 status
= ERROR_INVALID_LEVEL
;
230 HeapFree(GetProcessHeap(), 0, su
);
236 /******************************************************************************
237 * NetUserChangePassword (NETAPI32.@)
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.
247 * Success: NERR_Success.
248 * Failure: NERR_* failure code or win error code.
253 NetUserChangePassword(LPCWSTR domainname
,
258 struct sam_user
*user
;
260 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname
), debugstr_w(username
));
263 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname
));
265 if((user
= NETAPI_FindUser(username
)) == NULL
)
266 return NERR_UserNotFound
;
268 if(lstrcmpW(user
->user_password
, oldpassword
) != 0)
269 return ERROR_INVALID_PASSWORD
;
271 if(lstrlenW(newpassword
) > PWLEN
)
272 return ERROR_PASSWORD_RESTRICTION
;
274 lstrcpyW(user
->user_password
, newpassword
);
280 /************************************************************
281 * NetUserDel (NETAPI32.@)
285 NetUserDel(LPCWSTR servername
,
288 NET_API_STATUS status
;
289 struct sam_user
*user
;
291 TRACE("(%s, %s)\n", debugstr_w(servername
), debugstr_w(username
));
293 if((status
= NETAPI_ValidateServername(servername
))!= NERR_Success
)
296 if ((user
= NETAPI_FindUser(username
)) == NULL
)
297 return NERR_UserNotFound
;
299 list_remove(&user
->entry
);
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
);
310 /************************************************************
311 * NetUserEnum (NETAPI32.@)
315 NetUserEnum(LPCWSTR servername
,
321 LPDWORD totalentries
,
322 LPDWORD resume_handle
)
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
;
336 SAM_HANDLE UserHandle
= NULL
;
337 PUSER_ACCOUNT_INFORMATION UserInfo
= NULL
;
339 NET_API_STATUS ApiStatus
= NERR_Success
;
340 NTSTATUS Status
= STATUS_SUCCESS
;
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
);
349 if (resume_handle
!= NULL
&& *resume_handle
!= 0)
351 EnumContext
= (PENUM_CONTEXT
)*resume_handle
;
355 ApiStatus
= NetApiBufferAllocate(sizeof(ENUM_CONTEXT
), (PVOID
*)&EnumContext
);
356 if (ApiStatus
!= NERR_Success
)
359 EnumContext
->EnumerationContext
= 0;
360 EnumContext
->Buffer
= NULL
;
361 EnumContext
->Returned
= 0;
362 EnumContext
->Index
= 0;
363 EnumContext
->BuiltinDone
= FALSE
;
365 Status
= SamConnect(NULL
,
366 &EnumContext
->ServerHandle
,
367 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
369 if (!NT_SUCCESS(Status
))
371 ERR("SamConnect failed (Status %08lx)\n", Status
);
372 ApiStatus
= NetpNtStatusToApiStatus(Status
);
376 Status
= GetAccountDomainSid(&DomainSid
);
377 if (!NT_SUCCESS(Status
))
379 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
380 ApiStatus
= NetpNtStatusToApiStatus(Status
);
384 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
385 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
387 &EnumContext
->AccountDomainHandle
);
389 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
391 if (!NT_SUCCESS(Status
))
393 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
394 ApiStatus
= NetpNtStatusToApiStatus(Status
);
398 Status
= GetBuiltinDomainSid(&DomainSid
);
399 if (!NT_SUCCESS(Status
))
401 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status
);
402 ApiStatus
= NetpNtStatusToApiStatus(Status
);
406 Status
= SamOpenDomain(EnumContext
->ServerHandle
,
407 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
409 &EnumContext
->BuiltinDomainHandle
);
411 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid
);
413 if (!NT_SUCCESS(Status
))
415 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
416 ApiStatus
= NetpNtStatusToApiStatus(Status
);
423 TRACE("EnumContext->Index: %lu\n", EnumContext
->Index
);
424 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
426 if (EnumContext
->Index
>= EnumContext
->Returned
)
428 // if (EnumContext->BuiltinDone == TRUE)
430 // ApiStatus = NERR_Success;
434 TRACE("Calling SamEnumerateUsersInDomain\n");
435 Status
= SamEnumerateUsersInDomain(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
436 &EnumContext
->EnumerationContext
,
438 (PVOID
*)&EnumContext
->Buffer
,
440 &EnumContext
->Returned
);
442 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status
);
443 if (!NT_SUCCESS(Status
))
445 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status
);
446 ApiStatus
= NetpNtStatusToApiStatus(Status
);
450 if (Status
== STATUS_MORE_ENTRIES
)
452 ApiStatus
= NERR_BufTooSmall
;
457 EnumContext
->BuiltinDone
= TRUE
;
461 TRACE("EnumContext: %lu\n", EnumContext
);
462 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
463 TRACE("EnumContext->Buffer: %p\n", EnumContext
->Buffer
);
465 /* Get a pointer to the current user */
466 CurrentUser
= &EnumContext
->Buffer
[EnumContext
->Index
];
468 TRACE("RID: %lu\n", CurrentUser
->RelativeId
);
470 Status
= SamOpenUser(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
471 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
472 CurrentUser
->RelativeId
,
474 if (!NT_SUCCESS(Status
))
476 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
477 ApiStatus
= NetpNtStatusToApiStatus(Status
);
481 Status
= SamQueryInformationUser(UserHandle
,
482 UserAccountInformation
,
484 if (!NT_SUCCESS(Status
))
486 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
487 ApiStatus
= NetpNtStatusToApiStatus(Status
);
491 SamCloseHandle(UserHandle
);
497 Size
= sizeof(USER_INFO_0
) +
498 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
502 Size
= sizeof(USER_INFO_1
) +
503 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
505 if (UserInfo
->HomeDirectory
.Length
> 0)
506 Size
+= UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
);
508 if (UserInfo
->AdminComment
.Length
> 0)
509 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
511 if (UserInfo
->ScriptPath
.Length
> 0)
512 Size
= UserInfo
->ScriptPath
.Length
+ sizeof(WCHAR
);
521 Size
= sizeof(USER_INFO_20
) +
522 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
524 if (UserInfo
->FullName
.Length
> 0)
525 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
527 if (UserInfo
->AdminComment
.Length
> 0)
528 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
534 ApiStatus
= ERROR_INVALID_LEVEL
;
538 ApiStatus
= NetApiBufferAllocate(Size
, &Buffer
);
539 if (ApiStatus
!= NERR_Success
)
545 UserInfo0
= (PUSER_INFO_0
)Buffer
;
547 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo0
+ sizeof(USER_INFO_0
));
548 UserInfo0
->usri0_name
= Ptr
;
550 memcpy(UserInfo0
->usri0_name
,
551 UserInfo
->UserName
.Buffer
,
552 UserInfo
->UserName
.Length
);
553 UserInfo0
->usri0_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
557 UserInfo1
= (PUSER_INFO_1
)Buffer
;
559 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo1
+ sizeof(USER_INFO_1
));
561 UserInfo1
->usri1_name
= Ptr
;
563 memcpy(UserInfo1
->usri1_name
,
564 UserInfo
->UserName
.Buffer
,
565 UserInfo
->UserName
.Length
);
566 UserInfo1
->usri1_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
568 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
570 UserInfo1
->usri1_password
= NULL
;
572 UserInfo1
->usri1_password_age
= 0; /* FIXME */
574 UserInfo1
->usri1_priv
= 0; /* FIXME */
576 if (UserInfo
->HomeDirectory
.Length
> 0)
578 UserInfo1
->usri1_home_dir
= Ptr
;
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
;
585 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
));
588 if (UserInfo
->AdminComment
.Length
> 0)
590 UserInfo1
->usri1_comment
= Ptr
;
592 memcpy(UserInfo1
->usri1_comment
,
593 UserInfo
->AdminComment
.Buffer
,
594 UserInfo
->AdminComment
.Length
);
595 UserInfo1
->usri1_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
597 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
600 UserInfo1
->usri1_flags
= UserInfo
->UserAccountControl
;
602 if (UserInfo
->ScriptPath
.Length
> 0)
604 UserInfo1
->usri1_script_path
= Ptr
;
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
;
619 UserInfo20
= (PUSER_INFO_20
)Buffer
;
621 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo20
+ sizeof(USER_INFO_20
));
623 UserInfo20
->usri20_name
= Ptr
;
625 memcpy(UserInfo20
->usri20_name
,
626 UserInfo
->UserName
.Buffer
,
627 UserInfo
->UserName
.Length
);
628 UserInfo20
->usri20_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
630 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
632 if (UserInfo
->FullName
.Length
> 0)
634 UserInfo20
->usri20_full_name
= Ptr
;
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
;
641 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->FullName
.Length
+ sizeof(WCHAR
));
644 if (UserInfo
->AdminComment
.Length
> 0)
646 UserInfo20
->usri20_comment
= Ptr
;
648 memcpy(UserInfo20
->usri20_comment
,
649 UserInfo
->AdminComment
.Buffer
,
650 UserInfo
->AdminComment
.Length
);
651 UserInfo20
->usri20_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
653 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
656 UserInfo20
->usri20_flags
= UserInfo
->UserAccountControl
;
657 UserInfo20
->usri20_user_id
= CurrentUser
->RelativeId
;
663 if (UserInfo
!= NULL
)
665 if (UserInfo
->UserName
.Buffer
!= NULL
)
666 SamFreeMemory(UserInfo
->UserName
.Buffer
);
668 if (UserInfo
->FullName
.Buffer
!= NULL
)
669 SamFreeMemory(UserInfo
->FullName
.Buffer
);
671 if (UserInfo
->HomeDirectory
.Buffer
!= NULL
)
672 SamFreeMemory(UserInfo
->HomeDirectory
.Buffer
);
674 if (UserInfo
->HomeDirectoryDrive
.Buffer
!= NULL
)
675 SamFreeMemory(UserInfo
->HomeDirectoryDrive
.Buffer
);
677 if (UserInfo
->ScriptPath
.Buffer
!= NULL
)
678 SamFreeMemory(UserInfo
->ScriptPath
.Buffer
);
680 if (UserInfo
->ProfilePath
.Buffer
!= NULL
)
681 SamFreeMemory(UserInfo
->ProfilePath
.Buffer
);
683 if (UserInfo
->AdminComment
.Buffer
!= NULL
)
684 SamFreeMemory(UserInfo
->AdminComment
.Buffer
);
686 if (UserInfo
->WorkStations
.Buffer
!= NULL
)
687 SamFreeMemory(UserInfo
->WorkStations
.Buffer
);
689 if (UserInfo
->LogonHours
.LogonHours
!= NULL
)
690 SamFreeMemory(UserInfo
->LogonHours
.LogonHours
);
692 SamFreeMemory(UserInfo
);
696 EnumContext
->Index
++;
702 if (ApiStatus
== NERR_Success
&& EnumContext
->Index
< EnumContext
->Returned
)
703 ApiStatus
= ERROR_MORE_DATA
;
705 if (EnumContext
!= NULL
)
706 *totalentries
= EnumContext
->Returned
;
708 if (resume_handle
== NULL
|| ApiStatus
!= ERROR_MORE_DATA
)
710 if (EnumContext
!= NULL
)
712 if (EnumContext
->BuiltinDomainHandle
!= NULL
)
713 SamCloseHandle(EnumContext
->BuiltinDomainHandle
);
715 if (EnumContext
->AccountDomainHandle
!= NULL
)
716 SamCloseHandle(EnumContext
->AccountDomainHandle
);
718 if (EnumContext
->ServerHandle
!= NULL
)
719 SamCloseHandle(EnumContext
->ServerHandle
);
721 if (EnumContext
->Buffer
!= NULL
)
723 for (i
= 0; i
< EnumContext
->Returned
; i
++)
725 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
728 SamFreeMemory(EnumContext
->Buffer
);
731 NetApiBufferFree(EnumContext
);
736 if (UserHandle
!= NULL
)
737 SamCloseHandle(UserHandle
);
739 if (UserInfo
!= NULL
)
741 if (UserInfo
->UserName
.Buffer
!= NULL
)
742 SamFreeMemory(UserInfo
->UserName
.Buffer
);
744 if (UserInfo
->FullName
.Buffer
!= NULL
)
745 SamFreeMemory(UserInfo
->FullName
.Buffer
);
747 if (UserInfo
->HomeDirectory
.Buffer
!= NULL
)
748 SamFreeMemory(UserInfo
->HomeDirectory
.Buffer
);
750 if (UserInfo
->HomeDirectoryDrive
.Buffer
!= NULL
)
751 SamFreeMemory(UserInfo
->HomeDirectoryDrive
.Buffer
);
753 if (UserInfo
->ScriptPath
.Buffer
!= NULL
)
754 SamFreeMemory(UserInfo
->ScriptPath
.Buffer
);
756 if (UserInfo
->ProfilePath
.Buffer
!= NULL
)
757 SamFreeMemory(UserInfo
->ProfilePath
.Buffer
);
759 if (UserInfo
->AdminComment
.Buffer
!= NULL
)
760 SamFreeMemory(UserInfo
->AdminComment
.Buffer
);
762 if (UserInfo
->WorkStations
.Buffer
!= NULL
)
763 SamFreeMemory(UserInfo
->WorkStations
.Buffer
);
765 if (UserInfo
->LogonHours
.LogonHours
!= NULL
)
766 SamFreeMemory(UserInfo
->LogonHours
.LogonHours
);
768 SamFreeMemory(UserInfo
);
771 if (resume_handle
!= NULL
)
772 *resume_handle
= (DWORD_PTR
)EnumContext
;
774 *bufptr
= (LPBYTE
)Buffer
;
776 TRACE("return %lu\n", ApiStatus
);
782 /************************************************************
783 * NetUserGetGroups (NETAPI32.@)
787 NetUserGetGroups(LPCWSTR servername
,
793 LPDWORD totalentries
)
795 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername
),
796 debugstr_w(username
), level
, bufptr
, prefixmaxlen
, entriesread
,
803 return ERROR_INVALID_LEVEL
;
807 /************************************************************
808 * NetUserGetInfo (NETAPI32.@)
812 NetUserGetInfo(LPCWSTR servername
,
817 NET_API_STATUS status
;
818 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername
), debugstr_w(username
),
820 status
= NETAPI_ValidateServername(servername
);
821 if (status
!= NERR_Success
)
824 if(!NETAPI_IsLocalComputer(servername
))
826 FIXME("Only implemented for local computer, but remote server"
827 "%s was requested.\n", debugstr_w(servername
));
828 return NERR_InvalidComputer
;
831 if(!NETAPI_FindUser(username
) && !NETAPI_IsCurrentUser(username
))
833 TRACE("User %s is unknown.\n", debugstr_w(username
));
834 return NERR_UserNotFound
;
844 name_sz
= lstrlenW(username
) + 1;
847 NetApiBufferAllocate(sizeof(USER_INFO_0
) + name_sz
* sizeof(WCHAR
),
850 ui
= (PUSER_INFO_0
) *bufptr
;
851 ui
->usri0_name
= (LPWSTR
) (*bufptr
+ sizeof(USER_INFO_0
));
854 lstrcpyW(ui
->usri0_name
, username
);
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
;
871 status
= NetUserGetInfo(servername
, username
, 0, (LPBYTE
*) &ui0
);
872 if (status
!= NERR_Success
)
874 NetApiBufferFree(ui0
);
877 name_sz
= lstrlenW(ui0
->usri0_name
) + 1;
880 NetApiBufferAllocate(sizeof(USER_INFO_10
) +
881 (name_sz
+ comment_sz
+ usr_comment_sz
+
882 full_name_sz
) * sizeof(WCHAR
),
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
));
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;
904 static const WCHAR homedirW
[] = {'H','O','M','E',0};
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
;
911 password_sz
= 1; /* not filled out for security reasons for NetUserGetInfo*/
916 status
= NetUserGetInfo(servername
, username
, 0, (LPBYTE
*) &ui0
);
917 if (status
!= NERR_Success
)
919 NetApiBufferFree(ui0
);
922 name_sz
= lstrlenW(ui0
->usri0_name
) + 1;
923 home_dir_sz
= GetEnvironmentVariableW(homedirW
, NULL
,0);
925 NetApiBufferAllocate(sizeof(USER_INFO_1
) +
926 (name_sz
+ password_sz
+ home_dir_sz
+
927 comment_sz
+ script_path_sz
) * sizeof(WCHAR
),
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
;
937 lstrcpyW(ui
->usri1_name
, ui0
->usri0_name
);
938 NetApiBufferFree(ui0
);
939 ui
->usri1_password
[0] = 0;
940 ui
->usri1_password_age
= 0;
942 GetEnvironmentVariableW(homedirW
, ui
->usri1_home_dir
,home_dir_sz
);
943 ui
->usri1_comment
[0] = 0;
945 ui
->usri1_script_path
[0] = 0;
975 FIXME("Level %d is not implemented\n", level
);
976 return NERR_InternalError
;
979 TRACE("Invalid level %d is specified\n", level
);
980 return ERROR_INVALID_LEVEL
;
986 /************************************************************
987 * NetUserGetLocalGroups (NETAPI32.@)
991 NetUserGetLocalGroups(LPCWSTR servername
,
998 LPDWORD totalentries
)
1000 NET_API_STATUS status
;
1001 const WCHAR admins
[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0};
1003 LOCALGROUP_USERS_INFO_0
* info
;
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
);
1010 status
= NETAPI_ValidateServername(servername
);
1011 if (status
!= NERR_Success
)
1015 NetApiBufferAllocate(size
* sizeof(WCHAR
), (LPVOID
*)¤tuser
);
1016 GetUserNameW(currentuser
, &size
);
1018 if (lstrcmpiW(username
, currentuser
) && NETAPI_FindUser(username
))
1020 NetApiBufferFree(currentuser
);
1021 return NERR_UserNotFound
;
1024 NetApiBufferFree(currentuser
);
1026 size
= sizeof(*info
) + sizeof(admins
);
1028 if(prefmaxlen
< size
)
1029 status
= ERROR_MORE_DATA
;
1031 status
= NetApiBufferAllocate(size
, (LPVOID
*)&info
);
1033 if(status
!= NERR_Success
)
1040 info
->lgrui0_name
= (LPWSTR
)((LPBYTE
)info
+ sizeof(*info
));
1041 lstrcpyW(info
->lgrui0_name
, admins
);
1043 *bufptr
= (LPBYTE
)info
;
1046 return NERR_Success
;
1050 /******************************************************************************
1051 * NetUserSetGroups (NETAPI32.@)
1055 NetUserSetGroups(LPCWSTR servername
,
1061 FIXME("(%s %s %lu %p %lu)\n",
1062 debugstr_w(servername
), debugstr_w(username
), level
, buf
, num_entries
);
1063 return ERROR_ACCESS_DENIED
;
1067 /******************************************************************************
1068 * NetUserSetInfo (NETAPI32.@)
1072 NetUserSetInfo(LPCWSTR servername
,
1078 FIXME("(%s %s %lu %p %p)\n",
1079 debugstr_w(servername
), debugstr_w(username
), level
, buf
, parm_err
);
1080 return ERROR_ACCESS_DENIED
;