mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3234 lines
89 KiB
3234 lines
89 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ApiUser.c
|
|
|
|
Abstract:
|
|
|
|
This module contains individual API handlers for the NetUser APIs.
|
|
|
|
SUPPORTED : NetUserAdd2, NetUserDel, NetUserEnum, NetUserEnum2,
|
|
NetUserGetGroups, NetUserGetInfo, NetUserModalsGet,
|
|
NetUserModalsSet, NetUserSetGroups, NetUserSetInfo2,
|
|
NetUserSetInfo, NetUserPasswordSet2
|
|
|
|
UNSUPPORTED : NetUserValidate2.
|
|
|
|
Author:
|
|
|
|
Shanku Niyogi (w-shanku) 11-Feb-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// NetUser APIs are UNICODE only.
|
|
//
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
|
|
#include "xactsrvp.h"
|
|
#include <crypt.h>
|
|
#include "changepw.h"
|
|
#include <loghours.h>
|
|
#include <netlibnt.h>
|
|
#include <names.h>
|
|
#include <prefix.h> // PREFIX_ equates.
|
|
|
|
//
|
|
// Declaration of descriptor strings.
|
|
//
|
|
|
|
STATIC const LPDESC Desc16_user_info_0 = REM16_user_info_0;
|
|
STATIC const LPDESC Desc32_user_info_0 = REM32_user_info_0;
|
|
|
|
STATIC const LPDESC Desc16_user_info_1 = REM16_user_info_1;
|
|
STATIC const LPDESC Desc32_user_info_1 = REM32_user_info_1;
|
|
STATIC const LPDESC Desc32_user_info_1_NC = REM32_user_info_1_NOCRYPT;
|
|
STATIC const LPDESC Desc32_user_info_1_OWF = REM32_user_info_1_OWF;
|
|
STATIC const LPDESC Desc16_user_info_1_setinfo = REM16_user_info_1_setinfo;
|
|
STATIC const LPDESC Desc32_user_info_1_setinfo = REM32_user_info_1_setinfo;
|
|
STATIC const LPDESC Desc32_user_info_1_setinfo_NC = REM32_user_info_1_setinfo_NOCRYPT;
|
|
|
|
STATIC const LPDESC Desc16_user_info_2 = REM16_user_info_2;
|
|
STATIC const LPDESC Desc32_user_info_2 = REM32_user_info_2;
|
|
STATIC const LPDESC Desc32_user_info_2_NC = REM32_user_info_2_NOCRYPT;
|
|
STATIC const LPDESC Desc16_user_info_2_setinfo = REM16_user_info_2_setinfo;
|
|
STATIC const LPDESC Desc32_user_info_2_setinfo = REM32_user_info_2_setinfo;
|
|
STATIC const LPDESC Desc32_user_info_2_setinfo_NC = REM32_user_info_2_setinfo_NOCRYPT;
|
|
|
|
STATIC const LPDESC Desc16_user_info_10 = REM16_user_info_10;
|
|
STATIC const LPDESC Desc32_user_info_10 = REM32_user_info_10;
|
|
STATIC const LPDESC Desc16_user_info_11 = REM16_user_info_11;
|
|
STATIC const LPDESC Desc32_user_info_11 = REM32_user_info_11;
|
|
STATIC const LPDESC Desc32_user_info_22 = REM32_user_info_22;
|
|
|
|
STATIC const LPDESC Desc16_user_group_info_0 = REM16_group_info_0;
|
|
STATIC const LPDESC Desc32_user_group_info_0 = REM32_group_info_0;
|
|
STATIC const LPDESC Desc16_user_group_info_0_set
|
|
= REM16_group_users_info_0_set;
|
|
STATIC const LPDESC Desc32_user_group_info_0_set
|
|
= REM32_group_users_info_0_set;
|
|
|
|
STATIC const LPDESC Desc16_user_modals_info_0 = REM16_user_modals_info_0;
|
|
STATIC const LPDESC Desc32_user_modals_info_0 = REM32_user_modals_info_0;
|
|
STATIC const LPDESC Desc16_user_modals_info_0_setinfo
|
|
= REM16_user_modals_info_0_setinfo;
|
|
STATIC const LPDESC Desc32_user_modals_info_0_setinfo
|
|
= REM32_user_modals_info_0_setinfo;
|
|
STATIC const LPDESC Desc16_user_modals_info_1 = REM16_user_modals_info_1;
|
|
STATIC const LPDESC Desc32_user_modals_info_1 = REM32_user_modals_info_1;
|
|
STATIC const LPDESC Desc16_user_modals_info_1_setinfo
|
|
= REM16_user_modals_info_1_setinfo;
|
|
STATIC const LPDESC Desc32_user_modals_info_1_setinfo
|
|
= REM32_user_modals_info_1_setinfo;
|
|
|
|
|
|
STATIC NET_API_STATUS
|
|
XsGetMinPasswordLength(
|
|
LPDWORD minPasswordLength
|
|
)
|
|
{
|
|
NET_API_STATUS apiStatus;
|
|
LPUSER_MODALS_INFO_0 modals = NULL;
|
|
HANDLE OpenedToken;
|
|
|
|
NetpAssert( minPasswordLength != NULL );
|
|
|
|
//
|
|
// Revert to Local System
|
|
//
|
|
(VOID)NtOpenThreadToken(
|
|
NtCurrentThread(),
|
|
MAXIMUM_ALLOWED,
|
|
TRUE,
|
|
&OpenedToken
|
|
);
|
|
|
|
RevertToSelf();
|
|
|
|
//
|
|
// Find out how long the password has to be.
|
|
//
|
|
|
|
apiStatus = NetUserModalsGet(
|
|
NULL, // local (no server name)
|
|
0, // level
|
|
(LPBYTE *)&modals ); // alloc and set ptr
|
|
|
|
//
|
|
// Re-impersonate the client
|
|
//
|
|
(VOID)NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&OpenedToken,
|
|
sizeof( OpenedToken )
|
|
);
|
|
|
|
if ( apiStatus != NO_ERROR ) {
|
|
NetpKdPrint(( PREFIX_XACTSRV
|
|
"XsGetMinPasswordLength: Problems getting modals: "
|
|
FORMAT_API_STATUS ".\n", apiStatus ));
|
|
return (apiStatus);
|
|
}
|
|
NetpAssert( modals != NULL );
|
|
|
|
*minPasswordLength = modals->usrmod0_min_passwd_len;
|
|
(VOID) NetApiBufferFree( (LPVOID)modals );
|
|
return (NO_ERROR);
|
|
|
|
} // XsGetMinPasswordLength
|
|
|
|
|
|
STATIC NET_API_STATUS
|
|
XsCheckAndReplacePassword (
|
|
IN DWORD Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This routine checks the current password's real length to make sure
|
|
it is valid, and then generates a reasonably random replacement password
|
|
long enough to satisfy the system's modal for minimum password length.
|
|
This routine is used by Add and SetInfo handlers below.
|
|
|
|
Arguments:
|
|
|
|
Length - Real length of the current password.
|
|
|
|
Seed - A seed number.
|
|
|
|
TempPassword - Receives a pointer to a new temporary password. If
|
|
this is not specified, the new password is not generated.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success on successful completion, or some other
|
|
error status.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
DWORD minPasswordLength;
|
|
|
|
//
|
|
// Find out how long the password has to be.
|
|
//
|
|
|
|
status = XsGetMinPasswordLength( &minPasswordLength );
|
|
|
|
|
|
if ( status != NERR_Success ) {
|
|
NetpKdPrint(( PREFIX_XACTSRV
|
|
"XsCheckAndReplacePassword: Problems getting min PW len: "
|
|
FORMAT_API_STATUS ".\n", status ));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Check length of current password.
|
|
//
|
|
|
|
if ( Length < minPasswordLength ) {
|
|
|
|
return NERR_PasswordTooShort;
|
|
}
|
|
|
|
|
|
return NERR_Success;
|
|
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
XsNameToRid(
|
|
IN LPCTSTR Name, // may be user or group name.
|
|
IN SID_NAME_USE ExpectedType,
|
|
OUT PULONG UserRid
|
|
)
|
|
{
|
|
NET_API_STATUS status;
|
|
PSID_NAME_USE nameUse;
|
|
NTSTATUS ntstatus;
|
|
UNICODE_STRING unicodeName;
|
|
PULONG tempRid;
|
|
PSID accountsDomainId;
|
|
SAM_HANDLE samConnectHandle;
|
|
SAM_HANDLE samAccountsDomainHandle;
|
|
|
|
if( ARGUMENT_PRESENT( UserRid ) ) {
|
|
*UserRid = 0;
|
|
}
|
|
|
|
//
|
|
// Get a connection to SAM.
|
|
//
|
|
|
|
ntstatus = SamConnect(
|
|
NULL, // no server name (local)
|
|
&samConnectHandle, // resulting SAM handle
|
|
SAM_SERVER_LOOKUP_DOMAIN, // desired access
|
|
NULL // no object attributes
|
|
);
|
|
if ( !NT_SUCCESS( ntstatus ) ) {
|
|
status = NetpNtStatusToApiStatus( ntstatus );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// To open the accounts domain, we'll need the domain ID.
|
|
//
|
|
|
|
status = NetpGetLocalDomainId (
|
|
LOCAL_DOMAIN_TYPE_ACCOUNTS, // type we want.
|
|
&accountsDomainId
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
SamCloseHandle( samConnectHandle );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Open the accounts domain.
|
|
//
|
|
|
|
ntstatus = SamOpenDomain(
|
|
samConnectHandle,
|
|
DOMAIN_LOOKUP,
|
|
accountsDomainId,
|
|
&samAccountsDomainHandle
|
|
);
|
|
if ( !NT_SUCCESS( ntstatus ) ) {
|
|
LocalFree( accountsDomainId );
|
|
SamCloseHandle( samConnectHandle );
|
|
status = NetpNtStatusToApiStatus( ntstatus );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get a RID for this user name.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&unicodeName, // dest (NT struct)
|
|
Name ); // src (null-terminated)
|
|
|
|
ntstatus = SamLookupNamesInDomain(
|
|
samAccountsDomainHandle, // users live in accounts domain
|
|
(ULONG)1, // only want one name.
|
|
&unicodeName, // name (in NT struct)
|
|
&tempRid, // alloc and set RIDs.
|
|
&nameUse // alloc and set name types.
|
|
);
|
|
|
|
if ( !NT_SUCCESS( ntstatus ) ) {
|
|
status = NetpNtStatusToApiStatus( ntstatus );
|
|
goto cleanup;
|
|
}
|
|
|
|
*UserRid = *tempRid;
|
|
|
|
//
|
|
// Did type user wanted match the actual one?
|
|
//
|
|
|
|
if ( ExpectedType != *nameUse ) {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Free memory which SAM allocated for us.
|
|
//
|
|
|
|
ntstatus = SamFreeMemory( nameUse );
|
|
if ( !NT_SUCCESS( ntstatus ) ) {
|
|
status = NetpNtStatusToApiStatus( ntstatus );
|
|
}
|
|
|
|
ntstatus = SamFreeMemory( tempRid );
|
|
if ( !NT_SUCCESS( ntstatus ) ) {
|
|
status = NetpNtStatusToApiStatus( ntstatus );
|
|
}
|
|
|
|
cleanup:
|
|
|
|
LocalFree( accountsDomainId );
|
|
SamCloseHandle( samAccountsDomainHandle );
|
|
SamCloseHandle( samConnectHandle );
|
|
|
|
return status;
|
|
|
|
} // XsNameToRid
|
|
|
|
|
|
NET_API_STATUS
|
|
XsSetMacPrimaryGroup(
|
|
IN LPCTSTR UserName,
|
|
IN LPCTSTR MacPrimaryField // field in "mGroup:junk" format.
|
|
)
|
|
{
|
|
NET_API_STATUS status;
|
|
LPTSTR groupName = NULL;
|
|
ULONG groupRid;
|
|
USER_INFO_1051 userInfo;
|
|
|
|
//
|
|
// Extract the primary group name from the Mac field.
|
|
//
|
|
|
|
status = NetpGetPrimaryGroupFromMacField(
|
|
MacPrimaryField, // name in "mGroup:" format.
|
|
&groupName // alloc and set ptr.
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Make sure this user is a member of the group (add to group if needed).
|
|
// This will also check if the group and user exist.
|
|
//
|
|
|
|
status = NetGroupAddUser(
|
|
NULL, // local (no server name)
|
|
groupName, // group to update
|
|
(LPTSTR)UserName // user name to add to group
|
|
);
|
|
if ( (status != NO_ERROR) && (status != NERR_UserInGroup) ) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Convert the group name to a RID.
|
|
//
|
|
|
|
status = XsNameToRid(
|
|
(LPCWSTR)groupName,
|
|
SidTypeGroup, // expected type
|
|
&groupRid
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Call NetUserSetInfo to set the primary group ID using the RID.
|
|
//
|
|
|
|
userInfo.usri1051_primary_group_id = (DWORD)groupRid;
|
|
|
|
status = NetUserSetInfo (
|
|
NULL, // local (no server name)
|
|
(LPTSTR)UserName,
|
|
PARMNUM_BASE_INFOLEVEL + USER_PRIMARY_GROUP_PARMNUM,
|
|
(LPVOID)&userInfo,
|
|
NULL // don't care about parmnum
|
|
);
|
|
|
|
cleanup:
|
|
|
|
if ( groupName != NULL ) {
|
|
NetpMemoryFree( groupName );
|
|
}
|
|
|
|
return status;
|
|
|
|
} // XsSetMacPrimaryGroup
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserAdd2 (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserAdd. A remote NetUserAdd call
|
|
from a 16-bit machine will translate to a NetUserAdd2 call, with
|
|
a doubly encrypted password. We will call a special level of
|
|
NetUserSetInfo to set this later, after the user has been added.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_ADD_2 parameters = Parameters;
|
|
LPVOID buffer = NULL; // Native parameters
|
|
LPBYTE stringLocation = NULL; // Conversion variables
|
|
DWORD bytesRequired = 0;
|
|
DWORD bufferSize;
|
|
LPBYTE nativeStructureDesc;
|
|
LPUSER_INFO_1 user = NULL;
|
|
DWORD parmError;
|
|
DWORD level;
|
|
BOOLEAN encryptionSupported = TRUE;
|
|
PUSER_INFO_22 usri22;
|
|
BYTE tempPwdBuffer[ENCRYPTED_PWLEN];
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserAdd2: header at %lx, params at %lx, "
|
|
"level %ld\n",
|
|
Header, parameters,
|
|
SmbGetUshort( ¶meters->Level ) ));
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Check if password is encrypted. We know for a fact that dos redirs
|
|
// don't support encryption
|
|
//
|
|
|
|
encryptionSupported = (BOOLEAN)
|
|
( SmbGetUshort( ¶meters->DataEncryption ) == TRUE );
|
|
level = SmbGetUshort( ¶meters->Level );
|
|
|
|
//
|
|
// Check for password length
|
|
//
|
|
|
|
status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( ¶meters->PasswordLength )) );
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd2: XsCheckAndReplacePassword failed: "
|
|
"%X\n", status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Use the requested level to determine the format of the 32-bit
|
|
// we need to pass to NetUserAdd. The format of the
|
|
// 16-bit structure is stored in the transaction block, and we
|
|
// got a pointer to it as a parameter.
|
|
//
|
|
|
|
switch ( level ) {
|
|
|
|
case 1:
|
|
StructureDesc = Desc16_user_info_1;
|
|
nativeStructureDesc = Desc32_user_info_1_OWF;
|
|
break;
|
|
|
|
case 2:
|
|
StructureDesc = Desc16_user_info_2;
|
|
nativeStructureDesc = Desc32_user_info_22;
|
|
break;
|
|
|
|
default:
|
|
status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Figure out if there is enough room in the buffer for all the
|
|
// data required. If not, return NERR_BufTooSmall.
|
|
//
|
|
|
|
if ( !XsCheckBufferSize(
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
FALSE // not in native format
|
|
)) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd2: Buffer too small.\n" ));
|
|
}
|
|
status = NERR_BufTooSmall;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Find out how big a buffer we need to allocate to hold the native
|
|
// 32-bit version of the input data structure. Always allocate
|
|
// a level 22 buffer since we will always be making a level 22
|
|
// call to netuseradd.
|
|
//
|
|
|
|
bufferSize = XsBytesForConvertedStructure(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
StructureDesc,
|
|
Desc32_user_info_22,
|
|
RapToNative,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// Allocate enough memory to hold the converted native buffer.
|
|
//
|
|
|
|
buffer = NetpMemoryAllocate( bufferSize );
|
|
|
|
if ( buffer == NULL ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd2: failed to create buffer" ));
|
|
}
|
|
status = NERR_NoRoom;
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserAdd2: buffer of %ld bytes at %lx\n",
|
|
bufferSize, buffer ));
|
|
}
|
|
|
|
//
|
|
// Convert the buffer from 16-bit to 32-bit.
|
|
//
|
|
|
|
stringLocation = (LPBYTE)buffer + bufferSize;
|
|
bytesRequired = 0;
|
|
|
|
status = RapConvertSingleEntry(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
StructureDesc,
|
|
TRUE,
|
|
buffer,
|
|
buffer,
|
|
nativeStructureDesc,
|
|
FALSE,
|
|
&stringLocation,
|
|
&bytesRequired,
|
|
Response,
|
|
RapToNative
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd: RapConvertSingleEntry failed: "
|
|
"%X\n", status ));
|
|
}
|
|
|
|
status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
|
|
usri22 = buffer;
|
|
|
|
//
|
|
// If this is a level 1 call, then we did not fill up all the
|
|
// entries required for a level 22 call. Put the default values
|
|
// here.
|
|
//
|
|
|
|
if ( level == 1 ) {
|
|
|
|
//
|
|
// These are not used in a NetUserAdd.
|
|
//
|
|
// usri22->usri22_last_logon
|
|
// usri22->usri22_last_logoff
|
|
// usri22->usri22_units_per_week
|
|
// usri22->usri22_bad_pw_count
|
|
// usri22->usri22_num_logons
|
|
//
|
|
|
|
usri22->usri22_auth_flags = 0;
|
|
usri22->usri22_full_name = NULL;
|
|
usri22->usri22_usr_comment = NULL;
|
|
usri22->usri22_parms = NULL;
|
|
usri22->usri22_workstations = NULL;
|
|
usri22->usri22_acct_expires = TIMEQ_FOREVER;
|
|
usri22->usri22_max_storage = USER_MAXSTORAGE_UNLIMITED;
|
|
usri22->usri22_logon_hours = NULL;
|
|
usri22->usri22_logon_server = NULL;
|
|
usri22->usri22_country_code = 0;
|
|
usri22->usri22_code_page = 0;
|
|
|
|
} else if ( usri22->usri22_logon_hours != NULL ) {
|
|
|
|
//
|
|
// Call NetpRotateLogonHours to make sure we behave properly
|
|
// during DST.
|
|
//
|
|
|
|
if ( !NetpRotateLogonHours(
|
|
usri22->usri22_logon_hours,
|
|
usri22->usri22_units_per_week,
|
|
TRUE
|
|
) ) {
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the password is clear text, we need to convert it to an OWF
|
|
// password. This is to fix a LMUNIX bug which forgets to upper
|
|
// case the password it sends across. Converting it to OWF
|
|
// tells sam not to do upcasing.
|
|
//
|
|
// If the password is encrypted, then we get the owf by decrypting
|
|
// it with the session key.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
tempPwdBuffer,
|
|
usri22->usri22_password,
|
|
ENCRYPTED_PWLEN
|
|
);
|
|
|
|
if ( !encryptionSupported ) {
|
|
|
|
(VOID) RtlCalculateLmOwfPassword(
|
|
(PLM_PASSWORD) tempPwdBuffer,
|
|
(PLM_OWF_PASSWORD) usri22->usri22_password
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
(VOID) RtlDecryptLmOwfPwdWithLmSesKey(
|
|
(PENCRYPTED_LM_OWF_PASSWORD) tempPwdBuffer,
|
|
(PLM_SESSION_KEY) Header->EncryptionKey,
|
|
(PLM_OWF_PASSWORD) usri22->usri22_password
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserAdd(
|
|
NULL,
|
|
22,
|
|
(LPBYTE) usri22,
|
|
&parmError
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd2: NetUserAdd failed: %X\n", status ));
|
|
if ( status == ERROR_INVALID_PARAMETER ) {
|
|
NetpKdPrint(( "XsNetUserAdd2: ParmError: %ld\n",
|
|
parmError ));
|
|
|
|
}
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// If there was a Macintosh primary group field for this user, then
|
|
// set the primary group.
|
|
//
|
|
|
|
if ( NetpIsMacPrimaryGroupFieldValid( (LPCTSTR)usri22->usri22_parms ) ) {
|
|
NET_API_STATUS status1;
|
|
status1 = XsSetMacPrimaryGroup(
|
|
(LPCTSTR)usri22->usri22_name,
|
|
(LPCTSTR)usri22->usri22_parms
|
|
);
|
|
if ( !XsApiSuccess( status1 )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserAdd2: SetMacPrimaryGroup failed: %X\n",
|
|
status1 ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// There is no real return information for this API.
|
|
//
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
Header->Status = (WORD)status;
|
|
|
|
NetpMemoryFree( buffer );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserAdd2
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserDel (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserDel.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_DEL parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserDel: header at %lx, params at %lx, name %s\n",
|
|
Header, parameters, SmbGetUlong( ¶meters->UserName )));
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Translate parameters, check for errors.
|
|
//
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserDel(
|
|
NULL,
|
|
nativeUserName
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserDel: NetUserDel failed: %X\n", status ));
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetpMemoryFree( nativeUserName );
|
|
|
|
//
|
|
// Nothing to return.
|
|
//
|
|
|
|
Header->Status = (WORD)status;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserEnum (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This routine handles a call to NetUserEnum.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_ENUM parameters = Parameters;
|
|
LPVOID outBuffer = NULL; // Native parameters
|
|
DWORD entriesRead;
|
|
DWORD totalEntries;
|
|
|
|
DWORD entriesFilled = 0; // Conversion variables
|
|
DWORD bytesRequired = 0;
|
|
LPBYTE nativeStructureDesc;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid parameters
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum: header at %lx, params at %lx, "
|
|
"level %ld, buf size %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ),
|
|
SmbGetUshort( ¶meters->BufLen )));
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Check for errors.
|
|
//
|
|
|
|
if (( XsWordParamOutOfRange( parameters->Level, 0, 2 ))
|
|
&& SmbGetUshort( ¶meters->Level ) != 10 ) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserEnum(
|
|
NULL,
|
|
(DWORD)SmbGetUshort( ¶meters->Level ),
|
|
FILTER_NORMAL_ACCOUNT,
|
|
(LPBYTE *)&outBuffer,
|
|
XsNativeBufferSize( SmbGetUshort( ¶meters->BufLen )),
|
|
&entriesRead,
|
|
&totalEntries,
|
|
NULL
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserEnum: NetUserEnum failed: %X\n", status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum: received %ld entries at %lx\n",
|
|
entriesRead, outBuffer ));
|
|
}
|
|
|
|
//
|
|
// Use the requested level to determine the format of the
|
|
// data structure.
|
|
//
|
|
|
|
switch ( SmbGetUshort( ¶meters->Level ) ) {
|
|
|
|
case 0:
|
|
|
|
nativeStructureDesc = Desc32_user_info_0;
|
|
StructureDesc = Desc16_user_info_0;
|
|
break;
|
|
|
|
case 1:
|
|
|
|
nativeStructureDesc = Desc32_user_info_1;
|
|
StructureDesc = Desc16_user_info_1;
|
|
break;
|
|
|
|
case 2:
|
|
|
|
nativeStructureDesc = Desc32_user_info_2;
|
|
StructureDesc = Desc16_user_info_2;
|
|
break;
|
|
|
|
case 10:
|
|
|
|
nativeStructureDesc = Desc32_user_info_10;
|
|
StructureDesc = Desc16_user_info_10;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do the actual conversion from the 32-bit structures to 16-bit
|
|
// structures.
|
|
//
|
|
|
|
XsFillEnumBuffer(
|
|
outBuffer,
|
|
entriesRead,
|
|
nativeStructureDesc,
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
NULL, // verify function
|
|
&bytesRequired,
|
|
&entriesFilled,
|
|
NULL
|
|
);
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR,"
|
|
" Entries %ld of %ld\n",
|
|
outBuffer, SmbGetUlong( ¶meters->Buffer ),
|
|
bytesRequired, entriesFilled, totalEntries ));
|
|
}
|
|
|
|
//
|
|
// If all the entries could not be filled, return ERROR_MORE_DATA,
|
|
// and return the buffer as is. Otherwise, the data needs to be
|
|
// packed so that we don't send too much useless data.
|
|
//
|
|
|
|
if ( entriesFilled < totalEntries ) {
|
|
|
|
Header->Status = ERROR_MORE_DATA;
|
|
|
|
} else {
|
|
|
|
Header->Converter = XsPackReturnData(
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
entriesFilled
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Set up the response parameters.
|
|
//
|
|
|
|
SmbPutUshort( ¶meters->EntriesRead, (WORD)entriesFilled );
|
|
SmbPutUshort( ¶meters->TotalAvail, (WORD)totalEntries );
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
|
|
//
|
|
// Determine return buffer size.
|
|
//
|
|
|
|
XsSetDataCount(
|
|
¶meters->BufLen,
|
|
StructureDesc,
|
|
Header->Converter,
|
|
entriesFilled,
|
|
Header->Status
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserEnum
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserEnum2 (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserEnum. This version supports a
|
|
resumable handle.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_ENUM_2 parameters = Parameters;
|
|
LPVOID outBuffer = NULL; // Native parameters
|
|
DWORD TotalEntriesToReturn = 0;
|
|
LPDESC nativeStructureDesc;
|
|
DWORD nativeBufferSize = 0xFFFFFFFF;
|
|
|
|
DWORD entriesRead = 0;
|
|
DWORD PreviousEntriesRead;
|
|
DWORD totalEntries;
|
|
DWORD entriesFilled = 0; // Conversion variables
|
|
DWORD bytesRequired;
|
|
|
|
LPBYTE bufferBegin;
|
|
DWORD bufferSize;
|
|
DWORD totalEntriesRead= 0;
|
|
DWORD resumeKey;
|
|
|
|
LPBYTE SavedBufferBegin;
|
|
DWORD SavedBufferSize;
|
|
DWORD SavedTotalEntriesRead;
|
|
DWORD SavedResumeKey;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: header at %lx, params at %lx, "
|
|
"level %ld, buf size %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ),
|
|
SmbGetUshort( ¶meters->BufLen )));
|
|
}
|
|
|
|
//
|
|
// Copy input resume handle to output resume handle, and get a copy of it.
|
|
//
|
|
|
|
resumeKey = SmbGetUlong( ¶meters->ResumeIn );
|
|
SmbPutUlong( ¶meters->ResumeOut, resumeKey );
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: resume key is %ld\n", resumeKey ));
|
|
}
|
|
|
|
//
|
|
// Use the level to determine the descriptor string.
|
|
//
|
|
|
|
switch ( SmbGetUshort( ¶meters->Level ) ) {
|
|
|
|
case 0:
|
|
|
|
nativeStructureDesc = Desc32_user_info_0;
|
|
StructureDesc = Desc16_user_info_0;
|
|
break;
|
|
|
|
case 1:
|
|
|
|
nativeStructureDesc = Desc32_user_info_1;
|
|
StructureDesc = Desc16_user_info_1;
|
|
break;
|
|
|
|
case 2:
|
|
|
|
nativeStructureDesc = Desc32_user_info_2;
|
|
StructureDesc = Desc16_user_info_2;
|
|
break;
|
|
|
|
case 10:
|
|
|
|
nativeStructureDesc = Desc32_user_info_10;
|
|
StructureDesc = Desc16_user_info_10;
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Unsupported levels, abort before any work.
|
|
//
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// NetUserEnum2 is a resumable API, so we cannot get more information
|
|
// from the native call than we can send back. The most efficient way
|
|
// to do this is in a loop...we use the 16-bit buffer size to determine
|
|
// a safe native buffer size, make the call, fill the entries, then
|
|
// take the amount of space remaining and determine a safe size again,
|
|
// and so on, until NetUserEnum returns either no entries or all entries
|
|
// read.
|
|
//
|
|
|
|
//
|
|
// Initialize important variables for loop.
|
|
//
|
|
|
|
bufferBegin = (LPBYTE)XsSmbGetPointer( ¶meters->Buffer );
|
|
bufferSize = (DWORD)SmbGetUshort( ¶meters->BufLen );
|
|
totalEntriesRead = 0;
|
|
|
|
for ( ; ; ) {
|
|
|
|
|
|
//
|
|
// Compute a safe size for the native buffer.
|
|
//
|
|
// It is better to underguess than overguess. NetUserEnum is relatively
|
|
// efficient (especially in the local case) at resuming an enumeration.
|
|
// It is relatively inefficient at returning detailed information about
|
|
// the enumerated users.
|
|
//
|
|
// If nativeBufferSize reaches 1 (or 0),
|
|
// NetUserEnum will typically enumerate a single user.
|
|
//
|
|
|
|
if ( nativeBufferSize > bufferSize/2 ) {
|
|
nativeBufferSize = bufferSize/2;
|
|
}
|
|
|
|
//
|
|
// Remember how many we read last time to ensure we make progress.
|
|
//
|
|
|
|
PreviousEntriesRead = entriesRead;
|
|
|
|
//
|
|
// Save away a copy of all the important variables.
|
|
//
|
|
// The NetUserEnum API can actually overshoot its PrefMaxLen. The
|
|
// values being saved are values known to not already have been overshot.
|
|
// We can restore these values later if needed.
|
|
//
|
|
|
|
SavedBufferBegin = bufferBegin;
|
|
SavedBufferSize = bufferSize;
|
|
SavedTotalEntriesRead = totalEntriesRead;
|
|
SavedResumeKey = resumeKey;
|
|
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserEnum(
|
|
NULL,
|
|
(DWORD)SmbGetUshort( ¶meters->Level ),
|
|
FILTER_NORMAL_ACCOUNT,
|
|
(LPBYTE *)&outBuffer,
|
|
nativeBufferSize,
|
|
&entriesRead,
|
|
&totalEntries,
|
|
&resumeKey
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserEnum2: NetUserEnum failed: %X\n",
|
|
status ));
|
|
}
|
|
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: received %ld entries out of %ld at %lx asking for %ld bytes.\n",
|
|
entriesRead, totalEntries, outBuffer, nativeBufferSize ));
|
|
|
|
NetpKdPrint(( "XsNetUserEnum2: resume key is now %ld\n",
|
|
resumeKey ));
|
|
}
|
|
|
|
//
|
|
// Keep track of the total entries available.
|
|
//
|
|
|
|
if ( totalEntries > TotalEntriesToReturn ) {
|
|
TotalEntriesToReturn = totalEntries;
|
|
}
|
|
|
|
//
|
|
// Was NetUserEnum able to read at least one complete entry?
|
|
//
|
|
|
|
if ( entriesRead == 0 ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Do the actual conversion from the 32-bit structures to 16-bit
|
|
// structures.
|
|
//
|
|
|
|
XsFillEnumBuffer(
|
|
outBuffer,
|
|
entriesRead,
|
|
nativeStructureDesc,
|
|
bufferBegin,
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
bufferSize,
|
|
StructureDesc,
|
|
NULL, // verify function
|
|
&bytesRequired,
|
|
&entriesFilled,
|
|
NULL
|
|
);
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: 32-bit data at %lx, 16-bit data at %lx, %ld BR,"
|
|
" Entries %ld of %ld\n",
|
|
outBuffer, SmbGetUlong( ¶meters->Buffer ),
|
|
bytesRequired, entriesFilled, entriesRead ));
|
|
}
|
|
|
|
//
|
|
// If NetUserEnum overshot PrefMaxLen,
|
|
// we can't simply return the collected data since we wouldn't
|
|
// know what to use as a ResumeHandle.
|
|
//
|
|
|
|
if ( entriesRead != entriesFilled ) {
|
|
|
|
//
|
|
// Restore the saved values.
|
|
//
|
|
|
|
bufferBegin = SavedBufferBegin;
|
|
bufferSize = SavedBufferSize;
|
|
totalEntriesRead = SavedTotalEntriesRead;
|
|
resumeKey = SavedResumeKey;
|
|
|
|
//
|
|
// If we have ANY data to return to the caller,
|
|
// return the short list now rather than trying to outguess NetUserEnum
|
|
//
|
|
|
|
if ( totalEntriesRead != 0 ) {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: couldn't pack data: return previous data\n" ));
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we've already asked NetUserEnum for the smallest amount,
|
|
// just give up.
|
|
//
|
|
|
|
if ( nativeBufferSize == 1 || entriesRead == 1 ) {
|
|
|
|
status = NERR_BufTooSmall;
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserEnum2: NetUserEnum buffer too small: %X\n",
|
|
status ));
|
|
}
|
|
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Otherwise, trim it down and try again.
|
|
// If we've tried twice and gotten the same result,
|
|
// be really agressive.
|
|
//
|
|
|
|
if ( entriesRead == PreviousEntriesRead || entriesRead < 10 ) {
|
|
nativeBufferSize = 1;
|
|
} else {
|
|
nativeBufferSize /= 2;
|
|
}
|
|
|
|
//
|
|
// If NetUserEnum returned useful data,
|
|
// account for it.
|
|
//
|
|
|
|
} else {
|
|
//
|
|
// Update count of entries read.
|
|
//
|
|
|
|
totalEntriesRead += entriesRead;
|
|
|
|
//
|
|
// Are there any more entries to read?
|
|
//
|
|
|
|
if ( entriesRead == totalEntries ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we've made the nativeBufferSize so small we're barely making
|
|
// progress,
|
|
// just return what we have to the caller.
|
|
//
|
|
|
|
if ( entriesRead == 1 ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Calculate new buffer beginning and size.
|
|
//
|
|
|
|
bufferBegin += entriesRead *
|
|
RapStructureSize( StructureDesc, Response, FALSE );
|
|
bufferSize -= bytesRequired;
|
|
|
|
//
|
|
// Don't hassle the last few bytes,
|
|
// we'll just overshoot anyway.
|
|
//
|
|
|
|
if ( bufferSize < 50 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Free last native buffer.
|
|
//
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
outBuffer = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Upon exit from the loop, totalEntriesRead has the number of entries
|
|
// read, TotalEntriesToReturn has the number available from NetUserEnum.
|
|
// Formulate return codes, etc. from these values.
|
|
//
|
|
|
|
if ( totalEntriesRead < TotalEntriesToReturn ) {
|
|
|
|
Header->Status = ERROR_MORE_DATA;
|
|
|
|
} else {
|
|
|
|
Header->Converter = XsPackReturnData(
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
totalEntriesRead
|
|
);
|
|
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserEnum2: returning %ld entries of %ld. Resume key is now %ld\n",
|
|
totalEntriesRead,
|
|
TotalEntriesToReturn,
|
|
resumeKey ));
|
|
}
|
|
|
|
//
|
|
// Set up the response parameters.
|
|
//
|
|
|
|
SmbPutUshort( ¶meters->EntriesRead, (WORD)totalEntriesRead );
|
|
SmbPutUshort( ¶meters->TotalAvail,
|
|
(WORD)( TotalEntriesToReturn ));
|
|
SmbPutUlong( ¶meters->ResumeOut, resumeKey );
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
|
|
//
|
|
// Determine return buffer size.
|
|
//
|
|
|
|
XsSetDataCount(
|
|
¶meters->BufLen,
|
|
StructureDesc,
|
|
Header->Converter,
|
|
totalEntriesRead,
|
|
Header->Status
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserEnum2
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserGetGroups (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserGetGroups.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_GET_GROUPS parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
LPVOID outBuffer= NULL;
|
|
DWORD entriesRead;
|
|
DWORD totalEntries;
|
|
|
|
DWORD entriesFilled = 0; // Conversion variables
|
|
DWORD bytesRequired = 0;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserGetGroups: header at %lx, params at %lx, "
|
|
"level %ld, buf size %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ),
|
|
SmbGetUshort( ¶meters->BufLen )));
|
|
}
|
|
|
|
//
|
|
// Translate parameters, check for errors.
|
|
//
|
|
|
|
if ( SmbGetUshort( ¶meters->Level ) != 0 ) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
//
|
|
// Get the actual information from the local 32-bit call.
|
|
//
|
|
|
|
status = NetUserGetGroups(
|
|
NULL,
|
|
nativeUserName,
|
|
(DWORD)SmbGetUshort( ¶meters->Level ),
|
|
(LPBYTE *)&outBuffer,
|
|
XsNativeBufferSize( SmbGetUshort( ¶meters->BufLen )),
|
|
&entriesRead,
|
|
&totalEntries
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserGetGroups: NetUserGetGroups failed: %X\n",
|
|
status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserGetGroups: received %ld entries at %lx\n",
|
|
entriesRead, outBuffer ));
|
|
}
|
|
|
|
//
|
|
// Do the conversion from 32- to 16-bit data.
|
|
//
|
|
|
|
XsFillEnumBuffer(
|
|
outBuffer,
|
|
entriesRead,
|
|
Desc32_user_group_info_0,
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
Desc16_user_group_info_0,
|
|
NULL, // verify function
|
|
&bytesRequired,
|
|
&entriesFilled,
|
|
NULL
|
|
);
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR,"
|
|
" Entries %ld of %ld\n",
|
|
outBuffer, SmbGetUlong( ¶meters->Buffer ),
|
|
bytesRequired, entriesFilled, totalEntries ));
|
|
}
|
|
|
|
//
|
|
// If there is no room for one fixed structure, return NERR_BufTooSmall.
|
|
// If all the entries could not be filled, return ERROR_MORE_DATA,
|
|
// and return the buffer as is. GROUP_INFO_0 structures don't
|
|
// need to be packed, because they have no variable data.
|
|
//
|
|
|
|
if ( !XsCheckBufferSize(
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
Desc16_user_group_info_0,
|
|
FALSE // not in native format
|
|
)) {
|
|
|
|
Header->Status = NERR_BufTooSmall;
|
|
|
|
} else if ( entriesFilled < totalEntries ) {
|
|
|
|
Header->Status = ERROR_MORE_DATA;
|
|
|
|
}
|
|
|
|
//
|
|
// Set up the response parameters.
|
|
//
|
|
|
|
SmbPutUshort( ¶meters->EntriesRead, (WORD)entriesFilled );
|
|
SmbPutUshort( ¶meters->TotalAvail, (WORD)totalEntries );
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
NetpMemoryFree( nativeUserName );
|
|
|
|
//
|
|
// Determine return buffer size.
|
|
//
|
|
|
|
XsSetDataCount(
|
|
¶meters->BufLen,
|
|
Desc16_user_group_info_0,
|
|
Header->Converter,
|
|
entriesFilled,
|
|
Header->Status
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserGetGroups
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserGetInfo (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserGetInfo.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_GET_INFO parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
LPVOID outBuffer = NULL;
|
|
|
|
LPBYTE stringLocation = NULL; // Conversion variables
|
|
DWORD bytesRequired = 0;
|
|
LPBYTE nativeStructureDesc;
|
|
DWORD level;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserGetInfo: header at %lx, "
|
|
"params at %lx, level %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ) ));
|
|
}
|
|
|
|
//
|
|
// Translate parameters, check for errors.
|
|
//
|
|
|
|
level = SmbGetUshort( ¶meters->Level );
|
|
|
|
if ( XsWordParamOutOfRange( level, 0, 2 )
|
|
&& XsWordParamOutOfRange( level, 10, 11 )) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserGetInfo(
|
|
NULL,
|
|
nativeUserName,
|
|
level,
|
|
(LPBYTE *)&outBuffer
|
|
);
|
|
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserGetInfo: NetUserGetInfo failed: "
|
|
"%X\n", status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Use the requested level to determine the format of the
|
|
// data structure.
|
|
//
|
|
|
|
switch ( level ) {
|
|
|
|
case 0:
|
|
|
|
nativeStructureDesc = Desc32_user_info_0;
|
|
StructureDesc = Desc16_user_info_0;
|
|
break;
|
|
|
|
case 1:
|
|
|
|
nativeStructureDesc = Desc32_user_info_1;
|
|
StructureDesc = Desc16_user_info_1;
|
|
break;
|
|
|
|
case 2:
|
|
|
|
{
|
|
PUSER_INFO_2 usri2 = outBuffer;
|
|
|
|
//
|
|
// Call NetpRotateLogonHours to make sure we behave properly
|
|
// during DST.
|
|
//
|
|
|
|
if ( usri2->usri2_logon_hours != NULL ) {
|
|
|
|
if ( !NetpRotateLogonHours(
|
|
usri2->usri2_logon_hours,
|
|
usri2->usri2_units_per_week,
|
|
FALSE
|
|
) ) {
|
|
|
|
Header->Status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Truncate UserParms to 48 bytes
|
|
//
|
|
|
|
if (( usri2->usri2_parms != NULL ) &&
|
|
(wcslen(usri2->usri2_parms) > LM20_MAXCOMMENTSZ))
|
|
{
|
|
*(usri2->usri2_parms + LM20_MAXCOMMENTSZ) = UNICODE_NULL;
|
|
}
|
|
|
|
nativeStructureDesc = Desc32_user_info_2;
|
|
StructureDesc = Desc16_user_info_2;
|
|
}
|
|
break;
|
|
|
|
case 10:
|
|
|
|
nativeStructureDesc = Desc32_user_info_10;
|
|
StructureDesc = Desc16_user_info_10;
|
|
break;
|
|
|
|
case 11:
|
|
|
|
{
|
|
PUSER_INFO_11 usri11 = outBuffer;
|
|
|
|
//
|
|
// Call NetpRotateLogonHours to make sure we behave properly
|
|
// during DST.
|
|
//
|
|
|
|
if ( usri11->usri11_logon_hours != NULL ) {
|
|
if ( !NetpRotateLogonHours(
|
|
usri11->usri11_logon_hours,
|
|
usri11->usri11_units_per_week,
|
|
FALSE
|
|
) ) {
|
|
|
|
Header->Status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Truncate UserParms to 48 bytes
|
|
//
|
|
|
|
if (( usri11->usri11_parms != NULL ) &&
|
|
(wcslen(usri11->usri11_parms) > LM20_MAXCOMMENTSZ))
|
|
{
|
|
*(usri11->usri11_parms + LM20_MAXCOMMENTSZ) = UNICODE_NULL;
|
|
}
|
|
|
|
nativeStructureDesc = Desc32_user_info_11;
|
|
StructureDesc = Desc16_user_info_11;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Convert the structure returned by the 32-bit call to a 16-bit
|
|
// structure. The last possible location for variable data is
|
|
// calculated from buffer location and length.
|
|
//
|
|
|
|
stringLocation = (LPBYTE)( XsSmbGetPointer( ¶meters->Buffer )
|
|
+ SmbGetUshort( ¶meters->BufLen ) );
|
|
|
|
status = RapConvertSingleEntry(
|
|
outBuffer,
|
|
nativeStructureDesc,
|
|
FALSE,
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
StructureDesc,
|
|
TRUE,
|
|
&stringLocation,
|
|
&bytesRequired,
|
|
Response,
|
|
NativeToRap
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserGetInfo: RapConvertSingleEntry failed: "
|
|
"%X\n", status ));
|
|
}
|
|
|
|
Header->Status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR\n",
|
|
outBuffer, SmbGetUlong( ¶meters->Buffer ),
|
|
bytesRequired ));
|
|
}
|
|
|
|
//
|
|
// Determine return code based on the size of the buffer.
|
|
//
|
|
|
|
if ( !XsCheckBufferSize(
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
FALSE // not in native format
|
|
)) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserGetInfo: Buffer too small %ld s.b. %ld.\n",
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
RapStructureSize(
|
|
StructureDesc,
|
|
Response,
|
|
FALSE ) ));
|
|
}
|
|
Header->Status = NERR_BufTooSmall;
|
|
|
|
} else if ( bytesRequired > (DWORD)SmbGetUshort( ¶meters-> BufLen )) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "NetUserGetInfo: More data available.\n" ));
|
|
}
|
|
Header->Status = ERROR_MORE_DATA;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Pack the response data.
|
|
//
|
|
|
|
Header->Converter = XsPackReturnData(
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
1
|
|
);
|
|
}
|
|
|
|
//
|
|
// Set up the response parameters.
|
|
//
|
|
|
|
SmbPutUshort( ¶meters->TotalAvail, (WORD)bytesRequired );
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
NetpMemoryFree( nativeUserName );
|
|
|
|
//
|
|
// Determine return buffer size.
|
|
//
|
|
|
|
XsSetDataCount(
|
|
¶meters->BufLen,
|
|
StructureDesc,
|
|
Header->Converter,
|
|
1,
|
|
Header->Status
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserGetInfo
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserModalsGet (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserModalsGet.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_MODALS_GET parameters = Parameters;
|
|
LPVOID outBuffer = NULL; // Native parameters
|
|
|
|
LPBYTE stringLocation = NULL; // Conversion variables
|
|
DWORD bytesRequired = 0;
|
|
LPBYTE nativeStructureDesc;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserModalsGet: header at %lx, "
|
|
"params at %lx, level %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ) ));
|
|
}
|
|
|
|
//
|
|
// Check for errors.
|
|
//
|
|
|
|
if ( XsWordParamOutOfRange( parameters->Level, 0, 1 )) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserModalsGet(
|
|
NULL,
|
|
(DWORD)SmbGetUshort( ¶meters->Level ),
|
|
(LPBYTE *)&outBuffer
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserModalsGet: NetUserModalsGet failed: "
|
|
"%X\n", status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Use the requested level to determine the format of the
|
|
// data structure.
|
|
//
|
|
|
|
switch ( SmbGetUshort( ¶meters->Level ) ) {
|
|
|
|
case 0:
|
|
|
|
nativeStructureDesc = Desc32_user_modals_info_0;
|
|
StructureDesc = Desc16_user_modals_info_0;
|
|
break;
|
|
|
|
case 1:
|
|
|
|
nativeStructureDesc = Desc32_user_modals_info_1;
|
|
StructureDesc = Desc16_user_modals_info_1;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Convert the structure returned by the 32-bit call to a 16-bit
|
|
// structure. The last possible location for variable data is
|
|
// calculated from buffer location and length.
|
|
//
|
|
|
|
stringLocation = (LPBYTE)( XsSmbGetPointer( ¶meters->Buffer )
|
|
+ SmbGetUshort( ¶meters->BufLen ) );
|
|
|
|
status = RapConvertSingleEntry(
|
|
outBuffer,
|
|
nativeStructureDesc,
|
|
FALSE,
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
StructureDesc,
|
|
TRUE,
|
|
&stringLocation,
|
|
&bytesRequired,
|
|
Response,
|
|
NativeToRap
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserModalsGet: RapConvertSingleEntry failed: "
|
|
"%X\n", status ));
|
|
}
|
|
|
|
Header->Status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR\n",
|
|
outBuffer, SmbGetUlong( ¶meters->Buffer ),
|
|
bytesRequired ));
|
|
}
|
|
|
|
//
|
|
// Determine return code based on the size of the buffer.
|
|
//
|
|
|
|
if ( !XsCheckBufferSize(
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
FALSE // not in native format
|
|
)) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserModalsGet: Buffer too small.\n" ));
|
|
}
|
|
Header->Status = NERR_BufTooSmall;
|
|
|
|
} else if ( bytesRequired > (DWORD)SmbGetUshort( ¶meters-> BufLen )) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "NetUserModalsGet: More data available.\n" ));
|
|
}
|
|
Header->Status = ERROR_MORE_DATA;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Pack the response data.
|
|
//
|
|
|
|
Header->Converter = XsPackReturnData(
|
|
(LPVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
StructureDesc,
|
|
1
|
|
);
|
|
}
|
|
|
|
//
|
|
// Set up the response parameters.
|
|
//
|
|
|
|
SmbPutUshort( ¶meters->TotalAvail, (WORD)bytesRequired );
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetApiBufferFree( outBuffer );
|
|
|
|
//
|
|
// Determine return buffer size.
|
|
//
|
|
|
|
XsSetDataCount(
|
|
¶meters->BufLen,
|
|
StructureDesc,
|
|
Header->Converter,
|
|
1,
|
|
Header->Status
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserModalsGet
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserModalsSet (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserModalsSet.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_MODALS_SET parameters = Parameters;
|
|
DWORD nativeLevel; // Native parameters
|
|
LPVOID buffer = NULL;
|
|
|
|
LPDESC setInfoDesc; // Conversion variables
|
|
LPDESC nativeSetInfoDesc;
|
|
LPDESC nativeStructureDesc;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
//
|
|
// Check for errors.
|
|
//
|
|
|
|
if ( XsWordParamOutOfRange( parameters->Level, 0, 1 )) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// First of all, the 32-bit parmnum is a bit messed up. If the level
|
|
// is 2, the new parmnum is 5 plus the old parmnum.
|
|
//
|
|
|
|
nativeLevel = XsLevelFromParmNum( SmbGetUshort( ¶meters->Level ),
|
|
SmbGetUshort( ¶meters->ParmNum ));
|
|
|
|
switch ( SmbGetUshort( ¶meters->Level )) {
|
|
|
|
case 0:
|
|
|
|
StructureDesc = Desc16_user_modals_info_0;
|
|
nativeStructureDesc = Desc32_user_modals_info_0;
|
|
setInfoDesc = Desc16_user_modals_info_0_setinfo;
|
|
nativeSetInfoDesc = Desc32_user_modals_info_0_setinfo;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
StructureDesc = Desc16_user_modals_info_1;
|
|
nativeStructureDesc = Desc32_user_modals_info_1;
|
|
setInfoDesc = Desc16_user_modals_info_1_setinfo;
|
|
nativeSetInfoDesc = Desc32_user_modals_info_1_setinfo;
|
|
if ( nativeLevel != (DWORD)SmbGetUshort( ¶meters->Level )) {
|
|
nativeLevel += 5;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
status = XsConvertSetInfoBuffer(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
SmbGetUshort( ¶meters->ParmNum ),
|
|
TRUE,
|
|
TRUE,
|
|
StructureDesc,
|
|
nativeStructureDesc,
|
|
setInfoDesc,
|
|
nativeSetInfoDesc,
|
|
(LPBYTE *)&buffer,
|
|
NULL
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserModalsSet: Problem with conversion: %X\n",
|
|
status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserModalsSet(
|
|
NULL,
|
|
nativeLevel,
|
|
buffer,
|
|
NULL
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserModalsSet: NetUserModalsSet failed: %X\n",
|
|
status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// No return information for this API.
|
|
//
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
//
|
|
// If there is a native 32-bit buffer, free it.
|
|
//
|
|
|
|
NetpMemoryFree( buffer );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserModalsSet
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserPasswordSet2 (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserPasswordSet. This call is
|
|
translated to NetUserPasswordSet2 when remotely called from a
|
|
16-bit machine.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_PASSWORD_SET_2 parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
UNICODE_STRING UserName;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
//
|
|
// Convert the username.
|
|
//
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&UserName,
|
|
nativeUserName
|
|
);
|
|
|
|
//
|
|
// Check the password length.
|
|
//
|
|
status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( ¶meters->PasswordLength )) );
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserPasswordSet2: XsCheckAndReplacePassword "
|
|
"failed: %X\n", status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
status = XsChangePasswordSam(
|
|
&UserName,
|
|
parameters->OldPassword,
|
|
parameters->NewPassword,
|
|
(BOOLEAN)SmbGetUshort( ¶meters->DataEncryption )
|
|
);
|
|
|
|
|
|
//
|
|
// No return data.
|
|
//
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetpMemoryFree( nativeUserName );
|
|
Header->Status = (WORD)status;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserPasswordSet2
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserSetGroups (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserSetGroups.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PXS_NET_USER_SET_GROUPS parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
LPBYTE actualBuffer = NULL;
|
|
DWORD groupCount;
|
|
|
|
LPBYTE stringLocation = NULL; // Conversion variables
|
|
LPVOID buffer = NULL;
|
|
DWORD bytesRequired = 0;
|
|
LPDESC longDescriptor = NULL;
|
|
LPDESC longNativeDescriptor = NULL;
|
|
DWORD bufferSize;
|
|
DWORD i;
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: header at %lx, params at %lx,"
|
|
"level %ld\n",
|
|
Header, parameters, SmbGetUshort( ¶meters->Level ) ));
|
|
}
|
|
|
|
//
|
|
// Translate parameters, check for errors.
|
|
//
|
|
|
|
if ( SmbGetUshort( ¶meters->Level ) != 0 ) {
|
|
|
|
Header->Status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
StructureDesc = Desc16_user_group_info_0_set;
|
|
AuxStructureDesc = Desc16_user_group_info_0;
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
//
|
|
// Use the count of group_info_0 structures to form a long
|
|
// descriptor string which can be used to do all the conversion
|
|
// in one pass.
|
|
//
|
|
|
|
groupCount = (DWORD)SmbGetUshort( ¶meters->Entries );
|
|
|
|
longDescriptor = NetpMemoryAllocate(
|
|
strlen( StructureDesc )
|
|
+ strlen( AuxStructureDesc ) * groupCount
|
|
+ 1 );
|
|
longNativeDescriptor = NetpMemoryAllocate(
|
|
strlen( Desc32_user_group_info_0_set )
|
|
+ strlen( Desc32_user_group_info_0 )
|
|
* groupCount
|
|
+ 1 );
|
|
|
|
if (( longDescriptor == NULL ) || ( longNativeDescriptor == NULL )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: failed to allocate memory" ));
|
|
}
|
|
Header->Status = NERR_NoRoom;
|
|
goto cleanup;
|
|
}
|
|
|
|
strcpy( longDescriptor, StructureDesc );
|
|
strcpy( longNativeDescriptor, Desc32_user_group_info_0_set );
|
|
for ( i = 0; i < groupCount; i++ ) {
|
|
strcat( longDescriptor, AuxStructureDesc );
|
|
strcat( longNativeDescriptor, Desc32_user_group_info_0 );
|
|
}
|
|
|
|
//
|
|
// Figure out if there is enough room in the buffer for all this
|
|
// data. If not, return NERR_BufTooSmall.
|
|
//
|
|
|
|
if ( !XsCheckBufferSize(
|
|
SmbGetUshort( ¶meters->BufLen ),
|
|
longDescriptor,
|
|
FALSE // not in native format
|
|
)) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: Buffer too small.\n" ));
|
|
}
|
|
Header->Status = NERR_BufTooSmall;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Find out how big a buffer we need to allocate to hold the native
|
|
// 32-bit version of the input data structure.
|
|
//
|
|
|
|
bufferSize = XsBytesForConvertedStructure(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
longDescriptor,
|
|
longNativeDescriptor,
|
|
RapToNative,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// Allocate enough memory to hold the converted native buffer.
|
|
//
|
|
|
|
buffer = NetpMemoryAllocate( bufferSize );
|
|
|
|
if ( buffer == NULL ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: failed to create buffer" ));
|
|
}
|
|
Header->Status = NERR_NoRoom;
|
|
goto cleanup;
|
|
}
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: buffer of %ld bytes at %lx\n",
|
|
bufferSize, buffer ));
|
|
}
|
|
|
|
//
|
|
// Convert the buffer from 16-bit to 32-bit.
|
|
//
|
|
|
|
stringLocation = (LPBYTE)buffer + bufferSize;
|
|
bytesRequired = 0;
|
|
|
|
status = RapConvertSingleEntry(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
longDescriptor,
|
|
TRUE,
|
|
buffer,
|
|
buffer,
|
|
longNativeDescriptor,
|
|
FALSE,
|
|
&stringLocation,
|
|
&bytesRequired,
|
|
Response,
|
|
RapToNative
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: RapConvertSingleEntry failed: "
|
|
"%X\n", status ));
|
|
}
|
|
|
|
Header->Status = NERR_InternalError;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Check if we got all the entries. If not, we'll quit.
|
|
//
|
|
|
|
if ( RapAuxDataCount( buffer, Desc32_user_group_info_0_set, Both, TRUE )
|
|
!= groupCount ) {
|
|
|
|
Header->Status = NERR_BufTooSmall;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// If there are no entries, there's no data. Otherwise, the data comes
|
|
// after an initial header structure.
|
|
//
|
|
|
|
if ( groupCount > 0 ) {
|
|
|
|
actualBuffer = (LPBYTE)buffer + RapStructureSize(
|
|
Desc32_user_group_info_0_set,
|
|
Both,
|
|
TRUE
|
|
);
|
|
|
|
} else {
|
|
|
|
actualBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserSetGroups(
|
|
NULL,
|
|
nativeUserName,
|
|
(DWORD)SmbGetUshort( ¶meters->Level ),
|
|
actualBuffer,
|
|
(DWORD)groupCount
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetGroups: NetUserSetGroups failed: %X\n",
|
|
status ));
|
|
}
|
|
Header->Status = (WORD)status;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// There is no real return information for this API.
|
|
//
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
NetpMemoryFree( buffer );
|
|
NetpMemoryFree( longDescriptor );
|
|
NetpMemoryFree( longNativeDescriptor );
|
|
NetpMemoryFree( nativeUserName );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserSetGroups
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserSetInfo2 (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserSetInfo2. A remote NetUserGetInfo2
|
|
call from a 16-bit machine is translated to NetUserGetInfo2, with
|
|
an encrypted password. This routine has to check for a password set
|
|
and handle it properly, by using level 21 to set the password.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status = NO_ERROR;
|
|
|
|
PXS_NET_USER_SET_INFO_2 parameters = Parameters;
|
|
LPTSTR nativeUserName = NULL; // Native parameters
|
|
LPVOID buffer = NULL;
|
|
WORD bufLen;
|
|
DWORD level;
|
|
BYTE newPassword[ENCRYPTED_PWLEN];
|
|
|
|
LPDESC setInfoDesc; // Conversion variables
|
|
LPVOID nativePasswordArea = NULL; // Points to Unicode or encrypted.
|
|
LPDESC nativeSetInfoDesc;
|
|
LPDESC nativeStructureDesc;
|
|
LPUSER_INFO_2 user = NULL;
|
|
PUSER_16_INFO_1 user16 = NULL;
|
|
USER_INFO_1020 usri1020;
|
|
BOOLEAN changePassword = FALSE;
|
|
BOOLEAN changeUserInfo = FALSE;
|
|
BOOLEAN encryptionSupported = TRUE;
|
|
WORD parmNum;
|
|
PUSER_INFO_2 Susri2 = NULL;
|
|
|
|
//
|
|
// avoid warnings;
|
|
//
|
|
|
|
API_HANDLER_PARAMETERS_REFERENCE;
|
|
|
|
try {
|
|
bufLen = SmbGetUshort( ¶meters->BufLen );
|
|
level = SmbGetUshort( ¶meters->Level );
|
|
parmNum = SmbGetUshort( ¶meters->ParmNum );
|
|
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint((
|
|
"XsNetUserSetInfo2: header at " FORMAT_LPVOID ", "
|
|
"params at " FORMAT_LPVOID ",\n "
|
|
"level " FORMAT_DWORD ", parmnum " FORMAT_DWORD ", "
|
|
"buflen " FORMAT_WORD_ONLY "\n",
|
|
Header, parameters,
|
|
level, parmNum, bufLen ));
|
|
}
|
|
|
|
//
|
|
// Translate parameters
|
|
//
|
|
|
|
XsConvertTextParameter(
|
|
nativeUserName,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->UserName )
|
|
);
|
|
|
|
//
|
|
// Check if password is encrypted. We know for a fact that dos redirs
|
|
// don't support encryption
|
|
//
|
|
|
|
encryptionSupported = (BOOLEAN)
|
|
( SmbGetUshort( ¶meters->DataEncryption ) == TRUE );
|
|
|
|
//
|
|
// Determine descriptor strings based on level.
|
|
//
|
|
|
|
switch ( level ) {
|
|
|
|
case 1:
|
|
|
|
StructureDesc = Desc16_user_info_1;
|
|
setInfoDesc = Desc16_user_info_1_setinfo;
|
|
|
|
if ( encryptionSupported ) {
|
|
nativeStructureDesc = Desc32_user_info_1;
|
|
nativeSetInfoDesc = Desc32_user_info_1_setinfo;
|
|
} else {
|
|
nativeStructureDesc = Desc32_user_info_1_NC;
|
|
nativeSetInfoDesc = Desc32_user_info_1_setinfo_NC;
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
StructureDesc = Desc16_user_info_2;
|
|
setInfoDesc = Desc16_user_info_2_setinfo;
|
|
|
|
if ( encryptionSupported ) {
|
|
nativeStructureDesc = Desc32_user_info_2;
|
|
nativeSetInfoDesc = Desc32_user_info_2_setinfo;
|
|
} else {
|
|
nativeStructureDesc = Desc32_user_info_2_NC;
|
|
nativeSetInfoDesc = Desc32_user_info_2_setinfo_NC;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
status = ERROR_INVALID_LEVEL;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (parmNum != USER_PASSWORD_PARMNUM) {
|
|
status = XsConvertSetInfoBuffer(
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer ),
|
|
bufLen,
|
|
parmNum,
|
|
TRUE, // yes, convert strings
|
|
TRUE, // yes, meaningless input pointers
|
|
StructureDesc,
|
|
nativeStructureDesc,
|
|
setInfoDesc,
|
|
nativeSetInfoDesc,
|
|
(LPBYTE *)&buffer,
|
|
NULL // don't need output buffer size
|
|
);
|
|
|
|
if ( status != NERR_Success ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint((
|
|
"XsNetUserSetInfo2: Problem with conversion: "
|
|
FORMAT_API_STATUS "\n",
|
|
status ));
|
|
}
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
XsConvertTextParameter(
|
|
buffer,
|
|
(LPSTR)XsSmbGetPointer( ¶meters->Buffer ) );
|
|
}
|
|
NetpAssert( buffer != NULL );
|
|
|
|
|
|
//
|
|
// Check the password length. A value of -1 means caller wants us
|
|
// to compute the length; see XsNetUserSetInfo below.
|
|
//
|
|
|
|
if ( parmNum == PARMNUM_ALL || parmNum == USER_PASSWORD_PARMNUM) {
|
|
WORD passwordLength = SmbGetUshort( ¶meters->PasswordLength );
|
|
|
|
if (parmNum == PARMNUM_ALL) {
|
|
LPUSER_INFO_2 userInfo = (LPVOID) buffer; // Native structure.
|
|
nativePasswordArea = userInfo->usri2_password; // May be NULL.
|
|
} else {
|
|
nativePasswordArea = buffer; // Entire native buffer.
|
|
if (nativePasswordArea == NULL) {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (passwordLength == (WORD)(-1)) {
|
|
if (parameters->DataEncryption) {
|
|
parameters->PasswordLength = ENCRYPTED_PWLEN;
|
|
} else if (nativePasswordArea != NULL) {
|
|
// Unencrypted, count is number of chars, w/o null char.
|
|
parameters->PasswordLength = (USHORT)wcslen( nativePasswordArea );
|
|
} else {
|
|
parameters->PasswordLength = 0;
|
|
}
|
|
}
|
|
|
|
status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( ¶meters->PasswordLength )) );
|
|
|
|
if ( status != NERR_Success ) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetInfo2: XsCheckAndReplacePassword "
|
|
"failed: " FORMAT_API_STATUS "\n", status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If necessary, do work with passwords. Also, translate the parmnum to
|
|
// an info level.
|
|
//
|
|
|
|
switch( parmNum ) {
|
|
|
|
case PARMNUM_ALL:
|
|
|
|
//
|
|
// Get the encrypted password.
|
|
//
|
|
|
|
user16 = (PUSER_16_INFO_1)XsSmbGetPointer( ¶meters->Buffer );
|
|
|
|
RtlCopyMemory(
|
|
newPassword,
|
|
user16->usri1_password,
|
|
ENCRYPTED_PWLEN
|
|
);
|
|
|
|
user = (LPUSER_INFO_2)buffer;
|
|
user->usri2_password = NULL;
|
|
|
|
if ( level == 2 && user->usri2_logon_hours != NULL ) {
|
|
|
|
//
|
|
// Call NetpRotateLogonHours to make sure we behave properly
|
|
// during DST.
|
|
//
|
|
|
|
if ( !NetpRotateLogonHours(
|
|
user->usri2_logon_hours,
|
|
user->usri2_units_per_week,
|
|
TRUE
|
|
) ) {
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
changePassword = TRUE;
|
|
changeUserInfo = TRUE;
|
|
break;
|
|
|
|
case USER_PASSWORD_PARMNUM:
|
|
|
|
//
|
|
// We will use level 21 for changing passwords.
|
|
//
|
|
|
|
//
|
|
// Get the encrypted password.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
newPassword,
|
|
(PVOID)XsSmbGetPointer( ¶meters->Buffer ),
|
|
ENCRYPTED_PWLEN
|
|
);
|
|
|
|
changePassword = TRUE;
|
|
break;
|
|
|
|
case USER_LOGON_HOURS_PARMNUM:
|
|
|
|
usri1020.usri1020_units_per_week = UNITS_PER_WEEK;
|
|
usri1020.usri1020_logon_hours =
|
|
(LPBYTE)XsSmbGetPointer( ¶meters->Buffer );
|
|
|
|
//
|
|
// Call NetpRotateLogonHours to make sure we behave properly
|
|
// during DST.
|
|
//
|
|
|
|
if ( !NetpRotateLogonHours(
|
|
usri1020.usri1020_logon_hours,
|
|
usri1020.usri1020_units_per_week,
|
|
TRUE
|
|
) ) {
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Lack of break is intentional
|
|
//
|
|
|
|
default:
|
|
|
|
changeUserInfo = TRUE;
|
|
level = PARMNUM_BASE_INFOLEVEL + parmNum;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Bug 114883
|
|
// Downlevel clients cannot set more than 48 wchars and if the server
|
|
// did have more than 48 wchars, we were truncating it! We merge the
|
|
// data that the client sent with what exists on the server
|
|
//
|
|
|
|
if ((buffer != NULL) &&
|
|
(changeUserInfo) &&
|
|
((level == 2) || (parmNum == USER_PARMS_PARMNUM)))
|
|
{
|
|
PUSER_INFO_2 Cusri2 = NULL;
|
|
PUSER_INFO_1013 Cusri1013 = NULL;
|
|
LPWSTR UserParms = NULL;
|
|
|
|
// Get the pointer to the client's userparms
|
|
|
|
if (level == 2)
|
|
{
|
|
Cusri2 = buffer;
|
|
UserParms = Cusri2->usri2_parms;
|
|
}
|
|
else
|
|
{
|
|
Cusri1013 = buffer;
|
|
UserParms = Cusri1013->usri1013_parms;
|
|
}
|
|
|
|
//
|
|
// Make the local call.
|
|
//
|
|
|
|
status = NetUserGetInfo(
|
|
NULL,
|
|
nativeUserName,
|
|
level,
|
|
(LPBYTE *)&Susri2
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(API_ERRORS) {
|
|
NetpKdPrint(( "XsNetUserGetInfo: NetUserGetInfo failed: "
|
|
"%X\n", status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
// If the server userparms field is > 48, we want to do something special
|
|
|
|
if (( Susri2->usri2_parms != NULL ) &&
|
|
(wcslen(Susri2->usri2_parms) > LM20_MAXCOMMENTSZ))
|
|
{
|
|
//
|
|
// We need to merge the returned bytes with the local ones
|
|
//
|
|
|
|
UINT Length = 0;
|
|
|
|
if ( UserParms != NULL )
|
|
{
|
|
//
|
|
// Just to be safe, we never over-write more than 48 wchars.
|
|
//
|
|
|
|
Length = wcslen(UserParms);
|
|
|
|
if (Length > LM20_MAXCOMMENTSZ)
|
|
{
|
|
Length = LM20_MAXCOMMENTSZ;
|
|
}
|
|
}
|
|
|
|
// we copy the bytes that the client sent, but only upto
|
|
// 48 wchars.
|
|
|
|
RtlCopyMemory( Susri2->usri2_parms,
|
|
UserParms,
|
|
Length * sizeof(WCHAR));
|
|
|
|
// From Length to LM20_MAXCOMMENTSZ, we pad with blanks
|
|
|
|
while (Length < LM20_MAXCOMMENTSZ)
|
|
{
|
|
Susri2->usri2_parms[Length++] = L' ';
|
|
}
|
|
|
|
// Save the merged user parms
|
|
|
|
if (level == 2 )
|
|
{
|
|
Cusri2->usri2_parms = Susri2->usri2_parms;
|
|
}
|
|
else
|
|
{
|
|
Cusri1013->usri1013_parms = Susri2->usri2_parms;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change user infos other than the password
|
|
//
|
|
|
|
if ( changeUserInfo ) {
|
|
|
|
status = NetUserSetInfo(
|
|
NULL,
|
|
nativeUserName,
|
|
level,
|
|
buffer,
|
|
NULL
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetInfo2: NetUserSetInfo failed: %X\n",
|
|
status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// If there was a Macintosh primary group field for this user, then
|
|
// set the primary group.
|
|
//
|
|
|
|
if ( (level == 2) &&
|
|
NetpIsMacPrimaryGroupFieldValid( (LPCTSTR)user->usri2_parms ) ) {
|
|
NET_API_STATUS status1;
|
|
status1 = XsSetMacPrimaryGroup(
|
|
(LPCTSTR)nativeUserName,
|
|
(LPCTSTR)user->usri2_parms
|
|
);
|
|
if ( !XsApiSuccess( status1 )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetInfo2: SetMacPrimaryGroup "
|
|
"failed: %X\n", status1 ));
|
|
}
|
|
}
|
|
} else if ( (level == USER_PARMS_INFOLEVEL) &&
|
|
NetpIsMacPrimaryGroupFieldValid(
|
|
(LPCTSTR)((LPUSER_INFO_1013)buffer)->usri1013_parms ) ) {
|
|
NET_API_STATUS status1;
|
|
status1 = XsSetMacPrimaryGroup(
|
|
(LPCTSTR)nativeUserName,
|
|
(LPCTSTR)((LPUSER_INFO_1013)buffer)->usri1013_parms
|
|
);
|
|
if ( !XsApiSuccess( status1 )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetInfo2: SetMacPrimaryGroup "
|
|
"failed: %X\n", status1 ));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If there is a pending password change, do it now.
|
|
//
|
|
|
|
if ( changePassword ) {
|
|
|
|
USER_INFO_21 user21;
|
|
|
|
if ( !encryptionSupported ) {
|
|
|
|
//
|
|
// Do not change password if user sent all blanks. Clear text
|
|
// passwords are only 14 bytes (LM20_PWLEN) long.
|
|
//
|
|
|
|
if ( RtlCompareMemory(
|
|
newPassword,
|
|
NULL_USERSETINFO_PASSWD,
|
|
LM20_PWLEN
|
|
) == LM20_PWLEN ) {
|
|
|
|
status = NERR_Success;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Change clear text password to OWF
|
|
//
|
|
|
|
(VOID) RtlCalculateLmOwfPassword(
|
|
(PLM_PASSWORD) newPassword,
|
|
(PLM_OWF_PASSWORD) user21.usri21_password
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
BYTE NullOwfPassword[ENCRYPTED_PWLEN];
|
|
|
|
//
|
|
// Decrypt doubly encrypted password with the encryption key
|
|
// provided creating an OWF encrypted password.
|
|
//
|
|
|
|
(VOID) RtlDecryptLmOwfPwdWithLmSesKey(
|
|
(PENCRYPTED_LM_OWF_PASSWORD) newPassword,
|
|
(PLM_SESSION_KEY) Header->EncryptionKey,
|
|
(PLM_OWF_PASSWORD) user21.usri21_password
|
|
);
|
|
|
|
//
|
|
// Generate the NULL Owf Password.
|
|
//
|
|
|
|
(VOID) RtlCalculateLmOwfPassword(
|
|
(PLM_PASSWORD) NULL_USERSETINFO_PASSWD,
|
|
(PLM_OWF_PASSWORD) NullOwfPassword
|
|
);
|
|
|
|
//
|
|
// Compare the Owf password the client sent and the Owf password
|
|
// for the NULL password. Do not change the password if this is
|
|
// the case.
|
|
//
|
|
|
|
if ( RtlCompareMemory(
|
|
user21.usri21_password,
|
|
NullOwfPassword,
|
|
ENCRYPTED_PWLEN
|
|
) == ENCRYPTED_PWLEN ) {
|
|
|
|
status = NERR_Success;
|
|
goto cleanup;
|
|
|
|
}
|
|
}
|
|
|
|
status = NetUserSetInfo(
|
|
NULL,
|
|
nativeUserName,
|
|
21,
|
|
(LPBYTE)&user21,
|
|
NULL
|
|
);
|
|
|
|
if ( !XsApiSuccess( status )) {
|
|
IF_DEBUG(ERRORS) {
|
|
NetpKdPrint(( "XsNetUserSetInfo2: NetUserSetInfo failed: "
|
|
"%X\n", status ));
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// No return information for this API.
|
|
//
|
|
|
|
cleanup:
|
|
;
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
|
|
}
|
|
|
|
//
|
|
// If there is a native 32-bit buffer, free it.
|
|
//
|
|
|
|
if (Susri2)
|
|
NetApiBufferFree( Susri2);
|
|
Header->Status = (WORD)status;
|
|
NetpMemoryFree( buffer );
|
|
NetpMemoryFree( nativeUserName );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // XsNetUserSetInfo2
|
|
|
|
|
|
NTSTATUS
|
|
XsNetUserSetInfo (
|
|
API_HANDLER_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles a call to NetUserSetInfo. Since this is a subset
|
|
of the newer NetUserSetInfo2, we just convert into a call to that.
|
|
|
|
Arguments:
|
|
|
|
API_HANDLER_PARAMETERS - information about the API call. See
|
|
XsTypes.h for details.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD dataEncryption;
|
|
WORD bufLen;
|
|
WORD level;
|
|
NTSTATUS ntStatus;
|
|
WORD parmNum;
|
|
PXS_NET_USER_SET_INFO subsetParameters = Parameters;
|
|
XS_NET_USER_SET_INFO_2 supersetParameters;
|
|
|
|
bufLen = SmbGetUshort( &subsetParameters->BufLen );
|
|
dataEncryption = SmbGetUshort( &subsetParameters->DataEncryption );
|
|
level = SmbGetUshort( &subsetParameters->Level );
|
|
parmNum = SmbGetUshort( &subsetParameters->ParmNum );
|
|
|
|
try {
|
|
IF_DEBUG(USER) {
|
|
NetpKdPrint((
|
|
"XsNetUserSetInfo: header at " FORMAT_LPVOID ", "
|
|
"params at " FORMAT_LPVOID ",\n level " FORMAT_DWORD ", "
|
|
"parmnum " FORMAT_DWORD ", buflen " FORMAT_LONG "\n",
|
|
Header, subsetParameters,
|
|
(DWORD) level, (DWORD) parmNum, (LONG) bufLen ));
|
|
}
|
|
|
|
//
|
|
// Create parms for XsNetUserSetInfo2()...
|
|
//
|
|
|
|
supersetParameters.Buffer = subsetParameters->Buffer;
|
|
supersetParameters.UserName = subsetParameters->UserName;
|
|
|
|
SmbPutUshort( &supersetParameters.Level, level );
|
|
SmbPutUshort( &supersetParameters.BufLen, bufLen );
|
|
SmbPutUshort( &supersetParameters.ParmNum, parmNum );
|
|
SmbPutUshort( &supersetParameters.DataEncryption, dataEncryption );
|
|
|
|
//
|
|
// Set info 2 will calc password length for us if we give it -1.
|
|
//
|
|
SmbPutUshort( &supersetParameters.PasswordLength, (WORD)(-1) );
|
|
|
|
|
|
//
|
|
// Invoke new version of API.
|
|
//
|
|
|
|
ntStatus = XsNetUserSetInfo2(
|
|
Header,
|
|
&supersetParameters,
|
|
StructureDesc,
|
|
AuxStructureDesc );
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
ntStatus = GetExceptionCode();
|
|
}
|
|
|
|
return (ntStatus);
|
|
|
|
} // XsNetUserSetInfo
|