1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Terminal Server Gateway (TSG)
4 *
5 * Copyright 2012 Fujitsu Technology Solutions GmbH
6 * Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
7 * Copyright 2015 Thincast Technologies GmbH
8 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <assert.h>
28 #include <winpr/crt.h>
29 #include <winpr/ndr.h>
30 #include <winpr/error.h>
31 #include <winpr/print.h>
32 #include <winpr/stream.h>
33
34 #include <freerdp/log.h>
35
36 #include "rpc_bind.h"
37 #include "rpc_client.h"
38 #include "tsg.h"
39 #include "../../crypto/opensslcompat.h"
40
41 #define TAG FREERDP_TAG("core.gateway.tsg")
42
43 #define TSG_CAPABILITY_TYPE_NAP 0x00000001
44
45 #define TSG_PACKET_TYPE_HEADER 0x00004844
46 #define TSG_PACKET_TYPE_VERSIONCAPS 0x00005643
47 #define TSG_PACKET_TYPE_QUARCONFIGREQUEST 0x00005143
48 #define TSG_PACKET_TYPE_QUARREQUEST 0x00005152
49 #define TSG_PACKET_TYPE_RESPONSE 0x00005052
50 #define TSG_PACKET_TYPE_QUARENC_RESPONSE 0x00004552
51 #define TSG_PACKET_TYPE_CAPS_RESPONSE 0x00004350
52 #define TSG_PACKET_TYPE_MSGREQUEST_PACKET 0x00004752
53 #define TSG_PACKET_TYPE_MESSAGE_PACKET 0x00004750
54 #define TSG_PACKET_TYPE_AUTH 0x00004054
55 #define TSG_PACKET_TYPE_REAUTH 0x00005250
56
57 typedef WCHAR* RESOURCENAME;
58
59 typedef struct _tsendpointinfo
60 {
61 RESOURCENAME* resourceName;
62 UINT32 numResourceNames;
63 RESOURCENAME* alternateResourceNames;
64 UINT16 numAlternateResourceNames;
65 UINT32 Port;
66 } TSENDPOINTINFO, *PTSENDPOINTINFO;
67
68 typedef struct _TSG_PACKET_HEADER
69 {
70 UINT16 ComponentId;
71 UINT16 PacketId;
72 } TSG_PACKET_HEADER, *PTSG_PACKET_HEADER;
73
74 typedef struct _TSG_CAPABILITY_NAP
75 {
76 UINT32 capabilities;
77 } TSG_CAPABILITY_NAP, *PTSG_CAPABILITY_NAP;
78
79 typedef union
80 {
81 TSG_CAPABILITY_NAP tsgCapNap;
82 } TSG_CAPABILITIES_UNION, *PTSG_CAPABILITIES_UNION;
83
84 typedef struct _TSG_PACKET_CAPABILITIES
85 {
86 UINT32 capabilityType;
87 TSG_CAPABILITIES_UNION tsgPacket;
88 } TSG_PACKET_CAPABILITIES, *PTSG_PACKET_CAPABILITIES;
89
90 typedef struct _TSG_PACKET_VERSIONCAPS
91 {
92 TSG_PACKET_HEADER tsgHeader;
93 PTSG_PACKET_CAPABILITIES tsgCaps;
94 UINT32 numCapabilities;
95 UINT16 majorVersion;
96 UINT16 minorVersion;
97 UINT16 quarantineCapabilities;
98 } TSG_PACKET_VERSIONCAPS, *PTSG_PACKET_VERSIONCAPS;
99
100 typedef struct _TSG_PACKET_QUARCONFIGREQUEST
101 {
102 UINT32 flags;
103 } TSG_PACKET_QUARCONFIGREQUEST, *PTSG_PACKET_QUARCONFIGREQUEST;
104
105 typedef struct _TSG_PACKET_QUARREQUEST
106 {
107 UINT32 flags;
108 WCHAR* machineName;
109 UINT32 nameLength;
110 BYTE* data;
111 UINT32 dataLen;
112 } TSG_PACKET_QUARREQUEST, *PTSG_PACKET_QUARREQUEST;
113
114 typedef struct _TSG_REDIRECTION_FLAGS
115 {
116 BOOL enableAllRedirections;
117 BOOL disableAllRedirections;
118 BOOL driveRedirectionDisabled;
119 BOOL printerRedirectionDisabled;
120 BOOL portRedirectionDisabled;
121 BOOL reserved;
122 BOOL clipboardRedirectionDisabled;
123 BOOL pnpRedirectionDisabled;
124 } TSG_REDIRECTION_FLAGS, *PTSG_REDIRECTION_FLAGS;
125
126 typedef struct _TSG_PACKET_RESPONSE
127 {
128 UINT32 flags;
129 UINT32 reserved;
130 BYTE* responseData;
131 UINT32 responseDataLen;
132 TSG_REDIRECTION_FLAGS redirectionFlags;
133 } TSG_PACKET_RESPONSE, *PTSG_PACKET_RESPONSE;
134
135 typedef struct _TSG_PACKET_QUARENC_RESPONSE
136 {
137 UINT32 flags;
138 UINT32 certChainLen;
139 WCHAR* certChainData;
140 GUID nonce;
141 PTSG_PACKET_VERSIONCAPS versionCaps;
142 } TSG_PACKET_QUARENC_RESPONSE, *PTSG_PACKET_QUARENC_RESPONSE;
143
144 typedef struct TSG_PACKET_STRING_MESSAGE
145 {
146 INT32 isDisplayMandatory;
147 INT32 isConsentMandatory;
148 UINT32 msgBytes;
149 WCHAR* msgBuffer;
150 } TSG_PACKET_STRING_MESSAGE;
151
152 typedef struct TSG_PACKET_REAUTH_MESSAGE
153 {
154 UINT64 tunnelContext;
155 } TSG_PACKET_REAUTH_MESSAGE, *PTSG_PACKET_REAUTH_MESSAGE;
156
157 typedef struct _TSG_PACKET_MSG_RESPONSE
158 {
159 UINT32 msgID;
160 UINT32 msgType;
161 INT32 isMsgPresent;
162 } TSG_PACKET_MSG_RESPONSE, *PTSG_PACKET_MSG_RESPONSE;
163
164 typedef struct TSG_PACKET_CAPS_RESPONSE
165 {
166 TSG_PACKET_QUARENC_RESPONSE pktQuarEncResponse;
167 TSG_PACKET_MSG_RESPONSE pktConsentMessage;
168 } TSG_PACKET_CAPS_RESPONSE, *PTSG_PACKET_CAPS_RESPONSE;
169
170 typedef struct TSG_PACKET_MSG_REQUEST
171 {
172 UINT32 maxMessagesPerBatch;
173 } TSG_PACKET_MSG_REQUEST, *PTSG_PACKET_MSG_REQUEST;
174
175 typedef struct _TSG_PACKET_AUTH
176 {
177 TSG_PACKET_VERSIONCAPS tsgVersionCaps;
178 UINT32 cookieLen;
179 BYTE* cookie;
180 } TSG_PACKET_AUTH, *PTSG_PACKET_AUTH;
181
182 typedef union
183 {
184 PTSG_PACKET_VERSIONCAPS packetVersionCaps;
185 PTSG_PACKET_AUTH packetAuth;
186 } TSG_INITIAL_PACKET_TYPE_UNION, *PTSG_INITIAL_PACKET_TYPE_UNION;
187
188 typedef struct TSG_PACKET_REAUTH
189 {
190 UINT64 tunnelContext;
191 UINT32 packetId;
192 TSG_INITIAL_PACKET_TYPE_UNION tsgInitialPacket;
193 } TSG_PACKET_REAUTH, *PTSG_PACKET_REAUTH;
194
195 typedef union
196 {
197 PTSG_PACKET_HEADER packetHeader;
198 PTSG_PACKET_VERSIONCAPS packetVersionCaps;
199 PTSG_PACKET_QUARCONFIGREQUEST packetQuarConfigRequest;
200 PTSG_PACKET_QUARREQUEST packetQuarRequest;
201 PTSG_PACKET_RESPONSE packetResponse;
202 PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse;
203 PTSG_PACKET_CAPS_RESPONSE packetCapsResponse;
204 PTSG_PACKET_MSG_REQUEST packetMsgRequest;
205 PTSG_PACKET_MSG_RESPONSE packetMsgResponse;
206 PTSG_PACKET_AUTH packetAuth;
207 PTSG_PACKET_REAUTH packetReauth;
208 } TSG_PACKET_TYPE_UNION;
209
210 typedef struct _TSG_PACKET
211 {
212 UINT32 packetId;
213 TSG_PACKET_TYPE_UNION tsgPacket;
214 } TSG_PACKET, *PTSG_PACKET;
215
216 struct rdp_tsg
217 {
218 BIO* bio;
219 rdpRpc* rpc;
220 UINT16 Port;
221 LPWSTR Hostname;
222 LPWSTR MachineName;
223 TSG_STATE state;
224 UINT32 TunnelId;
225 UINT32 ChannelId;
226 BOOL reauthSequence;
227 rdpTransport* transport;
228 UINT64 ReauthTunnelContext;
229 CONTEXT_HANDLE TunnelContext;
230 CONTEXT_HANDLE ChannelContext;
231 CONTEXT_HANDLE NewTunnelContext;
232 CONTEXT_HANDLE NewChannelContext;
233 TSG_PACKET_REAUTH packetReauth;
234 TSG_PACKET_CAPABILITIES tsgCaps;
235 TSG_PACKET_VERSIONCAPS packetVersionCaps;
236 };
237
tsg_packet_id_to_string(UINT32 packetId)238 static const char* tsg_packet_id_to_string(UINT32 packetId)
239 {
240 switch (packetId)
241 {
242 case TSG_PACKET_TYPE_HEADER:
243 return "TSG_PACKET_TYPE_HEADER";
244 case TSG_PACKET_TYPE_VERSIONCAPS:
245 return "TSG_PACKET_TYPE_VERSIONCAPS";
246 case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
247 return "TSG_PACKET_TYPE_QUARCONFIGREQUEST";
248 case TSG_PACKET_TYPE_QUARREQUEST:
249 return "TSG_PACKET_TYPE_QUARREQUEST";
250 case TSG_PACKET_TYPE_RESPONSE:
251 return "TSG_PACKET_TYPE_RESPONSE";
252 case TSG_PACKET_TYPE_QUARENC_RESPONSE:
253 return "TSG_PACKET_TYPE_QUARENC_RESPONSE";
254 case TSG_CAPABILITY_TYPE_NAP:
255 return "TSG_CAPABILITY_TYPE_NAP";
256 case TSG_PACKET_TYPE_CAPS_RESPONSE:
257 return "TSG_PACKET_TYPE_CAPS_RESPONSE";
258 case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
259 return "TSG_PACKET_TYPE_MSGREQUEST_PACKET";
260 case TSG_PACKET_TYPE_MESSAGE_PACKET:
261 return "TSG_PACKET_TYPE_MESSAGE_PACKET";
262 case TSG_PACKET_TYPE_AUTH:
263 return "TSG_PACKET_TYPE_AUTH";
264 case TSG_PACKET_TYPE_REAUTH:
265 return "TSG_PACKET_TYPE_REAUTH";
266 default:
267 return "UNKNOWN";
268 }
269 }
270
tsg_state_to_string(TSG_STATE state)271 static const char* tsg_state_to_string(TSG_STATE state)
272 {
273 switch (state)
274 {
275 case TSG_STATE_INITIAL:
276 return "TSG_STATE_INITIAL";
277 case TSG_STATE_CONNECTED:
278 return "TSG_STATE_CONNECTED";
279 case TSG_STATE_AUTHORIZED:
280 return "TSG_STATE_AUTHORIZED";
281 case TSG_STATE_CHANNEL_CREATED:
282 return "TSG_STATE_CHANNEL_CREATED";
283 case TSG_STATE_PIPE_CREATED:
284 return "TSG_STATE_PIPE_CREATED";
285 case TSG_STATE_TUNNEL_CLOSE_PENDING:
286 return "TSG_STATE_TUNNEL_CLOSE_PENDING";
287 case TSG_STATE_CHANNEL_CLOSE_PENDING:
288 return "TSG_STATE_CHANNEL_CLOSE_PENDING";
289 case TSG_STATE_FINAL:
290 return "TSG_STATE_FINAL";
291 default:
292 return "TSG_STATE_UNKNOWN";
293 }
294 }
295
tsg_print(char ** buffer,size_t * len,const char * fmt,...)296 static BOOL tsg_print(char** buffer, size_t* len, const char* fmt, ...)
297 {
298 int rc;
299 va_list ap;
300 if (!buffer || !len || !fmt)
301 return FALSE;
302 va_start(ap, fmt);
303 rc = vsnprintf(*buffer, *len, fmt, ap);
304 va_end(ap);
305 if ((rc < 0) || ((size_t)rc > *len))
306 return FALSE;
307 *len -= (size_t)rc;
308 *buffer += (size_t)rc;
309 return TRUE;
310 }
311
tsg_packet_header_to_string(char ** buffer,size_t * length,const TSG_PACKET_HEADER * header)312 static BOOL tsg_packet_header_to_string(char** buffer, size_t* length,
313 const TSG_PACKET_HEADER* header)
314 {
315 assert(buffer);
316 assert(length);
317 assert(header);
318
319 return tsg_print(buffer, length,
320 "header { ComponentId=0x%04" PRIx16 ", PacketId=0x%04" PRIx16 " }",
321 header->ComponentId, header->PacketId);
322 }
323
tsg_type_capability_nap_to_string(char ** buffer,size_t * length,const TSG_CAPABILITY_NAP * cur)324 static BOOL tsg_type_capability_nap_to_string(char** buffer, size_t* length,
325 const TSG_CAPABILITY_NAP* cur)
326 {
327 assert(buffer);
328 assert(length);
329 assert(cur);
330
331 return tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }",
332 tsg_packet_id_to_string(TSG_CAPABILITY_TYPE_NAP), cur->capabilities);
333 }
334
tsg_packet_capabilities_to_string(char ** buffer,size_t * length,const TSG_PACKET_CAPABILITIES * caps,UINT32 numCaps)335 static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
336 const TSG_PACKET_CAPABILITIES* caps, UINT32 numCaps)
337 {
338 UINT32 x;
339
340 assert(buffer);
341 assert(length);
342 assert(caps);
343
344 if (!tsg_print(buffer, length, "capabilities { "))
345 return FALSE;
346
347 for (x = 0; x < numCaps; x++)
348 {
349 const TSG_PACKET_CAPABILITIES* cur = &caps[x];
350 switch (cur->capabilityType)
351 {
352 case TSG_CAPABILITY_TYPE_NAP:
353 if (!tsg_type_capability_nap_to_string(buffer, length, &cur->tsgPacket.tsgCapNap))
354 return FALSE;
355 break;
356 default:
357 if (!tsg_print(buffer, length, "TSG_UNKNOWN_CAPABILITY"))
358 return FALSE;
359 break;
360 }
361 }
362 return tsg_print(buffer, length, " }");
363 }
364
tsg_packet_versioncaps_to_string(char ** buffer,size_t * length,const TSG_PACKET_VERSIONCAPS * caps)365 static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length,
366 const TSG_PACKET_VERSIONCAPS* caps)
367 {
368 assert(buffer);
369 assert(length);
370 assert(caps);
371
372 if (!tsg_print(buffer, length, "versioncaps { "))
373 return FALSE;
374 if (!tsg_packet_header_to_string(buffer, length, &caps->tsgHeader))
375 return FALSE;
376
377 if (!tsg_print(buffer, length, " "))
378 return FALSE;
379
380 if (!tsg_packet_capabilities_to_string(buffer, length, caps->tsgCaps, caps->numCapabilities))
381 return FALSE;
382
383 if (!tsg_print(buffer, length,
384 " numCapabilities=0x%08" PRIx32 ", majorVersion=0x%04" PRIx16
385 ", minorVersion=0x%04" PRIx16 ", quarantineCapabilities=0x%04" PRIx16,
386 caps->numCapabilities, caps->majorVersion, caps->minorVersion,
387 caps->quarantineCapabilities))
388 return FALSE;
389
390 return tsg_print(buffer, length, " }");
391 }
392
tsg_packet_quarconfigrequest_to_string(char ** buffer,size_t * length,const TSG_PACKET_QUARCONFIGREQUEST * caps)393 static BOOL tsg_packet_quarconfigrequest_to_string(char** buffer, size_t* length,
394 const TSG_PACKET_QUARCONFIGREQUEST* caps)
395 {
396 assert(buffer);
397 assert(length);
398 assert(caps);
399
400 if (!tsg_print(buffer, length, "quarconfigrequest { "))
401 return FALSE;
402
403 if (!tsg_print(buffer, length, " "))
404 return FALSE;
405
406 if (!tsg_print(buffer, length, " flags=0x%08" PRIx32, caps->flags))
407 return FALSE;
408
409 return tsg_print(buffer, length, " }");
410 }
411
tsg_packet_quarrequest_to_string(char ** buffer,size_t * length,const TSG_PACKET_QUARREQUEST * caps)412 static BOOL tsg_packet_quarrequest_to_string(char** buffer, size_t* length,
413 const TSG_PACKET_QUARREQUEST* caps)
414 {
415 BOOL rc = FALSE;
416 char* name = NULL;
417 char* strdata = NULL;
418
419 assert(buffer);
420 assert(length);
421 assert(caps);
422
423 if (!tsg_print(buffer, length, "quarrequest { "))
424 return FALSE;
425
426 if (!tsg_print(buffer, length, " "))
427 return FALSE;
428
429 if (caps->nameLength > 0)
430 {
431 if (caps->nameLength > INT_MAX)
432 return FALSE;
433 if (ConvertFromUnicode(CP_UTF8, 0, caps->machineName, (int)caps->nameLength, &name, 0, NULL,
434 NULL) < 0)
435 return FALSE;
436 }
437
438 strdata = winpr_BinToHexString(caps->data, caps->dataLen, TRUE);
439 if (strdata || (caps->dataLen == 0))
440 rc = tsg_print(buffer, length,
441 " flags=0x%08" PRIx32 ", machineName=%s [%" PRIu32 "], data[%" PRIu32 "]=%s",
442 caps->flags, name, caps->nameLength, caps->dataLen, strdata);
443 free(name);
444 free(strdata);
445 if (!rc)
446 return FALSE;
447
448 return tsg_print(buffer, length, " }");
449 }
450
tsg_bool_to_string(BOOL val)451 static const char* tsg_bool_to_string(BOOL val)
452 {
453 if (val)
454 return "true";
455 return "false";
456 }
457
tsg_redirection_flags_to_string(char * buffer,size_t size,const TSG_REDIRECTION_FLAGS * flags)458 static const char* tsg_redirection_flags_to_string(char* buffer, size_t size,
459 const TSG_REDIRECTION_FLAGS* flags)
460 {
461 assert(buffer || (size == 0));
462 assert(flags);
463
464 _snprintf(buffer, size,
465 "enableAllRedirections=%s, disableAllRedirections=%s, driveRedirectionDisabled=%s, "
466 "printerRedirectionDisabled=%s, portRedirectionDisabled=%s, reserved=%s, "
467 "clipboardRedirectionDisabled=%s, pnpRedirectionDisabled=%s",
468 tsg_bool_to_string(flags->enableAllRedirections),
469 tsg_bool_to_string(flags->disableAllRedirections),
470 tsg_bool_to_string(flags->driveRedirectionDisabled),
471 tsg_bool_to_string(flags->printerRedirectionDisabled),
472 tsg_bool_to_string(flags->portRedirectionDisabled),
473 tsg_bool_to_string(flags->reserved),
474 tsg_bool_to_string(flags->clipboardRedirectionDisabled),
475 tsg_bool_to_string(flags->pnpRedirectionDisabled));
476 return buffer;
477 }
478
tsg_packet_response_to_string(char ** buffer,size_t * length,const TSG_PACKET_RESPONSE * caps)479 static BOOL tsg_packet_response_to_string(char** buffer, size_t* length,
480 const TSG_PACKET_RESPONSE* caps)
481 {
482 BOOL rc = FALSE;
483 char* strdata = NULL;
484 char tbuffer[8192] = { 0 };
485
486 assert(buffer);
487 assert(length);
488 assert(caps);
489
490 if (!tsg_print(buffer, length, "response { "))
491 return FALSE;
492
493 if (!tsg_print(buffer, length, " "))
494 return FALSE;
495
496 strdata = winpr_BinToHexString(caps->responseData, caps->responseDataLen, TRUE);
497 if (strdata || (caps->responseDataLen == 0))
498 rc = tsg_print(
499 buffer, length,
500 " flags=0x%08" PRIx32 ", reserved=0x%08" PRIx32 ", responseData[%" PRIu32
501 "]=%s, redirectionFlags={ %s }",
502 caps->flags, caps->reserved, caps->responseDataLen, strdata,
503 tsg_redirection_flags_to_string(tbuffer, ARRAYSIZE(tbuffer), &caps->redirectionFlags));
504 free(strdata);
505 if (!rc)
506 return FALSE;
507
508 return tsg_print(buffer, length, " }");
509 }
510
tsg_packet_quarenc_response_to_string(char ** buffer,size_t * length,const TSG_PACKET_QUARENC_RESPONSE * caps)511 static BOOL tsg_packet_quarenc_response_to_string(char** buffer, size_t* length,
512 const TSG_PACKET_QUARENC_RESPONSE* caps)
513 {
514 BOOL rc = FALSE;
515 char* strdata = NULL;
516 RPC_CSTR uuid;
517 char tbuffer[8192] = { 0 };
518 size_t size = ARRAYSIZE(tbuffer);
519 char* ptbuffer = tbuffer;
520
521 assert(buffer);
522 assert(length);
523 assert(caps);
524
525 if (!tsg_print(buffer, length, "quarenc_response { "))
526 return FALSE;
527
528 if (!tsg_print(buffer, length, " "))
529 return FALSE;
530
531 if (caps->certChainLen > 0)
532 {
533 if (caps->certChainLen > INT_MAX)
534 return FALSE;
535 if (ConvertFromUnicode(CP_UTF8, 0, caps->certChainData, (int)caps->certChainLen, &strdata,
536 0, NULL, NULL) <= 0)
537 return FALSE;
538 }
539
540 tsg_packet_versioncaps_to_string(&ptbuffer, &size, caps->versionCaps);
541 UuidToStringA(&caps->nonce, &uuid);
542 if (strdata || (caps->certChainLen == 0))
543 rc =
544 tsg_print(buffer, length,
545 " flags=0x%08" PRIx32 ", certChain[%" PRIu32 "]=%s, nonce=%s, versionCaps=%s",
546 caps->flags, caps->certChainLen, strdata, uuid, tbuffer);
547 free(strdata);
548 free(uuid);
549 if (!rc)
550 return FALSE;
551
552 return tsg_print(buffer, length, " }");
553 }
554
tsg_packet_message_response_to_string(char ** buffer,size_t * length,const TSG_PACKET_MSG_RESPONSE * caps)555 static BOOL tsg_packet_message_response_to_string(char** buffer, size_t* length,
556 const TSG_PACKET_MSG_RESPONSE* caps)
557 {
558 assert(buffer);
559 assert(length);
560 assert(caps);
561
562 if (!tsg_print(buffer, length, "msg_response { "))
563 return FALSE;
564
565 if (!tsg_print(buffer, length,
566 " msgID=0x%08" PRIx32 ", msgType=0x%08" PRIx32 ", isMsgPresent=%" PRId32,
567 caps->msgID, caps->msgType, caps->isMsgPresent))
568 return FALSE;
569
570 return tsg_print(buffer, length, " }");
571 }
572
tsg_packet_caps_response_to_string(char ** buffer,size_t * length,const TSG_PACKET_CAPS_RESPONSE * caps)573 static BOOL tsg_packet_caps_response_to_string(char** buffer, size_t* length,
574 const TSG_PACKET_CAPS_RESPONSE* caps)
575 {
576 assert(buffer);
577 assert(length);
578 assert(caps);
579
580 if (!tsg_print(buffer, length, "caps_response { "))
581 return FALSE;
582
583 if (!tsg_packet_quarenc_response_to_string(buffer, length, &caps->pktQuarEncResponse))
584 return FALSE;
585
586 if (!tsg_packet_message_response_to_string(buffer, length, &caps->pktConsentMessage))
587 return FALSE;
588
589 return tsg_print(buffer, length, " }");
590 }
591
tsg_packet_message_request_to_string(char ** buffer,size_t * length,const TSG_PACKET_MSG_REQUEST * caps)592 static BOOL tsg_packet_message_request_to_string(char** buffer, size_t* length,
593 const TSG_PACKET_MSG_REQUEST* caps)
594 {
595 assert(buffer);
596 assert(length);
597 assert(caps);
598
599 if (!tsg_print(buffer, length, "caps_message_request { "))
600 return FALSE;
601
602 if (!tsg_print(buffer, length, " maxMessagesPerBatch=%" PRIu32, caps->maxMessagesPerBatch))
603 return FALSE;
604
605 return tsg_print(buffer, length, " }");
606 }
607
tsg_packet_auth_to_string(char ** buffer,size_t * length,const TSG_PACKET_AUTH * caps)608 static BOOL tsg_packet_auth_to_string(char** buffer, size_t* length, const TSG_PACKET_AUTH* caps)
609 {
610 BOOL rc = FALSE;
611 char* strdata = NULL;
612 assert(buffer);
613 assert(length);
614 assert(caps);
615
616 if (!tsg_print(buffer, length, "caps_message_request { "))
617 return FALSE;
618
619 if (!tsg_packet_versioncaps_to_string(buffer, length, &caps->tsgVersionCaps))
620 return FALSE;
621
622 strdata = winpr_BinToHexString(caps->cookie, caps->cookieLen, TRUE);
623 if (strdata || (caps->cookieLen == 0))
624 rc = tsg_print(buffer, length, " cookie[%" PRIu32 "]=%s", caps->cookieLen, strdata);
625 free(strdata);
626 if (!rc)
627 return FALSE;
628
629 return tsg_print(buffer, length, " }");
630 }
631
tsg_packet_reauth_to_string(char ** buffer,size_t * length,const TSG_PACKET_REAUTH * caps)632 static BOOL tsg_packet_reauth_to_string(char** buffer, size_t* length,
633 const TSG_PACKET_REAUTH* caps)
634 {
635 BOOL rc = FALSE;
636 assert(buffer);
637 assert(length);
638 assert(caps);
639
640 if (!tsg_print(buffer, length, "caps_message_request { "))
641 return FALSE;
642
643 if (!tsg_print(buffer, length, " tunnelContext=0x%016" PRIx64 ", packetId=%s [0x%08" PRIx32 "]",
644 caps->tunnelContext, tsg_packet_id_to_string(caps->packetId), caps->packetId))
645 return FALSE;
646
647 switch (caps->packetId)
648 {
649 case TSG_PACKET_TYPE_VERSIONCAPS:
650 rc = tsg_packet_versioncaps_to_string(buffer, length,
651 caps->tsgInitialPacket.packetVersionCaps);
652 break;
653 case TSG_PACKET_TYPE_AUTH:
654 rc = tsg_packet_auth_to_string(buffer, length, caps->tsgInitialPacket.packetAuth);
655 break;
656 default:
657 rc = tsg_print(buffer, length, "TODO: Unhandled packet type %s [0x%08" PRIx32 "]",
658 tsg_packet_id_to_string(caps->packetId), caps->packetId);
659 break;
660 }
661
662 if (!rc)
663 return FALSE;
664
665 return tsg_print(buffer, length, " }");
666 }
667
tsg_packet_to_string(const TSG_PACKET * packet)668 static const char* tsg_packet_to_string(const TSG_PACKET* packet)
669 {
670 size_t len = 8192;
671 static char sbuffer[8193] = { 0 };
672 char* buffer = sbuffer;
673
674 if (!tsg_print(&buffer, &len, "TSG_PACKET { packetId=%s [0x%08" PRIx32 "], ",
675 tsg_packet_id_to_string(packet->packetId), packet->packetId))
676 goto fail;
677
678 switch (packet->packetId)
679 {
680 case TSG_PACKET_TYPE_HEADER:
681 if (!tsg_packet_header_to_string(&buffer, &len, packet->tsgPacket.packetHeader))
682 goto fail;
683 break;
684 case TSG_PACKET_TYPE_VERSIONCAPS:
685 if (!tsg_packet_versioncaps_to_string(&buffer, &len,
686 packet->tsgPacket.packetVersionCaps))
687 goto fail;
688 break;
689 case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
690 if (!tsg_packet_quarconfigrequest_to_string(&buffer, &len,
691 packet->tsgPacket.packetQuarConfigRequest))
692 goto fail;
693 break;
694 case TSG_PACKET_TYPE_QUARREQUEST:
695 if (!tsg_packet_quarrequest_to_string(&buffer, &len,
696 packet->tsgPacket.packetQuarRequest))
697 goto fail;
698 break;
699 case TSG_PACKET_TYPE_RESPONSE:
700 if (!tsg_packet_response_to_string(&buffer, &len, packet->tsgPacket.packetResponse))
701 goto fail;
702 break;
703 case TSG_PACKET_TYPE_QUARENC_RESPONSE:
704 if (!tsg_packet_quarenc_response_to_string(&buffer, &len,
705 packet->tsgPacket.packetQuarEncResponse))
706 goto fail;
707 break;
708 case TSG_PACKET_TYPE_CAPS_RESPONSE:
709 if (!tsg_packet_caps_response_to_string(&buffer, &len,
710 packet->tsgPacket.packetCapsResponse))
711 goto fail;
712 break;
713 case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
714 if (!tsg_packet_message_request_to_string(&buffer, &len,
715 packet->tsgPacket.packetMsgRequest))
716 goto fail;
717 break;
718 case TSG_PACKET_TYPE_MESSAGE_PACKET:
719 if (!tsg_packet_message_response_to_string(&buffer, &len,
720 packet->tsgPacket.packetMsgResponse))
721 goto fail;
722 break;
723 case TSG_PACKET_TYPE_AUTH:
724 if (!tsg_packet_auth_to_string(&buffer, &len, packet->tsgPacket.packetAuth))
725 goto fail;
726 break;
727 case TSG_PACKET_TYPE_REAUTH:
728 if (!tsg_packet_reauth_to_string(&buffer, &len, packet->tsgPacket.packetReauth))
729 goto fail;
730 break;
731 default:
732 if (!tsg_print(&buffer, &len, "INVALID"))
733 goto fail;
734 break;
735 }
736
737 if (!tsg_print(&buffer, &len, " }"))
738 goto fail;
739
740 fail:
741 return sbuffer;
742 }
743
tsg_stream_align(wStream * s,size_t align)744 static BOOL tsg_stream_align(wStream* s, size_t align)
745 {
746 size_t pos;
747 size_t offset = 0;
748
749 if (!s)
750 return FALSE;
751
752 pos = Stream_GetPosition(s);
753
754 if ((pos % align) != 0)
755 offset = align - pos % align;
756
757 return Stream_SafeSeek(s, offset);
758 }
759
760 static BIO_METHOD* BIO_s_tsg(void);
761 /**
762 * RPC Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378623/
763 * Remote Procedure Call: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378651/
764 * RPC NDR Interface Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/hh802752/
765 */
766
767 /**
768 * call sequence with silent reauth:
769 *
770 * TsProxyCreateTunnelRequest()
771 * TsProxyCreateTunnelResponse(TunnelContext)
772 * TsProxyAuthorizeTunnelRequest(TunnelContext)
773 * TsProxyAuthorizeTunnelResponse()
774 * TsProxyMakeTunnelCallRequest(TunnelContext)
775 * TsProxyCreateChannelRequest(TunnelContext)
776 * TsProxyCreateChannelResponse(ChannelContext)
777 * TsProxySetupReceivePipeRequest(ChannelContext)
778 * TsProxySendToServerRequest(ChannelContext)
779 *
780 * ...
781 *
782 * TsProxyMakeTunnelCallResponse(reauth)
783 * TsProxyCreateTunnelRequest()
784 * TsProxyMakeTunnelCallRequest(TunnelContext)
785 * TsProxyCreateTunnelResponse(NewTunnelContext)
786 * TsProxyAuthorizeTunnelRequest(NewTunnelContext)
787 * TsProxyAuthorizeTunnelResponse()
788 * TsProxyCreateChannelRequest(NewTunnelContext)
789 * TsProxyCreateChannelResponse(NewChannelContext)
790 * TsProxyCloseChannelRequest(NewChannelContext)
791 * TsProxyCloseTunnelRequest(NewTunnelContext)
792 * TsProxyCloseChannelResponse(NullChannelContext)
793 * TsProxyCloseTunnelResponse(NullTunnelContext)
794 * TsProxySendToServerRequest(ChannelContext)
795 */
796
TsProxySendToServer(handle_t IDL_handle,const byte pRpcMessage[],UINT32 count,UINT32 * lengths)797 static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UINT32 count,
798 UINT32* lengths)
799 {
800 wStream* s;
801 rdpTsg* tsg;
802 size_t length;
803 const byte* buffer1 = NULL;
804 const byte* buffer2 = NULL;
805 const byte* buffer3 = NULL;
806 UINT32 buffer1Length;
807 UINT32 buffer2Length;
808 UINT32 buffer3Length;
809 UINT32 numBuffers = 0;
810 UINT32 totalDataBytes = 0;
811 tsg = (rdpTsg*)IDL_handle;
812 buffer1Length = buffer2Length = buffer3Length = 0;
813
814 if (count > 0)
815 {
816 numBuffers++;
817 buffer1 = &pRpcMessage[0];
818 buffer1Length = lengths[0];
819 totalDataBytes += lengths[0] + 4;
820 }
821
822 if (count > 1)
823 {
824 numBuffers++;
825 buffer2 = &pRpcMessage[1];
826 buffer2Length = lengths[1];
827 totalDataBytes += lengths[1] + 4;
828 }
829
830 if (count > 2)
831 {
832 numBuffers++;
833 buffer3 = &pRpcMessage[2];
834 buffer3Length = lengths[2];
835 totalDataBytes += lengths[2] + 4;
836 }
837
838 length = 28ull + totalDataBytes;
839 if (length > INT_MAX)
840 return -1;
841 s = Stream_New(NULL, length);
842
843 if (!s)
844 {
845 WLog_ERR(TAG, "Stream_New failed!");
846 return -1;
847 }
848
849 /* PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE_NR (20 bytes) */
850 Stream_Write(s, &tsg->ChannelContext.ContextType, 4); /* ContextType (4 bytes) */
851 Stream_Write(s, tsg->ChannelContext.ContextUuid, 16); /* ContextUuid (16 bytes) */
852 Stream_Write_UINT32_BE(s, totalDataBytes); /* totalDataBytes (4 bytes) */
853 Stream_Write_UINT32_BE(s, numBuffers); /* numBuffers (4 bytes) */
854
855 if (buffer1Length > 0)
856 Stream_Write_UINT32_BE(s, buffer1Length); /* buffer1Length (4 bytes) */
857
858 if (buffer2Length > 0)
859 Stream_Write_UINT32_BE(s, buffer2Length); /* buffer2Length (4 bytes) */
860
861 if (buffer3Length > 0)
862 Stream_Write_UINT32_BE(s, buffer3Length); /* buffer3Length (4 bytes) */
863
864 if (buffer1Length > 0)
865 Stream_Write(s, buffer1, buffer1Length); /* buffer1 (variable) */
866
867 if (buffer2Length > 0)
868 Stream_Write(s, buffer2, buffer2Length); /* buffer2 (variable) */
869
870 if (buffer3Length > 0)
871 Stream_Write(s, buffer3, buffer3Length); /* buffer3 (variable) */
872
873 if (!rpc_client_write_call(tsg->rpc, s, TsProxySendToServerOpnum))
874 return -1;
875
876 return (int)length;
877 }
878
879 /**
880 * OpNum = 1
881 *
882 * HRESULT TsProxyCreateTunnel(
883 * [in, ref] PTSG_PACKET tsgPacket,
884 * [out, ref] PTSG_PACKET* tsgPacketResponse,
885 * [out] PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext,
886 * [out] unsigned long* tunnelId
887 * );
888 */
889
TsProxyCreateTunnelWriteRequest(rdpTsg * tsg,const PTSG_PACKET tsgPacket)890 static BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg, const PTSG_PACKET tsgPacket)
891 {
892 BOOL rc = FALSE;
893 BOOL write = TRUE;
894 UINT16 opnum = 0;
895 wStream* s;
896 rdpRpc* rpc;
897
898 if (!tsg || !tsg->rpc)
899 return FALSE;
900
901 rpc = tsg->rpc;
902 WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_to_string(tsgPacket));
903 s = Stream_New(NULL, 108);
904
905 if (!s)
906 return FALSE;
907
908 switch (tsgPacket->packetId)
909 {
910 case TSG_PACKET_TYPE_VERSIONCAPS:
911 {
912 PTSG_PACKET_VERSIONCAPS packetVersionCaps = tsgPacket->tsgPacket.packetVersionCaps;
913 PTSG_CAPABILITY_NAP tsgCapNap = &packetVersionCaps->tsgCaps->tsgPacket.tsgCapNap;
914 Stream_Write_UINT32(s, tsgPacket->packetId); /* PacketId (4 bytes) */
915 Stream_Write_UINT32(s, tsgPacket->packetId); /* SwitchValue (4 bytes) */
916 Stream_Write_UINT32(s, 0x00020000); /* PacketVersionCapsPtr (4 bytes) */
917 Stream_Write_UINT16(
918 s, packetVersionCaps->tsgHeader.ComponentId); /* ComponentId (2 bytes) */
919 Stream_Write_UINT16(s, packetVersionCaps->tsgHeader.PacketId); /* PacketId (2 bytes) */
920 Stream_Write_UINT32(s, 0x00020004); /* TsgCapsPtr (4 bytes) */
921 Stream_Write_UINT32(s,
922 packetVersionCaps->numCapabilities); /* NumCapabilities (4 bytes) */
923 Stream_Write_UINT16(s, packetVersionCaps->majorVersion); /* MajorVersion (2 bytes) */
924 Stream_Write_UINT16(s, packetVersionCaps->minorVersion); /* MinorVersion (2 bytes) */
925 Stream_Write_UINT16(
926 s,
927 packetVersionCaps->quarantineCapabilities); /* QuarantineCapabilities (2 bytes) */
928 /* 4-byte alignment (30 + 2) */
929 Stream_Write_UINT16(s, 0x0000); /* pad (2 bytes) */
930 Stream_Write_UINT32(s, packetVersionCaps->numCapabilities); /* MaxCount (4 bytes) */
931 Stream_Write_UINT32(
932 s, packetVersionCaps->tsgCaps->capabilityType); /* CapabilityType (4 bytes) */
933 Stream_Write_UINT32(
934 s, packetVersionCaps->tsgCaps->capabilityType); /* SwitchValue (4 bytes) */
935 Stream_Write_UINT32(s, tsgCapNap->capabilities); /* capabilities (4 bytes) */
936 /**
937 * The following 60-byte structure is apparently undocumented,
938 * but parts of it can be matched to known C706 data structures.
939 */
940 /*
941 * 8-byte constant (8A E3 13 71 02 F4 36 71) also observed here:
942 * http://lists.samba.org/archive/cifs-protocol/2010-July/001543.html
943 */
944 Stream_Write_UINT8(s, 0x8A);
945 Stream_Write_UINT8(s, 0xE3);
946 Stream_Write_UINT8(s, 0x13);
947 Stream_Write_UINT8(s, 0x71);
948 Stream_Write_UINT8(s, 0x02);
949 Stream_Write_UINT8(s, 0xF4);
950 Stream_Write_UINT8(s, 0x36);
951 Stream_Write_UINT8(s, 0x71);
952 Stream_Write_UINT32(s, 0x00040001); /* 1.4 (version?) */
953 Stream_Write_UINT32(s, 0x00000001); /* 1 (element count?) */
954 /* p_cont_list_t */
955 Stream_Write_UINT8(s, 2); /* ncontext_elem */
956 Stream_Write_UINT8(s, 0x40); /* reserved1 */
957 Stream_Write_UINT16(s, 0x0028); /* reserved2 */
958 /* p_syntax_id_t */
959 Stream_Write(s, &TSGU_UUID, sizeof(p_uuid_t));
960 Stream_Write_UINT32(s, TSGU_SYNTAX_IF_VERSION);
961 /* p_syntax_id_t */
962 Stream_Write(s, &NDR_UUID, sizeof(p_uuid_t));
963 Stream_Write_UINT32(s, NDR_SYNTAX_IF_VERSION);
964 opnum = TsProxyCreateTunnelOpnum;
965 }
966 break;
967
968 case TSG_PACKET_TYPE_REAUTH:
969 {
970 PTSG_PACKET_REAUTH packetReauth = tsgPacket->tsgPacket.packetReauth;
971 PTSG_PACKET_VERSIONCAPS packetVersionCaps =
972 packetReauth->tsgInitialPacket.packetVersionCaps;
973 PTSG_CAPABILITY_NAP tsgCapNap = &packetVersionCaps->tsgCaps->tsgPacket.tsgCapNap;
974 Stream_Write_UINT32(s, tsgPacket->packetId); /* PacketId (4 bytes) */
975 Stream_Write_UINT32(s, tsgPacket->packetId); /* SwitchValue (4 bytes) */
976 Stream_Write_UINT32(s, 0x00020000); /* PacketReauthPtr (4 bytes) */
977 Stream_Write_UINT32(s, 0); /* ??? (4 bytes) */
978 Stream_Write_UINT64(s, packetReauth->tunnelContext); /* TunnelContext (8 bytes) */
979 Stream_Write_UINT32(s, TSG_PACKET_TYPE_VERSIONCAPS); /* PacketId (4 bytes) */
980 Stream_Write_UINT32(s, TSG_PACKET_TYPE_VERSIONCAPS); /* SwitchValue (4 bytes) */
981 Stream_Write_UINT32(s, 0x00020004); /* PacketVersionCapsPtr (4 bytes) */
982 Stream_Write_UINT16(
983 s, packetVersionCaps->tsgHeader.ComponentId); /* ComponentId (2 bytes) */
984 Stream_Write_UINT16(s, packetVersionCaps->tsgHeader.PacketId); /* PacketId (2 bytes) */
985 Stream_Write_UINT32(s, 0x00020008); /* TsgCapsPtr (4 bytes) */
986 Stream_Write_UINT32(s,
987 packetVersionCaps->numCapabilities); /* NumCapabilities (4 bytes) */
988 Stream_Write_UINT16(s, packetVersionCaps->majorVersion); /* MajorVersion (2 bytes) */
989 Stream_Write_UINT16(s, packetVersionCaps->minorVersion); /* MinorVersion (2 bytes) */
990 Stream_Write_UINT16(
991 s,
992 packetVersionCaps->quarantineCapabilities); /* QuarantineCapabilities (2 bytes) */
993 /* 4-byte alignment (30 + 2) */
994 Stream_Write_UINT16(s, 0x0000); /* pad (2 bytes) */
995 Stream_Write_UINT32(s, packetVersionCaps->numCapabilities); /* MaxCount (4 bytes) */
996 Stream_Write_UINT32(
997 s, packetVersionCaps->tsgCaps->capabilityType); /* CapabilityType (4 bytes) */
998 Stream_Write_UINT32(
999 s, packetVersionCaps->tsgCaps->capabilityType); /* SwitchValue (4 bytes) */
1000 Stream_Write_UINT32(s, tsgCapNap->capabilities); /* capabilities (4 bytes) */
1001 opnum = TsProxyCreateTunnelOpnum;
1002 }
1003 break;
1004
1005 default:
1006 write = FALSE;
1007 break;
1008 }
1009
1010 rc = TRUE;
1011
1012 if (write)
1013 return rpc_client_write_call(rpc, s, opnum);
1014
1015 Stream_Free(s, TRUE);
1016 return rc;
1017 }
1018
TsProxyCreateTunnelReadResponse(rdpTsg * tsg,RPC_PDU * pdu,CONTEXT_HANDLE * tunnelContext,UINT32 * tunnelId)1019 static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
1020 CONTEXT_HANDLE* tunnelContext, UINT32* tunnelId)
1021 {
1022 BOOL rc = FALSE;
1023 UINT32 count;
1024 UINT32 Pointer;
1025 PTSG_PACKET packet;
1026 UINT32 SwitchValue;
1027 UINT32 MessageSwitchValue = 0;
1028 UINT32 IsMessagePresent;
1029 rdpContext* context;
1030 PTSG_PACKET_CAPABILITIES tsgCaps = NULL;
1031 PTSG_PACKET_VERSIONCAPS versionCaps = NULL;
1032 TSG_PACKET_STRING_MESSAGE packetStringMessage;
1033 PTSG_PACKET_CAPS_RESPONSE packetCapsResponse = NULL;
1034 PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse = NULL;
1035
1036 assert(tsg);
1037 assert(tsg->rpc);
1038
1039 context = tsg->rpc->context;
1040 assert(context);
1041
1042 if (!pdu)
1043 return FALSE;
1044
1045 packet = (PTSG_PACKET)calloc(1, sizeof(TSG_PACKET));
1046
1047 if (!packet)
1048 return FALSE;
1049
1050 if (Stream_GetRemainingLength(pdu->s) < 12)
1051 goto fail;
1052
1053 Stream_Seek_UINT32(pdu->s); /* PacketPtr (4 bytes) */
1054 Stream_Read_UINT32(pdu->s, packet->packetId); /* PacketId (4 bytes) */
1055 Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1056
1057 WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet->packetId));
1058
1059 if ((packet->packetId == TSG_PACKET_TYPE_CAPS_RESPONSE) &&
1060 (SwitchValue == TSG_PACKET_TYPE_CAPS_RESPONSE))
1061 {
1062 packetCapsResponse = (PTSG_PACKET_CAPS_RESPONSE)calloc(1, sizeof(TSG_PACKET_CAPS_RESPONSE));
1063
1064 if (!packetCapsResponse)
1065 goto fail;
1066
1067 packet->tsgPacket.packetCapsResponse = packetCapsResponse;
1068
1069 if (Stream_GetRemainingLength(pdu->s) < 32)
1070 goto fail;
1071
1072 Stream_Seek_UINT32(pdu->s); /* PacketQuarResponsePtr (4 bytes) */
1073 Stream_Read_UINT32(pdu->s,
1074 packetCapsResponse->pktQuarEncResponse.flags); /* Flags (4 bytes) */
1075 Stream_Read_UINT32(
1076 pdu->s,
1077 packetCapsResponse->pktQuarEncResponse.certChainLen); /* CertChainLength (4 bytes) */
1078 Stream_Seek_UINT32(pdu->s); /* CertChainDataPtr (4 bytes) */
1079 Stream_Read(pdu->s, &packetCapsResponse->pktQuarEncResponse.nonce,
1080 16); /* Nonce (16 bytes) */
1081 Stream_Read_UINT32(pdu->s, Pointer); /* VersionCapsPtr (4 bytes) */
1082
1083 if ((Pointer == 0x0002000C) || (Pointer == 0x00020008))
1084 {
1085 if (Stream_GetRemainingLength(pdu->s) < 16)
1086 goto fail;
1087
1088 Stream_Seek_UINT32(pdu->s); /* MsgId (4 bytes) */
1089 Stream_Seek_UINT32(pdu->s); /* MsgType (4 bytes) */
1090 Stream_Read_UINT32(pdu->s, IsMessagePresent); /* IsMessagePresent (4 bytes) */
1091 Stream_Read_UINT32(pdu->s, MessageSwitchValue); /* MessageSwitchValue (4 bytes) */
1092 }
1093
1094 if (packetCapsResponse->pktQuarEncResponse.certChainLen > 0)
1095 {
1096 if (Stream_GetRemainingLength(pdu->s) < 16)
1097 goto fail;
1098
1099 Stream_Read_UINT32(pdu->s, Pointer); /* MsgPtr (4 bytes): 0x00020014 */
1100 Stream_Seek_UINT32(pdu->s); /* MaxCount (4 bytes) */
1101 Stream_Seek_UINT32(pdu->s); /* Offset (4 bytes) */
1102 Stream_Read_UINT32(pdu->s, count); /* ActualCount (4 bytes) */
1103
1104 /*
1105 * CertChainData is a wide character string, and the count is
1106 * given in characters excluding the null terminator, therefore:
1107 * size = (count * 2)
1108 */
1109 if (!Stream_SafeSeek(pdu->s, count * 2)) /* CertChainData */
1110 goto fail;
1111
1112 /* 4-byte alignment */
1113 if (!tsg_stream_align(pdu->s, 4))
1114 goto fail;
1115 }
1116 else
1117 {
1118 if (Stream_GetRemainingLength(pdu->s) < 4)
1119 goto fail;
1120
1121 Stream_Read_UINT32(pdu->s, Pointer); /* Ptr (4 bytes) */
1122 }
1123
1124 versionCaps = (PTSG_PACKET_VERSIONCAPS)calloc(1, sizeof(TSG_PACKET_VERSIONCAPS));
1125
1126 if (!versionCaps)
1127 goto fail;
1128
1129 packetCapsResponse->pktQuarEncResponse.versionCaps = versionCaps;
1130
1131 if (Stream_GetRemainingLength(pdu->s) < 18)
1132 goto fail;
1133
1134 Stream_Read_UINT16(pdu->s, versionCaps->tsgHeader.ComponentId); /* ComponentId (2 bytes) */
1135 Stream_Read_UINT16(pdu->s, versionCaps->tsgHeader.PacketId); /* PacketId (2 bytes) */
1136
1137 if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT)
1138 {
1139 WLog_ERR(TAG, "Unexpected ComponentId: 0x%04" PRIX16 ", Expected TS_GATEWAY_TRANSPORT",
1140 versionCaps->tsgHeader.ComponentId);
1141 goto fail;
1142 }
1143
1144 Stream_Read_UINT32(pdu->s, Pointer); /* TsgCapsPtr (4 bytes) */
1145 Stream_Read_UINT32(pdu->s, versionCaps->numCapabilities); /* NumCapabilities (4 bytes) */
1146 Stream_Read_UINT16(pdu->s, versionCaps->majorVersion); /* MajorVersion (2 bytes) */
1147 Stream_Read_UINT16(pdu->s, versionCaps->minorVersion); /* MinorVersion (2 bytes) */
1148 Stream_Read_UINT16(
1149 pdu->s, versionCaps->quarantineCapabilities); /* QuarantineCapabilities (2 bytes) */
1150
1151 /* 4-byte alignment */
1152 if (!tsg_stream_align(pdu->s, 4))
1153 goto fail;
1154
1155 tsgCaps = (PTSG_PACKET_CAPABILITIES)calloc(1, sizeof(TSG_PACKET_CAPABILITIES));
1156
1157 if (!tsgCaps)
1158 goto fail;
1159
1160 versionCaps->tsgCaps = tsgCaps;
1161
1162 if (Stream_GetRemainingLength(pdu->s) < 16)
1163 goto fail;
1164
1165 Stream_Seek_UINT32(pdu->s); /* MaxCount (4 bytes) */
1166 Stream_Read_UINT32(pdu->s, tsgCaps->capabilityType); /* CapabilityType (4 bytes) */
1167 Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1168
1169 if ((SwitchValue != TSG_CAPABILITY_TYPE_NAP) ||
1170 (tsgCaps->capabilityType != TSG_CAPABILITY_TYPE_NAP))
1171 {
1172 WLog_ERR(TAG,
1173 "Unexpected CapabilityType: 0x%08" PRIX32 ", Expected TSG_CAPABILITY_TYPE_NAP",
1174 tsgCaps->capabilityType);
1175 goto fail;
1176 }
1177
1178 Stream_Read_UINT32(pdu->s,
1179 tsgCaps->tsgPacket.tsgCapNap.capabilities); /* Capabilities (4 bytes) */
1180
1181 switch (MessageSwitchValue)
1182 {
1183 case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE:
1184 case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE:
1185 if (Stream_GetRemainingLength(pdu->s) < 16)
1186 goto fail;
1187
1188 Stream_Read_INT32(pdu->s, packetStringMessage.isDisplayMandatory);
1189 Stream_Read_INT32(pdu->s, packetStringMessage.isConsentMandatory);
1190 Stream_Read_UINT32(pdu->s, packetStringMessage.msgBytes);
1191 Stream_Read_UINT32(pdu->s, Pointer);
1192
1193 if (Pointer)
1194 {
1195 if (Stream_GetRemainingLength(pdu->s) < 12)
1196 goto fail;
1197
1198 Stream_Seek_UINT32(pdu->s); /* MaxCount (4 bytes) */
1199 Stream_Seek_UINT32(pdu->s); /* Offset (4 bytes) */
1200 Stream_Seek_UINT32(pdu->s); /* Length (4 bytes) */
1201 }
1202
1203 if (packetStringMessage.msgBytes > TSG_MESSAGING_MAX_MESSAGE_LENGTH)
1204 {
1205 WLog_ERR(TAG, "Out of Spec Message Length %" PRIu32 "",
1206 packetStringMessage.msgBytes);
1207 goto fail;
1208 }
1209
1210 packetStringMessage.msgBuffer = (WCHAR*)Stream_Pointer(pdu->s);
1211 if (Stream_GetRemainingLength(pdu->s) < packetStringMessage.msgBytes)
1212 {
1213 WLog_ERR(TAG, "Unable to read message (%" PRIu32 " remaining %" PRId32 ")",
1214 packetStringMessage.msgBytes, Stream_GetRemainingLength(pdu->s));
1215 goto fail;
1216 }
1217
1218 if (context->instance)
1219 {
1220 rc = IFCALLRESULT(
1221 TRUE, context->instance->PresentGatewayMessage, context->instance,
1222 TSG_ASYNC_MESSAGE_CONSENT_MESSAGE ? GATEWAY_MESSAGE_CONSENT
1223 : TSG_ASYNC_MESSAGE_SERVICE_MESSAGE,
1224 packetStringMessage.isDisplayMandatory != 0,
1225 packetStringMessage.isConsentMandatory != 0, packetStringMessage.msgBytes,
1226 packetStringMessage.msgBuffer);
1227 if (!rc)
1228 goto fail;
1229 }
1230
1231 Stream_Seek(pdu->s, packetStringMessage.msgBytes);
1232 break;
1233
1234 case TSG_ASYNC_MESSAGE_REAUTH:
1235 {
1236 if (!tsg_stream_align(pdu->s, 8))
1237 goto fail;
1238
1239 if (Stream_GetRemainingLength(pdu->s) < 8)
1240 goto fail;
1241
1242 Stream_Seek_UINT64(pdu->s); /* TunnelContext (8 bytes) */
1243 }
1244 break;
1245
1246 default:
1247 WLog_ERR(TAG, "Unexpected Message Type: 0x%" PRIX32 "", MessageSwitchValue);
1248 goto fail;
1249 }
1250
1251 if (!tsg_stream_align(pdu->s, 4))
1252 goto fail;
1253
1254 /* TunnelContext (20 bytes) */
1255 if (Stream_GetRemainingLength(pdu->s) < 24)
1256 goto fail;
1257
1258 Stream_Read_UINT32(pdu->s, tunnelContext->ContextType); /* ContextType (4 bytes) */
1259 Stream_Read(pdu->s, tunnelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1260 Stream_Read_UINT32(pdu->s, *tunnelId); /* TunnelId (4 bytes) */
1261 /* ReturnValue (4 bytes) */
1262 }
1263 else if ((packet->packetId == TSG_PACKET_TYPE_QUARENC_RESPONSE) &&
1264 (SwitchValue == TSG_PACKET_TYPE_QUARENC_RESPONSE))
1265 {
1266 packetQuarEncResponse =
1267 (PTSG_PACKET_QUARENC_RESPONSE)calloc(1, sizeof(TSG_PACKET_QUARENC_RESPONSE));
1268
1269 if (!packetQuarEncResponse)
1270 goto fail;
1271
1272 packet->tsgPacket.packetQuarEncResponse = packetQuarEncResponse;
1273
1274 if (Stream_GetRemainingLength(pdu->s) < 32)
1275 goto fail;
1276
1277 Stream_Seek_UINT32(pdu->s); /* PacketQuarResponsePtr (4 bytes) */
1278 Stream_Read_UINT32(pdu->s, packetQuarEncResponse->flags); /* Flags (4 bytes) */
1279 Stream_Read_UINT32(pdu->s,
1280 packetQuarEncResponse->certChainLen); /* CertChainLength (4 bytes) */
1281 Stream_Seek_UINT32(pdu->s); /* CertChainDataPtr (4 bytes) */
1282 Stream_Read(pdu->s, &packetQuarEncResponse->nonce, 16); /* Nonce (16 bytes) */
1283
1284 if (packetQuarEncResponse->certChainLen > 0)
1285 {
1286 if (Stream_GetRemainingLength(pdu->s) < 16)
1287 goto fail;
1288
1289 Stream_Read_UINT32(pdu->s, Pointer); /* Ptr (4 bytes): 0x0002000C */
1290 Stream_Seek_UINT32(pdu->s); /* MaxCount (4 bytes) */
1291 Stream_Seek_UINT32(pdu->s); /* Offset (4 bytes) */
1292 Stream_Read_UINT32(pdu->s, count); /* ActualCount (4 bytes) */
1293
1294 /*
1295 * CertChainData is a wide character string, and the count is
1296 * given in characters excluding the null terminator, therefore:
1297 * size = (count * 2)
1298 */
1299 if (!Stream_SafeSeek(pdu->s, count * 2)) /* CertChainData */
1300 goto fail;
1301
1302 /* 4-byte alignment */
1303 if (!tsg_stream_align(pdu->s, 4))
1304 goto fail;
1305 }
1306 else
1307 {
1308 if (Stream_GetRemainingLength(pdu->s) < 4)
1309 goto fail;
1310
1311 Stream_Read_UINT32(pdu->s, Pointer); /* Ptr (4 bytes): 0x00020008 */
1312 }
1313
1314 versionCaps = (PTSG_PACKET_VERSIONCAPS)calloc(1, sizeof(TSG_PACKET_VERSIONCAPS));
1315
1316 if (!versionCaps)
1317 goto fail;
1318
1319 packetQuarEncResponse->versionCaps = versionCaps;
1320
1321 if (Stream_GetRemainingLength(pdu->s) < 18)
1322 goto fail;
1323
1324 Stream_Read_UINT16(pdu->s, versionCaps->tsgHeader.ComponentId); /* ComponentId (2 bytes) */
1325 Stream_Read_UINT16(pdu->s, versionCaps->tsgHeader.PacketId); /* PacketId (2 bytes) */
1326
1327 if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT)
1328 {
1329 WLog_ERR(TAG, "Unexpected ComponentId: 0x%04" PRIX16 ", Expected TS_GATEWAY_TRANSPORT",
1330 versionCaps->tsgHeader.ComponentId);
1331 goto fail;
1332 }
1333
1334 Stream_Read_UINT32(pdu->s, Pointer); /* TsgCapsPtr (4 bytes) */
1335 Stream_Read_UINT32(pdu->s, versionCaps->numCapabilities); /* NumCapabilities (4 bytes) */
1336 Stream_Read_UINT16(pdu->s, versionCaps->majorVersion); /* MajorVersion (2 bytes) */
1337 Stream_Read_UINT16(pdu->s, versionCaps->minorVersion); /* MinorVersion (2 bytes) */
1338 Stream_Read_UINT16(
1339 pdu->s, versionCaps->quarantineCapabilities); /* QuarantineCapabilities (2 bytes) */
1340
1341 /* 4-byte alignment */
1342 if (!tsg_stream_align(pdu->s, 4))
1343 goto fail;
1344
1345 if (Stream_GetRemainingLength(pdu->s) < 36)
1346 goto fail;
1347
1348 /* Not sure exactly what this is */
1349 Stream_Seek_UINT32(pdu->s); /* 0x00000001 (4 bytes) */
1350 Stream_Seek_UINT32(pdu->s); /* 0x00000001 (4 bytes) */
1351 Stream_Seek_UINT32(pdu->s); /* 0x00000001 (4 bytes) */
1352 Stream_Seek_UINT32(pdu->s); /* 0x00000002 (4 bytes) */
1353 /* TunnelContext (20 bytes) */
1354 Stream_Read_UINT32(pdu->s, tunnelContext->ContextType); /* ContextType (4 bytes) */
1355 Stream_Read(pdu->s, tunnelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1356 }
1357 else
1358 {
1359 WLog_ERR(TAG,
1360 "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_CAPS_RESPONSE "
1361 "or TSG_PACKET_TYPE_QUARENC_RESPONSE",
1362 packet->packetId);
1363 goto fail;
1364 }
1365
1366 rc = TRUE;
1367 fail:
1368 free(packetQuarEncResponse);
1369 free(packetCapsResponse);
1370 free(versionCaps);
1371 free(tsgCaps);
1372 free(packet);
1373 return rc;
1374 }
1375
1376 /**
1377 * OpNum = 2
1378 *
1379 * HRESULT TsProxyAuthorizeTunnel(
1380 * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext,
1381 * [in, ref] PTSG_PACKET tsgPacket,
1382 * [out, ref] PTSG_PACKET* tsgPacketResponse
1383 * );
1384 *
1385 */
1386
TsProxyAuthorizeTunnelWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * tunnelContext)1387 static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
1388 {
1389 size_t pad;
1390 wStream* s;
1391 size_t count;
1392 size_t offset;
1393 rdpRpc* rpc;
1394
1395 if (!tsg || !tsg->rpc || !tunnelContext || !tsg->MachineName)
1396 return FALSE;
1397
1398 count = _wcslen(tsg->MachineName) + 1;
1399 if (count > UINT32_MAX)
1400 return FALSE;
1401
1402 rpc = tsg->rpc;
1403 WLog_DBG(TAG, "TsProxyAuthorizeTunnelWriteRequest");
1404 s = Stream_New(NULL, 1024 + count * 2);
1405
1406 if (!s)
1407 return FALSE;
1408
1409 /* TunnelContext (20 bytes) */
1410 Stream_Write_UINT32(s, tunnelContext->ContextType); /* ContextType (4 bytes) */
1411 Stream_Write(s, &tunnelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1412 /* 4-byte alignment */
1413 Stream_Write_UINT32(s, TSG_PACKET_TYPE_QUARREQUEST); /* PacketId (4 bytes) */
1414 Stream_Write_UINT32(s, TSG_PACKET_TYPE_QUARREQUEST); /* SwitchValue (4 bytes) */
1415 Stream_Write_UINT32(s, 0x00020000); /* PacketQuarRequestPtr (4 bytes) */
1416 Stream_Write_UINT32(s, 0x00000000); /* Flags (4 bytes) */
1417 Stream_Write_UINT32(s, 0x00020004); /* MachineNamePtr (4 bytes) */
1418 Stream_Write_UINT32(s, (UINT32)count); /* NameLength (4 bytes) */
1419 Stream_Write_UINT32(s, 0x00020008); /* DataPtr (4 bytes) */
1420 Stream_Write_UINT32(s, 0); /* DataLength (4 bytes) */
1421 /* MachineName */
1422 Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */
1423 Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
1424 Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */
1425 Stream_Write_UTF16_String(s, tsg->MachineName, count); /* Array */
1426 /* 4-byte alignment */
1427 offset = Stream_GetPosition(s);
1428 pad = rpc_offset_align(&offset, 4);
1429 Stream_Zero(s, pad);
1430 Stream_Write_UINT32(s, 0x00000000); /* MaxCount (4 bytes) */
1431 Stream_SealLength(s);
1432 return rpc_client_write_call(rpc, s, TsProxyAuthorizeTunnelOpnum);
1433 }
1434
TsProxyAuthorizeTunnelReadResponse(RPC_PDU * pdu)1435 static BOOL TsProxyAuthorizeTunnelReadResponse(RPC_PDU* pdu)
1436 {
1437 BOOL rc = FALSE;
1438 UINT32 Pointer;
1439 UINT32 SizeValue;
1440 UINT32 SwitchValue;
1441 UINT32 idleTimeout;
1442 PTSG_PACKET packet = NULL;
1443 PTSG_PACKET_RESPONSE packetResponse = NULL;
1444
1445 if (!pdu)
1446 return FALSE;
1447
1448 packet = (PTSG_PACKET)calloc(1, sizeof(TSG_PACKET));
1449
1450 if (!packet)
1451 return FALSE;
1452
1453 if (Stream_GetRemainingLength(pdu->s) < 68)
1454 goto fail;
1455
1456 Stream_Seek_UINT32(pdu->s); /* PacketPtr (4 bytes) */
1457 Stream_Read_UINT32(pdu->s, packet->packetId); /* PacketId (4 bytes) */
1458 Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1459
1460 WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet->packetId));
1461
1462 if (packet->packetId == E_PROXY_NAP_ACCESSDENIED)
1463 {
1464 WLog_ERR(TAG, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)", E_PROXY_NAP_ACCESSDENIED);
1465 WLog_ERR(TAG, "Ensure that the Gateway Connection Authorization Policy is correct");
1466 goto fail;
1467 }
1468
1469 if ((packet->packetId != TSG_PACKET_TYPE_RESPONSE) || (SwitchValue != TSG_PACKET_TYPE_RESPONSE))
1470 {
1471 WLog_ERR(TAG, "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_RESPONSE",
1472 packet->packetId);
1473 goto fail;
1474 }
1475
1476 packetResponse = (PTSG_PACKET_RESPONSE)calloc(1, sizeof(TSG_PACKET_RESPONSE));
1477
1478 if (!packetResponse)
1479 goto fail;
1480
1481 packet->tsgPacket.packetResponse = packetResponse;
1482 Stream_Read_UINT32(pdu->s, Pointer); /* PacketResponsePtr (4 bytes) */
1483 Stream_Read_UINT32(pdu->s, packetResponse->flags); /* Flags (4 bytes) */
1484
1485 if (packetResponse->flags != TSG_PACKET_TYPE_QUARREQUEST)
1486 {
1487 WLog_ERR(TAG,
1488 "Unexpected Packet Response Flags: 0x%08" PRIX32
1489 ", Expected TSG_PACKET_TYPE_QUARREQUEST",
1490 packetResponse->flags);
1491 goto fail;
1492 }
1493
1494 Stream_Seek_UINT32(pdu->s); /* Reserved (4 bytes) */
1495 Stream_Read_UINT32(pdu->s, Pointer); /* ResponseDataPtr (4 bytes) */
1496 Stream_Read_UINT32(pdu->s, packetResponse->responseDataLen); /* ResponseDataLength (4 bytes) */
1497 Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
1498 .enableAllRedirections); /* EnableAllRedirections (4 bytes) */
1499 Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
1500 .disableAllRedirections); /* DisableAllRedirections (4 bytes) */
1501 Stream_Read_INT32(pdu->s,
1502 packetResponse->redirectionFlags
1503 .driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */
1504 Stream_Read_INT32(pdu->s,
1505 packetResponse->redirectionFlags
1506 .printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */
1507 Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
1508 .portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */
1509 Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags.reserved); /* Reserved (4 bytes) */
1510 Stream_Read_INT32(
1511 pdu->s, packetResponse->redirectionFlags
1512 .clipboardRedirectionDisabled); /* ClipboardRedirectionDisabled (4 bytes) */
1513 Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
1514 .pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */
1515 Stream_Read_UINT32(pdu->s, SizeValue); /* (4 bytes) */
1516
1517 if (SizeValue != packetResponse->responseDataLen)
1518 {
1519 WLog_ERR(TAG, "Unexpected size value: %" PRIu32 ", expected: %" PRIu32 "", SizeValue,
1520 packetResponse->responseDataLen);
1521 goto fail;
1522 }
1523
1524 if (Stream_GetRemainingLength(pdu->s) < SizeValue)
1525 goto fail;
1526
1527 if (SizeValue == 4)
1528 Stream_Read_UINT32(pdu->s, idleTimeout);
1529 else
1530 Stream_Seek(pdu->s, SizeValue); /* ResponseData */
1531
1532 rc = TRUE;
1533 fail:
1534 free(packetResponse);
1535 free(packet);
1536 return rc;
1537 }
1538
1539 /**
1540 * OpNum = 3
1541 *
1542 * HRESULT TsProxyMakeTunnelCall(
1543 * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext,
1544 * [in] unsigned long procId,
1545 * [in, ref] PTSG_PACKET tsgPacket,
1546 * [out, ref] PTSG_PACKET* tsgPacketResponse
1547 * );
1548 */
1549
TsProxyMakeTunnelCallWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * tunnelContext,UINT32 procId)1550 static BOOL TsProxyMakeTunnelCallWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext,
1551 UINT32 procId)
1552 {
1553 wStream* s;
1554 rdpRpc* rpc;
1555
1556 if (!tsg || !tsg->rpc || !tunnelContext)
1557 return FALSE;
1558
1559 rpc = tsg->rpc;
1560 WLog_DBG(TAG, "TsProxyMakeTunnelCallWriteRequest");
1561 s = Stream_New(NULL, 40);
1562
1563 if (!s)
1564 return FALSE;
1565
1566 /* TunnelContext (20 bytes) */
1567 Stream_Write_UINT32(s, tunnelContext->ContextType); /* ContextType (4 bytes) */
1568 Stream_Write(s, tunnelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1569 Stream_Write_UINT32(s, procId); /* ProcId (4 bytes) */
1570 /* 4-byte alignment */
1571 Stream_Write_UINT32(s, TSG_PACKET_TYPE_MSGREQUEST_PACKET); /* PacketId (4 bytes) */
1572 Stream_Write_UINT32(s, TSG_PACKET_TYPE_MSGREQUEST_PACKET); /* SwitchValue (4 bytes) */
1573 Stream_Write_UINT32(s, 0x00020000); /* PacketMsgRequestPtr (4 bytes) */
1574 Stream_Write_UINT32(s, 0x00000001); /* MaxMessagesPerBatch (4 bytes) */
1575 return rpc_client_write_call(rpc, s, TsProxyMakeTunnelCallOpnum);
1576 }
1577
TsProxyReadPacketSTringMessage(rdpTsg * tsg,wStream * s,TSG_PACKET_STRING_MESSAGE * msg)1578 static BOOL TsProxyReadPacketSTringMessage(rdpTsg* tsg, wStream* s, TSG_PACKET_STRING_MESSAGE* msg)
1579 {
1580 UINT32 Pointer, ActualCount, MaxCount;
1581 if (!tsg || !s || !msg)
1582 return FALSE;
1583
1584 if (Stream_GetRemainingLength(s) < 32)
1585 return FALSE;
1586
1587 Stream_Read_UINT32(s, Pointer); /* ConsentMessagePtr (4 bytes) */
1588 Stream_Read_INT32(s, msg->isDisplayMandatory); /* IsDisplayMandatory (4 bytes) */
1589 Stream_Read_INT32(s, msg->isConsentMandatory); /* IsConsentMandatory (4 bytes) */
1590 Stream_Read_UINT32(s, msg->msgBytes); /* MsgBytes (4 bytes) */
1591 Stream_Read_UINT32(s, Pointer); /* MsgPtr (4 bytes) */
1592 Stream_Read_UINT32(s, MaxCount); /* MaxCount (4 bytes) */
1593 Stream_Seek_UINT32(s); /* Offset (4 bytes) */
1594 Stream_Read_UINT32(s, ActualCount); /* ActualCount (4 bytes) */
1595
1596 if (msg->msgBytes < ActualCount * 2)
1597 return FALSE;
1598
1599 if (Stream_GetRemainingLength(s) < msg->msgBytes)
1600 return FALSE;
1601
1602 msg->msgBuffer = (WCHAR*)Stream_Pointer(s);
1603 Stream_Seek(s, msg->msgBytes);
1604
1605 return TRUE;
1606 }
1607
TsProxyMakeTunnelCallReadResponse(rdpTsg * tsg,RPC_PDU * pdu)1608 static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
1609 {
1610 BOOL rc = FALSE;
1611 UINT32 Pointer;
1612 UINT32 SwitchValue;
1613 TSG_PACKET packet;
1614 rdpContext* context;
1615 char* messageText = NULL;
1616 TSG_PACKET_MSG_RESPONSE packetMsgResponse = { 0 };
1617 TSG_PACKET_STRING_MESSAGE packetStringMessage = { 0 };
1618 TSG_PACKET_REAUTH_MESSAGE packetReauthMessage = { 0 };
1619
1620 assert(tsg);
1621 assert(tsg->rpc);
1622
1623 context = tsg->rpc->context;
1624 assert(context);
1625
1626 /* This is an asynchronous response */
1627
1628 if (!pdu)
1629 return FALSE;
1630
1631 if (Stream_GetRemainingLength(pdu->s) < 28)
1632 goto fail;
1633
1634 Stream_Seek_UINT32(pdu->s); /* PacketPtr (4 bytes) */
1635 Stream_Read_UINT32(pdu->s, packet.packetId); /* PacketId (4 bytes) */
1636 Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1637
1638 WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet.packetId));
1639
1640 if ((packet.packetId != TSG_PACKET_TYPE_MESSAGE_PACKET) ||
1641 (SwitchValue != TSG_PACKET_TYPE_MESSAGE_PACKET))
1642 {
1643 WLog_ERR(TAG,
1644 "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_MESSAGE_PACKET",
1645 packet.packetId);
1646 goto fail;
1647 }
1648
1649 Stream_Read_UINT32(pdu->s, Pointer); /* PacketMsgResponsePtr (4 bytes) */
1650 Stream_Read_UINT32(pdu->s, packetMsgResponse.msgID); /* MsgId (4 bytes) */
1651 Stream_Read_UINT32(pdu->s, packetMsgResponse.msgType); /* MsgType (4 bytes) */
1652 Stream_Read_INT32(pdu->s, packetMsgResponse.isMsgPresent); /* IsMsgPresent (4 bytes) */
1653
1654 /* 2.2.9.2.1.9 TSG_PACKET_MSG_RESPONSE: Ignore empty message body. */
1655 if (!packetMsgResponse.isMsgPresent)
1656 {
1657 rc = TRUE;
1658 goto fail;
1659 }
1660
1661 Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1662
1663 switch (SwitchValue)
1664 {
1665 case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE:
1666 if (!TsProxyReadPacketSTringMessage(tsg, pdu->s, &packetStringMessage))
1667 goto fail;
1668
1669 ConvertFromUnicode(CP_UTF8, 0, packetStringMessage.msgBuffer,
1670 packetStringMessage.msgBytes / 2, &messageText, 0, NULL, NULL);
1671
1672 WLog_INFO(TAG, "Consent Message: %s", messageText);
1673 free(messageText);
1674
1675 if (context->instance)
1676 {
1677 rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
1678 GATEWAY_MESSAGE_CONSENT,
1679 packetStringMessage.isDisplayMandatory != 0,
1680 packetStringMessage.isConsentMandatory != 0,
1681 packetStringMessage.msgBytes, packetStringMessage.msgBuffer);
1682 }
1683
1684 break;
1685
1686 case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE:
1687 if (!TsProxyReadPacketSTringMessage(tsg, pdu->s, &packetStringMessage))
1688 goto fail;
1689
1690 ConvertFromUnicode(CP_UTF8, 0, packetStringMessage.msgBuffer,
1691 packetStringMessage.msgBytes / 2, &messageText, 0, NULL, NULL);
1692
1693 WLog_INFO(TAG, "Service Message: %s", messageText);
1694 free(messageText);
1695
1696 if (context->instance)
1697 {
1698 rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
1699 GATEWAY_MESSAGE_SERVICE,
1700 packetStringMessage.isDisplayMandatory != 0,
1701 packetStringMessage.isConsentMandatory != 0,
1702 packetStringMessage.msgBytes, packetStringMessage.msgBuffer);
1703 }
1704 break;
1705
1706 case TSG_ASYNC_MESSAGE_REAUTH:
1707 if (Stream_GetRemainingLength(pdu->s) < 20)
1708 goto fail;
1709
1710 Stream_Read_UINT32(pdu->s, Pointer); /* ReauthMessagePtr (4 bytes) */
1711 Stream_Seek_UINT32(pdu->s); /* alignment pad (4 bytes) */
1712 Stream_Read_UINT64(pdu->s,
1713 packetReauthMessage.tunnelContext); /* TunnelContext (8 bytes) */
1714 Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
1715 tsg->ReauthTunnelContext = packetReauthMessage.tunnelContext;
1716 break;
1717
1718 default:
1719 WLog_ERR(TAG, "unexpected message type: %" PRIu32 "", SwitchValue);
1720 goto fail;
1721 }
1722
1723 rc = TRUE;
1724 fail:
1725 return rc;
1726 }
1727
1728 /**
1729 * OpNum = 4
1730 *
1731 * HRESULT TsProxyCreateChannel(
1732 * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext,
1733 * [in, ref] PTSENDPOINTINFO tsEndPointInfo,
1734 * [out] PCHANNEL_CONTEXT_HANDLE_SERIALIZE* channelContext,
1735 * [out] unsigned long* channelId
1736 * );
1737 */
1738
TsProxyCreateChannelWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * tunnelContext)1739 static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
1740 {
1741 size_t count;
1742 wStream* s;
1743 rdpRpc* rpc;
1744 WLog_DBG(TAG, "TsProxyCreateChannelWriteRequest");
1745
1746 if (!tsg || !tsg->rpc || !tunnelContext || !tsg->Hostname)
1747 return FALSE;
1748
1749 rpc = tsg->rpc;
1750 count = _wcslen(tsg->Hostname) + 1;
1751 if (count > UINT32_MAX)
1752 return FALSE;
1753 s = Stream_New(NULL, 60 + count * 2);
1754
1755 if (!s)
1756 return FALSE;
1757
1758 /* TunnelContext (20 bytes) */
1759 Stream_Write_UINT32(s, tunnelContext->ContextType); /* ContextType (4 bytes) */
1760 Stream_Write(s, tunnelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1761 /* TSENDPOINTINFO */
1762 Stream_Write_UINT32(s, 0x00020000); /* ResourceNamePtr (4 bytes) */
1763 Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */
1764 Stream_Write_UINT32(s, 0x00000000); /* AlternateResourceNamesPtr (4 bytes) */
1765 Stream_Write_UINT16(s, 0x0000); /* NumAlternateResourceNames (2 bytes) */
1766 Stream_Write_UINT16(s, 0x0000); /* Pad (2 bytes) */
1767 /* Port (4 bytes) */
1768 Stream_Write_UINT16(s, 0x0003); /* ProtocolId (RDP = 3) (2 bytes) */
1769 Stream_Write_UINT16(s, tsg->Port); /* PortNumber (0xD3D = 3389) (2 bytes) */
1770 Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */
1771 Stream_Write_UINT32(s, 0x00020004); /* ResourceNamePtr (4 bytes) */
1772 Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */
1773 Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
1774 Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */
1775 Stream_Write_UTF16_String(s, tsg->Hostname, count); /* Array */
1776 return rpc_client_write_call(rpc, s, TsProxyCreateChannelOpnum);
1777 }
1778
TsProxyCreateChannelReadResponse(RPC_PDU * pdu,CONTEXT_HANDLE * channelContext,UINT32 * channelId)1779 static BOOL TsProxyCreateChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* channelContext,
1780 UINT32* channelId)
1781 {
1782 BOOL rc = FALSE;
1783 WLog_DBG(TAG, "TsProxyCreateChannelReadResponse");
1784
1785 if (!pdu)
1786 return FALSE;
1787
1788 if (Stream_GetRemainingLength(pdu->s) < 28)
1789 goto fail;
1790
1791 /* ChannelContext (20 bytes) */
1792 Stream_Read_UINT32(pdu->s, channelContext->ContextType); /* ContextType (4 bytes) */
1793 Stream_Read(pdu->s, channelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1794 Stream_Read_UINT32(pdu->s, *channelId); /* ChannelId (4 bytes) */
1795 Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
1796 rc = TRUE;
1797 fail:
1798 return rc;
1799 }
1800
1801 /**
1802 * HRESULT TsProxyCloseChannel(
1803 * [in, out] PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* context
1804 * );
1805 */
1806
TsProxyCloseChannelWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * context)1807 static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
1808 {
1809 wStream* s;
1810 rdpRpc* rpc;
1811 WLog_DBG(TAG, "TsProxyCloseChannelWriteRequest");
1812
1813 if (!tsg || !tsg->rpc || !context)
1814 return FALSE;
1815
1816 rpc = tsg->rpc;
1817 s = Stream_New(NULL, 20);
1818
1819 if (!s)
1820 return FALSE;
1821
1822 /* ChannelContext (20 bytes) */
1823 Stream_Write_UINT32(s, context->ContextType); /* ContextType (4 bytes) */
1824 Stream_Write(s, context->ContextUuid, 16); /* ContextUuid (16 bytes) */
1825 return rpc_client_write_call(rpc, s, TsProxyCloseChannelOpnum);
1826 }
1827
TsProxyCloseChannelReadResponse(RPC_PDU * pdu,CONTEXT_HANDLE * context)1828 static BOOL TsProxyCloseChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context)
1829 {
1830 BOOL rc = FALSE;
1831 WLog_DBG(TAG, "TsProxyCloseChannelReadResponse");
1832
1833 if (!pdu)
1834 return FALSE;
1835
1836 if (Stream_GetRemainingLength(pdu->s) < 24)
1837 goto fail;
1838
1839 /* ChannelContext (20 bytes) */
1840 Stream_Read_UINT32(pdu->s, context->ContextType); /* ContextType (4 bytes) */
1841 Stream_Read(pdu->s, context->ContextUuid, 16); /* ContextUuid (16 bytes) */
1842 Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
1843 rc = TRUE;
1844 fail:
1845 return rc;
1846 }
1847
1848 /**
1849 * HRESULT TsProxyCloseTunnel(
1850 * [in, out] PTUNNEL_CONTEXT_HANDLE_SERIALIZE* context
1851 * );
1852 */
1853
TsProxyCloseTunnelWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * context)1854 static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
1855 {
1856 wStream* s;
1857 rdpRpc* rpc;
1858 WLog_DBG(TAG, "TsProxyCloseTunnelWriteRequest");
1859
1860 if (!tsg || !tsg->rpc || !context)
1861 return FALSE;
1862
1863 rpc = tsg->rpc;
1864 s = Stream_New(NULL, 20);
1865
1866 if (!s)
1867 return FALSE;
1868
1869 /* TunnelContext (20 bytes) */
1870 Stream_Write_UINT32(s, context->ContextType); /* ContextType (4 bytes) */
1871 Stream_Write(s, context->ContextUuid, 16); /* ContextUuid (16 bytes) */
1872 return rpc_client_write_call(rpc, s, TsProxyCloseTunnelOpnum);
1873 }
1874
TsProxyCloseTunnelReadResponse(RPC_PDU * pdu,CONTEXT_HANDLE * context)1875 static BOOL TsProxyCloseTunnelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context)
1876 {
1877 BOOL rc = FALSE;
1878 WLog_DBG(TAG, "TsProxyCloseTunnelReadResponse");
1879
1880 if (!pdu || !context)
1881 return FALSE;
1882
1883 if (Stream_GetRemainingLength(pdu->s) < 24)
1884 goto fail;
1885
1886 /* TunnelContext (20 bytes) */
1887 Stream_Read_UINT32(pdu->s, context->ContextType); /* ContextType (4 bytes) */
1888 Stream_Read(pdu->s, context->ContextUuid, 16); /* ContextUuid (16 bytes) */
1889 Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
1890 rc = TRUE;
1891 fail:
1892 return rc;
1893 }
1894
1895 /**
1896 * OpNum = 8
1897 *
1898 * DWORD TsProxySetupReceivePipe(
1899 * [in, max_is(32767)] byte pRpcMessage[]
1900 * );
1901 */
1902
TsProxySetupReceivePipeWriteRequest(rdpTsg * tsg,CONTEXT_HANDLE * channelContext)1903 static BOOL TsProxySetupReceivePipeWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* channelContext)
1904 {
1905 wStream* s;
1906 rdpRpc* rpc;
1907 WLog_DBG(TAG, "TsProxySetupReceivePipeWriteRequest");
1908
1909 if (!tsg || !tsg->rpc || !channelContext)
1910 return FALSE;
1911
1912 rpc = tsg->rpc;
1913 s = Stream_New(NULL, 20);
1914
1915 if (!s)
1916 return FALSE;
1917
1918 /* ChannelContext (20 bytes) */
1919 Stream_Write_UINT32(s, channelContext->ContextType); /* ContextType (4 bytes) */
1920 Stream_Write(s, channelContext->ContextUuid, 16); /* ContextUuid (16 bytes) */
1921 return rpc_client_write_call(rpc, s, TsProxySetupReceivePipeOpnum);
1922 }
1923
tsg_transition_to_state(rdpTsg * tsg,TSG_STATE state)1924 static BOOL tsg_transition_to_state(rdpTsg* tsg, TSG_STATE state)
1925 {
1926 const char* oldState = tsg_state_to_string(tsg->state);
1927 const char* newState = tsg_state_to_string(state);
1928
1929 WLog_DBG(TAG, "%s -> %s", oldState, newState);
1930 return tsg_set_state(tsg, state);
1931 }
1932
tsg_proxy_begin(rdpTsg * tsg)1933 BOOL tsg_proxy_begin(rdpTsg* tsg)
1934 {
1935 TSG_PACKET tsgPacket = { 0 };
1936 PTSG_CAPABILITY_NAP tsgCapNap;
1937 PTSG_PACKET_VERSIONCAPS packetVersionCaps;
1938
1939 if (!tsg)
1940 return FALSE;
1941
1942 packetVersionCaps = &tsg->packetVersionCaps;
1943 packetVersionCaps->tsgCaps = &tsg->tsgCaps;
1944 tsgCapNap = &tsg->tsgCaps.tsgPacket.tsgCapNap;
1945 tsgPacket.packetId = TSG_PACKET_TYPE_VERSIONCAPS;
1946 tsgPacket.tsgPacket.packetVersionCaps = packetVersionCaps;
1947 packetVersionCaps->tsgHeader.ComponentId = TS_GATEWAY_TRANSPORT;
1948 packetVersionCaps->tsgHeader.PacketId = TSG_PACKET_TYPE_VERSIONCAPS;
1949 packetVersionCaps->numCapabilities = 1;
1950 packetVersionCaps->majorVersion = 1;
1951 packetVersionCaps->minorVersion = 1;
1952 packetVersionCaps->quarantineCapabilities = 0;
1953 packetVersionCaps->tsgCaps->capabilityType = TSG_CAPABILITY_TYPE_NAP;
1954 /*
1955 * Using reduced capabilities appears to trigger
1956 * TSG_PACKET_TYPE_QUARENC_RESPONSE instead of TSG_PACKET_TYPE_CAPS_RESPONSE
1957 *
1958 * However, reduced capabilities may break connectivity with servers enforcing features, such as
1959 * "Only allow connections from Remote Desktop Services clients that support RD Gateway
1960 * messaging"
1961 */
1962 tsgCapNap->capabilities = TSG_NAP_CAPABILITY_QUAR_SOH | TSG_NAP_CAPABILITY_IDLE_TIMEOUT |
1963 TSG_MESSAGING_CAP_CONSENT_SIGN | TSG_MESSAGING_CAP_SERVICE_MSG |
1964 TSG_MESSAGING_CAP_REAUTH;
1965
1966 if (!TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
1967 {
1968 WLog_ERR(TAG, "TsProxyCreateTunnel failure");
1969 tsg_transition_to_state(tsg, TSG_STATE_FINAL);
1970 return FALSE;
1971 }
1972
1973 return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
1974 }
1975
tsg_proxy_reauth(rdpTsg * tsg)1976 static BOOL tsg_proxy_reauth(rdpTsg* tsg)
1977 {
1978 TSG_PACKET tsgPacket = { 0 };
1979 PTSG_PACKET_REAUTH packetReauth;
1980 PTSG_PACKET_VERSIONCAPS packetVersionCaps;
1981
1982 if (!tsg)
1983 return FALSE;
1984
1985 tsg->reauthSequence = TRUE;
1986 packetReauth = &tsg->packetReauth;
1987 packetVersionCaps = &tsg->packetVersionCaps;
1988
1989 if (!packetReauth || !packetVersionCaps)
1990 return FALSE;
1991
1992 tsgPacket.packetId = TSG_PACKET_TYPE_REAUTH;
1993 tsgPacket.tsgPacket.packetReauth = &tsg->packetReauth;
1994 packetReauth->tunnelContext = tsg->ReauthTunnelContext;
1995 packetReauth->packetId = TSG_PACKET_TYPE_VERSIONCAPS;
1996 packetReauth->tsgInitialPacket.packetVersionCaps = packetVersionCaps;
1997
1998 if (!TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
1999 {
2000 WLog_ERR(TAG, "TsProxyCreateTunnel failure");
2001 tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2002 return FALSE;
2003 }
2004
2005 if (!TsProxyMakeTunnelCallWriteRequest(tsg, &tsg->TunnelContext,
2006 TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST))
2007 {
2008 WLog_ERR(TAG, "TsProxyMakeTunnelCall failure");
2009 tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2010 return FALSE;
2011 }
2012
2013 return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
2014 }
2015
tsg_recv_pdu(rdpTsg * tsg,RPC_PDU * pdu)2016 BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
2017 {
2018 BOOL rc = FALSE;
2019 RpcClientCall* call;
2020 rdpRpc* rpc;
2021
2022 if (!tsg || !tsg->rpc || !pdu)
2023 return FALSE;
2024
2025 rpc = tsg->rpc;
2026
2027 if (!(pdu->Flags & RPC_PDU_FLAG_STUB))
2028 {
2029 if (!Stream_SafeSeek(pdu->s, 24))
2030 return FALSE;
2031 }
2032
2033 switch (tsg->state)
2034 {
2035 case TSG_STATE_INITIAL:
2036 {
2037 CONTEXT_HANDLE* TunnelContext;
2038 TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
2039
2040 if (!TsProxyCreateTunnelReadResponse(tsg, pdu, TunnelContext, &tsg->TunnelId))
2041 {
2042 WLog_ERR(TAG, "TsProxyCreateTunnelReadResponse failure");
2043 return FALSE;
2044 }
2045
2046 if (!tsg_transition_to_state(tsg, TSG_STATE_CONNECTED))
2047 return FALSE;
2048
2049 if (!TsProxyAuthorizeTunnelWriteRequest(tsg, TunnelContext))
2050 {
2051 WLog_ERR(TAG, "TsProxyAuthorizeTunnel failure");
2052 return FALSE;
2053 }
2054
2055 rc = TRUE;
2056 }
2057 break;
2058
2059 case TSG_STATE_CONNECTED:
2060 {
2061 CONTEXT_HANDLE* TunnelContext;
2062 TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
2063
2064 if (!TsProxyAuthorizeTunnelReadResponse(pdu))
2065 {
2066 WLog_ERR(TAG, "TsProxyAuthorizeTunnelReadResponse failure");
2067 return FALSE;
2068 }
2069
2070 if (!tsg_transition_to_state(tsg, TSG_STATE_AUTHORIZED))
2071 return FALSE;
2072
2073 if (!tsg->reauthSequence)
2074 {
2075 if (!TsProxyMakeTunnelCallWriteRequest(tsg, TunnelContext,
2076 TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST))
2077 {
2078 WLog_ERR(TAG, "TsProxyMakeTunnelCall failure");
2079 return FALSE;
2080 }
2081 }
2082
2083 if (!TsProxyCreateChannelWriteRequest(tsg, TunnelContext))
2084 {
2085 WLog_ERR(TAG, "TsProxyCreateChannel failure");
2086 return FALSE;
2087 }
2088
2089 rc = TRUE;
2090 }
2091 break;
2092
2093 case TSG_STATE_AUTHORIZED:
2094 call = rpc_client_call_find_by_id(rpc->client, pdu->CallId);
2095
2096 if (!call)
2097 return FALSE;
2098
2099 if (call->OpNum == TsProxyMakeTunnelCallOpnum)
2100 {
2101 if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu))
2102 {
2103 WLog_ERR(TAG, "TsProxyMakeTunnelCallReadResponse failure");
2104 return FALSE;
2105 }
2106
2107 rc = TRUE;
2108 }
2109 else if (call->OpNum == TsProxyCreateChannelOpnum)
2110 {
2111 CONTEXT_HANDLE ChannelContext;
2112
2113 if (!TsProxyCreateChannelReadResponse(pdu, &ChannelContext, &tsg->ChannelId))
2114 {
2115 WLog_ERR(TAG, "TsProxyCreateChannelReadResponse failure");
2116 return FALSE;
2117 }
2118
2119 if (!tsg->reauthSequence)
2120 CopyMemory(&tsg->ChannelContext, &ChannelContext, sizeof(CONTEXT_HANDLE));
2121 else
2122 CopyMemory(&tsg->NewChannelContext, &ChannelContext, sizeof(CONTEXT_HANDLE));
2123
2124 if (!tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CREATED))
2125 return FALSE;
2126
2127 if (!tsg->reauthSequence)
2128 {
2129 if (!TsProxySetupReceivePipeWriteRequest(tsg, &tsg->ChannelContext))
2130 {
2131 WLog_ERR(TAG, "TsProxySetupReceivePipe failure");
2132 return FALSE;
2133 }
2134 }
2135 else
2136 {
2137 if (!TsProxyCloseChannelWriteRequest(tsg, &tsg->NewChannelContext))
2138 {
2139 WLog_ERR(TAG, "TsProxyCloseChannelWriteRequest failure");
2140 return FALSE;
2141 }
2142
2143 if (!TsProxyCloseTunnelWriteRequest(tsg, &tsg->NewTunnelContext))
2144 {
2145 WLog_ERR(TAG, "TsProxyCloseTunnelWriteRequest failure");
2146 return FALSE;
2147 }
2148 }
2149
2150 rc = tsg_transition_to_state(tsg, TSG_STATE_PIPE_CREATED);
2151 tsg->reauthSequence = FALSE;
2152 }
2153 else
2154 {
2155 WLog_ERR(TAG, "TSG_STATE_AUTHORIZED unexpected OpNum: %" PRIu32 "\n", call->OpNum);
2156 }
2157
2158 break;
2159
2160 case TSG_STATE_CHANNEL_CREATED:
2161 break;
2162
2163 case TSG_STATE_PIPE_CREATED:
2164 call = rpc_client_call_find_by_id(rpc->client, pdu->CallId);
2165
2166 if (!call)
2167 return FALSE;
2168
2169 if (call->OpNum == TsProxyMakeTunnelCallOpnum)
2170 {
2171 if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu))
2172 {
2173 WLog_ERR(TAG, "TsProxyMakeTunnelCallReadResponse failure");
2174 return FALSE;
2175 }
2176
2177 rc = TRUE;
2178
2179 if (tsg->ReauthTunnelContext)
2180 rc = tsg_proxy_reauth(tsg);
2181 }
2182 else if (call->OpNum == TsProxyCloseChannelOpnum)
2183 {
2184 CONTEXT_HANDLE ChannelContext;
2185
2186 if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext))
2187 {
2188 WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure");
2189 return FALSE;
2190 }
2191
2192 rc = TRUE;
2193 }
2194 else if (call->OpNum == TsProxyCloseTunnelOpnum)
2195 {
2196 CONTEXT_HANDLE TunnelContext;
2197
2198 if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext))
2199 {
2200 WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure");
2201 return FALSE;
2202 }
2203
2204 rc = TRUE;
2205 }
2206
2207 break;
2208
2209 case TSG_STATE_TUNNEL_CLOSE_PENDING:
2210 {
2211 CONTEXT_HANDLE ChannelContext;
2212
2213 if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext))
2214 {
2215 WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure");
2216 return FALSE;
2217 }
2218
2219 if (!tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CLOSE_PENDING))
2220 return FALSE;
2221
2222 if (!TsProxyCloseChannelWriteRequest(tsg, NULL))
2223 {
2224 WLog_ERR(TAG, "TsProxyCloseChannelWriteRequest failure");
2225 return FALSE;
2226 }
2227
2228 if (!TsProxyMakeTunnelCallWriteRequest(tsg, &tsg->TunnelContext,
2229 TSG_TUNNEL_CANCEL_ASYNC_MSG_REQUEST))
2230 {
2231 WLog_ERR(TAG, "TsProxyMakeTunnelCall failure");
2232 return FALSE;
2233 }
2234
2235 rc = TRUE;
2236 }
2237 break;
2238
2239 case TSG_STATE_CHANNEL_CLOSE_PENDING:
2240 {
2241 CONTEXT_HANDLE TunnelContext;
2242
2243 if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext))
2244 {
2245 WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure");
2246 return FALSE;
2247 }
2248
2249 rc = tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2250 }
2251 break;
2252
2253 case TSG_STATE_FINAL:
2254 break;
2255 }
2256
2257 return rc;
2258 }
2259
tsg_check_event_handles(rdpTsg * tsg)2260 BOOL tsg_check_event_handles(rdpTsg* tsg)
2261 {
2262 if (rpc_client_in_channel_recv(tsg->rpc) < 0)
2263 return FALSE;
2264
2265 if (rpc_client_out_channel_recv(tsg->rpc) < 0)
2266 return FALSE;
2267
2268 return TRUE;
2269 }
2270
tsg_get_event_handles(rdpTsg * tsg,HANDLE * events,DWORD count)2271 DWORD tsg_get_event_handles(rdpTsg* tsg, HANDLE* events, DWORD count)
2272 {
2273 UINT32 nCount = 0;
2274 rdpRpc* rpc = tsg->rpc;
2275 RpcVirtualConnection* connection = rpc->VirtualConnection;
2276
2277 if (events && (nCount < count))
2278 {
2279 events[nCount] = rpc->client->PipeEvent;
2280 nCount++;
2281 }
2282 else
2283 return 0;
2284
2285 if (connection->DefaultInChannel && connection->DefaultInChannel->common.tls)
2286 {
2287 if (events && (nCount < count))
2288 {
2289 BIO_get_event(connection->DefaultInChannel->common.tls->bio, &events[nCount]);
2290 nCount++;
2291 }
2292 else
2293 return 0;
2294 }
2295
2296 if (connection->NonDefaultInChannel && connection->NonDefaultInChannel->common.tls)
2297 {
2298 if (events && (nCount < count))
2299 {
2300 BIO_get_event(connection->NonDefaultInChannel->common.tls->bio, &events[nCount]);
2301 nCount++;
2302 }
2303 else
2304 return 0;
2305 }
2306
2307 if (connection->DefaultOutChannel && connection->DefaultOutChannel->common.tls)
2308 {
2309 if (events && (nCount < count))
2310 {
2311 BIO_get_event(connection->DefaultOutChannel->common.tls->bio, &events[nCount]);
2312 nCount++;
2313 }
2314 else
2315 return 0;
2316 }
2317
2318 if (connection->NonDefaultOutChannel && connection->NonDefaultOutChannel->common.tls)
2319 {
2320 if (events && (nCount < count))
2321 {
2322 BIO_get_event(connection->NonDefaultOutChannel->common.tls->bio, &events[nCount]);
2323 nCount++;
2324 }
2325 else
2326 return 0;
2327 }
2328
2329 return nCount;
2330 }
2331
tsg_set_hostname(rdpTsg * tsg,const char * hostname)2332 static BOOL tsg_set_hostname(rdpTsg* tsg, const char* hostname)
2333 {
2334 free(tsg->Hostname);
2335 tsg->Hostname = NULL;
2336 ConvertToUnicode(CP_UTF8, 0, hostname, -1, &tsg->Hostname, 0);
2337 return TRUE;
2338 }
2339
tsg_set_machine_name(rdpTsg * tsg,const char * machineName)2340 static BOOL tsg_set_machine_name(rdpTsg* tsg, const char* machineName)
2341 {
2342 free(tsg->MachineName);
2343 tsg->MachineName = NULL;
2344 ConvertToUnicode(CP_UTF8, 0, machineName, -1, &tsg->MachineName, 0);
2345 return TRUE;
2346 }
2347
tsg_connect(rdpTsg * tsg,const char * hostname,UINT16 port,DWORD timeout)2348 BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout)
2349 {
2350 UINT64 looptimeout = timeout * 1000ULL;
2351 DWORD nCount;
2352 HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 };
2353 rdpRpc* rpc;
2354 rdpContext* context;
2355 rdpSettings* settings;
2356 rdpTransport* transport;
2357
2358 assert(tsg);
2359
2360 rpc = tsg->rpc;
2361 assert(rpc);
2362
2363 transport = rpc->transport;
2364 assert(transport);
2365
2366 context = tsg->rpc->context;
2367 assert(context);
2368
2369 settings = context->settings;
2370
2371 tsg->Port = port;
2372 tsg->transport = transport;
2373
2374 if (!settings->GatewayPort)
2375 settings->GatewayPort = 443;
2376
2377 if (!tsg_set_hostname(tsg, hostname))
2378 return FALSE;
2379
2380 if (!tsg_set_machine_name(tsg, settings->ComputerName))
2381 return FALSE;
2382
2383 if (!rpc_connect(rpc, timeout))
2384 {
2385 WLog_ERR(TAG, "rpc_connect error!");
2386 return FALSE;
2387 }
2388
2389 nCount = tsg_get_event_handles(tsg, events, ARRAYSIZE(events));
2390
2391 if (nCount == 0)
2392 return FALSE;
2393
2394 while (tsg->state != TSG_STATE_PIPE_CREATED)
2395 {
2396 const DWORD polltimeout = 250;
2397 DWORD status = WaitForMultipleObjects(nCount, events, FALSE, polltimeout);
2398 if (status == WAIT_TIMEOUT)
2399 {
2400 if (timeout > 0)
2401 {
2402 if (looptimeout < polltimeout)
2403 return FALSE;
2404 looptimeout -= polltimeout;
2405 }
2406 }
2407 else
2408 looptimeout = timeout * 1000ULL;
2409
2410 if (!tsg_check_event_handles(tsg))
2411 {
2412 WLog_ERR(TAG, "tsg_check failure");
2413 transport->layer = TRANSPORT_LAYER_CLOSED;
2414 return FALSE;
2415 }
2416 }
2417
2418 WLog_INFO(TAG, "TS Gateway Connection Success");
2419 tsg->bio = BIO_new(BIO_s_tsg());
2420
2421 if (!tsg->bio)
2422 return FALSE;
2423
2424 BIO_set_data(tsg->bio, (void*)tsg);
2425 return TRUE;
2426 }
2427
tsg_disconnect(rdpTsg * tsg)2428 BOOL tsg_disconnect(rdpTsg* tsg)
2429 {
2430 /**
2431 * Gateway Shutdown Phase
2432 *
2433 * Client Server
2434 * | |
2435 * |-------------TsProxyCloseChannel Request---------->|
2436 * | |
2437 * |<-------TsProxySetupReceivePipe Final Response-----|
2438 * |<-----------TsProxyCloseChannel Response-----------|
2439 * | |
2440 * |----TsProxyMakeTunnelCall Request (cancel async)-->|
2441 * | |
2442 * |<---TsProxyMakeTunnelCall Response (call async)----|
2443 * |<---TsProxyMakeTunnelCall Response (cancel async)--|
2444 * | |
2445 * |--------------TsProxyCloseTunnel Request---------->|
2446 * |<-------------TsProxyCloseTunnel Response----------|
2447 * | |
2448 */
2449 if (!tsg)
2450 return FALSE;
2451
2452 if (tsg->state != TSG_STATE_TUNNEL_CLOSE_PENDING)
2453 {
2454 if (!TsProxyCloseChannelWriteRequest(tsg, &tsg->ChannelContext))
2455 return FALSE;
2456
2457 return tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CLOSE_PENDING);
2458 }
2459
2460 return TRUE;
2461 }
2462
2463 /**
2464 * @brief
2465 *
2466 * @param[in] tsg
2467 * @param[in] data
2468 * @param[in] length
2469 * @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 bytes to read
2470 */
2471
tsg_read(rdpTsg * tsg,BYTE * data,size_t length)2472 static int tsg_read(rdpTsg* tsg, BYTE* data, size_t length)
2473 {
2474 rdpRpc* rpc;
2475 int status = 0;
2476
2477 if (!tsg || !data)
2478 return -1;
2479
2480 rpc = tsg->rpc;
2481
2482 if (rpc->transport->layer == TRANSPORT_LAYER_CLOSED)
2483 {
2484 WLog_ERR(TAG, "tsg_read error: connection lost");
2485 return -1;
2486 }
2487
2488 do
2489 {
2490 status = rpc_client_receive_pipe_read(rpc->client, data, length);
2491
2492 if (status < 0)
2493 return -1;
2494
2495 if (!status && !rpc->transport->blocking)
2496 return 0;
2497
2498 if (rpc->transport->layer == TRANSPORT_LAYER_CLOSED)
2499 {
2500 WLog_ERR(TAG, "tsg_read error: connection lost");
2501 return -1;
2502 }
2503
2504 if (status > 0)
2505 break;
2506
2507 if (rpc->transport->blocking)
2508 {
2509 while (WaitForSingleObject(rpc->client->PipeEvent, 0) != WAIT_OBJECT_0)
2510 {
2511 if (!tsg_check_event_handles(tsg))
2512 return -1;
2513
2514 WaitForSingleObject(rpc->client->PipeEvent, 100);
2515 }
2516 }
2517 } while (rpc->transport->blocking);
2518
2519 return status;
2520 }
2521
tsg_write(rdpTsg * tsg,const BYTE * data,UINT32 length)2522 static int tsg_write(rdpTsg* tsg, const BYTE* data, UINT32 length)
2523 {
2524 int status;
2525
2526 if (!tsg || !data || !tsg->rpc || !tsg->rpc->transport)
2527 return -1;
2528
2529 if (tsg->rpc->transport->layer == TRANSPORT_LAYER_CLOSED)
2530 {
2531 WLog_ERR(TAG, "error, connection lost");
2532 return -1;
2533 }
2534
2535 status = TsProxySendToServer((handle_t)tsg, data, 1, &length);
2536
2537 if (status < 0)
2538 return -1;
2539
2540 return (int)length;
2541 }
2542
tsg_new(rdpTransport * transport)2543 rdpTsg* tsg_new(rdpTransport* transport)
2544 {
2545 rdpTsg* tsg;
2546 tsg = (rdpTsg*)calloc(1, sizeof(rdpTsg));
2547
2548 if (!tsg)
2549 return NULL;
2550
2551 tsg->transport = transport;
2552 tsg->rpc = rpc_new(tsg->transport);
2553
2554 if (!tsg->rpc)
2555 goto out_free;
2556
2557 return tsg;
2558 out_free:
2559 free(tsg);
2560 return NULL;
2561 }
2562
tsg_free(rdpTsg * tsg)2563 void tsg_free(rdpTsg* tsg)
2564 {
2565 if (tsg)
2566 {
2567 rpc_free(tsg->rpc);
2568 free(tsg->Hostname);
2569 free(tsg->MachineName);
2570 free(tsg);
2571 }
2572 }
2573
transport_bio_tsg_write(BIO * bio,const char * buf,int num)2574 static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
2575 {
2576 int status;
2577 rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2578 BIO_clear_flags(bio, BIO_FLAGS_WRITE);
2579
2580 if (num < 0)
2581 return -1;
2582 status = tsg_write(tsg, (const BYTE*)buf, (UINT32)num);
2583
2584 if (status < 0)
2585 {
2586 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2587 return -1;
2588 }
2589 else if (status == 0)
2590 {
2591 BIO_set_flags(bio, BIO_FLAGS_WRITE);
2592 WSASetLastError(WSAEWOULDBLOCK);
2593 }
2594 else
2595 {
2596 BIO_set_flags(bio, BIO_FLAGS_WRITE);
2597 }
2598
2599 return status >= 0 ? status : -1;
2600 }
2601
transport_bio_tsg_read(BIO * bio,char * buf,int size)2602 static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
2603 {
2604 int status;
2605 rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2606
2607 if (!tsg || (size < 0))
2608 {
2609 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2610 return -1;
2611 }
2612
2613 BIO_clear_flags(bio, BIO_FLAGS_READ);
2614 status = tsg_read(tsg, (BYTE*)buf, (size_t)size);
2615
2616 if (status < 0)
2617 {
2618 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2619 return -1;
2620 }
2621 else if (status == 0)
2622 {
2623 BIO_set_flags(bio, BIO_FLAGS_READ);
2624 WSASetLastError(WSAEWOULDBLOCK);
2625 }
2626 else
2627 {
2628 BIO_set_flags(bio, BIO_FLAGS_READ);
2629 }
2630
2631 return status > 0 ? status : -1;
2632 }
2633
transport_bio_tsg_puts(BIO * bio,const char * str)2634 static int transport_bio_tsg_puts(BIO* bio, const char* str)
2635 {
2636 WINPR_UNUSED(bio);
2637 WINPR_UNUSED(str);
2638 return 1;
2639 }
2640
transport_bio_tsg_gets(BIO * bio,char * str,int size)2641 static int transport_bio_tsg_gets(BIO* bio, char* str, int size)
2642 {
2643 WINPR_UNUSED(bio);
2644 WINPR_UNUSED(str);
2645 WINPR_UNUSED(size);
2646 return 1;
2647 }
2648
transport_bio_tsg_ctrl(BIO * bio,int cmd,long arg1,void * arg2)2649 static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
2650 {
2651 long status = -1;
2652 rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2653 RpcVirtualConnection* connection = tsg->rpc->VirtualConnection;
2654 RpcInChannel* inChannel = connection->DefaultInChannel;
2655 RpcOutChannel* outChannel = connection->DefaultOutChannel;
2656
2657 switch (cmd)
2658 {
2659 case BIO_CTRL_FLUSH:
2660 (void)BIO_flush(inChannel->common.tls->bio);
2661 (void)BIO_flush(outChannel->common.tls->bio);
2662 status = 1;
2663 break;
2664
2665 case BIO_C_GET_EVENT:
2666 if (arg2)
2667 {
2668 *((HANDLE*)arg2) = tsg->rpc->client->PipeEvent;
2669 status = 1;
2670 }
2671
2672 break;
2673
2674 case BIO_C_SET_NONBLOCK:
2675 status = 1;
2676 break;
2677
2678 case BIO_C_READ_BLOCKED:
2679 {
2680 BIO* cbio = outChannel->common.bio;
2681 status = BIO_read_blocked(cbio);
2682 }
2683 break;
2684
2685 case BIO_C_WRITE_BLOCKED:
2686 {
2687 BIO* cbio = inChannel->common.bio;
2688 status = BIO_write_blocked(cbio);
2689 }
2690 break;
2691
2692 case BIO_C_WAIT_READ:
2693 {
2694 int timeout = (int)arg1;
2695 BIO* cbio = outChannel->common.bio;
2696
2697 if (BIO_read_blocked(cbio))
2698 return BIO_wait_read(cbio, timeout);
2699 else if (BIO_write_blocked(cbio))
2700 return BIO_wait_write(cbio, timeout);
2701 else
2702 status = 1;
2703 }
2704 break;
2705
2706 case BIO_C_WAIT_WRITE:
2707 {
2708 int timeout = (int)arg1;
2709 BIO* cbio = inChannel->common.bio;
2710
2711 if (BIO_write_blocked(cbio))
2712 status = BIO_wait_write(cbio, timeout);
2713 else if (BIO_read_blocked(cbio))
2714 status = BIO_wait_read(cbio, timeout);
2715 else
2716 status = 1;
2717 }
2718 break;
2719
2720 default:
2721 break;
2722 }
2723
2724 return status;
2725 }
2726
transport_bio_tsg_new(BIO * bio)2727 static int transport_bio_tsg_new(BIO* bio)
2728 {
2729 assert(bio);
2730 BIO_set_init(bio, 1);
2731 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2732 return 1;
2733 }
2734
transport_bio_tsg_free(BIO * bio)2735 static int transport_bio_tsg_free(BIO* bio)
2736 {
2737 assert(bio);
2738 WINPR_UNUSED(bio);
2739 return 1;
2740 }
2741
BIO_s_tsg(void)2742 BIO_METHOD* BIO_s_tsg(void)
2743 {
2744 static BIO_METHOD* bio_methods = NULL;
2745
2746 if (bio_methods == NULL)
2747 {
2748 if (!(bio_methods = BIO_meth_new(BIO_TYPE_TSG, "TSGateway")))
2749 return NULL;
2750
2751 BIO_meth_set_write(bio_methods, transport_bio_tsg_write);
2752 BIO_meth_set_read(bio_methods, transport_bio_tsg_read);
2753 BIO_meth_set_puts(bio_methods, transport_bio_tsg_puts);
2754 BIO_meth_set_gets(bio_methods, transport_bio_tsg_gets);
2755 BIO_meth_set_ctrl(bio_methods, transport_bio_tsg_ctrl);
2756 BIO_meth_set_create(bio_methods, transport_bio_tsg_new);
2757 BIO_meth_set_destroy(bio_methods, transport_bio_tsg_free);
2758 }
2759
2760 return bio_methods;
2761 }
2762
tsg_get_state(rdpTsg * tsg)2763 TSG_STATE tsg_get_state(rdpTsg* tsg)
2764 {
2765 if (!tsg)
2766 return TSG_STATE_INITIAL;
2767
2768 return tsg->state;
2769 }
2770
tsg_get_bio(rdpTsg * tsg)2771 BIO* tsg_get_bio(rdpTsg* tsg)
2772 {
2773 if (!tsg)
2774 return NULL;
2775
2776 return tsg->bio;
2777 }
2778
tsg_set_state(rdpTsg * tsg,TSG_STATE state)2779 BOOL tsg_set_state(rdpTsg* tsg, TSG_STATE state)
2780 {
2781 if (!tsg)
2782 return FALSE;
2783
2784 tsg->state = state;
2785 return TRUE;
2786 }
2787