1043 lines
36 KiB
C
1043 lines
36 KiB
C
/*******************************************************************************
|
|
* config.c
|
|
*
|
|
* Published Terminal Server APIs
|
|
*
|
|
* - user configuration routines
|
|
*
|
|
* Copyright 1998, Citrix Systems Inc.
|
|
* Copyright (C) 1997-1999 Microsoft Corp.
|
|
/******************************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntddkbd.h>
|
|
#include <ntddmou.h>
|
|
#include <windows.h>
|
|
#include <ntsecapi.h>
|
|
#include <lm.h>
|
|
#include <winbase.h>
|
|
#include <winerror.h>
|
|
#if(WINVER >= 0x0500)
|
|
#include <ntstatus.h>
|
|
#include <winsta.h>
|
|
#else
|
|
#include <citrix\cxstatus.h>
|
|
#include <citrix\winsta.h>
|
|
#endif
|
|
|
|
#include <utildll.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <lmaccess.h> // for NetGet[Any]DCName KLB 10-07-97
|
|
#include <lmerr.h> // for NERR_Success KLB 10-07-97
|
|
#include <lmapibuf.h> // for NetApiBufferFree KLB 10-07-97
|
|
|
|
#include <wtsapi32.h>
|
|
|
|
|
|
/*=============================================================================
|
|
== External procedures defined
|
|
=============================================================================*/
|
|
|
|
BOOL WINAPI WTSQueryUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR *, DWORD *);
|
|
BOOL WINAPI WTSQueryUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR *, DWORD *);
|
|
BOOL WINAPI WTSSetUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR, DWORD);
|
|
BOOL WINAPI WTSSetUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR, DWORD);
|
|
|
|
|
|
/*=============================================================================
|
|
== Internal procedures defined
|
|
=============================================================================*/
|
|
#ifdef NETWARE
|
|
|
|
//This should be defined in the wtsapi32.h
|
|
|
|
typedef struct _WTS_USER_CONFIG_SET_NWSERVERW {
|
|
LPWSTR pNWServerName;
|
|
LPWSTR pNWDomainAdminName;
|
|
LPWSTR pNWDomainAdminPassword;
|
|
} WTS_USER_CONFIG_SET_NWSERVERW, * PWTS_USER_CONFIG_SET_NWSERVERW;
|
|
|
|
BOOL
|
|
SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput,
|
|
LPWSTR pServerNameW,
|
|
LPWSTR pUserNameW,
|
|
PUSERCONFIGW pUserConfigW
|
|
);
|
|
|
|
|
|
#endif
|
|
/*=============================================================================
|
|
== Procedures used
|
|
=============================================================================*/
|
|
|
|
BOOL _CopyData( PVOID, ULONG, LPWSTR *, DWORD * );
|
|
BOOL _CopyStringW( LPWSTR, LPWSTR *, DWORD * );
|
|
BOOL _CopyStringA( LPSTR, LPWSTR *, DWORD * );
|
|
BOOL _CopyStringWtoA( LPWSTR, LPSTR *, DWORD * );
|
|
BOOL ValidateCopyAnsiToUnicode(LPSTR, DWORD, LPWSTR);
|
|
BOOL ValidateCopyUnicodeToUnicode(LPWSTR, DWORD, LPWSTR);
|
|
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
|
|
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
|
|
|
|
|
|
/*=============================================================================
|
|
== Local Data
|
|
=============================================================================*/
|
|
|
|
/****************************************************************************
|
|
*
|
|
* WTSQueryUserConfigW (UNICODE)
|
|
*
|
|
* Query information from the SAM for the specified user
|
|
*
|
|
* ENTRY:
|
|
* pServerName (input)
|
|
* Name of server to access (NULL for current machine).
|
|
* pUserName (input)
|
|
* User name to query
|
|
* WTSConfigClass (input)
|
|
* Specifies the type of information to retrieve about the specified user
|
|
* ppBuffer (output)
|
|
* Points to the address of a variable to receive information about
|
|
* the specified session. The format and contents of the data
|
|
* depend on the specified information class being queried. The
|
|
* buffer is allocated within this API and is disposed of using
|
|
* WTSFreeMemory.
|
|
* pBytesReturned (output)
|
|
* An optional parameter that if specified, receives the number of
|
|
* bytes returned.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
* HISTORY:
|
|
* Created KLB 10-06-97
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
WINAPI
|
|
WTSQueryUserConfigW(
|
|
IN LPWSTR pServerName,
|
|
IN LPWSTR pUserName,
|
|
IN WTS_CONFIG_CLASS WTSConfigClass,
|
|
OUT LPWSTR * ppBuffer,
|
|
OUT DWORD * pBytesReturned
|
|
)
|
|
{
|
|
USERCONFIGW UserConfigW;
|
|
ULONG ulReturnLength;
|
|
LONG rc;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwfInheritInitialProgram;
|
|
DWORD dwReturnValue;
|
|
PUSER_INFO_0 pUserInfo = NULL;
|
|
WCHAR netServerName[DOMAIN_LENGTH + 3];
|
|
|
|
/*
|
|
* Check the null buffer
|
|
*/
|
|
|
|
if (!ppBuffer || !pBytesReturned) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
fSuccess = FALSE;
|
|
goto done;
|
|
}
|
|
/*
|
|
* First, we want to make sure the user actually exists on the specified
|
|
* machine.
|
|
*/
|
|
|
|
rc = NetUserGetInfo( pServerName, // server name (can be NULL)
|
|
pUserName, // user name
|
|
0, // level to query (0 = just name)
|
|
(LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
|
|
|
|
/*
|
|
* append the "\\" in front of server name to check the user name existence again
|
|
*/
|
|
|
|
if ( rc != NERR_Success && pServerName) {
|
|
|
|
lstrcpyW(netServerName, L"\\\\");
|
|
lstrcatW(netServerName, pServerName);
|
|
|
|
rc = NetUserGetInfo( netServerName, // server name (can be NULL)
|
|
pUserName, // user name
|
|
0, // level to query (0 = user name)
|
|
(LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
|
|
|
|
if ( rc != NERR_Success ) {
|
|
SetLastError( ERROR_NO_SUCH_USER );
|
|
goto done; // exit with fSuccess = FALSE
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Query the user. If the user config doesn't exist for the user, then
|
|
* we query the default values.
|
|
*/
|
|
rc = RegUserConfigQuery( pServerName, // server name
|
|
pUserName, // user name
|
|
&UserConfigW, // returned user config
|
|
(ULONG)sizeof(UserConfigW),// user config length
|
|
&ulReturnLength ); // #bytes returned
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
rc = RegDefaultUserConfigQuery( pServerName, // server name
|
|
&UserConfigW, // returned user config
|
|
(ULONG)sizeof(UserConfigW),// user config length
|
|
&ulReturnLength ); // #bytes returned
|
|
}
|
|
|
|
/*
|
|
* Now, process the results. Note that in each case, we're allocating a
|
|
* new buffer which the caller must free
|
|
* (WTSUserConfigfInheritInitialProgram is just a boolean, but we allocate
|
|
* a DWORD to send it back).
|
|
*/
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
switch ( WTSConfigClass ) {
|
|
case WTSUserConfigInitialProgram:
|
|
fSuccess = _CopyStringW( UserConfigW.InitialProgram,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigWorkingDirectory:
|
|
fSuccess = _CopyStringW( UserConfigW.WorkDirectory,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigfInheritInitialProgram:
|
|
dwReturnValue = UserConfigW.fInheritInitialProgram;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigfAllowLogonTerminalServer: //DWORD returned/expected
|
|
|
|
dwReturnValue = !(UserConfigW.fLogonDisabled);
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
|
|
|
|
break;
|
|
//Timeout settings
|
|
case WTSUserConfigTimeoutSettingsConnections:
|
|
dwReturnValue = UserConfigW.MaxConnectionTime;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigTimeoutSettingsDisconnections: //DWORD
|
|
dwReturnValue = UserConfigW.MaxDisconnectionTime;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigTimeoutSettingsIdle: //DWORD
|
|
dwReturnValue = UserConfigW.MaxIdleTime;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
case WTSUserConfigfDeviceClientDrives: //DWORD
|
|
dwReturnValue = UserConfigW.fAutoClientDrives;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigfDeviceClientPrinters: //DWORD
|
|
dwReturnValue = UserConfigW.fAutoClientLpts;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD
|
|
dwReturnValue = UserConfigW.fForceClientLptDef;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
|
|
//Connection settings
|
|
case WTSUserConfigBrokenTimeoutSettings: //DWORD
|
|
dwReturnValue = UserConfigW.fResetBroken;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
case WTSUserConfigReconnectSettings:
|
|
dwReturnValue = UserConfigW.fReconnectSame;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
//Modem settings
|
|
case WTSUserConfigModemCallbackSettings: //DWORD
|
|
dwReturnValue = UserConfigW.Callback;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
case WTSUserConfigModemCallbackPhoneNumber:
|
|
fSuccess = _CopyStringW(UserConfigW.CallbackNumber,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigShadowingSettings: //DWORD
|
|
dwReturnValue = UserConfigW.Shadow;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
#ifdef NETWARE
|
|
case WTSUserConfigNWServerName: // string
|
|
fSuccess = _CopyStringW(UserConfigW.NWLogonServer,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
|
|
break;
|
|
#endif
|
|
case WTSUserConfigTerminalServerProfilePath: // string
|
|
fSuccess = _CopyStringW(UserConfigW.WFProfilePath,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigTerminalServerHomeDir: // string
|
|
fSuccess = _CopyStringW(UserConfigW.WFHomeDir,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
case WTSUserConfigTerminalServerHomeDirDrive: // string
|
|
fSuccess = _CopyStringW(UserConfigW.WFHomeDirDrive,
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
|
|
case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE
|
|
if (wcslen(UserConfigW.WFHomeDirDrive) > 0 ) {
|
|
dwReturnValue = 1;
|
|
|
|
} else {
|
|
dwReturnValue = 0;
|
|
}
|
|
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
|
|
|
|
break;
|
|
#ifdef NETWARE
|
|
case WTSUserConfigfNWMapRoot:
|
|
dwReturnValue = UserConfigW.fHomeDirectoryMapRoot;
|
|
fSuccess = _CopyData( &dwReturnValue,
|
|
sizeof(DWORD),
|
|
ppBuffer,
|
|
pBytesReturned );
|
|
break;
|
|
#endif
|
|
} // switch()
|
|
} //if (rc == ERROR_SUCCESS)
|
|
|
|
done:
|
|
|
|
if ( pUserInfo ) {
|
|
NetApiBufferFree( pUserInfo );
|
|
}
|
|
|
|
return( fSuccess );
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* WTSQueryUserConfigA (ANSI)
|
|
*
|
|
* Query information from the SAM for the specified user
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WTSQueryUserConfigW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
* HISTORY:
|
|
* Created KLB 10-06-97
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
WINAPI
|
|
WTSQueryUserConfigA(
|
|
IN LPSTR pServerName,
|
|
IN LPSTR pUserName,
|
|
IN WTS_CONFIG_CLASS WTSConfigClass,
|
|
OUT LPSTR * ppBuffer,
|
|
OUT DWORD * pBytesReturned
|
|
)
|
|
{
|
|
LPWSTR lpBufferW = NULL;
|
|
BOOL fSuccess;
|
|
LONG rc;
|
|
LPWSTR pUserNameW = NULL;
|
|
LPWSTR pServerNameW = NULL;
|
|
|
|
if (!ppBuffer || !pBytesReturned) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
fSuccess = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL );
|
|
if ( fSuccess ) {
|
|
fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL );
|
|
}
|
|
if ( fSuccess ) {
|
|
fSuccess = WTSQueryUserConfigW( pServerNameW,
|
|
pUserNameW,
|
|
WTSConfigClass,
|
|
&lpBufferW,
|
|
pBytesReturned );
|
|
LocalFree( pUserNameW );
|
|
}
|
|
// Now, process the results.
|
|
if ( fSuccess ) switch ( WTSConfigClass ) {
|
|
case WTSUserConfigInitialProgram:
|
|
case WTSUserConfigWorkingDirectory:
|
|
case WTSUserConfigModemCallbackPhoneNumber:
|
|
#ifdef NETWARE
|
|
case WTSUserConfigNWServerName: // string returned/expected
|
|
#endif
|
|
case WTSUserConfigTerminalServerProfilePath: // string returned/expected
|
|
case WTSUserConfigTerminalServerHomeDir: // string returned/expected
|
|
case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected
|
|
/*
|
|
* String Data - Convert to ANSI
|
|
*/
|
|
fSuccess = _CopyStringWtoA( lpBufferW, ppBuffer, pBytesReturned );
|
|
LocalFree( lpBufferW );
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Just a DWORD, point buffer at the one returned (caller is
|
|
* responsible for freeing, so this is cool).
|
|
*/
|
|
*ppBuffer = (LPSTR)lpBufferW;
|
|
break;
|
|
} // switch()
|
|
done:
|
|
return( fSuccess );
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* WTSSetUserConfigW (UNICODE)
|
|
*
|
|
* Set information in the SAM for the specified user
|
|
*
|
|
* ENTRY:
|
|
* pServerName (input)
|
|
* Name of server to access (NULL for current machine).
|
|
* pUserName (input)
|
|
* User name to query
|
|
* WTSConfigClass (input)
|
|
* Specifies the type of information to change for the specified user
|
|
* pBuffer (input)
|
|
* Pointer to the data used to modify the specified user's information.
|
|
* DataLength (input)
|
|
* The length of the data provided.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
* HISTORY:
|
|
* Created KLB 10-06-97
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
WINAPI
|
|
WTSSetUserConfigW(
|
|
IN LPWSTR pServerName,
|
|
IN LPWSTR pUserName,
|
|
IN WTS_CONFIG_CLASS WTSConfigClass,
|
|
IN LPWSTR pBuffer,
|
|
IN DWORD DataLength
|
|
)
|
|
{
|
|
USERCONFIGW UserConfigW;
|
|
ULONG ulReturnLength;
|
|
LONG rc;
|
|
BOOL fSuccess = FALSE;
|
|
BOOL fUserConfig = TRUE; //TRUE - We use RegUserConfigSet
|
|
//FALSE - Use NetUserSetInfo
|
|
DWORD dwfInheritInitialProgram;
|
|
PDWORD pdwValue = (DWORD *) pBuffer;
|
|
PUSER_INFO_0 pUserInfo = NULL;
|
|
DWORD dwParam = 0;
|
|
WCHAR netServerName[DOMAIN_LENGTH + 3];
|
|
|
|
|
|
if (!pBuffer || DataLength == 0) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
goto done; // exit with fSuccess = FALSE
|
|
}
|
|
/*
|
|
* First, we want to make sure the user actually exists on the specified
|
|
* machine.
|
|
*/
|
|
|
|
|
|
rc = NetUserGetInfo( pServerName, // server name (can be NULL)
|
|
pUserName, // user name
|
|
0, // level to query (0 = just name)
|
|
(LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
|
|
|
|
if ( rc != NERR_Success ) {
|
|
|
|
if (pServerName != NULL) {
|
|
lstrcpyW(netServerName, L"\\\\");
|
|
lstrcatW(netServerName, pServerName);
|
|
|
|
rc = NetUserGetInfo( netServerName, // server name (can be NULL)
|
|
pUserName, // user name
|
|
3, // level to query (3 = ust name)
|
|
(LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
|
|
}
|
|
else {
|
|
rc = NetUserGetInfo( NULL, // server name is NULL
|
|
pUserName, // user name
|
|
3, // level to query (3 = ust name)
|
|
(LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
|
|
}
|
|
|
|
if ( rc != NERR_Success ) {
|
|
SetLastError( ERROR_NO_SUCH_USER );
|
|
goto done; // exit with fSuccess = FALSE
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Query the user. If the user config doesn't exist for the user, then
|
|
* we query the default values.
|
|
*/
|
|
rc = RegUserConfigQuery( pServerName, // server name
|
|
pUserName, // user name
|
|
&UserConfigW, // returned user config
|
|
(ULONG)sizeof(UserConfigW),// user config length
|
|
&ulReturnLength ); // #bytes returned
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
rc = RegDefaultUserConfigQuery( pServerName, // server name
|
|
&UserConfigW, // returned user config
|
|
(ULONG)sizeof(UserConfigW),// user config length
|
|
&ulReturnLength ); // #bytes returned
|
|
}
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Now, we plug in the part we want to change.
|
|
*/
|
|
switch ( WTSConfigClass ) {
|
|
case WTSUserConfigInitialProgram:
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
INITIALPROGRAM_LENGTH,
|
|
UserConfigW.InitialProgram)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
case WTSUserConfigWorkingDirectory:
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
DIRECTORY_LENGTH,
|
|
UserConfigW.WorkDirectory)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
case WTSUserConfigfInheritInitialProgram:
|
|
/*
|
|
* We have to point a DWORD pointer at the data, then assign it
|
|
* from the DWORD, as that's how it's defined (and this will
|
|
* ensure that it works okay on non-Intel architectures).
|
|
*/
|
|
UserConfigW.fInheritInitialProgram = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case WTSUserConfigfAllowLogonTerminalServer:
|
|
if (*pdwValue) {
|
|
UserConfigW.fLogonDisabled = FALSE;
|
|
} else {
|
|
UserConfigW.fLogonDisabled = TRUE;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
break;
|
|
|
|
case WTSUserConfigTimeoutSettingsConnections:
|
|
UserConfigW.MaxConnectionTime = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case WTSUserConfigTimeoutSettingsDisconnections: //DWORD
|
|
UserConfigW.MaxDisconnectionTime = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case WTSUserConfigTimeoutSettingsIdle: //DWORD
|
|
UserConfigW.MaxIdleTime = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
case WTSUserConfigfDeviceClientDrives: //DWORD
|
|
UserConfigW.fAutoClientDrives = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case WTSUserConfigfDeviceClientPrinters: //DWORD
|
|
UserConfigW.fAutoClientLpts = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD
|
|
UserConfigW.fForceClientLptDef = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
|
|
case WTSUserConfigBrokenTimeoutSettings: //DWORD
|
|
UserConfigW.fResetBroken= *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
case WTSUserConfigReconnectSettings:
|
|
UserConfigW.fReconnectSame = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
//Modem settings
|
|
case WTSUserConfigModemCallbackSettings: //DWORD
|
|
UserConfigW.Callback = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
case WTSUserConfigModemCallbackPhoneNumber:
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
sizeof(UserConfigW.CallbackNumber) - 1,
|
|
UserConfigW.CallbackNumber)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
|
|
case WTSUserConfigShadowingSettings: //DWORD
|
|
UserConfigW.Shadow = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
#ifdef NETWARE
|
|
case WTSUserConfigNWServerName: // WTS_USER_CONFIG_SET_NWSERVERW
|
|
|
|
// Make sure the data structure is correct
|
|
//
|
|
|
|
if (DataLength < sizeof (WTS_USER_CONFIG_SET_NWSERVERW)) {
|
|
fSuccess = FALSE;
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto done;
|
|
}
|
|
fSuccess = SetNWAuthenticationServer((PWTS_USER_CONFIG_SET_NWSERVERW)pBuffer,
|
|
pServerName,
|
|
pUserName,
|
|
pBuffer,
|
|
&UserConfigW);
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
break;
|
|
#endif
|
|
|
|
case WTSUserConfigTerminalServerProfilePath: // string
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
sizeof(UserConfigW.WFProfilePath) - 1,
|
|
UserConfigW.WFProfilePath)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
|
|
case WTSUserConfigTerminalServerHomeDir: // string
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
sizeof(UserConfigW.WFHomeDir) - 1,
|
|
UserConfigW.WFHomeDir)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
case WTSUserConfigTerminalServerHomeDirDrive: // string
|
|
if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
|
|
sizeof(UserConfigW.WFHomeDirDrive) - 1,
|
|
UserConfigW.WFHomeDirDrive)) ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
goto done;
|
|
}
|
|
break;
|
|
|
|
case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE
|
|
fSuccess = FALSE;
|
|
SetLastError (ERROR_INVALID_PARAMETER); // We don't set this parameter
|
|
goto done;
|
|
break;
|
|
#ifdef NETWARE
|
|
case WTSUserConfigfNWMapRoot:
|
|
UserConfigW.fHomeDirectoryMapRoot = *pdwValue;
|
|
fSuccess = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
fSuccess = FALSE;
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
goto done;
|
|
|
|
}
|
|
|
|
if ( fSuccess ) {
|
|
if (fUserConfig) {
|
|
/*
|
|
* Only in here if we successfully changed the data in UserConfigW.
|
|
* So, we can now write it out to the SAM.
|
|
*/
|
|
|
|
rc = RegUserConfigSet( pServerName, // server name
|
|
pUserName, // user name
|
|
&UserConfigW, // returned user config
|
|
(ULONG)sizeof(UserConfigW));// user config length
|
|
}
|
|
fSuccess = (ERROR_SUCCESS == rc);
|
|
if ( !fSuccess ) {
|
|
SetLastError( rc );
|
|
}
|
|
}
|
|
|
|
done:
|
|
if ( pUserInfo ) {
|
|
NetApiBufferFree( pUserInfo );
|
|
}
|
|
|
|
return(fSuccess);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* WTSSetUserConfigA (ANSI)
|
|
*
|
|
* Set information in the SAM for the specified user
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WTSSetUserConfigW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
* HISTORY:
|
|
* Created KLB 10-06-97
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
WINAPI
|
|
WTSSetUserConfigA(
|
|
IN LPSTR pServerName,
|
|
IN LPSTR pUserName,
|
|
IN WTS_CONFIG_CLASS WTSConfigClass,
|
|
IN LPSTR pBuffer,
|
|
IN DWORD DataLength
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
BOOL fFreepBufferW = TRUE;
|
|
LPWSTR pUserNameW = NULL;
|
|
LPWSTR pServerNameW = NULL;
|
|
LPWSTR pBufferW = NULL;
|
|
DWORD dwDataLength;
|
|
|
|
|
|
if (!pBuffer || DataLength == 0) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
goto done; // exit with fSuccess = FALSE
|
|
}
|
|
|
|
/*
|
|
* We're going to call WTSSetUserConfigW() to do the actual work. We need
|
|
* to convert all ANSI strings to Unicode before calling. These are the
|
|
* user name, and the pBuffer data if it's the initial program or the
|
|
* working directory; if it's the flag for inherit initial program, it'll
|
|
* be a DWORD in either case, so no conversion is necessary.
|
|
*/
|
|
fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL );
|
|
if ( fSuccess ) {
|
|
fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL );
|
|
}
|
|
if ( fSuccess ) switch ( WTSConfigClass ) {
|
|
case WTSUserConfigInitialProgram:
|
|
case WTSUserConfigWorkingDirectory:
|
|
case WTSUserConfigModemCallbackPhoneNumber:
|
|
|
|
case WTSUserConfigTerminalServerProfilePath: // string returned/expected
|
|
case WTSUserConfigTerminalServerHomeDir: // string returned/expected
|
|
case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected
|
|
/*
|
|
* String Data - Convert to Unicode (_CopyStringA() allocates
|
|
* pBufferW for us)
|
|
*/
|
|
fSuccess = _CopyStringA( pBuffer, &pBufferW, &dwDataLength );
|
|
break;
|
|
#ifdef NETWARE
|
|
case WTSUserConfigNWServerName: // string returned/expected
|
|
{
|
|
//Need to convert the data structure from ASCII to UNICODE
|
|
PWTS_USER_CONFIG_SET_NWSERVERW pSetNWServerParamW = LocalAlloc(LPTR, sizeof(WTS_USER_CONFIG_SET_NWSERVERW));
|
|
PWTS_USER_CONFIG_SET_NWSERVERA pSetNWServerParamA = (PWTS_USER_CONFIG_SET_NWSERVERA)pBuffer;
|
|
DWORD dwLen = 0;
|
|
if (pSetNWServerParamW == NULL) {
|
|
fSuccess = FALSE;
|
|
break;
|
|
}
|
|
pBufferW = pSetNWServerParamW;
|
|
|
|
//----------------------------------------//
|
|
// Allocate the buffer to hold the //
|
|
// required unicode string //
|
|
//----------------------------------------//
|
|
dwLen = strlen(pSetNWServerParamA -> pNWServerName);
|
|
if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWServerName,
|
|
&pSetNWServerParamW -> pNWServerName,
|
|
&dwLen)) {
|
|
dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminName);
|
|
if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminName,
|
|
&pSetNWServerParamW -> pNWDomainAdminName,
|
|
&dwLen)) {
|
|
dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminPassword);
|
|
fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminPassword,
|
|
&pSetNWServerParamW -> pNWDomainAdminPassword,
|
|
&dwLen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------//
|
|
// Call the UNICODE function //
|
|
//-----------------------------------------//
|
|
|
|
if (fSuccess) {
|
|
|
|
fSuccess = WTSSetUserConfigW( pServerNameW,
|
|
pUserNameW,
|
|
WTSConfigClass,
|
|
pBufferW,
|
|
dwDataLength );
|
|
}
|
|
|
|
|
|
//----------------------------------------------//
|
|
// Free the storage for the specific function //
|
|
//----------------------------------------------//
|
|
|
|
if (pSetNWServerParamW -> pNWServerName) {
|
|
LocalFree( pSetNWServerParamW -> pNWServerName );
|
|
}
|
|
if (pSetNWServerParamW -> pNWDomainAdminName) {
|
|
LocalFree( pSetNWServerParamW -> pNWDomainAdminName );
|
|
}
|
|
|
|
if (pSetNWServerParamW -> pNWDomainAdminPassword) {
|
|
LocalFree( pSetNWServerParamW -> pNWDomainAdminPassword );
|
|
}
|
|
goto done;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
/*
|
|
* Just a DWORD, point our wide buffer at the narrow buffer passed
|
|
* in to us and set the data length variable we'll pass down.
|
|
* NOTE: WE DON'T WANT TO FREE THE BUFFER, since we're re-using
|
|
* the buffer sent in and the caller expects to free it. We'll
|
|
* use a BOOL to decide, rather than allocating an extra buffer
|
|
* here (performance, memory fragmentation, etc.). KLB 10-08-97
|
|
*/
|
|
pBufferW = (LPWSTR) pBuffer;
|
|
dwDataLength = sizeof(DWORD);
|
|
fFreepBufferW = FALSE;
|
|
break;
|
|
} // switch()
|
|
|
|
/*
|
|
* Now, if fSuccess is TRUE, we've copied all the strings we need. So, we
|
|
* can now call WTSSetUserConfigW().
|
|
*/
|
|
if ( fSuccess ) {
|
|
fSuccess = WTSSetUserConfigW( pServerNameW,
|
|
pUserNameW,
|
|
WTSConfigClass,
|
|
pBufferW,
|
|
dwDataLength );
|
|
}
|
|
done:
|
|
if ( pUserNameW ) {
|
|
LocalFree( pUserNameW );
|
|
}
|
|
if ( fFreepBufferW && pBufferW ) {
|
|
LocalFree( pBufferW );
|
|
}
|
|
return(fSuccess);
|
|
}
|
|
|
|
|
|
#ifdef NETWARE
|
|
BOOL
|
|
SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput,
|
|
LPWSTR pServerNameW,
|
|
LPWSTR pUserNameW,
|
|
PUSERCONFIGW pUserConfigW
|
|
)
|
|
|
|
{
|
|
BOOL bStatus = TRUE;
|
|
PWKSTA_INFO_100 pWkstaInfo = NULL;
|
|
NWLOGONADMIN nwLogonAdmin;
|
|
HANDLE hServer;
|
|
DWORD dwStatus;
|
|
//----------------------------------//
|
|
// Get a Server handle
|
|
//----------------------------------//
|
|
hServer = RegOpenServer(pServerNameW);
|
|
if (!hServer) {
|
|
SetLastError(GetLastError());
|
|
bStatus = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
//----------------------------------
|
|
//find the domain name
|
|
//------------------------------------
|
|
dwStatus = NetWkstaGetInfo(
|
|
pServerNameW,
|
|
100,
|
|
&pWkstaInfo
|
|
);
|
|
if (dwStatus != ERROR_SUCCESS) {
|
|
SetLastError(dwStatus);
|
|
goto done;
|
|
}
|
|
//-----------------------------------------------------
|
|
//Copy the parameter to the NWLOGONADMIN structure
|
|
//-----------------------------------------------------
|
|
bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminName,
|
|
sizeof(nwLogonAdmin.Username)-1,
|
|
nwLogonAdmin.Username);
|
|
if (!bStatus) {
|
|
goto done;
|
|
}
|
|
|
|
bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminPassword,
|
|
sizeof(nwLogonAdmin.Password)-1,
|
|
nwLogonAdmin.Password);
|
|
if (!bStatus) {
|
|
goto done;
|
|
}
|
|
|
|
bStatus = ValidateCopyUnicodeToUnicode(pWkstaInfo -> wki100_langroup,
|
|
sizeof(nwLogonAdmin.Domain)-1,
|
|
nwLogonAdmin.Domain);
|
|
if (!bStatus) {
|
|
goto done;
|
|
}
|
|
|
|
|
|
//------------------------------------------//
|
|
// Set the admin //
|
|
//-----------------------------------------//
|
|
|
|
bStatus = _NWLogonSetAdmin(hServer,
|
|
&nwLogonAdmin,
|
|
sizeof(nwLogonAdmin));
|
|
|
|
if (!bStatus) {
|
|
SetLastError(GetLastError());
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (pWkstaInfo) {
|
|
NetApiBufferFree(pWkstaInfo);
|
|
}
|
|
|
|
return bStatus;
|
|
|
|
}
|
|
|
|
#endif
|
|
|