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
23 WINE_DEFAULT_DEBUG_CHANNEL(netapi32
);
26 typedef struct _ENUM_CONTEXT
28 SAM_HANDLE ServerHandle
;
29 SAM_HANDLE BuiltinDomainHandle
;
30 SAM_HANDLE AccountDomainHandle
;
32 SAM_ENUMERATE_HANDLE EnumerationContext
;
33 PSAM_RID_ENUMERATION Buffer
;
38 } ENUM_CONTEXT
, *PENUM_CONTEXT
;
41 /* NOTE: So far, this is implemented to support tests that require user logins,
42 * but not designed to handle real user databases. Those should probably
43 * be synced with either the host's user database or with Samba.
45 * FIXME: The user database should hold all the information the USER_INFO_4 struct
46 * needs, but for the first try, I will just implement the USER_INFO_1 fields.
52 WCHAR user_name
[LM20_UNLEN
+1];
53 WCHAR user_password
[PWLEN
+ 1];
54 DWORD sec_since_passwd_change
;
59 LPWSTR user_logon_script_path
;
62 static struct list user_list
= LIST_INIT( user_list
);
64 BOOL
NETAPI_IsLocalComputer(LPCWSTR ServerName
);
66 /************************************************************
67 * NETAPI_ValidateServername
69 * Validates server name
71 static NET_API_STATUS
NETAPI_ValidateServername(LPCWSTR ServerName
)
75 if (ServerName
[0] == 0)
76 return ERROR_BAD_NETPATH
;
78 ((ServerName
[0] == '\\') &&
79 (ServerName
[1] != '\\'))
81 ((ServerName
[0] == '\\') &&
82 (ServerName
[1] == '\\') &&
85 return ERROR_INVALID_NAME
;
90 /************************************************************
93 * Looks for a user in the user database.
94 * Returns a pointer to the entry in the user list when the user
95 * is found, NULL otherwise.
97 static struct sam_user
* NETAPI_FindUser(LPCWSTR UserName
)
99 struct sam_user
*user
;
101 LIST_FOR_EACH_ENTRY(user
, &user_list
, struct sam_user
, entry
)
103 if(lstrcmpW(user
->user_name
, UserName
) == 0)
112 BuildUserInfoBuffer(PUSER_ACCOUNT_INFORMATION UserInfo
,
117 LPVOID LocalBuffer
= NULL
;
118 PUSER_INFO_0 UserInfo0
;
119 PUSER_INFO_1 UserInfo1
;
120 PUSER_INFO_10 UserInfo10
;
121 PUSER_INFO_20 UserInfo20
;
124 NET_API_STATUS ApiStatus
= NERR_Success
;
131 Size
= sizeof(USER_INFO_0
) +
132 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
136 Size
= sizeof(USER_INFO_1
) +
137 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
139 if (UserInfo
->HomeDirectory
.Length
> 0)
140 Size
+= UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
);
142 if (UserInfo
->AdminComment
.Length
> 0)
143 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
145 if (UserInfo
->ScriptPath
.Length
> 0)
146 Size
= UserInfo
->ScriptPath
.Length
+ sizeof(WCHAR
);
154 Size
= sizeof(USER_INFO_10
) +
155 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
157 if (UserInfo
->AdminComment
.Length
> 0)
158 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
160 /* FIXME: usri10_usr_comment */
162 if (UserInfo
->FullName
.Length
> 0)
163 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
169 Size
= sizeof(USER_INFO_20
) +
170 UserInfo
->UserName
.Length
+ sizeof(WCHAR
);
172 if (UserInfo
->FullName
.Length
> 0)
173 Size
+= UserInfo
->FullName
.Length
+ sizeof(WCHAR
);
175 if (UserInfo
->AdminComment
.Length
> 0)
176 Size
+= UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
182 ApiStatus
= ERROR_INVALID_LEVEL
;
186 ApiStatus
= NetApiBufferAllocate(Size
, &LocalBuffer
);
187 if (ApiStatus
!= NERR_Success
)
190 ZeroMemory(LocalBuffer
, Size
);
195 UserInfo0
= (PUSER_INFO_0
)LocalBuffer
;
197 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo0
+ sizeof(USER_INFO_0
));
198 UserInfo0
->usri0_name
= Ptr
;
200 memcpy(UserInfo0
->usri0_name
,
201 UserInfo
->UserName
.Buffer
,
202 UserInfo
->UserName
.Length
);
203 UserInfo0
->usri0_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
207 UserInfo1
= (PUSER_INFO_1
)LocalBuffer
;
209 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo1
+ sizeof(USER_INFO_1
));
211 UserInfo1
->usri1_name
= Ptr
;
213 memcpy(UserInfo1
->usri1_name
,
214 UserInfo
->UserName
.Buffer
,
215 UserInfo
->UserName
.Length
);
216 UserInfo1
->usri1_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
218 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
220 UserInfo1
->usri1_password
= NULL
;
222 /* FIXME: UserInfo1->usri1_password_age */
223 /* FIXME: UserInfo1->usri1_priv */
225 if (UserInfo
->HomeDirectory
.Length
> 0)
227 UserInfo1
->usri1_home_dir
= Ptr
;
229 memcpy(UserInfo1
->usri1_home_dir
,
230 UserInfo
->HomeDirectory
.Buffer
,
231 UserInfo
->HomeDirectory
.Length
);
232 UserInfo1
->usri1_home_dir
[UserInfo
->HomeDirectory
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
234 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->HomeDirectory
.Length
+ sizeof(WCHAR
));
237 if (UserInfo
->AdminComment
.Length
> 0)
239 UserInfo1
->usri1_comment
= Ptr
;
241 memcpy(UserInfo1
->usri1_comment
,
242 UserInfo
->AdminComment
.Buffer
,
243 UserInfo
->AdminComment
.Length
);
244 UserInfo1
->usri1_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
246 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
249 UserInfo1
->usri1_flags
= UserInfo
->UserAccountControl
;
251 if (UserInfo
->ScriptPath
.Length
> 0)
253 UserInfo1
->usri1_script_path
= Ptr
;
255 memcpy(UserInfo1
->usri1_script_path
,
256 UserInfo
->ScriptPath
.Buffer
,
257 UserInfo
->ScriptPath
.Length
);
258 UserInfo1
->usri1_script_path
[UserInfo
->ScriptPath
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
267 UserInfo10
= (PUSER_INFO_10
)LocalBuffer
;
269 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo10
+ sizeof(USER_INFO_10
));
271 UserInfo10
->usri10_name
= Ptr
;
273 memcpy(UserInfo10
->usri10_name
,
274 UserInfo
->UserName
.Buffer
,
275 UserInfo
->UserName
.Length
);
276 UserInfo10
->usri10_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
278 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
280 if (UserInfo
->AdminComment
.Length
> 0)
282 UserInfo10
->usri10_comment
= Ptr
;
284 memcpy(UserInfo10
->usri10_comment
,
285 UserInfo
->AdminComment
.Buffer
,
286 UserInfo
->AdminComment
.Length
);
287 UserInfo10
->usri10_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
289 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
292 /* FIXME: UserInfo10->usri10_usr_comment */
294 if (UserInfo
->FullName
.Length
> 0)
296 UserInfo10
->usri10_full_name
= Ptr
;
298 memcpy(UserInfo10
->usri10_full_name
,
299 UserInfo
->FullName
.Buffer
,
300 UserInfo
->FullName
.Length
);
301 UserInfo10
->usri10_full_name
[UserInfo
->FullName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
308 UserInfo20
= (PUSER_INFO_20
)LocalBuffer
;
310 Ptr
= (LPWSTR
)((ULONG_PTR
)UserInfo20
+ sizeof(USER_INFO_20
));
312 UserInfo20
->usri20_name
= Ptr
;
314 memcpy(UserInfo20
->usri20_name
,
315 UserInfo
->UserName
.Buffer
,
316 UserInfo
->UserName
.Length
);
317 UserInfo20
->usri20_name
[UserInfo
->UserName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
319 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->UserName
.Length
+ sizeof(WCHAR
));
321 if (UserInfo
->FullName
.Length
> 0)
323 UserInfo20
->usri20_full_name
= Ptr
;
325 memcpy(UserInfo20
->usri20_full_name
,
326 UserInfo
->FullName
.Buffer
,
327 UserInfo
->FullName
.Length
);
328 UserInfo20
->usri20_full_name
[UserInfo
->FullName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
330 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->FullName
.Length
+ sizeof(WCHAR
));
333 if (UserInfo
->AdminComment
.Length
> 0)
335 UserInfo20
->usri20_comment
= Ptr
;
337 memcpy(UserInfo20
->usri20_comment
,
338 UserInfo
->AdminComment
.Buffer
,
339 UserInfo
->AdminComment
.Length
);
340 UserInfo20
->usri20_comment
[UserInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
342 Ptr
= (LPWSTR
)((ULONG_PTR
)Ptr
+ UserInfo
->AdminComment
.Length
+ sizeof(WCHAR
));
345 UserInfo20
->usri20_flags
= UserInfo
->UserAccountControl
;
346 UserInfo20
->usri20_user_id
= RelativeId
;
353 if (ApiStatus
== NERR_Success
)
355 *Buffer
= LocalBuffer
;
359 if (LocalBuffer
!= NULL
)
360 NetApiBufferFree(LocalBuffer
);
369 FreeUserInfo(PUSER_ACCOUNT_INFORMATION UserInfo
)
371 if (UserInfo
->UserName
.Buffer
!= NULL
)
372 SamFreeMemory(UserInfo
->UserName
.Buffer
);
374 if (UserInfo
->FullName
.Buffer
!= NULL
)
375 SamFreeMemory(UserInfo
->FullName
.Buffer
);
377 if (UserInfo
->HomeDirectory
.Buffer
!= NULL
)
378 SamFreeMemory(UserInfo
->HomeDirectory
.Buffer
);
380 if (UserInfo
->HomeDirectoryDrive
.Buffer
!= NULL
)
381 SamFreeMemory(UserInfo
->HomeDirectoryDrive
.Buffer
);
383 if (UserInfo
->ScriptPath
.Buffer
!= NULL
)
384 SamFreeMemory(UserInfo
->ScriptPath
.Buffer
);
386 if (UserInfo
->ProfilePath
.Buffer
!= NULL
)
387 SamFreeMemory(UserInfo
->ProfilePath
.Buffer
);
389 if (UserInfo
->AdminComment
.Buffer
!= NULL
)
390 SamFreeMemory(UserInfo
->AdminComment
.Buffer
);
392 if (UserInfo
->WorkStations
.Buffer
!= NULL
)
393 SamFreeMemory(UserInfo
->WorkStations
.Buffer
);
395 if (UserInfo
->LogonHours
.LogonHours
!= NULL
)
396 SamFreeMemory(UserInfo
->LogonHours
.LogonHours
);
398 SamFreeMemory(UserInfo
);
402 /************************************************************
403 * NetUserAdd (NETAPI32.@)
407 NetUserAdd(LPCWSTR servername
,
412 NET_API_STATUS status
;
413 struct sam_user
* su
= NULL
;
415 FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername
), level
, bufptr
, parm_err
);
417 if((status
= NETAPI_ValidateServername(servername
)) != NERR_Success
)
422 /* Level 3 and 4 are identical for the purposes of NetUserAdd */
425 FIXME("Level 3 and 4 not implemented.\n");
428 FIXME("Level 2 not implemented.\n");
432 PUSER_INFO_1 ui
= (PUSER_INFO_1
) bufptr
;
433 su
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user
));
436 status
= NERR_InternalError
;
440 if(lstrlenW(ui
->usri1_name
) > LM20_UNLEN
)
442 status
= NERR_BadUsername
;
446 /*FIXME: do other checks for a valid username */
447 lstrcpyW(su
->user_name
, ui
->usri1_name
);
449 if(lstrlenW(ui
->usri1_password
) > PWLEN
)
451 /* Always return PasswordTooShort on invalid passwords. */
452 status
= NERR_PasswordTooShort
;
455 lstrcpyW(su
->user_password
, ui
->usri1_password
);
457 su
->sec_since_passwd_change
= ui
->usri1_password_age
;
458 su
->user_priv
= ui
->usri1_priv
;
459 su
->user_flags
= ui
->usri1_flags
;
461 /*FIXME: set the other LPWSTRs to NULL for now */
463 su
->user_comment
= NULL
;
464 su
->user_logon_script_path
= NULL
;
466 list_add_head(&user_list
, &su
->entry
);
470 TRACE("Invalid level %d specified.\n", level
);
471 status
= ERROR_INVALID_LEVEL
;
475 HeapFree(GetProcessHeap(), 0, su
);
481 /******************************************************************************
482 * NetUserChangePassword (NETAPI32.@)
484 * domainname [I] Optional. Domain on which the user resides or the logon
485 * domain of the current user if NULL.
486 * username [I] Optional. Username to change the password for or the name
487 * of the current user if NULL.
488 * oldpassword [I] The user's current password.
489 * newpassword [I] The password that the user will be changed to using.
492 * Success: NERR_Success.
493 * Failure: NERR_* failure code or win error code.
498 NetUserChangePassword(LPCWSTR domainname
,
503 struct sam_user
*user
;
505 TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname
), debugstr_w(username
));
508 FIXME("Ignoring domainname %s.\n", debugstr_w(domainname
));
510 if((user
= NETAPI_FindUser(username
)) == NULL
)
511 return NERR_UserNotFound
;
513 if(lstrcmpW(user
->user_password
, oldpassword
) != 0)
514 return ERROR_INVALID_PASSWORD
;
516 if(lstrlenW(newpassword
) > PWLEN
)
517 return ERROR_PASSWORD_RESTRICTION
;
519 lstrcpyW(user
->user_password
, newpassword
);
525 /************************************************************
526 * NetUserDel (NETAPI32.@)
530 NetUserDel(LPCWSTR servername
,
533 NET_API_STATUS status
;
534 struct sam_user
*user
;
536 TRACE("(%s, %s)\n", debugstr_w(servername
), debugstr_w(username
));
538 if((status
= NETAPI_ValidateServername(servername
))!= NERR_Success
)
541 if ((user
= NETAPI_FindUser(username
)) == NULL
)
542 return NERR_UserNotFound
;
544 list_remove(&user
->entry
);
546 HeapFree(GetProcessHeap(), 0, user
->home_dir
);
547 HeapFree(GetProcessHeap(), 0, user
->user_comment
);
548 HeapFree(GetProcessHeap(), 0, user
->user_logon_script_path
);
549 HeapFree(GetProcessHeap(), 0, user
);
555 /************************************************************
556 * NetUserEnum (NETAPI32.@)
560 NetUserEnum(LPCWSTR servername
,
566 LPDWORD totalentries
,
567 LPDWORD resume_handle
)
569 UNICODE_STRING ServerName
;
570 PSAM_RID_ENUMERATION CurrentUser
;
571 PENUM_CONTEXT EnumContext
= NULL
;
572 LPVOID Buffer
= NULL
;
574 SAM_HANDLE UserHandle
= NULL
;
575 PUSER_ACCOUNT_INFORMATION UserInfo
= NULL
;
577 NET_API_STATUS ApiStatus
= NERR_Success
;
578 NTSTATUS Status
= STATUS_SUCCESS
;
580 FIXME("(%s %d 0x%d %p %d %p %p %p) stub!\n", debugstr_w(servername
), level
,
581 filter
, bufptr
, prefmaxlen
, entriesread
, totalentries
, resume_handle
);
587 if (servername
!= NULL
)
588 RtlInitUnicodeString(&ServerName
, servername
);
590 if (resume_handle
!= NULL
&& *resume_handle
!= 0)
592 EnumContext
= (PENUM_CONTEXT
)*resume_handle
;
596 ApiStatus
= NetApiBufferAllocate(sizeof(ENUM_CONTEXT
), (PVOID
*)&EnumContext
);
597 if (ApiStatus
!= NERR_Success
)
600 EnumContext
->EnumerationContext
= 0;
601 EnumContext
->Buffer
= NULL
;
602 EnumContext
->Returned
= 0;
603 EnumContext
->Index
= 0;
604 EnumContext
->BuiltinDone
= FALSE
;
606 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
607 &EnumContext
->ServerHandle
,
608 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
610 if (!NT_SUCCESS(Status
))
612 ERR("SamConnect failed (Status %08lx)\n", Status
);
613 ApiStatus
= NetpNtStatusToApiStatus(Status
);
617 Status
= OpenAccountDomain(EnumContext
->ServerHandle
,
618 (servername
!= NULL
) ? &ServerName
: NULL
,
619 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
620 &EnumContext
->AccountDomainHandle
);
621 if (!NT_SUCCESS(Status
))
623 ERR("OpenAccountDomain failed (Status %08lx)\n", Status
);
624 ApiStatus
= NetpNtStatusToApiStatus(Status
);
628 Status
= OpenBuiltinDomain(EnumContext
->ServerHandle
,
629 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
630 &EnumContext
->BuiltinDomainHandle
);
631 if (!NT_SUCCESS(Status
))
633 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status
);
634 ApiStatus
= NetpNtStatusToApiStatus(Status
);
641 TRACE("EnumContext->Index: %lu\n", EnumContext
->Index
);
642 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
644 if (EnumContext
->Index
>= EnumContext
->Returned
)
646 // if (EnumContext->BuiltinDone == TRUE)
648 // ApiStatus = NERR_Success;
652 TRACE("Calling SamEnumerateUsersInDomain\n");
653 Status
= SamEnumerateUsersInDomain(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
654 &EnumContext
->EnumerationContext
,
656 (PVOID
*)&EnumContext
->Buffer
,
658 &EnumContext
->Returned
);
660 TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status
);
661 if (!NT_SUCCESS(Status
))
663 ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status
);
664 ApiStatus
= NetpNtStatusToApiStatus(Status
);
668 if (Status
== STATUS_MORE_ENTRIES
)
670 ApiStatus
= NERR_BufTooSmall
;
675 EnumContext
->BuiltinDone
= TRUE
;
679 TRACE("EnumContext: %lu\n", EnumContext
);
680 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
681 TRACE("EnumContext->Buffer: %p\n", EnumContext
->Buffer
);
683 /* Get a pointer to the current user */
684 CurrentUser
= &EnumContext
->Buffer
[EnumContext
->Index
];
686 TRACE("RID: %lu\n", CurrentUser
->RelativeId
);
688 Status
= SamOpenUser(EnumContext
->AccountDomainHandle
, //BuiltinDomainHandle,
689 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
690 CurrentUser
->RelativeId
,
692 if (!NT_SUCCESS(Status
))
694 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
695 ApiStatus
= NetpNtStatusToApiStatus(Status
);
699 Status
= SamQueryInformationUser(UserHandle
,
700 UserAccountInformation
,
702 if (!NT_SUCCESS(Status
))
704 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
705 ApiStatus
= NetpNtStatusToApiStatus(Status
);
709 SamCloseHandle(UserHandle
);
712 ApiStatus
= BuildUserInfoBuffer(UserInfo
,
714 CurrentUser
->RelativeId
,
716 if (ApiStatus
!= NERR_Success
)
718 ERR("BuildUserInfoBuffer failed (ApiStatus %lu)\n", ApiStatus
);
722 if (UserInfo
!= NULL
)
724 FreeUserInfo(UserInfo
);
728 EnumContext
->Index
++;
734 if (ApiStatus
== NERR_Success
&& EnumContext
->Index
< EnumContext
->Returned
)
735 ApiStatus
= ERROR_MORE_DATA
;
737 if (EnumContext
!= NULL
)
738 *totalentries
= EnumContext
->Returned
;
740 if (resume_handle
== NULL
|| ApiStatus
!= ERROR_MORE_DATA
)
742 if (EnumContext
!= NULL
)
744 if (EnumContext
->BuiltinDomainHandle
!= NULL
)
745 SamCloseHandle(EnumContext
->BuiltinDomainHandle
);
747 if (EnumContext
->AccountDomainHandle
!= NULL
)
748 SamCloseHandle(EnumContext
->AccountDomainHandle
);
750 if (EnumContext
->ServerHandle
!= NULL
)
751 SamCloseHandle(EnumContext
->ServerHandle
);
753 if (EnumContext
->Buffer
!= NULL
)
755 for (i
= 0; i
< EnumContext
->Returned
; i
++)
757 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
760 SamFreeMemory(EnumContext
->Buffer
);
763 NetApiBufferFree(EnumContext
);
768 if (UserHandle
!= NULL
)
769 SamCloseHandle(UserHandle
);
771 if (UserInfo
!= NULL
)
772 FreeUserInfo(UserInfo
);
774 if (resume_handle
!= NULL
)
775 *resume_handle
= (DWORD_PTR
)EnumContext
;
777 *bufptr
= (LPBYTE
)Buffer
;
779 TRACE("return %lu\n", ApiStatus
);
785 /************************************************************
786 * NetUserGetGroups (NETAPI32.@)
790 NetUserGetGroups(LPCWSTR servername
,
796 LPDWORD totalentries
)
798 FIXME("%s %s %d %p %d %p %p stub\n", debugstr_w(servername
),
799 debugstr_w(username
), level
, bufptr
, prefixmaxlen
, entriesread
,
806 return ERROR_INVALID_LEVEL
;
810 /************************************************************
811 * NetUserGetInfo (NETAPI32.@)
815 NetUserGetInfo(LPCWSTR servername
,
820 UNICODE_STRING ServerName
;
821 UNICODE_STRING UserName
;
822 SAM_HANDLE ServerHandle
= NULL
;
823 SAM_HANDLE AccountDomainHandle
= NULL
;
824 SAM_HANDLE UserHandle
= NULL
;
825 PULONG RelativeIds
= NULL
;
826 PSID_NAME_USE Use
= NULL
;
827 PUSER_ACCOUNT_INFORMATION UserInfo
= NULL
;
828 LPVOID Buffer
= NULL
;
829 NET_API_STATUS ApiStatus
= NERR_Success
;
830 NTSTATUS Status
= STATUS_SUCCESS
;
832 TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername
),
833 debugstr_w(username
), level
, bufptr
);
835 if (servername
!= NULL
)
836 RtlInitUnicodeString(&ServerName
, servername
);
838 RtlInitUnicodeString(&UserName
, username
);
840 /* Connect to the SAM Server */
841 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
843 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
845 if (!NT_SUCCESS(Status
))
847 ERR("SamConnect failed (Status %08lx)\n", Status
);
848 ApiStatus
= NetpNtStatusToApiStatus(Status
);
852 /* Open the Account Domain */
853 Status
= OpenAccountDomain(ServerHandle
,
854 (servername
!= NULL
) ? &ServerName
: NULL
,
855 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
856 &AccountDomainHandle
);
857 if (!NT_SUCCESS(Status
))
859 ERR("OpenAccountDomain failed (Status %08lx)\n", Status
);
860 ApiStatus
= NetpNtStatusToApiStatus(Status
);
864 /* Get the RID for the given user name */
865 Status
= SamLookupNamesInDomain(AccountDomainHandle
,
870 if (!NT_SUCCESS(Status
))
872 ERR("SamOpenDomain failed (Status %08lx)\n", Status
);
873 ApiStatus
= NetpNtStatusToApiStatus(Status
);
877 /* Check if the account is a user account */
878 if (Use
[0] != SidTypeUser
)
880 ERR("No user found!\n");
881 ApiStatus
= NERR_UserNotFound
;
885 TRACE("RID: %lu\n", RelativeIds
[0]);
887 /* Open the user object */
888 Status
= SamOpenUser(AccountDomainHandle
,
889 USER_READ_GENERAL
| USER_READ_PREFERENCES
| USER_READ_LOGON
| USER_READ_ACCOUNT
,
892 if (!NT_SUCCESS(Status
))
894 ERR("SamOpenUser failed (Status %08lx)\n", Status
);
895 ApiStatus
= NetpNtStatusToApiStatus(Status
);
899 Status
= SamQueryInformationUser(UserHandle
,
900 UserAccountInformation
,
902 if (!NT_SUCCESS(Status
))
904 ERR("SamQueryInformationUser failed (Status %08lx)\n", Status
);
905 ApiStatus
= NetpNtStatusToApiStatus(Status
);
909 ApiStatus
= BuildUserInfoBuffer(UserInfo
,
913 if (ApiStatus
!= NERR_Success
)
915 ERR("BuildUserInfoBuffer failed (ApiStatus %08lu)\n", ApiStatus
);
920 if (UserInfo
!= NULL
)
921 FreeUserInfo(UserInfo
);
923 if (UserHandle
!= NULL
)
924 SamCloseHandle(UserHandle
);
926 if (RelativeIds
!= NULL
)
927 SamFreeMemory(RelativeIds
);
932 if (AccountDomainHandle
!= NULL
)
933 SamCloseHandle(AccountDomainHandle
);
935 if (ServerHandle
!= NULL
)
936 SamCloseHandle(ServerHandle
);
938 *bufptr
= (LPBYTE
)Buffer
;
944 /************************************************************
945 * NetUserGetLocalGroups (NETAPI32.@)
949 NetUserGetLocalGroups(LPCWSTR servername
,
956 LPDWORD totalentries
)
958 NET_API_STATUS status
;
959 const WCHAR admins
[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0};
961 LOCALGROUP_USERS_INFO_0
* info
;
964 FIXME("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
965 debugstr_w(servername
), debugstr_w(username
), level
, flags
, bufptr
,
966 prefmaxlen
, entriesread
, totalentries
);
968 status
= NETAPI_ValidateServername(servername
);
969 if (status
!= NERR_Success
)
973 NetApiBufferAllocate(size
* sizeof(WCHAR
), (LPVOID
*)¤tuser
);
974 GetUserNameW(currentuser
, &size
);
976 if (lstrcmpiW(username
, currentuser
) && NETAPI_FindUser(username
))
978 NetApiBufferFree(currentuser
);
979 return NERR_UserNotFound
;
982 NetApiBufferFree(currentuser
);
984 size
= sizeof(*info
) + sizeof(admins
);
986 if(prefmaxlen
< size
)
987 status
= ERROR_MORE_DATA
;
989 status
= NetApiBufferAllocate(size
, (LPVOID
*)&info
);
991 if(status
!= NERR_Success
)
998 info
->lgrui0_name
= (LPWSTR
)((LPBYTE
)info
+ sizeof(*info
));
999 lstrcpyW(info
->lgrui0_name
, admins
);
1001 *bufptr
= (LPBYTE
)info
;
1004 return NERR_Success
;
1008 /******************************************************************************
1009 * NetUserSetGroups (NETAPI32.@)
1013 NetUserSetGroups(LPCWSTR servername
,
1019 FIXME("(%s %s %lu %p %lu)\n",
1020 debugstr_w(servername
), debugstr_w(username
), level
, buf
, num_entries
);
1021 return ERROR_ACCESS_DENIED
;
1025 /******************************************************************************
1026 * NetUserSetInfo (NETAPI32.@)
1030 NetUserSetInfo(LPCWSTR servername
,
1036 FIXME("(%s %s %lu %p %p)\n",
1037 debugstr_w(servername
), debugstr_w(username
), level
, buf
, parm_err
);
1038 return ERROR_ACCESS_DENIED
;