[NETAPI32]

- Implement NetUserEnum partially.
- Move common code into a separate file.

svn path=/trunk/; revision=57980
This commit is contained in:
Eric Kohl 2012-12-23 18:56:13 +00:00
parent 730e837148
commit da05d9ace1
5 changed files with 614 additions and 101 deletions

View file

@ -11,6 +11,7 @@ list(APPEND SOURCE
ds.c
group.c
local_group.c
misc.c
nbcmdqueue.c
nbnamecache.c
nbt.c

View file

@ -56,99 +56,6 @@ typedef struct _ENUM_CONTEXT
} ENUM_CONTEXT, *PENUM_CONTEXT;
static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
static
NTSTATUS
GetAccountDomainSid(PSID *AccountDomainSid)
{
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle = NULL;
ULONG Length = 0;
NTSTATUS Status;
memset(&ObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES));
Status = LsaOpenPolicy(NULL,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle);
if (!NT_SUCCESS(Status))
{
ERR("LsaOpenPolicy failed (Status %08lx)\n", Status);
return Status;
}
Status = LsaQueryInformationPolicy(PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *)&AccountDomainInfo);
if (!NT_SUCCESS(Status))
{
ERR("LsaQueryInformationPolicy failed (Status %08lx)\n", Status);
goto done;
}
Length = RtlLengthSid(AccountDomainInfo->DomainSid);
*AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
if (*AccountDomainSid == NULL)
{
ERR("Failed to allocate SID\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
memcpy(*AccountDomainSid, AccountDomainInfo->DomainSid, Length);
done:
if (AccountDomainInfo != NULL)
LsaFreeMemory(AccountDomainInfo);
LsaClose(PolicyHandle);
return Status;
}
static
NTSTATUS
GetBuiltinDomainSid(PSID *BuiltinDomainSid)
{
PSID Sid = NULL;
PULONG Ptr;
NTSTATUS Status = STATUS_SUCCESS;
*BuiltinDomainSid = NULL;
Sid = RtlAllocateHeap(RtlGetProcessHeap(),
0,
RtlLengthRequiredSid(1));
if (Sid == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlInitializeSid(Sid,
&NtAuthority,
1);
if (!NT_SUCCESS(Status))
goto done;
Ptr = RtlSubAuthoritySid(Sid, 0);
*Ptr = SECURITY_BUILTIN_DOMAIN_RID;
*BuiltinDomainSid = Sid;
done:
if (!NT_SUCCESS(Status))
{
if (Sid != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, Sid);
}
return Status;
}
/************************************************************
* NetLocalGroupAdd (NETAPI32.@)

View file

@ -0,0 +1,127 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: NetAPI DLL
* FILE: reactos/dll/win32/netapi32/misc.c
* PURPOSE: Helper functions
*
* PROGRAMMERS: Eric Kohl
*/
/* INCLUDES ******************************************************************/
#include <stdarg.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "lmcons.h"
#include "ntsecapi.h"
#include "wine/debug.h"
#define NTOS_MODE_USER
#include <ndk/rtlfuncs.h>
#include "ntsam.h"
#include "netapi32.h"
WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
/* GLOBALS *******************************************************************/
static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
/* FUNCTIONS *****************************************************************/
NTSTATUS
GetAccountDomainSid(PSID *AccountDomainSid)
{
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle = NULL;
ULONG Length = 0;
NTSTATUS Status;
memset(&ObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES));
Status = LsaOpenPolicy(NULL,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle);
if (!NT_SUCCESS(Status))
{
ERR("LsaOpenPolicy failed (Status %08lx)\n", Status);
return Status;
}
Status = LsaQueryInformationPolicy(PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *)&AccountDomainInfo);
if (!NT_SUCCESS(Status))
{
ERR("LsaQueryInformationPolicy failed (Status %08lx)\n", Status);
goto done;
}
Length = RtlLengthSid(AccountDomainInfo->DomainSid);
*AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
if (*AccountDomainSid == NULL)
{
ERR("Failed to allocate SID\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
memcpy(*AccountDomainSid, AccountDomainInfo->DomainSid, Length);
done:
if (AccountDomainInfo != NULL)
LsaFreeMemory(AccountDomainInfo);
LsaClose(PolicyHandle);
return Status;
}
NTSTATUS
GetBuiltinDomainSid(PSID *BuiltinDomainSid)
{
PSID Sid = NULL;
PULONG Ptr;
NTSTATUS Status = STATUS_SUCCESS;
*BuiltinDomainSid = NULL;
Sid = RtlAllocateHeap(RtlGetProcessHeap(),
0,
RtlLengthRequiredSid(1));
if (Sid == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlInitializeSid(Sid,
&NtAuthority,
1);
if (!NT_SUCCESS(Status))
goto done;
Ptr = RtlSubAuthoritySid(Sid, 0);
*Ptr = SECURITY_BUILTIN_DOMAIN_RID;
*BuiltinDomainSid = Sid;
done:
if (!NT_SUCCESS(Status))
{
if (Sid != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, Sid);
}
return Status;
}
/* EOF */

View file

@ -6,5 +6,12 @@ NET_API_STATUS
WINAPI
NetpNtStatusToApiStatus(NTSTATUS Status);
/* misc.c */
NTSTATUS
GetAccountDomainSid(PSID *AccountDomainSid);
NTSTATUS
GetBuiltinDomainSid(PSID *BuiltinDomainSid);
#endif

View file

@ -35,8 +35,29 @@
#include "wine/unicode.h"
#include "wine/list.h"
#define NTOS_MODE_USER
#include <ndk/rtlfuncs.h>
#include "ntsam.h"
#include "netapi32.h"
WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
typedef struct _ENUM_CONTEXT
{
SAM_HANDLE ServerHandle;
SAM_HANDLE BuiltinDomainHandle;
SAM_HANDLE AccountDomainHandle;
SAM_ENUMERATE_HANDLE EnumerationContext;
PSAM_RID_ENUMERATION Buffer;
ULONG Returned;
ULONG Index;
BOOLEAN BuiltinDone;
} ENUM_CONTEXT, *PENUM_CONTEXT;
/* NOTE: So far, this is implemented to support tests that require user logins,
* but not designed to handle real user databases. Those should probably
* be synced with either the host's user database or with Samba.
@ -134,7 +155,7 @@ end:
}
/************************************************************
* NetUserAdd (NETAPI32.@)
* NetUserAdd (NETAPI32.@)
*/
NET_API_STATUS
WINAPI
@ -257,7 +278,7 @@ NetUserChangePassword(LPCWSTR domainname,
/************************************************************
* NetUserDel (NETAPI32.@)
* NetUserDel (NETAPI32.@)
*/
NET_API_STATUS
WINAPI
@ -287,7 +308,7 @@ NetUserDel(LPCWSTR servername,
/************************************************************
* NetUserEnum (NETAPI32.@)
* NetUserEnum (NETAPI32.@)
*/
NET_API_STATUS
WINAPI
@ -300,15 +321,466 @@ NetUserEnum(LPCWSTR servername,
LPDWORD totalentries,
LPDWORD resume_handle)
{
FIXME("(%s,%d, 0x%d,%p,%d,%p,%p,%p) stub!\n", debugstr_w(servername), level,
filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
PSAM_RID_ENUMERATION CurrentUser;
PENUM_CONTEXT EnumContext = NULL;
LPVOID Buffer = NULL;
PSID DomainSid = NULL;
PUSER_INFO_0 UserInfo0;
PUSER_INFO_1 UserInfo1;
PUSER_INFO_20 UserInfo20;
return ERROR_ACCESS_DENIED;
LPWSTR Ptr;
ULONG i;
ULONG Size;
SAM_HANDLE UserHandle = NULL;
PUSER_ACCOUNT_INFORMATION UserInfo = NULL;
NET_API_STATUS ApiStatus = NERR_Success;
NTSTATUS Status = STATUS_SUCCESS;
FIXME("(%s %d 0x%d %p %d %p %p %p) stub!\n", debugstr_w(servername), level,
filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
*entriesread = 0;
*totalentries = 0;
*bufptr = NULL;
if (resume_handle != NULL && *resume_handle != 0)
{
EnumContext = (PENUM_CONTEXT)*resume_handle;
}
else
{
ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
if (ApiStatus != NERR_Success)
goto done;
EnumContext->EnumerationContext = 0;
EnumContext->Buffer = NULL;
EnumContext->Returned = 0;
EnumContext->Index = 0;
EnumContext->BuiltinDone = FALSE;
Status = SamConnect(NULL,
&EnumContext->ServerHandle,
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("SamConnect failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
Status = GetAccountDomainSid(&DomainSid);
if (!NT_SUCCESS(Status))
{
ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
Status = SamOpenDomain(EnumContext->ServerHandle,
DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
DomainSid,
&EnumContext->AccountDomainHandle);
RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
if (!NT_SUCCESS(Status))
{
ERR("SamOpenDomain failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
Status = GetBuiltinDomainSid(&DomainSid);
if (!NT_SUCCESS(Status))
{
ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
Status = SamOpenDomain(EnumContext->ServerHandle,
DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
DomainSid,
&EnumContext->BuiltinDomainHandle);
RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
if (!NT_SUCCESS(Status))
{
ERR("SamOpenDomain failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
}
// while (TRUE)
// {
TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
if (EnumContext->Index >= EnumContext->Returned)
{
// if (EnumContext->BuiltinDone == TRUE)
// {
// ApiStatus = NERR_Success;
// goto done;
// }
TRACE("Calling SamEnumerateUsersInDomain\n");
Status = SamEnumerateUsersInDomain(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
&EnumContext->EnumerationContext,
0,
(PVOID *)&EnumContext->Buffer,
prefmaxlen,
&EnumContext->Returned);
TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status);
if (!NT_SUCCESS(Status))
{
ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
if (Status == STATUS_MORE_ENTRIES)
{
ApiStatus = NERR_BufTooSmall;
goto done;
}
else
{
EnumContext->BuiltinDone = TRUE;
}
}
TRACE("EnumContext: %lu\n", EnumContext);
TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
/* Get a pointer to the current user */
CurrentUser = &EnumContext->Buffer[EnumContext->Index];
TRACE("RID: %lu\n", CurrentUser->RelativeId);
Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle,
USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT,
CurrentUser->RelativeId,
&UserHandle);
if (!NT_SUCCESS(Status))
{
ERR("SamOpenUser failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
Status = SamQueryInformationUser(UserHandle,
UserAccountInformation,
(PVOID *)&UserInfo);
if (!NT_SUCCESS(Status))
{
ERR("SamQueryInformationUser failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
SamCloseHandle(UserHandle);
UserHandle = NULL;
switch (level)
{
case 0:
Size = sizeof(USER_INFO_0) +
UserInfo->UserName.Length + sizeof(WCHAR);
break;
case 1:
Size = sizeof(USER_INFO_1) +
UserInfo->UserName.Length + sizeof(WCHAR);
if (UserInfo->HomeDirectory.Length > 0)
Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR);
if (UserInfo->AdminComment.Length > 0)
Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
if (UserInfo->ScriptPath.Length > 0)
Size = UserInfo->ScriptPath.Length + sizeof(WCHAR);
break;
// case 2:
// case 3:
// case 10:
// case 11:
case 20:
Size = sizeof(USER_INFO_20) +
UserInfo->UserName.Length + sizeof(WCHAR);
if (UserInfo->FullName.Length > 0)
Size += UserInfo->FullName.Length + sizeof(WCHAR);
if (UserInfo->AdminComment.Length > 0)
Size += UserInfo->AdminComment.Length + sizeof(WCHAR);
break;
// case 23:
default:
ApiStatus = ERROR_INVALID_LEVEL;
goto done;
}
ApiStatus = NetApiBufferAllocate(Size, &Buffer);
if (ApiStatus != NERR_Success)
goto done;
switch (level)
{
case 0:
UserInfo0 = (PUSER_INFO_0)Buffer;
Ptr = (LPWSTR)((ULONG_PTR)UserInfo0 + sizeof(USER_INFO_0));
UserInfo0->usri0_name = Ptr;
memcpy(UserInfo0->usri0_name,
UserInfo->UserName.Buffer,
UserInfo->UserName.Length);
UserInfo0->usri0_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
break;
case 1:
UserInfo1 = (PUSER_INFO_1)Buffer;
Ptr = (LPWSTR)((ULONG_PTR)UserInfo1 + sizeof(USER_INFO_1));
UserInfo1->usri1_name = Ptr;
memcpy(UserInfo1->usri1_name,
UserInfo->UserName.Buffer,
UserInfo->UserName.Length);
UserInfo1->usri1_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
UserInfo1->usri1_password = NULL;
UserInfo1->usri1_password_age = 0; /* FIXME */
UserInfo1->usri1_priv = 0; /* FIXME */
if (UserInfo->HomeDirectory.Length > 0)
{
UserInfo1->usri1_home_dir = Ptr;
memcpy(UserInfo1->usri1_home_dir,
UserInfo->HomeDirectory.Buffer,
UserInfo->HomeDirectory.Length);
UserInfo1->usri1_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR));
}
if (UserInfo->AdminComment.Length > 0)
{
UserInfo1->usri1_comment = Ptr;
memcpy(UserInfo1->usri1_comment,
UserInfo->AdminComment.Buffer,
UserInfo->AdminComment.Length);
UserInfo1->usri1_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
}
UserInfo1->usri1_flags = UserInfo->UserAccountControl;
if (UserInfo->ScriptPath.Length > 0)
{
UserInfo1->usri1_script_path = Ptr;
memcpy(UserInfo1->usri1_script_path,
UserInfo->ScriptPath.Buffer,
UserInfo->ScriptPath.Length);
UserInfo1->usri1_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
}
break;
// case 2:
// case 3:
// case 10:
// case 11:
case 20:
UserInfo20 = (PUSER_INFO_20)Buffer;
Ptr = (LPWSTR)((ULONG_PTR)UserInfo20 + sizeof(USER_INFO_20));
UserInfo20->usri20_name = Ptr;
memcpy(UserInfo20->usri20_name,
UserInfo->UserName.Buffer,
UserInfo->UserName.Length);
UserInfo20->usri20_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR));
if (UserInfo->FullName.Length > 0)
{
UserInfo20->usri20_full_name = Ptr;
memcpy(UserInfo20->usri20_full_name,
UserInfo->FullName.Buffer,
UserInfo->FullName.Length);
UserInfo20->usri20_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR));
}
if (UserInfo->AdminComment.Length > 0)
{
UserInfo20->usri20_comment = Ptr;
memcpy(UserInfo20->usri20_comment,
UserInfo->AdminComment.Buffer,
UserInfo->AdminComment.Length);
UserInfo20->usri20_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR));
}
UserInfo20->usri20_flags = UserInfo->UserAccountControl;
UserInfo20->usri20_user_id = CurrentUser->RelativeId;
break;
// case 23:
}
if (UserInfo != NULL)
{
if (UserInfo->UserName.Buffer != NULL)
SamFreeMemory(UserInfo->UserName.Buffer);
if (UserInfo->FullName.Buffer != NULL)
SamFreeMemory(UserInfo->FullName.Buffer);
if (UserInfo->HomeDirectory.Buffer != NULL)
SamFreeMemory(UserInfo->HomeDirectory.Buffer);
if (UserInfo->HomeDirectoryDrive.Buffer != NULL)
SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer);
if (UserInfo->ScriptPath.Buffer != NULL)
SamFreeMemory(UserInfo->ScriptPath.Buffer);
if (UserInfo->ProfilePath.Buffer != NULL)
SamFreeMemory(UserInfo->ProfilePath.Buffer);
if (UserInfo->AdminComment.Buffer != NULL)
SamFreeMemory(UserInfo->AdminComment.Buffer);
if (UserInfo->WorkStations.Buffer != NULL)
SamFreeMemory(UserInfo->WorkStations.Buffer);
if (UserInfo->LogonHours.LogonHours != NULL)
SamFreeMemory(UserInfo->LogonHours.LogonHours);
SamFreeMemory(UserInfo);
UserInfo = NULL;
}
EnumContext->Index++;
(*entriesread)++;
// }
done:
if (ApiStatus == NERR_Success && EnumContext->Index < EnumContext->Returned)
ApiStatus = ERROR_MORE_DATA;
if (EnumContext != NULL)
*totalentries = EnumContext->Returned;
if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
{
if (EnumContext != NULL)
{
if (EnumContext->BuiltinDomainHandle != NULL)
SamCloseHandle(EnumContext->BuiltinDomainHandle);
if (EnumContext->AccountDomainHandle != NULL)
SamCloseHandle(EnumContext->AccountDomainHandle);
if (EnumContext->ServerHandle != NULL)
SamCloseHandle(EnumContext->ServerHandle);
if (EnumContext->Buffer != NULL)
{
for (i = 0; i < EnumContext->Returned; i++)
{
SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
}
SamFreeMemory(EnumContext->Buffer);
}
NetApiBufferFree(EnumContext);
EnumContext = NULL;
}
}
if (UserHandle != NULL)
SamCloseHandle(UserHandle);
if (UserInfo != NULL)
{
if (UserInfo->UserName.Buffer != NULL)
SamFreeMemory(UserInfo->UserName.Buffer);
if (UserInfo->FullName.Buffer != NULL)
SamFreeMemory(UserInfo->FullName.Buffer);
if (UserInfo->HomeDirectory.Buffer != NULL)
SamFreeMemory(UserInfo->HomeDirectory.Buffer);
if (UserInfo->HomeDirectoryDrive.Buffer != NULL)
SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer);
if (UserInfo->ScriptPath.Buffer != NULL)
SamFreeMemory(UserInfo->ScriptPath.Buffer);
if (UserInfo->ProfilePath.Buffer != NULL)
SamFreeMemory(UserInfo->ProfilePath.Buffer);
if (UserInfo->AdminComment.Buffer != NULL)
SamFreeMemory(UserInfo->AdminComment.Buffer);
if (UserInfo->WorkStations.Buffer != NULL)
SamFreeMemory(UserInfo->WorkStations.Buffer);
if (UserInfo->LogonHours.LogonHours != NULL)
SamFreeMemory(UserInfo->LogonHours.LogonHours);
SamFreeMemory(UserInfo);
}
if (resume_handle != NULL)
*resume_handle = (DWORD_PTR)EnumContext;
*bufptr = (LPBYTE)Buffer;
TRACE("return %lu\n", ApiStatus);
return ApiStatus;
}
/************************************************************
* NetUserGetGroups (NETAPI32.@)
* NetUserGetGroups (NETAPI32.@)
*/
NET_API_STATUS
WINAPI
@ -592,7 +1064,6 @@ NetUserSetGroups(LPCWSTR servername,
}
/******************************************************************************
* NetUserSetInfo (NETAPI32.@)
*/