Coverage Report

Created: 2025-07-01 06:46

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