diff options
Diffstat (limited to 'channels/rail/rail_common.c')
-rw-r--r-- | channels/rail/rail_common.c | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c new file mode 100644 index 0000000..fb6bc80 --- /dev/null +++ b/channels/rail/rail_common.c @@ -0,0 +1,591 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL common functions + * + * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com> + * Copyright 2011 Vic Lee + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.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 "rail_common.h" + +#include <winpr/crt.h> +#include <freerdp/channels/log.h> + +#define TAG CHANNELS_TAG("rail.common") + +const char* rail_get_order_type_string(UINT16 orderType) +{ + switch (orderType) + { + case TS_RAIL_ORDER_EXEC: + return "TS_RAIL_ORDER_EXEC"; + case TS_RAIL_ORDER_ACTIVATE: + return "TS_RAIL_ORDER_ACTIVATE"; + case TS_RAIL_ORDER_SYSPARAM: + return "TS_RAIL_ORDER_SYSPARAM"; + case TS_RAIL_ORDER_SYSCOMMAND: + return "TS_RAIL_ORDER_SYSCOMMAND"; + case TS_RAIL_ORDER_HANDSHAKE: + return "TS_RAIL_ORDER_HANDSHAKE"; + case TS_RAIL_ORDER_NOTIFY_EVENT: + return "TS_RAIL_ORDER_NOTIFY_EVENT"; + case TS_RAIL_ORDER_WINDOWMOVE: + return "TS_RAIL_ORDER_WINDOWMOVE"; + case TS_RAIL_ORDER_LOCALMOVESIZE: + return "TS_RAIL_ORDER_LOCALMOVESIZE"; + case TS_RAIL_ORDER_MINMAXINFO: + return "TS_RAIL_ORDER_MINMAXINFO"; + case TS_RAIL_ORDER_CLIENTSTATUS: + return "TS_RAIL_ORDER_CLIENTSTATUS"; + case TS_RAIL_ORDER_SYSMENU: + return "TS_RAIL_ORDER_SYSMENU"; + case TS_RAIL_ORDER_LANGBARINFO: + return "TS_RAIL_ORDER_LANGBARINFO"; + case TS_RAIL_ORDER_GET_APPID_REQ: + return "TS_RAIL_ORDER_GET_APPID_REQ"; + case TS_RAIL_ORDER_GET_APPID_RESP: + return "TS_RAIL_ORDER_GET_APPID_RESP"; + case TS_RAIL_ORDER_TASKBARINFO: + return "TS_RAIL_ORDER_TASKBARINFO"; + case TS_RAIL_ORDER_LANGUAGEIMEINFO: + return "TS_RAIL_ORDER_LANGUAGEIMEINFO"; + case TS_RAIL_ORDER_COMPARTMENTINFO: + return "TS_RAIL_ORDER_COMPARTMENTINFO"; + case TS_RAIL_ORDER_HANDSHAKE_EX: + return "TS_RAIL_ORDER_HANDSHAKE_EX"; + case TS_RAIL_ORDER_ZORDER_SYNC: + return "TS_RAIL_ORDER_ZORDER_SYNC"; + case TS_RAIL_ORDER_CLOAK: + return "TS_RAIL_ORDER_CLOAK"; + case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST: + return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST"; + case TS_RAIL_ORDER_SNAP_ARRANGE: + return "TS_RAIL_ORDER_SNAP_ARRANGE"; + case TS_RAIL_ORDER_GET_APPID_RESP_EX: + return "TS_RAIL_ORDER_GET_APPID_RESP_EX"; + case TS_RAIL_ORDER_EXEC_RESULT: + return "TS_RAIL_ORDER_EXEC_RESULT"; + case TS_RAIL_ORDER_TEXTSCALEINFO: + return "TS_RAIL_ORDER_TEXTSCALEINFO"; + case TS_RAIL_ORDER_CARETBLINKINFO: + return "TS_RAIL_ORDER_CARETBLINKINFO"; + default: + return "TS_RAIL_ORDER_UNKNOWN"; + } +} + +const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length) +{ + _snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType), + orderType); + return buffer; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength) +{ + if (!s || !orderType || !orderLength) + return ERROR_INVALID_PARAMETER; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */ + Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */ + return CHANNEL_RC_OK; +} + +void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength) +{ + Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */ + Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ +} + +wStream* rail_pdu_init(size_t length) +{ + wStream* s = NULL; + s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH); + + if (!s) + return NULL; + + Stream_Seek(s, RAIL_PDU_HEADER_LENGTH); + return s; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake) +{ + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */ + return CHANNEL_RC_OK; +} + +void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake) +{ + Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */ +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx) +{ + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ + Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */ + return CHANNEL_RC_OK; +} + +void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) +{ + Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ + Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */ +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string) +{ + if (!s || !unicode_string) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */ + Stream_Write(s, unicode_string->string, unicode_string->length); /* string */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string) +{ + size_t length = 0; + + if (!s || !unicode_string) + return ERROR_INVALID_PARAMETER; + + length = unicode_string->length; + + if (length > 0) + { + if (!Stream_EnsureRemainingCapacity(s, length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write(s, unicode_string->string, length); /* string */ + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast) +{ + if (!s || !highContrast) + return ERROR_INVALID_PARAMETER; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */ + Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */ + + if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */ + return ERROR_INTERNAL_ERROR; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast) +{ + UINT32 colorSchemeLength = 0; + + if (!s || !highContrast) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 8)) + return CHANNEL_RC_NO_MEMORY; + + colorSchemeLength = highContrast->colorScheme.length + 2; + Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */ + return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */ +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys) +{ + if (!s || !filterKeys) + return ERROR_INVALID_PARAMETER; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 20)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, filterKeys->Flags); + Stream_Read_UINT32(s, filterKeys->WaitTime); + Stream_Read_UINT32(s, filterKeys->DelayTime); + Stream_Read_UINT32(s, filterKeys->RepeatTime); + Stream_Read_UINT32(s, filterKeys->BounceTime); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys) +{ + if (!s || !filterKeys) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 20)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT32(s, filterKeys->Flags); + Stream_Write_UINT32(s, filterKeys->WaitTime); + Stream_Write_UINT32(s, filterKeys->DelayTime); + Stream_Write_UINT32(s, filterKeys->RepeatTime); + Stream_Write_UINT32(s, filterKeys->BounceTime); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported) +{ + BYTE body = 0; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 5)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ + + sysparam->params = 0; /* bitflags of received params */ + + switch (sysparam->param) + { + /* Client sysparams */ + case SPI_SET_DRAG_FULL_WINDOWS: + sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->dragFullWindows = body != 0; + break; + + case SPI_SET_KEYBOARD_CUES: + sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardCues = body != 0; + break; + + case SPI_SET_KEYBOARD_PREF: + sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardPref = body != 0; + break; + + case SPI_SET_MOUSE_BUTTON_SWAP: + sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->mouseButtonSwap = body != 0; + break; + + case SPI_SET_WORK_AREA: + sysparam->params |= SPI_MASK_SET_WORK_AREA; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */ + break; + + case SPI_DISPLAY_CHANGE: + sysparam->params |= SPI_MASK_DISPLAY_CHANGE; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */ + break; + + case SPI_TASKBAR_POS: + sysparam->params |= SPI_MASK_TASKBAR_POS; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */ + break; + + case SPI_SET_HIGH_CONTRAST: + sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST; + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) + return ERROR_INVALID_DATA; + + error = rail_read_high_contrast(s, &sysparam->highContrast); + break; + + case SPI_SETCARETWIDTH: + sysparam->params |= SPI_MASK_SET_CARET_WIDTH; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, sysparam->caretWidth); + + if (sysparam->caretWidth < 0x0001) + return ERROR_INVALID_DATA; + + break; + + case SPI_SETSTICKYKEYS: + sysparam->params |= SPI_MASK_SET_STICKY_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, sysparam->stickyKeys); + break; + + case SPI_SETTOGGLEKEYS: + sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, sysparam->toggleKeys); + break; + + case SPI_SETFILTERKEYS: + sysparam->params |= SPI_MASK_SET_FILTER_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 20)) + return ERROR_INVALID_DATA; + + error = rail_read_filterkeys(s, &sysparam->filterKeys); + break; + + /* Server sysparams */ + case SPI_SETSCREENSAVEACTIVE: + sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE; + + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveActive = body != 0; + break; + + case SPI_SETSCREENSAVESECURE: + sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE; + + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveSecure = body != 0; + break; + + default: + break; + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 err2or code + */ +UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam, + BOOL extendedSpiSupported) +{ + BYTE body = 0; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 12)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ + + switch (sysparam->param) + { + /* Client sysparams */ + case SPI_SET_DRAG_FULL_WINDOWS: + body = sysparam->dragFullWindows ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_KEYBOARD_CUES: + body = sysparam->keyboardCues ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_KEYBOARD_PREF: + body = sysparam->keyboardPref ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_MOUSE_BUTTON_SWAP: + body = sysparam->mouseButtonSwap ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_WORK_AREA: + Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */ + break; + + case SPI_DISPLAY_CHANGE: + Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */ + break; + + case SPI_TASKBAR_POS: + Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */ + break; + + case SPI_SET_HIGH_CONTRAST: + error = rail_write_high_contrast(s, &sysparam->highContrast); + break; + + case SPI_SETCARETWIDTH: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (sysparam->caretWidth < 0x0001) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->caretWidth); + break; + + case SPI_SETSTICKYKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->stickyKeys); + break; + + case SPI_SETTOGGLEKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->toggleKeys); + break; + + case SPI_SETFILTERKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + error = rail_write_filterkeys(s, &sysparam->filterKeys); + break; + + /* Server sysparams */ + case SPI_SETSCREENSAVEACTIVE: + body = sysparam->setScreenSaveActive ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SETSCREENSAVESECURE: + body = sysparam->setScreenSaveSecure ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + default: + return ERROR_INVALID_PARAMETER; + } + + return error; +} + +BOOL rail_is_extended_spi_supported(UINT32 channelFlags) +{ + return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) ? TRUE : FALSE; +} |