3235 lines
89 KiB
C
3235 lines
89 KiB
C
/*++
|
||
|
||
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
|