837 lines
26 KiB
C
837 lines
26 KiB
C
|
|
||
|
/*************************************************************************
|
||
|
*
|
||
|
* winset.c
|
||
|
*
|
||
|
* Window station set APS
|
||
|
*
|
||
|
* Copyright Microsoft Corporation, 1998
|
||
|
*
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Includes
|
||
|
*/
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
#include "conntfy.h" // for SetLockedState
|
||
|
|
||
|
/*
|
||
|
* External Procedures
|
||
|
*/
|
||
|
NTSTATUS xxxWinStationSetInformation( ULONG, WINSTATIONINFOCLASS,
|
||
|
PVOID, ULONG );
|
||
|
VOID _ReadUserProfile( PWCHAR, PWCHAR, PUSERCONFIG );
|
||
|
extern BOOL IsCallerSystem( VOID );
|
||
|
extern BOOL IsCallerAdmin( VOID );
|
||
|
|
||
|
/*
|
||
|
* Internal Procedures used
|
||
|
*/
|
||
|
NTSTATUS _SetConfig( PWINSTATION, PWINSTATIONCONFIG, ULONG );
|
||
|
NTSTATUS _SetPdParams( PWINSTATION, PPDPARAMS, ULONG );
|
||
|
NTSTATUS _SetBeep( PWINSTATION, PBEEPINPUT, ULONG );
|
||
|
NTSTATUS WinStationShadowChangeMode( PWINSTATION, PWINSTATIONSHADOW, ULONG );
|
||
|
|
||
|
NTSTATUS FlushVirtualInput( PWINSTATION, VIRTUALCHANNELCLASS, ULONG );
|
||
|
|
||
|
NTSTATUS
|
||
|
RpcCheckClientAccess(
|
||
|
PWINSTATION pWinStation,
|
||
|
ACCESS_MASK DesiredAccess,
|
||
|
BOOLEAN AlreadyImpersonating
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
CheckWireBuffer(WINSTATIONINFOCLASS InfoClass,
|
||
|
PVOID WireBuf,
|
||
|
ULONG WireBufLen,
|
||
|
PVOID *ppLocalBuf,
|
||
|
PULONG pLocalBufLen);
|
||
|
|
||
|
/*
|
||
|
* Global data
|
||
|
*/
|
||
|
typedef ULONG_PTR (*PFN)();
|
||
|
HMODULE ghNetApiDll = NULL;
|
||
|
PFN pNetGetAnyDCName = NULL;
|
||
|
PFN pNetApiBufferFree = NULL;
|
||
|
|
||
|
/*
|
||
|
* External data
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
_CheckCallerLocalAndSystem()
|
||
|
/*++
|
||
|
|
||
|
Checking caller is calling from local and also is running
|
||
|
under system context
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
BOOL bRevert = FALSE;
|
||
|
UINT LocalFlag;
|
||
|
|
||
|
Status = RpcImpersonateClient( NULL );
|
||
|
if( Status != RPC_S_OK ) {
|
||
|
DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",Status));
|
||
|
Status = STATUS_CANNOT_IMPERSONATE;
|
||
|
goto CLEANUPANDEXIT;
|
||
|
}
|
||
|
|
||
|
bRevert = TRUE;
|
||
|
|
||
|
//
|
||
|
// Inquire if local RPC call
|
||
|
//
|
||
|
Status = I_RpcBindingIsClientLocal(
|
||
|
0, // Active RPC call we are servicing
|
||
|
&LocalFlag
|
||
|
);
|
||
|
|
||
|
if( Status != RPC_S_OK ) {
|
||
|
DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",Status));
|
||
|
Status = STATUS_ACCESS_DENIED;
|
||
|
goto CLEANUPANDEXIT;
|
||
|
}
|
||
|
|
||
|
if( !LocalFlag ) {
|
||
|
DBGPRINT((" Not a local client call\n"));
|
||
|
Status = STATUS_ACCESS_DENIED;
|
||
|
goto CLEANUPANDEXIT;
|
||
|
}
|
||
|
|
||
|
Status = (IsCallerSystem()) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||
|
|
||
|
CLEANUPANDEXIT:
|
||
|
|
||
|
if( TRUE == bRevert ) {
|
||
|
RpcRevertToSelf();
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* xxxWinStationSetInformation
|
||
|
*
|
||
|
* set window station information (worker routine)
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pWinStation (input)
|
||
|
* pointer to citrix window station structure
|
||
|
* WinStationInformationClass (input)
|
||
|
* Specifies the type of information to set at the specified window
|
||
|
* station object.
|
||
|
* pWinStationInformation (input)
|
||
|
* A pointer to a buffer that contains information to set for the
|
||
|
* specified window station. The format and contents of the buffer
|
||
|
* depend on the specified information class being set.
|
||
|
* WinStationInformationLength (input)
|
||
|
* Specifies the length in bytes of the window station information
|
||
|
* buffer.
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - no error
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
xxxWinStationSetInformation( ULONG LogonId,
|
||
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
||
|
PVOID pWinStationInformation,
|
||
|
ULONG WinStationInformationLength )
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PWINSTATION pWinStation;
|
||
|
ULONG cbReturned;
|
||
|
WINSTATION_APIMSG msg;
|
||
|
PWINSTATIONCONFIG pConfig;
|
||
|
ULONG ConfigLength;
|
||
|
PPDPARAMS pPdParams;
|
||
|
ULONG PdParamsLength;
|
||
|
RPC_STATUS RpcStatus;
|
||
|
|
||
|
TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationSetInformation LogonId=%d, Class=%d\n",
|
||
|
LogonId, (ULONG)WinStationInformationClass ));
|
||
|
|
||
|
/*
|
||
|
* Find the WinStation
|
||
|
* Return error if not found or currently terminating.
|
||
|
*/
|
||
|
pWinStation = FindWinStationById( LogonId, FALSE );
|
||
|
if ( !pWinStation )
|
||
|
return( STATUS_CTX_WINSTATION_NOT_FOUND );
|
||
|
if ( pWinStation->Terminating ) {
|
||
|
ReleaseWinStation( pWinStation );
|
||
|
return( STATUS_CTX_CLOSE_PENDING );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Verify that client has SET access
|
||
|
*/
|
||
|
Status = RpcCheckClientAccess( pWinStation, WINSTATION_SET, FALSE );
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
ReleaseWinStation( pWinStation );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
switch ( WinStationInformationClass ) {
|
||
|
|
||
|
case WinStationPdParams :
|
||
|
|
||
|
Status = CheckWireBuffer(WinStationInformationClass,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
&pPdParams,
|
||
|
&PdParamsLength);
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( pWinStation->hStack ) {
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl ) {
|
||
|
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_SET_PARAMS,
|
||
|
pPdParams,
|
||
|
PdParamsLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
else {
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree((PVOID)pPdParams);
|
||
|
break;
|
||
|
|
||
|
|
||
|
case WinStationConfiguration :
|
||
|
|
||
|
Status = CheckWireBuffer(WinStationInformationClass,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
&pConfig,
|
||
|
&ConfigLength);
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Status = _SetConfig( pWinStation,
|
||
|
pConfig,
|
||
|
ConfigLength );
|
||
|
|
||
|
LocalFree((PVOID)pConfig);
|
||
|
break;
|
||
|
|
||
|
case WinStationTrace :
|
||
|
|
||
|
RpcStatus = RpcImpersonateClient( NULL );
|
||
|
if( RpcStatus != RPC_S_OK ) {
|
||
|
Status = STATUS_CANNOT_IMPERSONATE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!IsCallerAdmin() && !IsCallerSystem()) {
|
||
|
Status = STATUS_ACCESS_DENIED;
|
||
|
}
|
||
|
RpcRevertToSelf();
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( WinStationInformationLength < sizeof(ICA_TRACE) ) {
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( pWinStation->hIca ) {
|
||
|
Status = IcaIoControl( pWinStation->hIca,
|
||
|
IOCTL_ICA_SET_TRACE,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationSystemTrace :
|
||
|
|
||
|
RpcStatus = RpcImpersonateClient( NULL );
|
||
|
if( RpcStatus != RPC_S_OK ) {
|
||
|
Status = STATUS_CANNOT_IMPERSONATE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!IsCallerAdmin() && !IsCallerSystem()) {
|
||
|
Status = STATUS_ACCESS_DENIED;
|
||
|
}
|
||
|
RpcRevertToSelf();
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( WinStationInformationLength < sizeof(ICA_TRACE) ) {
|
||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Open ICA device driver
|
||
|
*/
|
||
|
if ( hTrace == NULL ) {
|
||
|
Status = IcaOpen( &hTrace );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
hTrace = NULL;
|
||
|
}
|
||
|
|
||
|
if ( hTrace ) {
|
||
|
Status = IcaIoControl( hTrace,
|
||
|
IOCTL_ICA_SET_SYSTEM_TRACE,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationPrinter :
|
||
|
break;
|
||
|
|
||
|
case WinStationBeep :
|
||
|
|
||
|
if (WinStationInformationLength < sizeof(BEEPINPUT)) {
|
||
|
Status = STATUS_BUFFER_TOO_SMALL ;
|
||
|
break;
|
||
|
}
|
||
|
Status = _SetBeep( pWinStation,
|
||
|
(PBEEPINPUT) pWinStationInformation,
|
||
|
WinStationInformationLength );
|
||
|
break;
|
||
|
|
||
|
case WinStationEncryptionOff :
|
||
|
|
||
|
if ( pWinStation->hStack ) {
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl ) {
|
||
|
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_ENCRYPTION_OFF,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
else {
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationEncryptionPerm :
|
||
|
|
||
|
if ( pWinStation->hStack ) {
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl ) {
|
||
|
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_ENCRYPTION_PERM,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
else {
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationSecureDesktopEnter :
|
||
|
|
||
|
if ( pWinStation->hStack ) {
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl ) {
|
||
|
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_ENCRYPTION_ENTER,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
else {
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationSecureDesktopExit :
|
||
|
|
||
|
if ( pWinStation->hStack ) {
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl ) {
|
||
|
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_ENCRYPTION_EXIT,
|
||
|
pWinStationInformation,
|
||
|
WinStationInformationLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
else {
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* Give focus to winlogon security desktop
|
||
|
* -- used by progman.exe
|
||
|
*/
|
||
|
case WinStationNtSecurity :
|
||
|
|
||
|
/*
|
||
|
* Tell the WinStation to Send Winlogon the CTR-ALT-DEL message
|
||
|
*/
|
||
|
msg.ApiNumber = SMWinStationNtSecurity;
|
||
|
Status = SendWinStationCommand( pWinStation, &msg, 0 );
|
||
|
break;
|
||
|
|
||
|
case WinStationClientData :
|
||
|
//
|
||
|
// Handles multiple client data items. The data buffer
|
||
|
// format is:
|
||
|
// ULONG // Length of next data item
|
||
|
// WINSTATIONCLIENTDATA // Including variable length part
|
||
|
// ULONG // Length of next data item
|
||
|
// WINSTATIONCLIENTDATA // Including variable length part
|
||
|
// etc
|
||
|
//
|
||
|
// WinStationInformationLength is the length of the entire
|
||
|
// data buffer. Keep processing client data items until
|
||
|
// the buffer is exhausted.
|
||
|
//
|
||
|
if ( WinStationInformationLength < sizeof(ULONG) +
|
||
|
sizeof(WINSTATIONCLIENTDATA) )
|
||
|
{
|
||
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( pWinStation->hStack )
|
||
|
{
|
||
|
// Check for availability
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxIcaStackIoControl )
|
||
|
{
|
||
|
ULONG CurLen;
|
||
|
ULONG LenUsed =0;
|
||
|
PBYTE CurPtr = (PBYTE)pWinStationInformation;
|
||
|
|
||
|
while (LenUsed + sizeof(ULONG) < WinStationInformationLength)
|
||
|
{
|
||
|
CurLen = *(ULONG UNALIGNED *)CurPtr;
|
||
|
LenUsed += sizeof(ULONG);
|
||
|
CurPtr += sizeof(ULONG);
|
||
|
|
||
|
if ( (LenUsed + CurLen >= LenUsed) &&
|
||
|
(LenUsed + CurLen <= WinStationInformationLength))
|
||
|
{
|
||
|
Status = pWinStation->pWsx->pWsxIcaStackIoControl(
|
||
|
pWinStation->pWsxContext,
|
||
|
pWinStation->hIca,
|
||
|
pWinStation->hStack,
|
||
|
IOCTL_ICA_STACK_SET_CLIENT_DATA,
|
||
|
CurPtr,
|
||
|
CurLen,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
LenUsed += CurLen;
|
||
|
CurPtr += CurLen;
|
||
|
}else
|
||
|
{
|
||
|
Status = STATUS_INVALID_USER_BUFFER;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WinStationInitialProgram :
|
||
|
|
||
|
/*
|
||
|
* Identify first program, non-consoles only
|
||
|
*/
|
||
|
if ( LogonId != 0 ) {
|
||
|
|
||
|
/*
|
||
|
* Tell the WinStation this is the initial program
|
||
|
*/
|
||
|
msg.ApiNumber = SMWinStationInitialProgram;
|
||
|
Status = SendWinStationCommand( pWinStation, &msg, 0 );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WinStationShadowInfo:
|
||
|
Status = _CheckCallerLocalAndSystem();
|
||
|
if( NT_SUCCESS(Status) ) {
|
||
|
Status = WinStationShadowChangeMode( pWinStation,
|
||
|
(PWINSTATIONSHADOW) pWinStationInformation,
|
||
|
WinStationInformationLength );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WinStationLockedState:
|
||
|
{
|
||
|
|
||
|
BOOL bLockedState;
|
||
|
if (WinStationInformationLength == sizeof(bLockedState))
|
||
|
{
|
||
|
bLockedState = * (LPBOOL) pWinStationInformation;
|
||
|
Status = SetLockedState (pWinStation, bLockedState);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WinStationDisallowAutoReconnect:
|
||
|
{
|
||
|
|
||
|
RpcStatus = RpcImpersonateClient( NULL );
|
||
|
if( RpcStatus != RPC_S_OK ) {
|
||
|
Status = STATUS_CANNOT_IMPERSONATE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!IsCallerSystem()) {
|
||
|
Status = STATUS_ACCESS_DENIED;
|
||
|
}
|
||
|
RpcRevertToSelf();
|
||
|
if (Status != STATUS_SUCCESS) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (WinStationInformationLength == sizeof(BOOLEAN)) {
|
||
|
pWinStation->fDisallowAutoReconnect = * (PBOOLEAN) pWinStationInformation;
|
||
|
} else {
|
||
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WinStationMprNotifyInfo:
|
||
|
{
|
||
|
Status = _CheckCallerLocalAndSystem();
|
||
|
if (Status != STATUS_SUCCESS) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (WinStationInformationLength == sizeof(ExtendedClientCredentials)) {
|
||
|
|
||
|
pExtendedClientCredentials pMprInfo ;
|
||
|
pMprInfo = (pExtendedClientCredentials) pWinStationInformation;
|
||
|
|
||
|
wcsncpy(g_MprNotifyInfo.Domain, pMprInfo->Domain, EXTENDED_DOMAIN_LEN);
|
||
|
g_MprNotifyInfo.Domain[EXTENDED_DOMAIN_LEN] = L'\0';
|
||
|
|
||
|
wcsncpy(g_MprNotifyInfo.UserName, pMprInfo->UserName, EXTENDED_USERNAME_LEN);
|
||
|
g_MprNotifyInfo.UserName[EXTENDED_USERNAME_LEN] = L'\0';
|
||
|
|
||
|
wcsncpy(g_MprNotifyInfo.Password, pMprInfo->Password, EXTENDED_PASSWORD_LEN);
|
||
|
g_MprNotifyInfo.Password[EXTENDED_PASSWORD_LEN] = L'\0';
|
||
|
|
||
|
} else {
|
||
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
/*
|
||
|
* Fail the call
|
||
|
*/
|
||
|
Status = STATUS_INVALID_INFO_CLASS;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ReleaseWinStation( pWinStation );
|
||
|
|
||
|
TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationSetInformation LogonId=%d, Class=%d, Status=0x%x\n",
|
||
|
LogonId, (ULONG)WinStationInformationClass, Status));
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* _SetConfig
|
||
|
*
|
||
|
* set window station configuration
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pWinStation (input)
|
||
|
* pointer to citrix window station structure
|
||
|
* pConfig (input)
|
||
|
* pointer to configuration structure
|
||
|
* Length (input)
|
||
|
* length of configuration structure
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - no error
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_SetConfig( PWINSTATION pWinStation,
|
||
|
PWINSTATIONCONFIG pConfig,
|
||
|
ULONG Length )
|
||
|
{
|
||
|
USERCONFIG UserConfig;
|
||
|
|
||
|
/*
|
||
|
* Validate length
|
||
|
*/
|
||
|
if ( Length < sizeof(WINSTATIONCONFIG) )
|
||
|
return( STATUS_BUFFER_TOO_SMALL );
|
||
|
|
||
|
/*
|
||
|
* Copy structure
|
||
|
*/
|
||
|
pWinStation->Config.Config = *pConfig;
|
||
|
|
||
|
/*
|
||
|
* Merge client data into winstation structure
|
||
|
*/
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxInitializeUserConfig ) {
|
||
|
pWinStation->pWsx->pWsxInitializeUserConfig( pWinStation->pWsxContext,
|
||
|
pWinStation->hStack,
|
||
|
pWinStation->hIcaThinwireChannel,
|
||
|
&pWinStation->Config.Config.User,
|
||
|
&pWinStation->Client.HRes,
|
||
|
&pWinStation->Client.VRes,
|
||
|
&pWinStation->Client.ColorDepth);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If user is logged on -> merge user profile data
|
||
|
*/
|
||
|
if ( pWinStation->UserName[0] ) {
|
||
|
|
||
|
/*
|
||
|
* Read user profile data
|
||
|
*/
|
||
|
_ReadUserProfile( pWinStation->Domain,
|
||
|
pWinStation->UserName,
|
||
|
&UserConfig );
|
||
|
|
||
|
#if NT2195
|
||
|
/*
|
||
|
* Merge user config data into the winstation
|
||
|
*/
|
||
|
MergeUserConfigData( pWinStation, &UserConfig );
|
||
|
|
||
|
#else
|
||
|
// @@@
|
||
|
DbgPrint(("WARNING: _SetConfig is if-def'd out \n" ) );
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Convert any "published app" to absolute path
|
||
|
*/
|
||
|
if ( pWinStation->pWsx &&
|
||
|
pWinStation->pWsx->pWsxConvertPublishedApp ) {
|
||
|
(void) pWinStation->pWsx->pWsxConvertPublishedApp( pWinStation->pWsxContext,
|
||
|
&pWinStation->Config.Config.User);
|
||
|
}
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* _ReadUserProfile
|
||
|
*
|
||
|
* This routine reads the user profile data from the registry
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pDomain (input)
|
||
|
* domain of user
|
||
|
* pUserName (input)
|
||
|
* user name to read
|
||
|
* pUserConfig (output)
|
||
|
* address to return user profile data
|
||
|
*
|
||
|
* EXIT:
|
||
|
* None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
VOID
|
||
|
_ReadUserProfile( PWCHAR pDomain, PWCHAR pUserName, PUSERCONFIG pUserConfig )
|
||
|
{
|
||
|
PWCHAR pServerName;
|
||
|
ULONG Length;
|
||
|
LONG Error;
|
||
|
|
||
|
/*
|
||
|
* Get Domain Controller name and userconfig data.
|
||
|
* If no userconfig data for user then get default values.
|
||
|
*/
|
||
|
if ( ghNetApiDll == NULL ) {
|
||
|
ghNetApiDll = LoadLibrary( L"NETAPI32" );
|
||
|
if ( ghNetApiDll ) {
|
||
|
pNetGetAnyDCName = GetProcAddress( ghNetApiDll, "NetGetAnyDCName" );
|
||
|
pNetApiBufferFree = GetProcAddress( ghNetApiDll, "NetApiBufferFree" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check to make sure we got a server name
|
||
|
*/
|
||
|
if ( pNetGetAnyDCName == NULL ||
|
||
|
pNetGetAnyDCName( NULL, pDomain, (LPBYTE *)&pServerName ) != ERROR_SUCCESS )
|
||
|
pServerName = NULL;
|
||
|
|
||
|
/*
|
||
|
* Read user profile data
|
||
|
*/
|
||
|
Error = RegUserConfigQuery( pServerName,
|
||
|
pUserName,
|
||
|
pUserConfig,
|
||
|
sizeof(USERCONFIG),
|
||
|
&Length );
|
||
|
TRACE((hTrace,TC_ICASRV,TT_API1, "RegUserConfigQuery: \\\\%S\\%S, server %S, Error=%u\n",
|
||
|
pDomain, pUserName, pServerName, Error ));
|
||
|
|
||
|
if ( Error != ERROR_SUCCESS ) {
|
||
|
Error = RegDefaultUserConfigQuery( pServerName, pUserConfig,
|
||
|
sizeof(USERCONFIG), &Length );
|
||
|
TRACE((hTrace,TC_ICASRV,TT_ERROR, "RegDefaultUserConfigQuery, Error=%u\n", Error ));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Free memory
|
||
|
*/
|
||
|
if ( pServerName && pNetApiBufferFree )
|
||
|
pNetApiBufferFree( pServerName );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* _SetBeep
|
||
|
*
|
||
|
* Beep the WinStation
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pWinStation (input)
|
||
|
* pointer to citrix window station structure
|
||
|
* pBeepInput (input)
|
||
|
* pointer to Beep input structure
|
||
|
* Length (input)
|
||
|
* length of Beep input structure
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - no error
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_SetBeep( PWINSTATION pWinStation,
|
||
|
PBEEPINPUT pBeepInput,
|
||
|
ULONG Length)
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
BEEP_SET_PARAMETERS BeepParameters;
|
||
|
IO_STATUS_BLOCK IoStatus;
|
||
|
|
||
|
/*
|
||
|
* Do the regular Beep, so you can support fancy Beeps from
|
||
|
* sound cards.
|
||
|
*/
|
||
|
if ( pWinStation->LogonId == 0 ) {
|
||
|
if ( MessageBeep( pBeepInput->uType ) )
|
||
|
return( STATUS_SUCCESS );
|
||
|
else
|
||
|
return( STATUS_UNSUCCESSFUL );
|
||
|
}
|
||
|
|
||
|
BeepParameters.Frequency = 440;
|
||
|
BeepParameters.Duration = 125;
|
||
|
|
||
|
if ( pWinStation->hIcaBeepChannel ) {
|
||
|
Status = NtDeviceIoControlFile( pWinStation->hIcaBeepChannel,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&IoStatus,
|
||
|
IOCTL_BEEP_SET,
|
||
|
&BeepParameters,
|
||
|
sizeof( BeepParameters ),
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|