FreeRDP/channels/rail/server/rail_main.c
akallabeth 11b7633dc0
[channels] use Stream_BufferAs
For WTSVirtualChannelRead and WTSVirtualChannelWrite use Stream_BufferAs
to cast to correct type.
2024-10-01 10:28:13 +02:00

1732 lines
46 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RAIL Virtual Channel Plugin
*
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/types.h>
#include <freerdp/constants.h>
#include <freerdp/freerdp.h>
#include <freerdp/channels/log.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include "rail_main.h"
#define TAG CHANNELS_TAG("rail.server")
/**
* Sends a single rail PDU on the channel
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send(RailServerContext* context, wStream* s, ULONG length)
{
UINT status = CHANNEL_RC_OK;
ULONG written = 0;
if (!context)
return CHANNEL_RC_BAD_INIT_HANDLE;
if (!WTSVirtualChannelWrite(context->priv->rail_channel, Stream_BufferAs(s, char), length,
&written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
status = ERROR_INTERNAL_ERROR;
}
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16 orderType)
{
char buffer[128] = { 0 };
UINT16 orderLength = 0;
if (!context || !s)
return ERROR_INVALID_PARAMETER;
orderLength = (UINT16)Stream_GetPosition(s);
Stream_SetPosition(s, 0);
rail_write_pdu_header(s, orderType, orderLength);
Stream_SetPosition(s, orderLength);
WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
return rail_send(context, s, orderLength);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_local_move_size_order(wStream* s,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
if (!s || !localMoveSize)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, localMoveSize->windowId); /* WindowId (4 bytes) */
Stream_Write_UINT16(s, localMoveSize->isMoveSizeStart ? 1 : 0); /* IsMoveSizeStart (2 bytes) */
Stream_Write_UINT16(s, localMoveSize->moveSizeType); /* MoveSizeType (2 bytes) */
Stream_Write_UINT16(s, localMoveSize->posX); /* PosX (2 bytes) */
Stream_Write_UINT16(s, localMoveSize->posY); /* PosY (2 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_min_max_info_order(wStream* s, const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
if (!s || !minMaxInfo)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, minMaxInfo->windowId); /* WindowId (4 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxWidth); /* MaxWidth (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxHeight); /* MaxHeight (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxPosX); /* MaxPosX (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxPosY); /* MaxPosY (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->minTrackWidth); /* MinTrackWidth (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->minTrackHeight); /* MinTrackHeight (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxTrackWidth); /* MaxTrackWidth (2 bytes) */
Stream_Write_INT16(s, minMaxInfo->maxTrackHeight); /* MaxTrackHeight (2 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_taskbar_info_order(wStream* s, const RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
{
if (!s || !taskbarInfo)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, taskbarInfo->TaskbarMessage); /* TaskbarMessage (4 bytes) */
Stream_Write_UINT32(s, taskbarInfo->WindowIdTab); /* WindowIdTab (4 bytes) */
Stream_Write_UINT32(s, taskbarInfo->Body); /* Body (4 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
{
if (!s || !langbarInfo)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* LanguageBarStatus (4 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_exec_result_order(wStream* s, const RAIL_EXEC_RESULT_ORDER* execResult)
{
if (!s || !execResult)
return ERROR_INVALID_PARAMETER;
if (execResult->exeOrFile.length > 520 || execResult->exeOrFile.length < 1)
return ERROR_INVALID_DATA;
Stream_Write_UINT16(s, execResult->flags); /* Flags (2 bytes) */
Stream_Write_UINT16(s, execResult->execResult); /* ExecResult (2 bytes) */
Stream_Write_UINT32(s, execResult->rawResult); /* RawResult (4 bytes) */
Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
Stream_Write_UINT16(s, execResult->exeOrFile.length); /* ExeOrFileLength (2 bytes) */
Stream_Write(s, execResult->exeOrFile.string,
execResult->exeOrFile.length); /* ExeOrFile (variable) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_z_order_sync_order(wStream* s, const RAIL_ZORDER_SYNC* zOrderSync)
{
if (!s || !zOrderSync)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, zOrderSync->windowIdMarker); /* WindowIdMarker (4 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_cloak_order(wStream* s, const RAIL_CLOAK* cloak)
{
if (!s || !cloak)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
Stream_Write_UINT8(s, cloak->cloak ? 1 : 0); /* Cloaked (1 byte) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT
rail_write_power_display_request_order(wStream* s,
const RAIL_POWER_DISPLAY_REQUEST* powerDisplayRequest)
{
if (!s || !powerDisplayRequest)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, powerDisplayRequest->active ? 1 : 0); /* Active (4 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_get_app_id_resp_order(wStream* s,
const RAIL_GET_APPID_RESP_ORDER* getAppidResp)
{
if (!s || !getAppidResp)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, getAppidResp->windowId); /* WindowId (4 bytes) */
Stream_Write_UTF16_String(
s, getAppidResp->applicationId,
ARRAYSIZE(getAppidResp->applicationId)); /* ApplicationId (512 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_get_appid_resp_ex_order(wStream* s,
const RAIL_GET_APPID_RESP_EX* getAppidRespEx)
{
if (!s || !getAppidRespEx)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, getAppidRespEx->windowID); /* WindowId (4 bytes) */
Stream_Write_UTF16_String(
s, getAppidRespEx->applicationID,
ARRAYSIZE(getAppidRespEx->applicationID)); /* ApplicationId (520 bytes) */
Stream_Write_UINT32(s, getAppidRespEx->processId); /* ProcessId (4 bytes) */
Stream_Write_UTF16_String(
s, getAppidRespEx->processImageName,
ARRAYSIZE(getAppidRespEx->processImageName)); /* ProcessImageName (520 bytes) */
return ERROR_SUCCESS;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_handshake(RailServerContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !handshake)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_handshake_order(s, handshake);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_HANDSHAKE);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_handshake_ex(RailServerContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !handshakeEx || !context->priv)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_server_set_handshake_ex_flags(context, handshakeEx->railHandshakeFlags);
rail_write_handshake_ex_order(s, handshakeEx);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_HANDSHAKE_EX);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_sysparam(RailServerContext* context,
const RAIL_SYSPARAM_ORDER* sysparam)
{
wStream* s = NULL;
UINT error = 0;
RailServerPrivate* priv = NULL;
BOOL extendedSpiSupported = 0;
if (!context || !sysparam)
return ERROR_INVALID_PARAMETER;
priv = context->priv;
if (!priv)
return ERROR_INVALID_PARAMETER;
extendedSpiSupported = rail_is_extended_spi_supported(context->priv->channelFlags);
s = rail_pdu_init(RAIL_SYSPARAM_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_sysparam_order(s, sysparam, extendedSpiSupported);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_SYSPARAM);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_local_move_size(RailServerContext* context,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !localMoveSize)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_LOCALMOVESIZE_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_local_move_size_order(s, localMoveSize);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_LOCALMOVESIZE);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_min_max_info(RailServerContext* context,
const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !minMaxInfo)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_MINMAXINFO_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_min_max_info_order(s, minMaxInfo);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_MINMAXINFO);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_taskbar_info(RailServerContext* context,
const RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !taskbarInfo)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_TASKBAR_INFO_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_taskbar_info_order(s, taskbarInfo);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_TASKBARINFO);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_langbar_info(RailServerContext* context,
const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !langbarInfo)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_langbar_info_order(s, langbarInfo);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_LANGBARINFO);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_exec_result(RailServerContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !execResult)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_EXEC_RESULT_ORDER_LENGTH + execResult->exeOrFile.length);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_exec_result_order(s, execResult);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_EXEC_RESULT);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_z_order_sync(RailServerContext* context,
const RAIL_ZORDER_SYNC* zOrderSync)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !zOrderSync)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_Z_ORDER_SYNC_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_z_order_sync_order(s, zOrderSync);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_ZORDER_SYNC);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_cloak(RailServerContext* context, const RAIL_CLOAK* cloak)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !cloak)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_CLOAK_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_cloak_order(s, cloak);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_CLOAK);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT
rail_send_server_power_display_request(RailServerContext* context,
const RAIL_POWER_DISPLAY_REQUEST* powerDisplayRequest)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !powerDisplayRequest)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_power_display_request_order(s, powerDisplayRequest);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_POWER_DISPLAY_REQUEST);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error coie
*/
static UINT rail_send_server_get_app_id_resp(RailServerContext* context,
const RAIL_GET_APPID_RESP_ORDER* getAppidResp)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !getAppidResp)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_GET_APPID_RESP_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_get_app_id_resp_order(s, getAppidResp);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_GET_APPID_RESP);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_server_get_appid_resp_ex(RailServerContext* context,
const RAIL_GET_APPID_RESP_EX* getAppidRespEx)
{
wStream* s = NULL;
UINT error = 0;
if (!context || !getAppidRespEx)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_GET_APPID_RESP_EX_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
rail_write_get_appid_resp_ex_order(s, getAppidRespEx);
error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_GET_APPID_RESP_EX);
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* clientStatus)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLIENT_STATUS_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, clientStatus->flags); /* Flags (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_exec_order(wStream* s, RAIL_EXEC_ORDER* exec, char* args[])
{
RAIL_EXEC_ORDER order = { 0 };
UINT16 exeLen = 0;
UINT16 workLen = 0;
UINT16 argLen = 0;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_EXEC_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, exec->flags); /* Flags (2 bytes) */
Stream_Read_UINT16(s, exeLen); /* ExeOrFileLength (2 bytes) */
Stream_Read_UINT16(s, workLen); /* WorkingDirLength (2 bytes) */
Stream_Read_UINT16(s, argLen); /* ArgumentsLength (2 bytes) */
if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)exeLen + workLen + argLen))
return ERROR_INVALID_DATA;
if (exeLen > 0)
{
const size_t len = exeLen / sizeof(WCHAR);
exec->RemoteApplicationProgram = args[0] = Stream_Read_UTF16_String_As_UTF8(s, len, NULL);
if (!exec->RemoteApplicationProgram)
goto fail;
}
if (workLen > 0)
{
const size_t len = workLen / sizeof(WCHAR);
exec->RemoteApplicationWorkingDir = args[1] =
Stream_Read_UTF16_String_As_UTF8(s, len, NULL);
if (!exec->RemoteApplicationWorkingDir)
goto fail;
}
if (argLen > 0)
{
const size_t len = argLen / sizeof(WCHAR);
exec->RemoteApplicationArguments = args[2] = Stream_Read_UTF16_String_As_UTF8(s, len, NULL);
if (!exec->RemoteApplicationArguments)
goto fail;
}
return CHANNEL_RC_OK;
fail:
free(args[0]);
free(args[1]);
free(args[2]);
*exec = order;
return ERROR_INTERNAL_ERROR;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate)
{
BYTE enabled = 0;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_ACTIVATE_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, activate->windowId); /* WindowId (4 bytes) */
Stream_Read_UINT8(s, enabled); /* Enabled (1 byte) */
activate->enabled = (enabled != 0) ? TRUE : FALSE;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_SYSMENU_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, sysmenu->windowId); /* WindowId (4 bytes) */
Stream_Read_INT16(s, sysmenu->left); /* Left (2 bytes) */
Stream_Read_INT16(s, sysmenu->top); /* Top (2 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_SYSCOMMAND_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, syscommand->windowId); /* WindowId (4 bytes) */
Stream_Read_UINT16(s, syscommand->command); /* Command (2 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_NOTIFY_EVENT_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, notifyEvent->windowId); /* WindowId (4 bytes) */
Stream_Read_UINT32(s, notifyEvent->notifyIconId); /* NotifyIconId (4 bytes) */
Stream_Read_UINT32(s, notifyEvent->message); /* Message (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* getAppidReq)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_GET_APPID_REQ_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, getAppidReq->windowId); /* WindowId (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* windowMove)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_WINDOW_MOVE_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, windowMove->windowId); /* WindowId (4 bytes) */
Stream_Read_INT16(s, windowMove->left); /* Left (2 bytes) */
Stream_Read_INT16(s, windowMove->top); /* Top (2 bytes) */
Stream_Read_INT16(s, windowMove->right); /* Right (2 bytes) */
Stream_Read_INT16(s, windowMove->bottom); /* Bottom (2 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_snap_arange_order(wStream* s, RAIL_SNAP_ARRANGE* snapArrange)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_SNAP_ARRANGE_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, snapArrange->windowId); /* WindowId (4 bytes) */
Stream_Read_INT16(s, snapArrange->left); /* Left (2 bytes) */
Stream_Read_INT16(s, snapArrange->top); /* Top (2 bytes) */
Stream_Read_INT16(s, snapArrange->right); /* Right (2 bytes) */
Stream_Read_INT16(s, snapArrange->bottom); /* Bottom (2 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_LANGBAR_INFO_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* LanguageBarStatus (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_language_ime_info_order(wStream* s,
RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_LANGUAGEIME_INFO_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, languageImeInfo->ProfileType); /* ProfileType (4 bytes) */
Stream_Read_UINT16(s, languageImeInfo->LanguageID); /* LanguageID (2 bytes) */
Stream_Read(
s, &languageImeInfo->LanguageProfileCLSID,
sizeof(languageImeInfo->LanguageProfileCLSID)); /* LanguageProfileCLSID (16 bytes) */
Stream_Read(s, &languageImeInfo->ProfileGUID,
sizeof(languageImeInfo->ProfileGUID)); /* ProfileGUID (16 bytes) */
Stream_Read_UINT32(s, languageImeInfo->KeyboardLayout); /* KeyboardLayout (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_compartment_info_order(wStream* s,
RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
{
BYTE cloaked = 0;
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLOAK_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
cloak->cloak = (cloaked != 0) ? TRUE : FALSE;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_handshake_order(RailServerContext* context,
RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
{
UINT error = 0;
if (!context || !handshake || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_handshake_order(s, handshake)))
{
WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientHandshake, error, context, handshake);
if (error)
WLog_ERR(TAG, "context.ClientHandshake failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_client_status_order(RailServerContext* context,
RAIL_CLIENT_STATUS_ORDER* clientStatus, wStream* s)
{
UINT error = 0;
if (!context || !clientStatus || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_client_status_order(s, clientStatus)))
{
WLog_ERR(TAG, "rail_read_client_status_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientClientStatus, error, context, clientStatus);
if (error)
WLog_ERR(TAG, "context.ClientClientStatus failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_exec_order(RailServerContext* context, wStream* s)
{
UINT error = 0;
char* args[3] = { 0 };
RAIL_EXEC_ORDER exec = { 0 };
if (!context || !s)
return ERROR_INVALID_PARAMETER;
error = rail_read_exec_order(s, &exec, args);
if (error)
{
WLog_ERR(TAG, "rail_read_client_status_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientExec, error, context, &exec);
if (error)
WLog_ERR(TAG, "context.Exec failed with error %" PRIu32 "", error);
free(args[0]);
free(args[1]);
free(args[2]);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_sysparam_order(RailServerContext* context,
RAIL_SYSPARAM_ORDER* sysparam, wStream* s)
{
UINT error = 0;
BOOL extendedSpiSupported = 0;
if (!context || !sysparam || !s)
return ERROR_INVALID_PARAMETER;
extendedSpiSupported = rail_is_extended_spi_supported(context->priv->channelFlags);
if ((error = rail_read_sysparam_order(s, sysparam, extendedSpiSupported)))
{
WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientSysparam, error, context, sysparam);
if (error)
WLog_ERR(TAG, "context.ClientSysparam failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_activate_order(RailServerContext* context,
RAIL_ACTIVATE_ORDER* activate, wStream* s)
{
UINT error = 0;
if (!context || !activate || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_activate_order(s, activate)))
{
WLog_ERR(TAG, "rail_read_activate_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientActivate, error, context, activate);
if (error)
WLog_ERR(TAG, "context.ClientActivate failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_sysmenu_order(RailServerContext* context, RAIL_SYSMENU_ORDER* sysmenu,
wStream* s)
{
UINT error = 0;
if (!context || !sysmenu || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_sysmenu_order(s, sysmenu)))
{
WLog_ERR(TAG, "rail_read_sysmenu_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientSysmenu, error, context, sysmenu);
if (error)
WLog_ERR(TAG, "context.ClientSysmenu failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_syscommand_order(RailServerContext* context,
RAIL_SYSCOMMAND_ORDER* syscommand, wStream* s)
{
UINT error = 0;
if (!context || !syscommand || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_syscommand_order(s, syscommand)))
{
WLog_ERR(TAG, "rail_read_syscommand_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientSyscommand, error, context, syscommand);
if (error)
WLog_ERR(TAG, "context.ClientSyscommand failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_notify_event_order(RailServerContext* context,
RAIL_NOTIFY_EVENT_ORDER* notifyEvent, wStream* s)
{
UINT error = 0;
if (!context || !notifyEvent || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_notify_event_order(s, notifyEvent)))
{
WLog_ERR(TAG, "rail_read_notify_event_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientNotifyEvent, error, context, notifyEvent);
if (error)
WLog_ERR(TAG, "context.ClientNotifyEvent failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_window_move_order(RailServerContext* context,
RAIL_WINDOW_MOVE_ORDER* windowMove, wStream* s)
{
UINT error = 0;
if (!context || !windowMove || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_window_move_order(s, windowMove)))
{
WLog_ERR(TAG, "rail_read_window_move_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientWindowMove, error, context, windowMove);
if (error)
WLog_ERR(TAG, "context.ClientWindowMove failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_snap_arrange_order(RailServerContext* context,
RAIL_SNAP_ARRANGE* snapArrange, wStream* s)
{
UINT error = 0;
if (!context || !snapArrange || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_snap_arange_order(s, snapArrange)))
{
WLog_ERR(TAG, "rail_read_snap_arange_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientSnapArrange, error, context, snapArrange);
if (error)
WLog_ERR(TAG, "context.ClientSnapArrange failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_get_appid_req_order(RailServerContext* context,
RAIL_GET_APPID_REQ_ORDER* getAppidReq, wStream* s)
{
UINT error = 0;
if (!context || !getAppidReq || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_get_appid_req_order(s, getAppidReq)))
{
WLog_ERR(TAG, "rail_read_get_appid_req_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientGetAppidReq, error, context, getAppidReq);
if (error)
WLog_ERR(TAG, "context.ClientGetAppidReq failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_langbar_info_order(RailServerContext* context,
RAIL_LANGBAR_INFO_ORDER* langbarInfo, wStream* s)
{
UINT error = 0;
if (!context || !langbarInfo || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_langbar_info_order(s, langbarInfo)))
{
WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientLangbarInfo, error, context, langbarInfo);
if (error)
WLog_ERR(TAG, "context.ClientLangbarInfo failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_language_ime_info_order(RailServerContext* context,
RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo,
wStream* s)
{
UINT error = 0;
if (!context || !languageImeInfo || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_language_ime_info_order(s, languageImeInfo)))
{
WLog_ERR(TAG, "rail_read_language_ime_info_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientLanguageImeInfo, error, context, languageImeInfo);
if (error)
WLog_ERR(TAG, "context.ClientLanguageImeInfo failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_compartment_info(RailServerContext* context,
RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo,
wStream* s)
{
UINT error = 0;
if (!context || !compartmentInfo || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_compartment_info_order(s, compartmentInfo)))
{
WLog_ERR(TAG, "rail_read_compartment_info_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientCompartmentInfo, error, context, compartmentInfo);
if (error)
WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_recv_client_cloak_order(RailServerContext* context, RAIL_CLOAK* cloak, wStream* s)
{
UINT error = 0;
if (!context || !cloak || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_cloak_order(s, cloak)))
{
WLog_ERR(TAG, "rail_read_cloak_order failed with error %" PRIu32 "!", error);
return error;
}
IFCALLRET(context->ClientCloak, error, context, cloak);
if (error)
WLog_ERR(TAG, "context.Cloak failed with error %" PRIu32 "", error);
return error;
}
static UINT rail_recv_client_text_scale_order(RailServerContext* context, wStream* s)
{
UINT error = CHANNEL_RC_OK;
UINT32 TextScaleFactor = 0;
if (!context || !s)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, TextScaleFactor);
IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
if (error)
WLog_ERR(TAG, "context.TextScale failed with error %" PRIu32 "", error);
return error;
}
static UINT rail_recv_client_caret_blink(RailServerContext* context, wStream* s)
{
UINT error = CHANNEL_RC_OK;
UINT32 CaretBlinkRate = 0;
if (!context || !s)
return ERROR_INVALID_PARAMETER;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, CaretBlinkRate);
IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
if (error)
WLog_ERR(TAG, "context.CaretBlinkRate failed with error %" PRIu32 "", error);
return error;
}
static DWORD WINAPI rail_server_thread(LPVOID arg)
{
RailServerContext* context = (RailServerContext*)arg;
RailServerPrivate* priv = context->priv;
DWORD status = 0;
DWORD nCount = 0;
HANDLE events[8];
UINT error = CHANNEL_RC_OK;
events[nCount++] = priv->channelEvent;
events[nCount++] = priv->stopEvent;
while (TRUE)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
break;
}
status = WaitForSingleObject(context->priv->stopEvent, 0);
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
break;
}
if (status == WAIT_OBJECT_0)
break;
status = WaitForSingleObject(context->priv->channelEvent, 0);
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(
TAG,
"WaitForSingleObject(context->priv->channelEvent, 0) failed with error %" PRIu32
"!",
error);
break;
}
if (status == WAIT_OBJECT_0)
{
if ((error = rail_server_handle_messages(context)))
{
WLog_ERR(TAG, "rail_server_handle_messages failed with error %" PRIu32 "", error);
break;
}
}
}
if (error && context->rdpcontext)
setChannelError(context->rdpcontext, error, "rail_server_thread reported an error");
ExitThread(error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_start(RailServerContext* context)
{
void* buffer = NULL;
DWORD bytesReturned = 0;
RailServerPrivate* priv = context->priv;
UINT error = ERROR_INTERNAL_ERROR;
priv->rail_channel =
WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RAIL_SVC_CHANNEL_NAME);
if (!priv->rail_channel)
{
WLog_ERR(TAG, "WTSVirtualChannelOpen failed!");
return error;
}
if (!WTSVirtualChannelQuery(priv->rail_channel, WTSVirtualEventHandle, &buffer,
&bytesReturned) ||
(bytesReturned != sizeof(HANDLE)))
{
WLog_ERR(TAG,
"error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
"size(%" PRIu32 ")",
bytesReturned);
if (buffer)
WTSFreeMemory(buffer);
goto out_close;
}
CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
context->priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!context->priv->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
goto out_close;
}
context->priv->thread = CreateThread(NULL, 0, rail_server_thread, (void*)context, 0, NULL);
if (!context->priv->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
goto out_stop_event;
}
return CHANNEL_RC_OK;
out_stop_event:
(void)CloseHandle(context->priv->stopEvent);
context->priv->stopEvent = NULL;
out_close:
(void)WTSVirtualChannelClose(context->priv->rail_channel);
context->priv->rail_channel = NULL;
return error;
}
static BOOL rail_server_stop(RailServerContext* context)
{
RailServerPrivate* priv = context->priv;
if (priv->thread)
{
(void)SetEvent(priv->stopEvent);
if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
{
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
return FALSE;
}
(void)CloseHandle(priv->thread);
(void)CloseHandle(priv->stopEvent);
priv->thread = NULL;
priv->stopEvent = NULL;
}
if (priv->rail_channel)
{
(void)WTSVirtualChannelClose(priv->rail_channel);
priv->rail_channel = NULL;
}
priv->channelEvent = NULL;
return TRUE;
}
RailServerContext* rail_server_context_new(HANDLE vcm)
{
RailServerContext* context = NULL;
RailServerPrivate* priv = NULL;
context = (RailServerContext*)calloc(1, sizeof(RailServerContext));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
return NULL;
}
context->vcm = vcm;
context->Start = rail_server_start;
context->Stop = rail_server_stop;
context->ServerHandshake = rail_send_server_handshake;
context->ServerHandshakeEx = rail_send_server_handshake_ex;
context->ServerSysparam = rail_send_server_sysparam;
context->ServerLocalMoveSize = rail_send_server_local_move_size;
context->ServerMinMaxInfo = rail_send_server_min_max_info;
context->ServerTaskbarInfo = rail_send_server_taskbar_info;
context->ServerLangbarInfo = rail_send_server_langbar_info;
context->ServerExecResult = rail_send_server_exec_result;
context->ServerGetAppidResp = rail_send_server_get_app_id_resp;
context->ServerZOrderSync = rail_send_server_z_order_sync;
context->ServerCloak = rail_send_server_cloak;
context->ServerPowerDisplayRequest = rail_send_server_power_display_request;
context->ServerGetAppidRespEx = rail_send_server_get_appid_resp_ex;
context->priv = priv = (RailServerPrivate*)calloc(1, sizeof(RailServerPrivate));
if (!priv)
{
WLog_ERR(TAG, "calloc failed!");
goto out_free;
}
/* Create shared input stream */
priv->input_stream = Stream_New(NULL, 4096);
if (!priv->input_stream)
{
WLog_ERR(TAG, "Stream_New failed!");
goto out_free_priv;
}
return context;
out_free_priv:
free(context->priv);
out_free:
free(context);
return NULL;
}
void rail_server_context_free(RailServerContext* context)
{
if (context->priv)
Stream_Free(context->priv->input_stream, TRUE);
free(context->priv);
free(context);
}
void rail_server_set_handshake_ex_flags(RailServerContext* context, DWORD flags)
{
RailServerPrivate* priv = NULL;
if (!context || !context->priv)
return;
priv = context->priv;
priv->channelFlags = flags;
}
UINT rail_server_handle_messages(RailServerContext* context)
{
char buffer[128] = { 0 };
UINT status = CHANNEL_RC_OK;
DWORD bytesReturned = 0;
UINT16 orderType = 0;
UINT16 orderLength = 0;
RailServerPrivate* priv = context->priv;
wStream* s = priv->input_stream;
/* Read header */
if (!Stream_EnsureRemainingCapacity(s, RAIL_PDU_HEADER_LENGTH))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed, RAIL_PDU_HEADER_LENGTH");
return CHANNEL_RC_NO_MEMORY;
}
if (!WTSVirtualChannelRead(priv->rail_channel, 0, Stream_Pointer(s), RAIL_PDU_HEADER_LENGTH,
&bytesReturned))
{
if (GetLastError() == ERROR_NO_DATA)
return ERROR_NO_DATA;
WLog_ERR(TAG, "channel connection closed");
return ERROR_INTERNAL_ERROR;
}
/* Parse header */
if ((status = rail_read_pdu_header(s, &orderType, &orderLength)) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", status);
return status;
}
if (!Stream_EnsureRemainingCapacity(s, orderLength - RAIL_PDU_HEADER_LENGTH))
{
WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed, orderLength - RAIL_PDU_HEADER_LENGTH");
return CHANNEL_RC_NO_MEMORY;
}
/* Read body */
if (!WTSVirtualChannelRead(priv->rail_channel, 0, Stream_Pointer(s),
orderLength - RAIL_PDU_HEADER_LENGTH, &bytesReturned))
{
if (GetLastError() == ERROR_NO_DATA)
return ERROR_NO_DATA;
WLog_ERR(TAG, "channel connection closed");
return ERROR_INTERNAL_ERROR;
}
WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
switch (orderType)
{
case TS_RAIL_ORDER_HANDSHAKE:
{
RAIL_HANDSHAKE_ORDER handshake;
return rail_recv_client_handshake_order(context, &handshake, s);
}
case TS_RAIL_ORDER_CLIENTSTATUS:
{
RAIL_CLIENT_STATUS_ORDER clientStatus;
return rail_recv_client_client_status_order(context, &clientStatus, s);
}
case TS_RAIL_ORDER_EXEC:
return rail_recv_client_exec_order(context, s);
case TS_RAIL_ORDER_SYSPARAM:
{
RAIL_SYSPARAM_ORDER sysparam = { 0 };
return rail_recv_client_sysparam_order(context, &sysparam, s);
}
case TS_RAIL_ORDER_ACTIVATE:
{
RAIL_ACTIVATE_ORDER activate;
return rail_recv_client_activate_order(context, &activate, s);
}
case TS_RAIL_ORDER_SYSMENU:
{
RAIL_SYSMENU_ORDER sysmenu;
return rail_recv_client_sysmenu_order(context, &sysmenu, s);
}
case TS_RAIL_ORDER_SYSCOMMAND:
{
RAIL_SYSCOMMAND_ORDER syscommand;
return rail_recv_client_syscommand_order(context, &syscommand, s);
}
case TS_RAIL_ORDER_NOTIFY_EVENT:
{
RAIL_NOTIFY_EVENT_ORDER notifyEvent;
return rail_recv_client_notify_event_order(context, &notifyEvent, s);
}
case TS_RAIL_ORDER_WINDOWMOVE:
{
RAIL_WINDOW_MOVE_ORDER windowMove;
return rail_recv_client_window_move_order(context, &windowMove, s);
}
case TS_RAIL_ORDER_SNAP_ARRANGE:
{
RAIL_SNAP_ARRANGE snapArrange;
return rail_recv_client_snap_arrange_order(context, &snapArrange, s);
}
case TS_RAIL_ORDER_GET_APPID_REQ:
{
RAIL_GET_APPID_REQ_ORDER getAppidReq;
return rail_recv_client_get_appid_req_order(context, &getAppidReq, s);
}
case TS_RAIL_ORDER_LANGBARINFO:
{
RAIL_LANGBAR_INFO_ORDER langbarInfo;
return rail_recv_client_langbar_info_order(context, &langbarInfo, s);
}
case TS_RAIL_ORDER_LANGUAGEIMEINFO:
{
RAIL_LANGUAGEIME_INFO_ORDER languageImeInfo;
return rail_recv_client_language_ime_info_order(context, &languageImeInfo, s);
}
case TS_RAIL_ORDER_COMPARTMENTINFO:
{
RAIL_COMPARTMENT_INFO_ORDER compartmentInfo;
return rail_recv_client_compartment_info(context, &compartmentInfo, s);
}
case TS_RAIL_ORDER_CLOAK:
{
RAIL_CLOAK cloak;
return rail_recv_client_cloak_order(context, &cloak, s);
}
case TS_RAIL_ORDER_TEXTSCALEINFO:
{
return rail_recv_client_text_scale_order(context, s);
}
case TS_RAIL_ORDER_CARETBLINKINFO:
{
return rail_recv_client_caret_blink(context, s);
}
default:
WLog_ERR(TAG, "Unknown RAIL PDU order received.");
return ERROR_INVALID_DATA;
}
}