diff --git a/channels/rail/CMakeLists.txt b/channels/rail/CMakeLists.txt index 84100dcbd..d372dda35 100644 --- a/channels/rail/CMakeLists.txt +++ b/channels/rail/CMakeLists.txt @@ -20,3 +20,7 @@ define_channel("rail") if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/rail/client/rail_main.c b/channels/rail/client/rail_main.c index ce58070f0..0c0786ce7 100644 --- a/channels/rail/client/rail_main.c +++ b/channels/rail/client/rail_main.c @@ -129,12 +129,12 @@ static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDE if (!exeOrFile) return ERROR_INVALID_PARAMETER; - if (!rail_string_to_unicode_string(exec->RemoteApplicationProgram, - &ruExeOrFile) || /* RemoteApplicationProgram */ - !rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir, - &ruWorkingDir) || /* ShellWorkingDirectory */ - !rail_string_to_unicode_string(exec->RemoteApplicationArguments, - &ruArguments)) /* RemoteApplicationCmdLine */ + if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram, + &ruExeOrFile) || /* RemoteApplicationProgram */ + !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir, + &ruWorkingDir) || /* ShellWorkingDirectory */ + !utf8_string_to_rail_string(exec->RemoteApplicationArguments, + &ruArguments)) /* RemoteApplicationCmdLine */ error = ERROR_INTERNAL_ERROR; else error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments); @@ -219,7 +219,9 @@ static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ return CHANNEL_RC_NO_MEMORY; } - if ((error = rail_write_client_sysparam_order(rail, s, sysparam))) + if ((error = rail_write_sysparam_order( + s, sysparam, + (rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) != 0))) { WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error); Stream_Free(s, TRUE); @@ -331,20 +333,6 @@ static UINT rail_client_system_param(RailClientContext* context, return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_system_param(RailClientContext* context, - const RAIL_SYSPARAM_ORDER* sysparam) -{ - if (!context || !sysparam) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - /** * Function description * @@ -378,36 +366,6 @@ static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHA return rail_send_handshake_order(rail, handshake); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake) -{ - if (!context || !handshake) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_handshake_ex(RailClientContext* context, - const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) -{ - railPlugin* rail; - - if (!context || !handshakeEx) - return ERROR_INVALID_PARAMETER; - - rail = (railPlugin*)context->handle; - return CHANNEL_RC_OK; -} - /** * Function description * @@ -442,34 +400,6 @@ static UINT rail_client_window_move(RailClientContext* context, return rail_send_client_window_move_order(rail, windowMove); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_local_move_size(RailClientContext* context, - const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) -{ - if (!context || !localMoveSize) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_min_max_info(RailClientContext* context, - const RAIL_MINMAXINFO_ORDER* minMaxInfo) -{ - if (!context || !minMaxInfo) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - /** * Function description * @@ -520,20 +450,6 @@ static UINT rail_client_language_bar_info(RailClientContext* context, return rail_send_client_langbar_info_order(rail, langBarInfo); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_language_bar_info(RailClientContext* context, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo) -{ - if (!context || !langBarInfo) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - static UINT rail_client_language_ime_info(RailClientContext* context, const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo) { @@ -546,20 +462,6 @@ static UINT rail_client_language_ime_info(RailClientContext* context, return rail_send_client_languageime_info_order(rail, langImeInfo); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_execute_result(RailClientContext* context, - const RAIL_EXEC_RESULT_ORDER* execResult) -{ - if (!context || !execResult) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - /** * Function description * @@ -577,6 +479,18 @@ static UINT rail_client_get_appid_request(RailClientContext* context, return rail_send_client_get_appid_req_order(rail, getAppIdReq); } +static UINT rail_client_compartment_info(RailClientContext* context, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + railPlugin* rail; + + if (!context || !compartmentInfo || !context->handle) + return ERROR_INVALID_PARAMETER; + + rail = (railPlugin*)context->handle; + return rail_send_client_compartment_info_order(rail, compartmentInfo); +} + static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak) { railPlugin* rail; @@ -585,7 +499,7 @@ static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloa return ERROR_INVALID_PARAMETER; rail = (railPlugin*)context->handle; - return rail_send_client_order_cloak_order(rail, cloak); + return rail_send_client_cloak_order(rail, cloak); } static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap) @@ -596,21 +510,7 @@ static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP return ERROR_INVALID_PARAMETER; rail = (railPlugin*)context->handle; - return rail_send_client_order_snap_arrange_order(rail, snap); -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_get_appid_response(RailClientContext* context, - const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) -{ - if (!context || !getAppIdResp) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ + return rail_send_client_snap_arrange_order(rail, snap); } /** @@ -645,7 +545,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, void* pDa data_in = rail->data_in; - if (!Stream_EnsureRemainingCapacity(data_in, (int)dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; @@ -774,6 +674,7 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg) */ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength) { + RailClientContext* context = rail_get_client_interface(rail); UINT status; status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle, rail->channelDef.name, @@ -786,6 +687,15 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, return status; } + if (context) + { + IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake); + + if (status != CHANNEL_RC_OK) + WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); + } + rail->queue = MessageQueue_New(NULL); if (!rail->queue) @@ -919,9 +829,11 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } + /* Default to automatically replying to server handshakes */ + rail->sendHandshake = TRUE; rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), "rail"); + sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && @@ -941,25 +853,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p context->ClientExecute = rail_client_execute; context->ClientActivate = rail_client_activate; context->ClientSystemParam = rail_client_system_param; - context->ServerSystemParam = rail_server_system_param; context->ClientSystemCommand = rail_client_system_command; context->ClientHandshake = rail_client_handshake; - context->ServerHandshake = rail_server_handshake; - context->ServerHandshakeEx = rail_server_handshake_ex; context->ClientNotifyEvent = rail_client_notify_event; context->ClientWindowMove = rail_client_window_move; - context->ServerLocalMoveSize = rail_server_local_move_size; - context->ServerMinMaxInfo = rail_server_min_max_info; context->ClientInformation = rail_client_information; context->ClientSystemMenu = rail_client_system_menu; context->ClientLanguageBarInfo = rail_client_language_bar_info; - context->ServerLanguageBarInfo = rail_server_language_bar_info; context->ClientLanguageIMEInfo = rail_client_language_ime_info; - context->ServerExecuteResult = rail_server_execute_result; context->ClientGetAppIdRequest = rail_client_get_appid_request; - context->ServerGetAppIdResponse = rail_server_get_appid_response; context->ClientSnapArrange = rail_client_snap_arrange; context->ClientCloak = rail_client_cloak; + context->ClientCompartmentInfo = rail_client_compartment_info; rail->rdpcontext = pEntryPointsEx->context; rail->context = context; isFreerdp = TRUE; diff --git a/channels/rail/client/rail_main.h b/channels/rail/client/rail_main.h index 577a21b39..63e522efb 100644 --- a/channels/rail/client/rail_main.h +++ b/channels/rail/client/rail_main.h @@ -53,6 +53,7 @@ struct rail_plugin DWORD channelBuildNumber; DWORD channelFlags; RAIL_CLIENT_STATUS_ORDER clientStatus; + BOOL sendHandshake; }; typedef struct rail_plugin railPlugin; diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 309654287..903c53387 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -32,55 +32,6 @@ #include "rail_orders.h" -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static 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 - */ -static UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string) -{ - size_t length; - - 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 * @@ -103,37 +54,6 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) return rail_send_channel_data(rail, s); } -/** - * 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; - - if (!s || !highContrast) - return ERROR_INVALID_PARAMETER; - - 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 */ -} - -static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys) -{ - if (!s || !filterKeys) - return ERROR_INVALID_PARAMETER; - - 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 * @@ -144,7 +64,7 @@ static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDE if (!s || !execResult) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < RAIL_EXEC_RESULT_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -159,44 +79,6 @@ static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDE : ERROR_INTERNAL_ERROR; /* exeOrFile */ } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam) -{ - BYTE body; - - if (!s || !sysparam) - return ERROR_INVALID_PARAMETER; - - if (Stream_GetRemainingLength(s) < 5) - { - WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); - return ERROR_INVALID_DATA; - } - - Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ - Stream_Read_UINT8(s, body); /* body (1 byte) */ - - switch (sysparam->param) - { - case SPI_SETSCREENSAVEACTIVE: - sysparam->setScreenSaveActive = (body != 0) ? TRUE : FALSE; - break; - - case SPI_SETSCREENSAVESECURE: - sysparam->setScreenSaveSecure = (body != 0) ? TRUE : FALSE; - break; - - default: - break; - } - - return CHANNEL_RC_OK; -} - /** * Function description * @@ -207,7 +89,7 @@ static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* if (!s || !minmaxinfo) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 20) + if (Stream_GetRemainingLength(s) < RAIL_MINMAXINFO_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -238,7 +120,7 @@ static UINT rail_read_server_localmovesize_order(wStream* s, if (!s || !localMoveSize) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 12) + if (Stream_GetRemainingLength(s) < RAIL_LOCALMOVESIZE_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -264,15 +146,16 @@ static UINT rail_read_server_get_appid_resp_order(wStream* s, if (!s || !getAppidResp) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 524) + if (Stream_GetRemainingLength(s) < RAIL_GET_APPID_RESP_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */ - Stream_Read(s, (BYTE*)&(getAppidResp->applicationId), - 520); /* applicationId (260 UNICODE chars) */ + Stream_Read_UTF16_String( + s, getAppidResp->applicationId, + ARRAYSIZE(getAppidResp->applicationId)); /* applicationId (260 UNICODE chars) */ return CHANNEL_RC_OK; } @@ -286,7 +169,7 @@ static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* la if (!s || !langbarInfo) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < RAIL_LANGBAR_INFO_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -357,107 +240,6 @@ static UINT rail_write_client_exec_order(wStream* s, UINT16 flags, return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT rail_write_client_sysparam_order(railPlugin* rail, wStream* s, - const RAIL_SYSPARAM_ORDER* sysparam) -{ - BYTE body; - UINT error = CHANNEL_RC_OK; - - if (!s || !sysparam) - return ERROR_INVALID_PARAMETER; - - Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ - - switch (sysparam->param) - { - 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 ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0) - return ERROR_INVALID_DATA; - - if (sysparam->caretWidth < 0x0001) - return ERROR_INVALID_DATA; - - Stream_Write_UINT32(s, sysparam->caretWidth); - break; - - case SPI_SETSTICKYKEYS: - if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0) - return ERROR_INVALID_DATA; - - Stream_Write_UINT32(s, sysparam->stickyKeys); - break; - - case SPI_SETTOGGLEKEYS: - if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0) - return ERROR_INVALID_DATA; - - Stream_Write_UINT32(s, sysparam->toggleKeys); - break; - - case SPI_SETFILTERKEYS: - if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0) - return ERROR_INVALID_DATA; - - error = rail_write_filterkeys(s, &sysparam->filterKeys); - break; - - default: - return ERROR_INVALID_PARAMETER; - } - - return error; -} - static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate) { BYTE enabled; @@ -544,13 +326,26 @@ static UINT rail_write_languageime_info_order(wStream* s, return ERROR_INVALID_PARAMETER; Stream_Write_UINT32(s, langImeInfo->ProfileType); - Stream_Write_UINT32(s, langImeInfo->LanguageID); + Stream_Write_UINT16(s, langImeInfo->LanguageID); Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID)); Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID)); Stream_Write_UINT32(s, langImeInfo->KeyboardLayout); return ERROR_SUCCESS; } +static UINT rail_write_compartment_info_order(wStream* s, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + if (!s || !compartmentInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, compartmentInfo->ImeState); + Stream_Write_UINT32(s, compartmentInfo->ImeConvMode); + Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode); + Stream_Write_UINT32(s, compartmentInfo->KanaMode); + return ERROR_SUCCESS; +} + /** * Function description * @@ -560,7 +355,6 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); RAIL_HANDSHAKE_ORDER serverHandshake = { 0 }; - RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; UINT error; if (!context || !s) @@ -573,10 +367,13 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s) } rail->channelBuildNumber = serverHandshake.buildNumber; - clientHandshake.buildNumber = 0x00001DB0; - /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX) - * Client response is really a Handshake PDU */ - error = context->ClientHandshake(context, &clientHandshake); + + if (rail->sendHandshake) + { + RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; + clientHandshake.buildNumber = 0x00001DB0; + error = context->ClientHandshake(context, &clientHandshake); + } if (error != CHANNEL_RC_OK) return error; @@ -618,7 +415,6 @@ static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); RAIL_HANDSHAKE_EX_ORDER serverHandshake = { 0 }; - RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; UINT error; if (!rail || !context || !s) @@ -635,10 +431,15 @@ static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s) rail->channelBuildNumber = serverHandshake.buildNumber; rail->channelFlags = serverHandshake.railHandshakeFlags; - clientHandshake.buildNumber = 0x00001DB0; - /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX) - * Client response is really a Handshake PDU */ - error = context->ClientHandshake(context, &clientHandshake); + + if (rail->sendHandshake) + { + RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; + clientHandshake.buildNumber = 0x00001DB0; + /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX) + * Client response is really a Handshake PDU */ + error = context->ClientHandshake(context, &clientHandshake); + } if (error != CHANNEL_RC_OK) return error; @@ -701,9 +502,9 @@ static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s) if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_server_sysparam_order(s, &sysparam))) + if ((error = rail_read_sysparam_order(s, &sysparam, FALSE))) { - WLog_ERR(TAG, "rail_read_server_sysparam_order failed with error %" PRIu32 "!", error); + WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error); return error; } @@ -851,7 +652,7 @@ static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* ta if (!s || !taskbarInfo) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 12) + if (Stream_GetRemainingLength(s) < RAIL_TASKBAR_INFO_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -888,7 +689,7 @@ static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s) IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo); if (error) - WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error); + WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error); } return error; @@ -899,7 +700,7 @@ static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder) if (!s || !zorder) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < RAIL_Z_ORDER_SYNC_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -938,23 +739,23 @@ static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s) return error; } -static UINT rail_read_order_cloak(wStream* s, RAIL_CLOAK* cloak) +static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak) { - if (!s || !cloak) - return ERROR_INVALID_PARAMETER; + BYTE cloaked; - if (Stream_GetRemainingLength(s) < 5) + if (Stream_GetRemainingLength(s) < RAIL_CLOAK_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, cloak->windowId); - Stream_Read_UINT8(s, cloak->cloak); + 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; } -static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s) +static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); RAIL_CLOAK cloak = { 0 }; @@ -968,7 +769,7 @@ static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s) if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0) return ERROR_INVALID_DATA; - if ((error = rail_read_order_cloak(s, &cloak))) + if ((error = rail_read_cloak_order(s, &cloak))) { WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error); return error; @@ -987,16 +788,19 @@ static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s) static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power) { + UINT32 active; + if (!s || !power) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, power->active); + Stream_Read_UINT32(s, active); + power->active = active != 0; return CHANNEL_RC_OK; } @@ -1156,7 +960,7 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) return rail_recv_zorder_sync_order(rail, s); case TS_RAIL_ORDER_CLOAK: - return rail_recv_order_cloak(rail, s); + return rail_recv_cloak_order(rail, s); case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST: return rail_recv_power_display_request_order(rail, s); @@ -1300,215 +1104,6 @@ out: return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARAM_ORDER* sysparam) -{ - wStream* s; - size_t length = RAIL_SYSPARAM_ORDER_LENGTH; - UINT error; - - if (!rail || !sysparam) - return ERROR_INVALID_PARAMETER; - - switch (sysparam->param) - { - case SPI_SET_DRAG_FULL_WINDOWS: - case SPI_SET_KEYBOARD_CUES: - case SPI_SET_KEYBOARD_PREF: - case SPI_SET_MOUSE_BUTTON_SWAP: - length += 1; - break; - - case SPI_SETCARETWIDTH: - case SPI_SETSTICKYKEYS: - case SPI_SETTOGGLEKEYS: - length += 4; - break; - - case SPI_SETFILTERKEYS: - length += 20; - break; - - case SPI_SET_WORK_AREA: - case SPI_DISPLAY_CHANGE: - case SPI_TASKBAR_POS: - length += 8; - break; - - case SPI_SET_HIGH_CONTRAST: - length += sysparam->highContrast.colorSchemeLength + 10; - break; - - default: - length += 8; - break; - } - - s = rail_pdu_init(length); - - if (!s) - { - WLog_ERR(TAG, "rail_pdu_init failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - if ((error = rail_write_client_sysparam_order(rail, s, sysparam))) - { - WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error); - goto out; - } - - if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM))) - { - WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error); - goto out; - } - -out: - Stream_Free(s, TRUE); - return error; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam) -{ - UINT error = CHANNEL_RC_OK; - - if (!rail || !sysparam) - return ERROR_INVALID_PARAMETER; - - if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST) - { - sysparam->param = SPI_SET_HIGH_CONTRAST; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_TASKBAR_POS) - { - sysparam->param = SPI_TASKBAR_POS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_MOUSE_BUTTON_SWAP) - { - sysparam->param = SPI_SET_MOUSE_BUTTON_SWAP; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_KEYBOARD_PREF) - { - sysparam->param = SPI_SET_KEYBOARD_PREF; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_DRAG_FULL_WINDOWS) - { - sysparam->param = SPI_SET_DRAG_FULL_WINDOWS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_KEYBOARD_CUES) - { - sysparam->param = SPI_SET_KEYBOARD_CUES; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_WORK_AREA) - { - sysparam->param = SPI_SET_WORK_AREA; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_CARET_WIDTH) - { - sysparam->param = SPI_SETCARETWIDTH; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_STICKY_KEYS) - { - sysparam->param = SPI_SETSTICKYKEYS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_TOGGLE_KEYS) - { - sysparam->param = SPI_SETTOGGLEKEYS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - if (sysparam->params & SPI_MASK_SET_FILTER_KEYS) - { - sysparam->param = SPI_SETFILTERKEYS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error); - return error; - } - } - - return error; -} - /** * Function description * @@ -1754,7 +1349,33 @@ UINT rail_send_client_languageime_info_order(railPlugin* rail, return error; } -UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak) +UINT rail_send_client_compartment_info_order(railPlugin* rail, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + wStream* s; + UINT error; + + if (!rail || !compartmentInfo) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + error = rail_write_compartment_info_order(s, compartmentInfo); + + if (ERROR_SUCCESS == error) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO); + + Stream_Free(s, TRUE); + return error; +} + +UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak) { wStream* s; UINT error; @@ -1777,7 +1398,7 @@ UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloa return error; } -UINT rail_send_client_order_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap) +UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap) { wStream* s; UINT error; diff --git a/channels/rail/client/rail_orders.h b/channels/rail/client/rail_orders.h index f1dfd1cc8..89ba6cc4a 100644 --- a/channels/rail/client/rail_orders.h +++ b/channels/rail/client/rail_orders.h @@ -29,9 +29,6 @@ #define TAG CHANNELS_TAG("rail.client") -UINT rail_write_client_sysparam_order(railPlugin* rail, wStream* s, - const RAIL_SYSPARAM_ORDER* sysparam); - UINT rail_order_recv(railPlugin* rail, wStream* s); UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType); @@ -55,7 +52,9 @@ UINT rail_send_client_langbar_info_order(railPlugin* rail, const RAIL_LANGBAR_INFO_ORDER* langBarInfo); UINT rail_send_client_languageime_info_order(railPlugin* rail, const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo); -UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak); -UINT rail_send_client_order_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap); +UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak); +UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap); +UINT rail_send_client_compartment_info_order(railPlugin* rail, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo); #endif /* FREERDP_CHANNEL_RAIL_CLIENT_ORDERS_H */ diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index a9149248b..506ba5df5 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -23,6 +23,9 @@ #include "rail_common.h" #include +#include + +#define TAG CHANNELS_TAG("rail.common") const char* const RAIL_ORDER_TYPE_STRINGS[] = { "", "Execute", @@ -48,30 +51,6 @@ const char* const RAIL_ORDER_TYPE_STRINGS[] = { "", "", "" }; -BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string) -{ - WCHAR* buffer = NULL; - int length = 0; - free(unicode_string->string); - unicode_string->string = NULL; - unicode_string->length = 0; - - if (!string || strlen(string) < 1) - return TRUE; - - length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0); - - if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX)) - { - free(buffer); - return FALSE; - } - - unicode_string->string = (BYTE*)buffer; - unicode_string->length = (UINT16)length * sizeof(WCHAR); - return TRUE; -} - /** * Function description * @@ -147,3 +126,383 @@ void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* ha 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; + + 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; + + Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */ + Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */ + return rail_read_unicode_string(s, &highContrast->colorScheme); /* colorScheme */ +} + +/** + * 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; + + if (!s || !highContrast) + return ERROR_INVALID_PARAMETER; + + 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_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys) +{ + if (!s || !filterKeys) + return ERROR_INVALID_PARAMETER; + + 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; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 5) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ + + switch (sysparam->param) + { + /* Client sysparams */ + case SPI_SET_DRAG_FULL_WINDOWS: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->dragFullWindows = body != 0; + break; + + case SPI_SET_KEYBOARD_CUES: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardCues = body != 0; + break; + + case SPI_SET_KEYBOARD_PREF: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardPref = body != 0; + break; + + case SPI_SET_MOUSE_BUTTON_SWAP: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->mouseButtonSwap = body != 0; + break; + + case SPI_SET_WORK_AREA: + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + 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: + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + 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: + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + 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: + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + error = rail_read_high_contrast(s, &sysparam->highContrast); + break; + + case SPI_SETCARETWIDTH: + if (extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->caretWidth); + + if (sysparam->caretWidth < 0x0001) + return ERROR_INVALID_DATA; + + break; + + case SPI_SETSTICKYKEYS: + if (extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Write_UINT32(s, sysparam->stickyKeys); + break; + + case SPI_SETTOGGLEKEYS: + if (extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Write_UINT32(s, sysparam->toggleKeys); + break; + + case SPI_SETFILTERKEYS: + if (extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 20) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + error = rail_write_filterkeys(s, &sysparam->filterKeys); + break; + + /* Server sysparams */ + case SPI_SETSCREENSAVEACTIVE: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveActive = body != 0; + break; + + case SPI_SETSCREENSAVESECURE: + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveSecure = body != 0; + break; + + default: + break; + } + + return CHANNEL_RC_OK; +} + +/** + * 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; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + 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; +} diff --git a/channels/rail/rail_common.h b/channels/rail/rail_common.h index cbce3a2ee..ee88e7984 100644 --- a/channels/rail/rail_common.h +++ b/channels/rail/rail_common.h @@ -31,21 +31,31 @@ extern const char* const RAIL_ORDER_TYPE_STRINGS[]; #define RAIL_PDU_HEADER_LENGTH 4 /* Fixed length of PDUs, excluding variable lengths */ -#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */ -#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */ -#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */ -#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */ -#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */ -#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */ -#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */ -#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */ -#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */ -#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */ -#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */ -#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */ -#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 44 /* fixed */ +#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */ +#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */ +#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */ +#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */ +#define RAIL_EXEC_RESULT_ORDER_LENGTH 12 /* variable */ +#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */ +#define RAIL_MINMAXINFO_ORDER_LENGTH 20 /* fixed */ +#define RAIL_LOCALMOVESIZE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */ +#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */ +#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */ +#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */ +#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_SNAP_ARRANGE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */ +#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */ +#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 42 /* fixed */ +#define RAIL_COMPARTMENT_INFO_ORDER_LENGTH 16 /* fixed */ +#define RAIL_CLOAK_ORDER_LENGTH 5 /* fixed */ +#define RAIL_TASKBAR_INFO_ORDER_LENGTH 12 /* fixed */ +#define RAIL_Z_ORDER_SYNC_ORDER_LENGTH 4 /* fixed */ +#define RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH 4 /* fixed */ +#define RAIL_GET_APPID_RESP_ORDER_LENGTH 524 /* fixed */ +#define RAIL_GET_APPID_RESP_EX_ORDER_LENGTH 1048 /* fixed */ -BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string); UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake); void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake); UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx); @@ -55,4 +65,11 @@ wStream* rail_pdu_init(size_t length); UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength); void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength); +UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string); +UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string); + +UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported); +UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam, + BOOL extendedSpiSupported); + #endif /* FREERDP_CHANNEL_RAIL_COMMON_H */ diff --git a/channels/rail/server/CMakeLists.txt b/channels/rail/server/CMakeLists.txt new file mode 100644 index 000000000..c7f1c7a7f --- /dev/null +++ b/channels/rail/server/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Mati Shabtay +# +# 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. + +define_channel_server("rail") + +set(${MODULE_PREFIX}_SRCS + ../rail_common.c + ../rail_common.h + rail_main.c + rail_main.h) + +include_directories(..) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") + +target_link_libraries(${MODULE_NAME} freerdp) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rail/server/rail_main.c b/channels/rail/server/rail_main.c new file mode 100644 index 000000000..817ce9610 --- /dev/null +++ b/channels/rail/server/rail_main.c @@ -0,0 +1,1674 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL Virtual Channel Plugin + * + * Copyright 2019 Mati Shabtay + * + + * 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 +#include + +#include + +#include +#include +#include +#include + +#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; + + if (!context) + return CHANNEL_RC_BAD_INIT_HANDLE; + + if (!WTSVirtualChannelWrite(context->priv->rail_channel, (PCHAR)Stream_Buffer(s), length, + &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + status = ERROR_INTERNAL_ERROR; + } + + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_send_pdu(RailServerContext* context, wStream* s, UINT16 orderType) +{ + UINT16 orderLength; + + 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_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], 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_UINT16(s, minMaxInfo->maxWidth); /* MaxWidth (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->maxHeight); /* MaxHeight (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->maxPosX); /* MaxPosX (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->maxPosY); /* MaxPosY (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->minTrackWidth); /* MinTrackWidth (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->minTrackHeight); /* MinTrackHeight (2 bytes) */ + Stream_Write_UINT16(s, minMaxInfo->maxTrackWidth); /* MaxTrackWidth (2 bytes) */ + Stream_Write_UINT16(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; + UINT error; + + 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_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; + UINT error; + + if (!context || !handshakeEx || !context->priv) + return ERROR_INVALID_PARAMETER; + + /* Save channel flags to context */ + context->priv->channelFlags = handshakeEx->railHandshakeFlags; + s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_handshake_ex_order(s, handshakeEx); + error = rail_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; + UINT error; + RailServerPrivate* priv; + BOOL extendedSpiSupported; + + if (!context || !sysparam) + return ERROR_INVALID_PARAMETER; + + priv = context->priv; + + if (!priv) + return ERROR_INVALID_PARAMETER; + + extendedSpiSupported = + !((priv->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0); + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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; + UINT error; + + 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_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_GetRemainingLength(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) +{ + RAIL_EXEC_ORDER order = { 0 }; + UINT16 exeLen, workLen, argLen; + + if (Stream_GetRemainingLength(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_GetRemainingLength(s) < (size_t)exeLen + workLen + argLen) + return ERROR_INVALID_DATA; + + { + const int len = exeLen / sizeof(WCHAR); + int rc; + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, exeLen); + } + { + const int len = workLen / sizeof(WCHAR); + int rc; + + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, workLen); + } + { + const int len = argLen / sizeof(WCHAR); + int rc; + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, argLen); + } + + return CHANNEL_RC_OK; +fail: + free(exec->RemoteApplicationProgram); + free(exec->RemoteApplicationArguments); + free(exec->RemoteApplicationWorkingDir); + *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; + + if (Stream_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(s) < RAIL_WINDOW_MOVE_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, windowMove->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT16(s, windowMove->left); /* Left (2 bytes) */ + Stream_Read_UINT16(s, windowMove->top); /* Top (2 bytes) */ + Stream_Read_UINT16(s, windowMove->right); /* Right (2 bytes) */ + Stream_Read_UINT16(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_GetRemainingLength(s) < RAIL_SNAP_ARRANGE_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, snapArrange->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT16(s, snapArrange->left); /* Left (2 bytes) */ + Stream_Read_UINT16(s, snapArrange->top); /* Top (2 bytes) */ + Stream_Read_UINT16(s, snapArrange->right); /* Right (2 bytes) */ + Stream_Read_UINT16(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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; + + if (Stream_GetRemainingLength(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; + + 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; + + 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; + RAIL_EXEC_ORDER exec = { 0 }; + + if (!context || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_exec_order(s, &exec))) + { + 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(exec.RemoteApplicationProgram); + free(exec.RemoteApplicationArguments); + free(exec.RemoteApplicationWorkingDir); + 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; + + if (!context || !sysparam || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_sysparam_order(s, sysparam, FALSE))) + { + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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 DWORD WINAPI rail_server_thread(LPVOID arg) +{ + RailServerContext* context = (RailServerContext*)arg; + RailServerPrivate* priv = context->priv; + DWORD status; + 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; + 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: + CloseHandle(context->priv->stopEvent); + context->priv->stopEvent = NULL; +out_close: + WTSVirtualChannelClose(context->priv->rail_channel); + context->priv->rail_channel = NULL; + return error; +} + +static BOOL rail_server_stop(RailServerContext* context) +{ + RailServerPrivate* priv = (RailServerPrivate*)context->priv; + + if (priv->thread) + { + SetEvent(priv->stopEvent); + + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError()); + return FALSE; + } + + CloseHandle(priv->thread); + CloseHandle(priv->stopEvent); + priv->thread = NULL; + priv->stopEvent = NULL; + } + + if (priv->rail_channel) + { + WTSVirtualChannelClose(priv->rail_channel); + priv->rail_channel = NULL; + } + + priv->channelEvent = NULL; + return TRUE; +} + +RailServerContext* rail_server_context_new(HANDLE vcm) +{ + RailServerContext* context; + RailServerPrivate* priv; + 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); +} + +UINT rail_server_handle_messages(RailServerContext* context) +{ + UINT status = CHANNEL_RC_OK; + DWORD bytesReturned; + UINT16 orderType; + UINT16 orderLength; + 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, (PCHAR)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, (PCHAR)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_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], 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, ¬ifyEvent, 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); + } + + default: + WLog_ERR(TAG, "Unknown RAIL PDU order received."); + return ERROR_INVALID_DATA; + } + + Stream_SetPosition(s, 0); + return status; +} diff --git a/channels/rail/server/rail_main.h b/channels/rail/server/rail_main.h new file mode 100644 index 000000000..5c56331d4 --- /dev/null +++ b/channels/rail/server/rail_main.h @@ -0,0 +1,44 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL Virtual Channel Plugin + * + * Copyright 2019 Mati Shabtay + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_RAIL_SERVER_MAIN_H +#define FREERDP_CHANNEL_RAIL_SERVER_MAIN_H + +#include +#include + +#include +#include +#include + +#include "../rail_common.h" + +struct _rail_server_private +{ + HANDLE thread; + HANDLE stopEvent; + HANDLE channelEvent; + void* rail_channel; + + wStream* input_stream; + + DWORD channelFlags; +}; + +#endif /* FREERDP_CHANNEL_RAIL_SERVER_MAIN_H */ \ No newline at end of file diff --git a/channels/server/channels.c b/channels/server/channels.c index 3d342b2d8..40c55eecc 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ void freerdp_channels_dummy(void) RdpeiServerContext* rdpei; RemdeskServerContext* remdesk; EncomspServerContext* encomsp; + RailServerContext* rail; RdpgfxServerContext* rdpgfx; DispServerContext* disp; audin = audin_server_context_new(NULL); @@ -83,6 +85,8 @@ void freerdp_channels_dummy(void) remdesk_server_context_free(remdesk); encomsp = encomsp_server_context_new(NULL); encomsp_server_context_free(encomsp); + rail = rail_server_context_new(NULL); + rail_server_context_free(rail); rdpgfx = rdpgfx_server_context_new(NULL); rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); diff --git a/include/freerdp/client/rail.h b/include/freerdp/client/rail.h index 82d5a7bc9..0ce7dc332 100644 --- a/include/freerdp/client/rail.h +++ b/include/freerdp/client/rail.h @@ -31,10 +31,10 @@ * Client Interface */ -#define RAIL_SVC_CHANNEL_NAME "rail" - typedef struct _rail_client_context RailClientContext; +typedef UINT (*pcRailOnOpen)(RailClientContext* context, BOOL* sendHandshake); + typedef UINT (*pcRailClientExecute)(RailClientContext* context, const RAIL_EXEC_ORDER* exec); typedef UINT (*pcRailClientActivate)(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate); @@ -69,7 +69,7 @@ typedef UINT (*pcRailClientLanguageBarInfo)(RailClientContext* context, typedef UINT (*pcRailServerLanguageBarInfo)(RailClientContext* context, const RAIL_LANGBAR_INFO_ORDER* langBarInfo); typedef UINT (*pcRailClientLanguageIMEInfo)(RailClientContext* context, - const RAIL_LANGUAGEIME_INFO_ORDER* langBarInfo); + const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo); typedef UINT (*pcRailServerExecuteResult)(RailClientContext* context, const RAIL_EXEC_RESULT_ORDER* execResult); typedef UINT (*pcRailClientGetAppIdRequest)(RailClientContext* context, @@ -84,6 +84,8 @@ typedef UINT (*pcRailServerPowerDisplayRequest)(RailClientContext* context, typedef UINT (*pcRailClientSnapArrange)(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap); typedef UINT (*pcRailServerGetAppidResponseExtended)(RailClientContext* context, const RAIL_GET_APPID_RESP_EX* id); +typedef UINT (*pcRailClientCompartmentInfo)(RailClientContext* context, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo); struct _rail_client_context { @@ -117,6 +119,8 @@ struct _rail_client_context pcRailServerPowerDisplayRequest ServerPowerDisplayRequest; pcRailClientSnapArrange ClientSnapArrange; pcRailServerGetAppidResponseExtended ServerGetAppidResponseExtended; + pcRailClientCompartmentInfo ClientCompartmentInfo; + pcRailOnOpen OnOpen; }; #endif /* FREERDP_CHANNEL_RAIL_CLIENT_RAIL_H */ diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index 9abd8174f..961ea8f8f 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -26,6 +26,8 @@ #include +#define RAIL_SVC_CHANNEL_NAME "rail" + /* DEPRECATED: RAIL PDU flags use the spec conformant naming with TS_ prefix */ #define RAIL_EXEC_FLAG_EXPAND_WORKINGDIRECTORY 0x0001 #define RAIL_EXEC_FLAG_TRANSLATE_FILES 0x0002 @@ -580,6 +582,8 @@ extern "C" #endif FREERDP_API BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string); + FREERDP_API BOOL utf8_string_to_rail_string(const char* string, + RAIL_UNICODE_STRING* unicode_string); #ifdef __cplusplus } diff --git a/include/freerdp/server/rail.h b/include/freerdp/server/rail.h new file mode 100644 index 000000000..77f030eab --- /dev/null +++ b/include/freerdp/server/rail.h @@ -0,0 +1,149 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL Virtual Channel Plugin + * + * Copyright 2019 Mati Shabtay + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_RAIL_SERVER_RAIL_H +#define FREERDP_CHANNEL_RAIL_SERVER_RAIL_H + +#include +#include +#include + +#include +#include + +typedef struct _rail_server_context RailServerContext; +typedef struct _rail_server_private RailServerPrivate; + +typedef UINT (*psRailStart)(RailServerContext* context); +typedef BOOL (*psRailStop)(RailServerContext* context); + +/* Client side callback types */ +typedef UINT (*psRailClientHandshake)(RailServerContext* context, + const RAIL_HANDSHAKE_ORDER* handshake); +typedef UINT (*psRailClientClientStatus)(RailServerContext* context, + const RAIL_CLIENT_STATUS_ORDER* clientStatus); +typedef UINT (*psRailClientExec)(RailServerContext* context, const RAIL_EXEC_ORDER* exec); +typedef UINT (*psRailClientSysparam)(RailServerContext* context, + const RAIL_SYSPARAM_ORDER* sysparam); +typedef UINT (*psRailClientActivate)(RailServerContext* context, + const RAIL_ACTIVATE_ORDER* activate); +typedef UINT (*psRailClientSysmenu)(RailServerContext* context, const RAIL_SYSMENU_ORDER* sysmenu); +typedef UINT (*psRailClientSyscommand)(RailServerContext* context, + const RAIL_SYSCOMMAND_ORDER* syscommand); +typedef UINT (*psRailClientNotifyEvent)(RailServerContext* context, + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent); +typedef UINT (*psRailClientGetAppidReq)(RailServerContext* context, + const RAIL_GET_APPID_REQ_ORDER* getAppidReq); +typedef UINT (*psRailClientWindowMove)(RailServerContext* context, + const RAIL_WINDOW_MOVE_ORDER* windowMove); +typedef UINT (*psRailClientSnapArrange)(RailServerContext* context, + const RAIL_SNAP_ARRANGE* snapArrange); +typedef UINT (*psRailClientLangbarInfo)(RailServerContext* context, + const RAIL_LANGBAR_INFO_ORDER* langbarInfo); +typedef UINT (*psRailClientLanguageImeInfo)(RailServerContext* context, + const RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo); +typedef UINT (*psRailClientCompartmentInfo)(RailServerContext* context, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo); +typedef UINT (*psRailClientCloak)(RailServerContext* context, const RAIL_CLOAK* cloak); + +/* Server side messages sending methods */ +typedef UINT (*psRailServerHandshake)(RailServerContext* context, + const RAIL_HANDSHAKE_ORDER* handshake); +typedef UINT (*psRailServerHandshakeEx)(RailServerContext* context, + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx); +typedef UINT (*psRailServerSysparam)(RailServerContext* context, + const RAIL_SYSPARAM_ORDER* sysparam); +typedef UINT (*psRailServerLocalMoveSize)(RailServerContext* context, + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize); +typedef UINT (*psRailServerMinMaxInfo)(RailServerContext* context, + const RAIL_MINMAXINFO_ORDER* minMaxInfo); +typedef UINT (*psRailServerTaskbarInfo)(RailServerContext* context, + const RAIL_TASKBAR_INFO_ORDER* taskbarInfo); +typedef UINT (*psRailServerLangbarInfo)(RailServerContext* context, + const RAIL_LANGBAR_INFO_ORDER* langbarInfo); +typedef UINT (*psRailServerExecResult)(RailServerContext* context, + const RAIL_EXEC_RESULT_ORDER* execResult); +typedef UINT (*psRailServerGetAppidResp)(RailServerContext* context, + const RAIL_GET_APPID_RESP_ORDER* getAppIdResp); +typedef UINT (*psRailServerZOrderSync)(RailServerContext* context, + const RAIL_ZORDER_SYNC* zOrderSync); +typedef UINT (*psRailServerCloak)(RailServerContext* context, const RAIL_CLOAK* cloak); +typedef UINT (*psRailServerPowerDisplayRequest)( + RailServerContext* context, const RAIL_POWER_DISPLAY_REQUEST* PowerDisplayRequest); +typedef UINT (*psRailServerGetAppidRespEx)(RailServerContext* context, + const RAIL_GET_APPID_RESP_EX* GetAppidRespEx); + +struct _rail_server_context +{ + HANDLE vcm; + void* custom; + + psRailStart Start; + psRailStop Stop; + + /* Callbacks from client */ + psRailClientHandshake ClientHandshake; + psRailClientClientStatus ClientClientStatus; + psRailClientExec ClientExec; + psRailClientSysparam ClientSysparam; + psRailClientActivate ClientActivate; + psRailClientSysmenu ClientSysmenu; + psRailClientSyscommand ClientSyscommand; + psRailClientNotifyEvent ClientNotifyEvent; + psRailClientGetAppidReq ClientGetAppidReq; + psRailClientWindowMove ClientWindowMove; + psRailClientSnapArrange ClientSnapArrange; + psRailClientLangbarInfo ClientLangbarInfo; + psRailClientLanguageImeInfo ClientLanguageImeInfo; + psRailClientCompartmentInfo ClientCompartmentInfo; + psRailClientCloak ClientCloak; + + /* Methods for sending server side messages */ + psRailServerHandshake ServerHandshake; + psRailServerHandshakeEx ServerHandshakeEx; + psRailServerSysparam ServerSysparam; + psRailServerLocalMoveSize ServerLocalMoveSize; + psRailServerMinMaxInfo ServerMinMaxInfo; + psRailServerTaskbarInfo ServerTaskbarInfo; + psRailServerLangbarInfo ServerLangbarInfo; + psRailServerExecResult ServerExecResult; + psRailServerZOrderSync ServerZOrderSync; + psRailServerCloak ServerCloak; + psRailServerPowerDisplayRequest ServerPowerDisplayRequest; + psRailServerGetAppidResp ServerGetAppidResp; + psRailServerGetAppidRespEx ServerGetAppidRespEx; + + RailServerPrivate* priv; + rdpContext* rdpContext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API RailServerContext* rail_server_context_new(HANDLE vcm); + FREERDP_API void rail_server_context_free(RailServerContext* context); + FREERDP_API UINT rail_server_handle_messages(RailServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_RAIL_SERVER_RAIL_H */ diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 35e6536bc..a71c9c9a4 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -86,7 +86,6 @@ static BOOL update_recv_orders(rdpUpdate* update, wStream* s) static BOOL update_read_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* bitmapData) { WINPR_UNUSED(update); - if (Stream_GetRemainingLength(s) < 18) return FALSE; @@ -2251,7 +2250,6 @@ BOOL update_send_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* order Stream_Write_UINT16(s, orderSize); Stream_SetPosition(s, orderEndPos); update->numberOrders++; - /* Write body */ return TRUE; } diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c index 3e2688ada..b56fc1bc2 100644 --- a/libfreerdp/core/window.c +++ b/libfreerdp/core/window.c @@ -68,6 +68,30 @@ BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string) return TRUE; } +BOOL utf8_string_to_rail_string(const char* string, RAIL_UNICODE_STRING* unicode_string) +{ + WCHAR* buffer = NULL; + int length = 0; + free(unicode_string->string); + unicode_string->string = NULL; + unicode_string->length = 0; + + if (!string || strlen(string) < 1) + return TRUE; + + length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0); + + if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX)) + { + free(buffer); + return FALSE; + } + + unicode_string->string = (BYTE*)buffer; + unicode_string->length = (UINT16)length * sizeof(WCHAR); + return TRUE; +} + /* See [MS-RDPERP] 2.2.1.2.3 Icon Info (TS_ICON_INFO) */ static BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo) { @@ -993,7 +1017,10 @@ BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s) } if (!window_order_supported(update->context->settings, orderInfo.fieldFlags)) + { + WLog_INFO(TAG, "Window order %08" PRIx32 " not supported!", orderInfo.fieldFlags); return FALSE; + } if (orderInfo.fieldFlags & WINDOW_ORDER_TYPE_WINDOW) rc = update_recv_window_info_order(update, s, &orderInfo);