1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Remote Applications Integrated Locally (RAIL) Orders
4  *
5  * Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
7  * Copyright 2015 Thincast Technologies GmbH
8  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9  * Copyright 2017 Armin Novak <armin.novak@thincast.com>
10  * Copyright 2017 Thincast Technologies GmbH
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <winpr/crt.h>
30 
31 #include <freerdp/channels/log.h>
32 
33 #include "rail_orders.h"
34 
35 /**
36  * Function description
37  *
38  * @return 0 on success, otherwise a Win32 error code
39  */
rail_send_pdu(railPlugin * rail,wStream * s,UINT16 orderType)40 UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
41 {
42 	UINT16 orderLength;
43 
44 	if (!rail || !s)
45 		return ERROR_INVALID_PARAMETER;
46 
47 	orderLength = (UINT16)Stream_GetPosition(s);
48 	Stream_SetPosition(s, 0);
49 	rail_write_pdu_header(s, orderType, orderLength);
50 	Stream_SetPosition(s, orderLength);
51 	WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %" PRIu16 "",
52 	           rail_get_order_type_string(orderType), orderLength);
53 	return rail_send_channel_data(rail, s);
54 }
55 
56 /**
57  * Function description
58  *
59  * @return 0 on success, otherwise a Win32 error code
60  */
rail_read_server_exec_result_order(wStream * s,RAIL_EXEC_RESULT_ORDER * execResult)61 static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* execResult)
62 {
63 	if (!s || !execResult)
64 		return ERROR_INVALID_PARAMETER;
65 
66 	if (Stream_GetRemainingLength(s) < RAIL_EXEC_RESULT_ORDER_LENGTH)
67 	{
68 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
69 		return ERROR_INVALID_DATA;
70 	}
71 
72 	Stream_Read_UINT16(s, execResult->flags);      /* flags (2 bytes) */
73 	Stream_Read_UINT16(s, execResult->execResult); /* execResult (2 bytes) */
74 	Stream_Read_UINT32(s, execResult->rawResult);  /* rawResult (4 bytes) */
75 	Stream_Seek_UINT16(s);                         /* padding (2 bytes) */
76 	return rail_read_unicode_string(s, &execResult->exeOrFile)
77 	           ? CHANNEL_RC_OK
78 	           : ERROR_INTERNAL_ERROR; /* exeOrFile */
79 }
80 
81 /**
82  * Function description
83  *
84  * @return 0 on success, otherwise a Win32 error code
85  */
rail_read_server_minmaxinfo_order(wStream * s,RAIL_MINMAXINFO_ORDER * minmaxinfo)86 static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo)
87 {
88 	if (!s || !minmaxinfo)
89 		return ERROR_INVALID_PARAMETER;
90 
91 	if (Stream_GetRemainingLength(s) < RAIL_MINMAXINFO_ORDER_LENGTH)
92 	{
93 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
94 		return ERROR_INVALID_DATA;
95 	}
96 
97 	Stream_Read_UINT32(s, minmaxinfo->windowId);      /* windowId (4 bytes) */
98 	Stream_Read_INT16(s, minmaxinfo->maxWidth);       /* maxWidth (2 bytes) */
99 	Stream_Read_INT16(s, minmaxinfo->maxHeight);      /* maxHeight (2 bytes) */
100 	Stream_Read_INT16(s, minmaxinfo->maxPosX);        /* maxPosX (2 bytes) */
101 	Stream_Read_INT16(s, minmaxinfo->maxPosY);        /* maxPosY (2 bytes) */
102 	Stream_Read_INT16(s, minmaxinfo->minTrackWidth);  /* minTrackWidth (2 bytes) */
103 	Stream_Read_INT16(s, minmaxinfo->minTrackHeight); /* minTrackHeight (2 bytes) */
104 	Stream_Read_INT16(s, minmaxinfo->maxTrackWidth);  /* maxTrackWidth (2 bytes) */
105 	Stream_Read_INT16(s, minmaxinfo->maxTrackHeight); /* maxTrackHeight (2 bytes) */
106 	return CHANNEL_RC_OK;
107 }
108 
109 /**
110  * Function description
111  *
112  * @return 0 on success, otherwise a Win32 error code
113  */
rail_read_server_localmovesize_order(wStream * s,RAIL_LOCALMOVESIZE_ORDER * localMoveSize)114 static UINT rail_read_server_localmovesize_order(wStream* s,
115                                                  RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
116 {
117 	UINT16 isMoveSizeStart;
118 
119 	if (!s || !localMoveSize)
120 		return ERROR_INVALID_PARAMETER;
121 
122 	if (Stream_GetRemainingLength(s) < RAIL_LOCALMOVESIZE_ORDER_LENGTH)
123 	{
124 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
125 		return ERROR_INVALID_DATA;
126 	}
127 
128 	Stream_Read_UINT32(s, localMoveSize->windowId); /* windowId (4 bytes) */
129 	Stream_Read_UINT16(s, isMoveSizeStart);         /* isMoveSizeStart (2 bytes) */
130 	localMoveSize->isMoveSizeStart = (isMoveSizeStart != 0) ? TRUE : FALSE;
131 	Stream_Read_UINT16(s, localMoveSize->moveSizeType); /* moveSizeType (2 bytes) */
132 	Stream_Read_INT16(s, localMoveSize->posX);          /* posX (2 bytes) */
133 	Stream_Read_INT16(s, localMoveSize->posY);          /* posY (2 bytes) */
134 	return CHANNEL_RC_OK;
135 }
136 
137 /**
138  * Function description
139  *
140  * @return 0 on success, otherwise a Win32 error code
141  */
rail_read_server_get_appid_resp_order(wStream * s,RAIL_GET_APPID_RESP_ORDER * getAppidResp)142 static UINT rail_read_server_get_appid_resp_order(wStream* s,
143                                                   RAIL_GET_APPID_RESP_ORDER* getAppidResp)
144 {
145 	if (!s || !getAppidResp)
146 		return ERROR_INVALID_PARAMETER;
147 
148 	if (Stream_GetRemainingLength(s) < RAIL_GET_APPID_RESP_ORDER_LENGTH)
149 	{
150 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
151 		return ERROR_INVALID_DATA;
152 	}
153 
154 	Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */
155 	Stream_Read_UTF16_String(
156 	    s, getAppidResp->applicationId,
157 	    ARRAYSIZE(getAppidResp->applicationId)); /* applicationId (260 UNICODE chars) */
158 	return CHANNEL_RC_OK;
159 }
160 
161 /**
162  * Function description
163  *
164  * @return 0 on success, otherwise a Win32 error code
165  */
rail_read_langbar_info_order(wStream * s,RAIL_LANGBAR_INFO_ORDER * langbarInfo)166 static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
167 {
168 	if (!s || !langbarInfo)
169 		return ERROR_INVALID_PARAMETER;
170 
171 	if (Stream_GetRemainingLength(s) < RAIL_LANGBAR_INFO_ORDER_LENGTH)
172 	{
173 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
174 		return ERROR_INVALID_DATA;
175 	}
176 
177 	Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
178 	return CHANNEL_RC_OK;
179 }
180 
rail_write_client_status_order(wStream * s,const RAIL_CLIENT_STATUS_ORDER * clientStatus)181 static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
182 {
183 	if (!s || !clientStatus)
184 		return ERROR_INVALID_PARAMETER;
185 
186 	Stream_Write_UINT32(s, clientStatus->flags); /* flags (4 bytes) */
187 	return ERROR_SUCCESS;
188 }
189 
190 /**
191  * Function description
192  *
193  * @return 0 on success, otherwise a Win32 error code
194  */
rail_write_client_exec_order(wStream * s,UINT16 flags,const RAIL_UNICODE_STRING * exeOrFile,const RAIL_UNICODE_STRING * workingDir,const RAIL_UNICODE_STRING * arguments)195 static UINT rail_write_client_exec_order(wStream* s, UINT16 flags,
196                                          const RAIL_UNICODE_STRING* exeOrFile,
197                                          const RAIL_UNICODE_STRING* workingDir,
198                                          const RAIL_UNICODE_STRING* arguments)
199 {
200 	UINT error;
201 
202 	if (!s || !exeOrFile || !workingDir || !arguments)
203 		return ERROR_INVALID_PARAMETER;
204 
205 	/* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC)
206 	 * Check argument limits */
207 	if ((exeOrFile->length > 520) || (workingDir->length > 520) || (arguments->length > 16000))
208 	{
209 		WLog_ERR(TAG,
210 		         "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%" PRIu16
211 		         " [max=520], WorkingDir=%" PRIu16 " [max=520], Arguments=%" PRIu16 " [max=16000]",
212 		         exeOrFile->length, workingDir->length, arguments->length);
213 		return ERROR_BAD_ARGUMENTS;
214 	}
215 
216 	Stream_Write_UINT16(s, flags);              /* flags (2 bytes) */
217 	Stream_Write_UINT16(s, exeOrFile->length);  /* exeOrFileLength (2 bytes) */
218 	Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */
219 	Stream_Write_UINT16(s, arguments->length);  /* argumentsLength (2 bytes) */
220 
221 	if ((error = rail_write_unicode_string_value(s, exeOrFile)))
222 	{
223 		WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
224 		return error;
225 	}
226 
227 	if ((error = rail_write_unicode_string_value(s, workingDir)))
228 	{
229 		WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
230 		return error;
231 	}
232 
233 	if ((error = rail_write_unicode_string_value(s, arguments)))
234 	{
235 		WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
236 		return error;
237 	}
238 
239 	return error;
240 }
241 
rail_write_client_activate_order(wStream * s,const RAIL_ACTIVATE_ORDER * activate)242 static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate)
243 {
244 	BYTE enabled;
245 
246 	if (!s || !activate)
247 		return ERROR_INVALID_PARAMETER;
248 
249 	Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */
250 	enabled = activate->enabled ? 1 : 0;
251 	Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */
252 	return ERROR_SUCCESS;
253 }
254 
rail_write_client_sysmenu_order(wStream * s,const RAIL_SYSMENU_ORDER * sysmenu)255 static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER* sysmenu)
256 {
257 	if (!s || !sysmenu)
258 		return ERROR_INVALID_PARAMETER;
259 
260 	Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */
261 	Stream_Write_INT16(s, sysmenu->left);      /* left (2 bytes) */
262 	Stream_Write_INT16(s, sysmenu->top);       /* top (2 bytes) */
263 	return ERROR_SUCCESS;
264 }
265 
rail_write_client_syscommand_order(wStream * s,const RAIL_SYSCOMMAND_ORDER * syscommand)266 static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND_ORDER* syscommand)
267 {
268 	if (!s || !syscommand)
269 		return ERROR_INVALID_PARAMETER;
270 
271 	Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */
272 	Stream_Write_UINT16(s, syscommand->command);  /* command (2 bytes) */
273 	return ERROR_SUCCESS;
274 }
275 
rail_write_client_notify_event_order(wStream * s,const RAIL_NOTIFY_EVENT_ORDER * notifyEvent)276 static UINT rail_write_client_notify_event_order(wStream* s,
277                                                  const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
278 {
279 	if (!s || !notifyEvent)
280 		return ERROR_INVALID_PARAMETER;
281 
282 	Stream_Write_UINT32(s, notifyEvent->windowId);     /* windowId (4 bytes) */
283 	Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */
284 	Stream_Write_UINT32(s, notifyEvent->message);      /* notifyIconId (4 bytes) */
285 	return ERROR_SUCCESS;
286 }
287 
rail_write_client_window_move_order(wStream * s,const RAIL_WINDOW_MOVE_ORDER * windowMove)288 static UINT rail_write_client_window_move_order(wStream* s,
289                                                 const RAIL_WINDOW_MOVE_ORDER* windowMove)
290 {
291 	if (!s || !windowMove)
292 		return ERROR_INVALID_PARAMETER;
293 
294 	Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */
295 	Stream_Write_INT16(s, windowMove->left);      /* left (2 bytes) */
296 	Stream_Write_INT16(s, windowMove->top);       /* top (2 bytes) */
297 	Stream_Write_INT16(s, windowMove->right);     /* right (2 bytes) */
298 	Stream_Write_INT16(s, windowMove->bottom);    /* bottom (2 bytes) */
299 	return ERROR_SUCCESS;
300 }
301 
rail_write_client_get_appid_req_order(wStream * s,const RAIL_GET_APPID_REQ_ORDER * getAppidReq)302 static UINT rail_write_client_get_appid_req_order(wStream* s,
303                                                   const RAIL_GET_APPID_REQ_ORDER* getAppidReq)
304 {
305 	if (!s || !getAppidReq)
306 		return ERROR_INVALID_PARAMETER;
307 
308 	Stream_Write_UINT32(s, getAppidReq->windowId); /* windowId (4 bytes) */
309 	return ERROR_SUCCESS;
310 }
311 
rail_write_langbar_info_order(wStream * s,const RAIL_LANGBAR_INFO_ORDER * langbarInfo)312 static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
313 {
314 	if (!s || !langbarInfo)
315 		return ERROR_INVALID_PARAMETER;
316 
317 	Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
318 	return ERROR_SUCCESS;
319 }
320 
rail_write_languageime_info_order(wStream * s,const RAIL_LANGUAGEIME_INFO_ORDER * langImeInfo)321 static UINT rail_write_languageime_info_order(wStream* s,
322                                               const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
323 {
324 	if (!s || !langImeInfo)
325 		return ERROR_INVALID_PARAMETER;
326 
327 	Stream_Write_UINT32(s, langImeInfo->ProfileType);
328 	Stream_Write_UINT16(s, langImeInfo->LanguageID);
329 	Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID));
330 	Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID));
331 	Stream_Write_UINT32(s, langImeInfo->KeyboardLayout);
332 	return ERROR_SUCCESS;
333 }
334 
rail_write_compartment_info_order(wStream * s,const RAIL_COMPARTMENT_INFO_ORDER * compartmentInfo)335 static UINT rail_write_compartment_info_order(wStream* s,
336                                               const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
337 {
338 	if (!s || !compartmentInfo)
339 		return ERROR_INVALID_PARAMETER;
340 
341 	Stream_Write_UINT32(s, compartmentInfo->ImeState);
342 	Stream_Write_UINT32(s, compartmentInfo->ImeConvMode);
343 	Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode);
344 	Stream_Write_UINT32(s, compartmentInfo->KanaMode);
345 	return ERROR_SUCCESS;
346 }
347 
348 /**
349  * Function description
350  *
351  * @return 0 on success, otherwise a Win32 error code
352  */
rail_recv_handshake_order(railPlugin * rail,wStream * s)353 static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
354 {
355 	RailClientContext* context = rail_get_client_interface(rail);
356 	RAIL_HANDSHAKE_ORDER serverHandshake = { 0 };
357 	UINT error;
358 
359 	if (!context || !s)
360 		return ERROR_INVALID_PARAMETER;
361 
362 	if ((error = rail_read_handshake_order(s, &serverHandshake)))
363 	{
364 		WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error);
365 		return error;
366 	}
367 
368 	rail->channelBuildNumber = serverHandshake.buildNumber;
369 
370 	if (rail->sendHandshake)
371 	{
372 		RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
373 		clientHandshake.buildNumber = 0x00001DB0;
374 		error = context->ClientHandshake(context, &clientHandshake);
375 	}
376 
377 	if (error != CHANNEL_RC_OK)
378 		return error;
379 
380 	if (context->custom)
381 	{
382 		IFCALLRET(context->ServerHandshake, error, context, &serverHandshake);
383 
384 		if (error)
385 			WLog_ERR(TAG, "context.ServerHandshake failed with error %" PRIu32 "", error);
386 	}
387 
388 	return error;
389 }
390 
rail_is_feature_supported(const rdpContext * context,UINT32 featureMask)391 static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
392 {
393 	UINT32 supported, masked;
394 
395 	if (!context || !context->settings)
396 		return FALSE;
397 
398 	supported = context->settings->RemoteApplicationSupportLevel &
399 	            context->settings->RemoteApplicationSupportMask;
400 	masked = (supported & featureMask);
401 
402 	if (masked != featureMask)
403 		return FALSE;
404 
405 	return TRUE;
406 }
407 
408 /**
409  * Function description
410  *
411  * @return 0 on success, otherwise a Win32 error code
412  */
rail_recv_handshake_ex_order(railPlugin * rail,wStream * s)413 static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
414 {
415 	RailClientContext* context = rail_get_client_interface(rail);
416 	RAIL_HANDSHAKE_EX_ORDER serverHandshake = { 0 };
417 	UINT error;
418 
419 	if (!rail || !context || !s)
420 		return ERROR_INVALID_PARAMETER;
421 
422 	if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED))
423 		return ERROR_BAD_CONFIGURATION;
424 
425 	if ((error = rail_read_handshake_ex_order(s, &serverHandshake)))
426 	{
427 		WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %" PRIu32 "!", error);
428 		return error;
429 	}
430 
431 	rail->channelBuildNumber = serverHandshake.buildNumber;
432 	rail->channelFlags = serverHandshake.railHandshakeFlags;
433 
434 	if (rail->sendHandshake)
435 	{
436 		RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
437 		clientHandshake.buildNumber = 0x00001DB0;
438 		/* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
439 		 * Client response is really a Handshake PDU */
440 		error = context->ClientHandshake(context, &clientHandshake);
441 	}
442 
443 	if (error != CHANNEL_RC_OK)
444 		return error;
445 
446 	if (context->custom)
447 	{
448 		IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake);
449 
450 		if (error)
451 			WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %" PRIu32 "", error);
452 	}
453 
454 	return error;
455 }
456 
457 /**
458  * Function description
459  *
460  * @return 0 on success, otherwise a Win32 error code
461  */
rail_recv_exec_result_order(railPlugin * rail,wStream * s)462 static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s)
463 {
464 	RailClientContext* context = rail_get_client_interface(rail);
465 	RAIL_EXEC_RESULT_ORDER execResult = { 0 };
466 	UINT error;
467 
468 	if (!context || !s)
469 		return ERROR_INVALID_PARAMETER;
470 
471 	if ((error = rail_read_server_exec_result_order(s, &execResult)))
472 	{
473 		WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %" PRIu32 "!", error);
474 		goto fail;
475 	}
476 
477 	if (context->custom)
478 	{
479 		IFCALLRET(context->ServerExecuteResult, error, context, &execResult);
480 
481 		if (error)
482 			WLog_ERR(TAG, "context.ServerExecuteResult failed with error %" PRIu32 "", error);
483 	}
484 
485 fail:
486 	free(execResult.exeOrFile.string);
487 	return error;
488 }
489 
490 /**
491  * Function description
492  *
493  * @return 0 on success, otherwise a Win32 error code
494  */
rail_recv_server_sysparam_order(railPlugin * rail,wStream * s)495 static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
496 {
497 	RailClientContext* context = rail_get_client_interface(rail);
498 	RAIL_SYSPARAM_ORDER sysparam;
499 	UINT error;
500 	BOOL extendedSpiSupported;
501 
502 	if (!context || !s)
503 		return ERROR_INVALID_PARAMETER;
504 
505 	extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
506 	if ((error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported)))
507 	{
508 		WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
509 		return error;
510 	}
511 
512 	if (context->custom)
513 	{
514 		IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
515 
516 		if (error)
517 			WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error);
518 	}
519 
520 	return error;
521 }
522 
523 /**
524  * Function description
525  *
526  * @return 0 on success, otherwise a Win32 error code
527  */
rail_recv_server_minmaxinfo_order(railPlugin * rail,wStream * s)528 static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
529 {
530 	RailClientContext* context = rail_get_client_interface(rail);
531 	RAIL_MINMAXINFO_ORDER minMaxInfo = { 0 };
532 	UINT error;
533 
534 	if (!context || !s)
535 		return ERROR_INVALID_PARAMETER;
536 
537 	if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
538 	{
539 		WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error);
540 		return error;
541 	}
542 
543 	if (context->custom)
544 	{
545 		IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
546 
547 		if (error)
548 			WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error);
549 	}
550 
551 	return error;
552 }
553 
554 /**
555  * Function description
556  *
557  * @return 0 on success, otherwise a Win32 error code
558  */
rail_recv_server_localmovesize_order(railPlugin * rail,wStream * s)559 static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
560 {
561 	RailClientContext* context = rail_get_client_interface(rail);
562 	RAIL_LOCALMOVESIZE_ORDER localMoveSize = { 0 };
563 	UINT error;
564 
565 	if (!context || !s)
566 		return ERROR_INVALID_PARAMETER;
567 
568 	if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
569 	{
570 		WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error);
571 		return error;
572 	}
573 
574 	if (context->custom)
575 	{
576 		IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
577 
578 		if (error)
579 			WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error);
580 	}
581 
582 	return error;
583 }
584 
585 /**
586  * Function description
587  *
588  * @return 0 on success, otherwise a Win32 error code
589  */
rail_recv_server_get_appid_resp_order(railPlugin * rail,wStream * s)590 static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
591 {
592 	RailClientContext* context = rail_get_client_interface(rail);
593 	RAIL_GET_APPID_RESP_ORDER getAppIdResp = { 0 };
594 	UINT error;
595 
596 	if (!context || !s)
597 		return ERROR_INVALID_PARAMETER;
598 
599 	if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
600 	{
601 		WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!",
602 		         error);
603 		return error;
604 	}
605 
606 	if (context->custom)
607 	{
608 		IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
609 
610 		if (error)
611 			WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error);
612 	}
613 
614 	return error;
615 }
616 
617 /**
618  * Function description
619  *
620  * @return 0 on success, otherwise a Win32 error code
621  */
rail_recv_langbar_info_order(railPlugin * rail,wStream * s)622 static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
623 {
624 	RailClientContext* context = rail_get_client_interface(rail);
625 	RAIL_LANGBAR_INFO_ORDER langBarInfo = { 0 };
626 	UINT error;
627 
628 	if (!context)
629 		return ERROR_INVALID_PARAMETER;
630 
631 	if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
632 		return ERROR_BAD_CONFIGURATION;
633 
634 	if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
635 	{
636 		WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
637 		return error;
638 	}
639 
640 	if (context->custom)
641 	{
642 		IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
643 
644 		if (error)
645 			WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
646 	}
647 
648 	return error;
649 }
650 
rail_read_taskbar_info_order(wStream * s,RAIL_TASKBAR_INFO_ORDER * taskbarInfo)651 static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
652 {
653 	if (!s || !taskbarInfo)
654 		return ERROR_INVALID_PARAMETER;
655 
656 	if (Stream_GetRemainingLength(s) < RAIL_TASKBAR_INFO_ORDER_LENGTH)
657 	{
658 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
659 		return ERROR_INVALID_DATA;
660 	}
661 
662 	Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
663 	Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
664 	Stream_Read_UINT32(s, taskbarInfo->Body);
665 	return CHANNEL_RC_OK;
666 }
667 
rail_recv_taskbar_info_order(railPlugin * rail,wStream * s)668 static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
669 {
670 	RailClientContext* context = rail_get_client_interface(rail);
671 	RAIL_TASKBAR_INFO_ORDER taskBarInfo = { 0 };
672 	UINT error;
673 
674 	if (!context)
675 		return ERROR_INVALID_PARAMETER;
676 
677 	/* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
678 	 * server -> client message only supported if announced. */
679 	if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
680 		return ERROR_BAD_CONFIGURATION;
681 
682 	if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
683 	{
684 		WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
685 		return error;
686 	}
687 
688 	if (context->custom)
689 	{
690 		IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
691 
692 		if (error)
693 			WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
694 	}
695 
696 	return error;
697 }
698 
rail_read_zorder_sync_order(wStream * s,RAIL_ZORDER_SYNC * zorder)699 static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
700 {
701 	if (!s || !zorder)
702 		return ERROR_INVALID_PARAMETER;
703 
704 	if (Stream_GetRemainingLength(s) < RAIL_Z_ORDER_SYNC_ORDER_LENGTH)
705 	{
706 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
707 		return ERROR_INVALID_DATA;
708 	}
709 
710 	Stream_Read_UINT32(s, zorder->windowIdMarker);
711 	return CHANNEL_RC_OK;
712 }
713 
rail_recv_zorder_sync_order(railPlugin * rail,wStream * s)714 static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
715 {
716 	RailClientContext* context = rail_get_client_interface(rail);
717 	RAIL_ZORDER_SYNC zorder = { 0 };
718 	UINT error;
719 
720 	if (!context)
721 		return ERROR_INVALID_PARAMETER;
722 
723 	if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
724 		return ERROR_INVALID_DATA;
725 
726 	if ((error = rail_read_zorder_sync_order(s, &zorder)))
727 	{
728 		WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
729 		return error;
730 	}
731 
732 	if (context->custom)
733 	{
734 		IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
735 
736 		if (error)
737 			WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
738 	}
739 
740 	return error;
741 }
742 
rail_read_cloak_order(wStream * s,RAIL_CLOAK * cloak)743 static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
744 {
745 	BYTE cloaked;
746 
747 	if (Stream_GetRemainingLength(s) < RAIL_CLOAK_ORDER_LENGTH)
748 	{
749 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
750 		return ERROR_INVALID_DATA;
751 	}
752 
753 	Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
754 	Stream_Read_UINT8(s, cloaked);          /* Cloaked (1 byte) */
755 	cloak->cloak = (cloaked != 0) ? TRUE : FALSE;
756 	return CHANNEL_RC_OK;
757 }
758 
rail_recv_cloak_order(railPlugin * rail,wStream * s)759 static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
760 {
761 	RailClientContext* context = rail_get_client_interface(rail);
762 	RAIL_CLOAK cloak = { 0 };
763 	UINT error;
764 
765 	if (!context)
766 		return ERROR_INVALID_PARAMETER;
767 
768 	/* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
769 	 * server -> client message only supported if announced. */
770 	if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
771 		return ERROR_INVALID_DATA;
772 
773 	if ((error = rail_read_cloak_order(s, &cloak)))
774 	{
775 		WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
776 		return error;
777 	}
778 
779 	if (context->custom)
780 	{
781 		IFCALLRET(context->ServerCloak, error, context, &cloak);
782 
783 		if (error)
784 			WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
785 	}
786 
787 	return error;
788 }
789 
rail_read_power_display_request_order(wStream * s,RAIL_POWER_DISPLAY_REQUEST * power)790 static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
791 {
792 	UINT32 active;
793 
794 	if (!s || !power)
795 		return ERROR_INVALID_PARAMETER;
796 
797 	if (Stream_GetRemainingLength(s) < RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH)
798 	{
799 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
800 		return ERROR_INVALID_DATA;
801 	}
802 
803 	Stream_Read_UINT32(s, active);
804 	power->active = active != 0;
805 	return CHANNEL_RC_OK;
806 }
807 
rail_recv_power_display_request_order(railPlugin * rail,wStream * s)808 static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
809 {
810 	RailClientContext* context = rail_get_client_interface(rail);
811 	RAIL_POWER_DISPLAY_REQUEST power = { 0 };
812 	UINT error;
813 
814 	if (!context)
815 		return ERROR_INVALID_PARAMETER;
816 
817 	/* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
818 	 */
819 	if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
820 		return ERROR_INVALID_DATA;
821 
822 	if ((error = rail_read_power_display_request_order(s, &power)))
823 	{
824 		WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
825 		return error;
826 	}
827 
828 	if (context->custom)
829 	{
830 		IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
831 
832 		if (error)
833 			WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error);
834 	}
835 
836 	return error;
837 }
838 
rail_read_get_application_id_extended_response_order(wStream * s,RAIL_GET_APPID_RESP_EX * id)839 static UINT rail_read_get_application_id_extended_response_order(wStream* s,
840                                                                  RAIL_GET_APPID_RESP_EX* id)
841 {
842 	if (!s || !id)
843 		return ERROR_INVALID_PARAMETER;
844 
845 	if (Stream_GetRemainingLength(s) < 4)
846 	{
847 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
848 		return ERROR_INVALID_DATA;
849 	}
850 
851 	Stream_Read_UINT32(s, id->windowID);
852 
853 	if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
854 		return ERROR_INVALID_DATA;
855 
856 	if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
857 		return ERROR_INVALID_DATA;
858 
859 	if (Stream_GetRemainingLength(s) < 4)
860 	{
861 		WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
862 		return ERROR_INVALID_DATA;
863 	}
864 
865 	Stream_Read_UINT32(s, id->processId);
866 
867 	if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
868 		return ERROR_INVALID_DATA;
869 
870 	if (_wcsnlen(id->applicationID, ARRAYSIZE(id->processImageName)) >=
871 	    ARRAYSIZE(id->processImageName))
872 		return ERROR_INVALID_DATA;
873 
874 	return CHANNEL_RC_OK;
875 }
876 
rail_recv_get_application_id_extended_response_order(railPlugin * rail,wStream * s)877 static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s)
878 {
879 	RailClientContext* context = rail_get_client_interface(rail);
880 	RAIL_GET_APPID_RESP_EX id = { 0 };
881 	UINT error;
882 
883 	if (!context)
884 		return ERROR_INVALID_PARAMETER;
885 
886 	if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
887 	{
888 		WLog_ERR(TAG,
889 		         "rail_read_get_application_id_extended_response_order failed with error %" PRIu32
890 		         "!",
891 		         error);
892 		return error;
893 	}
894 
895 	if (context->custom)
896 	{
897 		IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
898 
899 		if (error)
900 			WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "",
901 			         error);
902 	}
903 
904 	return error;
905 }
906 
907 /**
908  * Function description
909  *
910  * @return 0 on success, otherwise a Win32 error code
911  */
rail_order_recv(railPlugin * rail,wStream * s)912 UINT rail_order_recv(railPlugin* rail, wStream* s)
913 {
914 	UINT16 orderType;
915 	UINT16 orderLength;
916 	UINT error;
917 
918 	if (!rail || !s)
919 		return ERROR_INVALID_PARAMETER;
920 
921 	if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
922 	{
923 		WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error);
924 		return error;
925 	}
926 
927 	WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
928 	           rail_get_order_type_string(orderType), orderLength);
929 
930 	switch (orderType)
931 	{
932 		case TS_RAIL_ORDER_HANDSHAKE:
933 			return rail_recv_handshake_order(rail, s);
934 
935 		case TS_RAIL_ORDER_HANDSHAKE_EX:
936 			return rail_recv_handshake_ex_order(rail, s);
937 
938 		case TS_RAIL_ORDER_EXEC_RESULT:
939 			return rail_recv_exec_result_order(rail, s);
940 
941 		case TS_RAIL_ORDER_SYSPARAM:
942 			return rail_recv_server_sysparam_order(rail, s);
943 
944 		case TS_RAIL_ORDER_MINMAXINFO:
945 			return rail_recv_server_minmaxinfo_order(rail, s);
946 
947 		case TS_RAIL_ORDER_LOCALMOVESIZE:
948 			return rail_recv_server_localmovesize_order(rail, s);
949 
950 		case TS_RAIL_ORDER_GET_APPID_RESP:
951 			return rail_recv_server_get_appid_resp_order(rail, s);
952 
953 		case TS_RAIL_ORDER_LANGBARINFO:
954 			return rail_recv_langbar_info_order(rail, s);
955 
956 		case TS_RAIL_ORDER_TASKBARINFO:
957 			return rail_recv_taskbar_info_order(rail, s);
958 
959 		case TS_RAIL_ORDER_ZORDER_SYNC:
960 			return rail_recv_zorder_sync_order(rail, s);
961 
962 		case TS_RAIL_ORDER_CLOAK:
963 			return rail_recv_cloak_order(rail, s);
964 
965 		case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
966 			return rail_recv_power_display_request_order(rail, s);
967 
968 		case TS_RAIL_ORDER_GET_APPID_RESP_EX:
969 			return rail_recv_get_application_id_extended_response_order(rail, s);
970 
971 		default:
972 			WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
973 			return ERROR_INVALID_DATA;
974 	}
975 
976 	return CHANNEL_RC_OK;
977 }
978 
979 /**
980  * Function description
981  *
982  * @return 0 on success, otherwise a Win32 error code
983  */
rail_send_handshake_order(railPlugin * rail,const RAIL_HANDSHAKE_ORDER * handshake)984 UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake)
985 {
986 	wStream* s;
987 	UINT error;
988 
989 	if (!rail || !handshake)
990 		return ERROR_INVALID_PARAMETER;
991 
992 	s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
993 
994 	if (!s)
995 	{
996 		WLog_ERR(TAG, "rail_pdu_init failed!");
997 		return CHANNEL_RC_NO_MEMORY;
998 	}
999 
1000 	rail_write_handshake_order(s, handshake);
1001 	error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE);
1002 	Stream_Free(s, TRUE);
1003 	return error;
1004 }
1005 
1006 /**
1007  * Function description
1008  *
1009  * @return 0 on success, otherwise a Win32 error code
1010  */
rail_send_handshake_ex_order(railPlugin * rail,const RAIL_HANDSHAKE_EX_ORDER * handshakeEx)1011 UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
1012 {
1013 	wStream* s;
1014 	UINT error;
1015 
1016 	if (!rail || !handshakeEx)
1017 		return ERROR_INVALID_PARAMETER;
1018 
1019 	s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
1020 
1021 	if (!s)
1022 	{
1023 		WLog_ERR(TAG, "rail_pdu_init failed!");
1024 		return CHANNEL_RC_NO_MEMORY;
1025 	}
1026 
1027 	rail_write_handshake_ex_order(s, handshakeEx);
1028 	error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX);
1029 	Stream_Free(s, TRUE);
1030 	return error;
1031 }
1032 
1033 /**
1034  * Function description
1035  *
1036  * @return 0 on success, otherwise a Win32 error code
1037  */
rail_send_client_status_order(railPlugin * rail,const RAIL_CLIENT_STATUS_ORDER * clientStatus)1038 UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
1039 {
1040 	wStream* s;
1041 	UINT error;
1042 
1043 	if (!rail || !clientStatus)
1044 		return ERROR_INVALID_PARAMETER;
1045 
1046 	rail->clientStatus = *clientStatus;
1047 	s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
1048 
1049 	if (!s)
1050 	{
1051 		WLog_ERR(TAG, "rail_pdu_init failed!");
1052 		return CHANNEL_RC_NO_MEMORY;
1053 	}
1054 
1055 	error = rail_write_client_status_order(s, clientStatus);
1056 
1057 	if (error == ERROR_SUCCESS)
1058 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS);
1059 
1060 	Stream_Free(s, TRUE);
1061 	return error;
1062 }
1063 
1064 /**
1065  * Function description
1066  *
1067  * @return 0 on success, otherwise a Win32 error code
1068  */
rail_send_client_exec_order(railPlugin * rail,UINT16 flags,const RAIL_UNICODE_STRING * exeOrFile,const RAIL_UNICODE_STRING * workingDir,const RAIL_UNICODE_STRING * arguments)1069 UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
1070                                  const RAIL_UNICODE_STRING* exeOrFile,
1071                                  const RAIL_UNICODE_STRING* workingDir,
1072                                  const RAIL_UNICODE_STRING* arguments)
1073 {
1074 	wStream* s;
1075 	UINT error;
1076 	size_t length;
1077 
1078 	if (!rail || !exeOrFile || !workingDir || !arguments)
1079 		return ERROR_INVALID_PARAMETER;
1080 
1081 	length = RAIL_EXEC_ORDER_LENGTH + exeOrFile->length + workingDir->length + arguments->length;
1082 	s = rail_pdu_init(length);
1083 
1084 	if (!s)
1085 	{
1086 		WLog_ERR(TAG, "rail_pdu_init failed!");
1087 		return CHANNEL_RC_NO_MEMORY;
1088 	}
1089 
1090 	if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments)))
1091 	{
1092 		WLog_ERR(TAG, "rail_write_client_exec_order failed with error %" PRIu32 "!", error);
1093 		goto out;
1094 	}
1095 
1096 	if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC)))
1097 	{
1098 		WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error);
1099 		goto out;
1100 	}
1101 
1102 out:
1103 	Stream_Free(s, TRUE);
1104 	return error;
1105 }
1106 
1107 /**
1108  * Function description
1109  *
1110  * @return 0 on success, otherwise a Win32 error code
1111  */
rail_send_client_activate_order(railPlugin * rail,const RAIL_ACTIVATE_ORDER * activate)1112 UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate)
1113 {
1114 	wStream* s;
1115 	UINT error;
1116 
1117 	if (!rail || !activate)
1118 		return ERROR_INVALID_PARAMETER;
1119 
1120 	s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
1121 
1122 	if (!s)
1123 	{
1124 		WLog_ERR(TAG, "rail_pdu_init failed!");
1125 		return CHANNEL_RC_NO_MEMORY;
1126 	}
1127 
1128 	error = rail_write_client_activate_order(s, activate);
1129 
1130 	if (error == ERROR_SUCCESS)
1131 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE);
1132 
1133 	Stream_Free(s, TRUE);
1134 	return error;
1135 }
1136 
1137 /**
1138  * Function description
1139  *
1140  * @return 0 on success, otherwise a Win32 error code
1141  */
rail_send_client_sysmenu_order(railPlugin * rail,const RAIL_SYSMENU_ORDER * sysmenu)1142 UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu)
1143 {
1144 	wStream* s;
1145 	UINT error;
1146 
1147 	if (!rail || !sysmenu)
1148 		return ERROR_INVALID_PARAMETER;
1149 
1150 	s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
1151 
1152 	if (!s)
1153 	{
1154 		WLog_ERR(TAG, "rail_pdu_init failed!");
1155 		return CHANNEL_RC_NO_MEMORY;
1156 	}
1157 
1158 	error = rail_write_client_sysmenu_order(s, sysmenu);
1159 
1160 	if (error == ERROR_SUCCESS)
1161 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU);
1162 
1163 	Stream_Free(s, TRUE);
1164 	return error;
1165 }
1166 
1167 /**
1168  * Function description
1169  *
1170  * @return 0 on success, otherwise a Win32 error code
1171  */
rail_send_client_syscommand_order(railPlugin * rail,const RAIL_SYSCOMMAND_ORDER * syscommand)1172 UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand)
1173 {
1174 	wStream* s;
1175 	UINT error;
1176 
1177 	if (!rail || !syscommand)
1178 		return ERROR_INVALID_PARAMETER;
1179 
1180 	s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
1181 
1182 	if (!s)
1183 	{
1184 		WLog_ERR(TAG, "rail_pdu_init failed!");
1185 		return CHANNEL_RC_NO_MEMORY;
1186 	}
1187 
1188 	error = rail_write_client_syscommand_order(s, syscommand);
1189 
1190 	if (error == ERROR_SUCCESS)
1191 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND);
1192 
1193 	Stream_Free(s, TRUE);
1194 	return error;
1195 }
1196 
1197 /**
1198  * Function description
1199  *
1200  * @return 0 on success, otherwise a Win32 error code
1201  */
rail_send_client_notify_event_order(railPlugin * rail,const RAIL_NOTIFY_EVENT_ORDER * notifyEvent)1202 UINT rail_send_client_notify_event_order(railPlugin* rail,
1203                                          const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
1204 {
1205 	wStream* s;
1206 	UINT error;
1207 
1208 	if (!rail || !notifyEvent)
1209 		return ERROR_INVALID_PARAMETER;
1210 
1211 	s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
1212 
1213 	if (!s)
1214 	{
1215 		WLog_ERR(TAG, "rail_pdu_init failed!");
1216 		return CHANNEL_RC_NO_MEMORY;
1217 	}
1218 
1219 	error = rail_write_client_notify_event_order(s, notifyEvent);
1220 
1221 	if (ERROR_SUCCESS == error)
1222 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT);
1223 
1224 	Stream_Free(s, TRUE);
1225 	return error;
1226 }
1227 
1228 /**
1229  * Function description
1230  *
1231  * @return 0 on success, otherwise a Win32 error code
1232  */
rail_send_client_window_move_order(railPlugin * rail,const RAIL_WINDOW_MOVE_ORDER * windowMove)1233 UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove)
1234 {
1235 	wStream* s;
1236 	UINT error;
1237 
1238 	if (!rail || !windowMove)
1239 		return ERROR_INVALID_PARAMETER;
1240 
1241 	s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
1242 
1243 	if (!s)
1244 	{
1245 		WLog_ERR(TAG, "rail_pdu_init failed!");
1246 		return CHANNEL_RC_NO_MEMORY;
1247 	}
1248 
1249 	error = rail_write_client_window_move_order(s, windowMove);
1250 
1251 	if (error == ERROR_SUCCESS)
1252 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE);
1253 
1254 	Stream_Free(s, TRUE);
1255 	return error;
1256 }
1257 
1258 /**
1259  * Function description
1260  *
1261  * @return 0 on success, otherwise a Win32 error code
1262  */
rail_send_client_get_appid_req_order(railPlugin * rail,const RAIL_GET_APPID_REQ_ORDER * getAppIdReq)1263 UINT rail_send_client_get_appid_req_order(railPlugin* rail,
1264                                           const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
1265 {
1266 	wStream* s;
1267 	UINT error;
1268 
1269 	if (!rail || !getAppIdReq)
1270 		return ERROR_INVALID_PARAMETER;
1271 
1272 	s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
1273 
1274 	if (!s)
1275 	{
1276 		WLog_ERR(TAG, "rail_pdu_init failed!");
1277 		return CHANNEL_RC_NO_MEMORY;
1278 	}
1279 
1280 	error = rail_write_client_get_appid_req_order(s, getAppIdReq);
1281 
1282 	if (error == ERROR_SUCCESS)
1283 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ);
1284 
1285 	Stream_Free(s, TRUE);
1286 	return error;
1287 }
1288 
1289 /**
1290  * Function description
1291  *
1292  * @return 0 on success, otherwise a Win32 error code
1293  */
rail_send_client_langbar_info_order(railPlugin * rail,const RAIL_LANGBAR_INFO_ORDER * langBarInfo)1294 UINT rail_send_client_langbar_info_order(railPlugin* rail,
1295                                          const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
1296 {
1297 	wStream* s;
1298 	UINT error;
1299 
1300 	if (!rail || !langBarInfo)
1301 		return ERROR_INVALID_PARAMETER;
1302 
1303 	if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
1304 		return ERROR_BAD_CONFIGURATION;
1305 
1306 	s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
1307 
1308 	if (!s)
1309 	{
1310 		WLog_ERR(TAG, "rail_pdu_init failed!");
1311 		return CHANNEL_RC_NO_MEMORY;
1312 	}
1313 
1314 	error = rail_write_langbar_info_order(s, langBarInfo);
1315 
1316 	if (ERROR_SUCCESS == error)
1317 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO);
1318 
1319 	Stream_Free(s, TRUE);
1320 	return error;
1321 }
1322 
rail_send_client_languageime_info_order(railPlugin * rail,const RAIL_LANGUAGEIME_INFO_ORDER * langImeInfo)1323 UINT rail_send_client_languageime_info_order(railPlugin* rail,
1324                                              const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
1325 {
1326 	wStream* s;
1327 	UINT error;
1328 
1329 	if (!rail || !langImeInfo)
1330 		return ERROR_INVALID_PARAMETER;
1331 
1332 	if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1333 		return ERROR_BAD_CONFIGURATION;
1334 
1335 	s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH);
1336 
1337 	if (!s)
1338 	{
1339 		WLog_ERR(TAG, "rail_pdu_init failed!");
1340 		return CHANNEL_RC_NO_MEMORY;
1341 	}
1342 
1343 	error = rail_write_languageime_info_order(s, langImeInfo);
1344 
1345 	if (ERROR_SUCCESS == error)
1346 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO);
1347 
1348 	Stream_Free(s, TRUE);
1349 	return error;
1350 }
1351 
rail_send_client_compartment_info_order(railPlugin * rail,const RAIL_COMPARTMENT_INFO_ORDER * compartmentInfo)1352 UINT rail_send_client_compartment_info_order(railPlugin* rail,
1353                                              const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
1354 {
1355 	wStream* s;
1356 	UINT error;
1357 
1358 	if (!rail || !compartmentInfo)
1359 		return ERROR_INVALID_PARAMETER;
1360 
1361 	s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
1362 
1363 	if (!s)
1364 	{
1365 		WLog_ERR(TAG, "rail_pdu_init failed!");
1366 		return CHANNEL_RC_NO_MEMORY;
1367 	}
1368 
1369 	error = rail_write_compartment_info_order(s, compartmentInfo);
1370 
1371 	if (ERROR_SUCCESS == error)
1372 		error = rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO);
1373 
1374 	Stream_Free(s, TRUE);
1375 	return error;
1376 }
1377 
rail_send_client_cloak_order(railPlugin * rail,const RAIL_CLOAK * cloak)1378 UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
1379 {
1380 	wStream* s;
1381 	UINT error;
1382 
1383 	if (!rail || !cloak)
1384 		return ERROR_INVALID_PARAMETER;
1385 
1386 	s = rail_pdu_init(5);
1387 
1388 	if (!s)
1389 	{
1390 		WLog_ERR(TAG, "rail_pdu_init failed!");
1391 		return CHANNEL_RC_NO_MEMORY;
1392 	}
1393 
1394 	Stream_Write_UINT32(s, cloak->windowId);
1395 	Stream_Write_UINT8(s, cloak->cloak ? 1 : 0);
1396 	error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK);
1397 	Stream_Free(s, TRUE);
1398 	return error;
1399 }
1400 
rail_send_client_snap_arrange_order(railPlugin * rail,const RAIL_SNAP_ARRANGE * snap)1401 UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
1402 {
1403 	wStream* s;
1404 	UINT error;
1405 
1406 	if (!rail)
1407 		return ERROR_INVALID_PARAMETER;
1408 
1409 	/* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */
1410 	if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0)
1411 	{
1412 		RAIL_WINDOW_MOVE_ORDER move = { 0 };
1413 		move.top = snap->top;
1414 		move.left = snap->left;
1415 		move.right = snap->right;
1416 		move.bottom = snap->bottom;
1417 		move.windowId = snap->windowId;
1418 		return rail_send_client_window_move_order(rail, &move);
1419 	}
1420 
1421 	s = rail_pdu_init(12);
1422 
1423 	if (!s)
1424 	{
1425 		WLog_ERR(TAG, "rail_pdu_init failed!");
1426 		return CHANNEL_RC_NO_MEMORY;
1427 	}
1428 
1429 	Stream_Write_UINT32(s, snap->windowId);
1430 	Stream_Write_INT16(s, snap->left);
1431 	Stream_Write_INT16(s, snap->top);
1432 	Stream_Write_INT16(s, snap->right);
1433 	Stream_Write_INT16(s, snap->bottom);
1434 	error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE);
1435 	Stream_Free(s, TRUE);
1436 	return error;
1437 }
1438