FreeRDP
tsg.c
1 
23 #include <freerdp/config.h>
24 
25 #include "../settings.h"
26 
27 #include <winpr/assert.h>
28 #include <winpr/crt.h>
29 #include <winpr/error.h>
30 #include <winpr/print.h>
31 #include <winpr/stream.h>
32 
33 #include <freerdp/log.h>
34 
35 #include "rpc_bind.h"
36 #include "rpc_client.h"
37 #include "tsg.h"
38 #include "../utils.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
60 {
61  RESOURCENAME* resourceName;
62  UINT32 numResourceNames;
63  RESOURCENAME* alternateResourceNames;
64  UINT16 numAlternateResourceNames;
65  UINT32 Port;
66 } TSENDPOINTINFO;
67 
68 typedef struct
69 {
70  UINT16 ComponentId;
71  UINT16 PacketId;
72 } TSG_PACKET_HEADER;
73 
74 typedef struct
75 {
76  UINT32 capabilities;
77 } TSG_CAPABILITY_NAP;
78 
79 typedef union
80 {
81  TSG_CAPABILITY_NAP tsgCapNap;
82 } TSG_CAPABILITIES_UNION;
83 
84 typedef struct
85 {
86  UINT32 capabilityType;
87  TSG_CAPABILITIES_UNION tsgPacket;
88 } TSG_PACKET_CAPABILITIES;
89 
90 typedef struct
91 {
92  TSG_PACKET_HEADER tsgHeader;
93  TSG_PACKET_CAPABILITIES tsgCaps;
94  UINT32 numCapabilities;
95  UINT16 majorVersion;
96  UINT16 minorVersion;
97  UINT16 quarantineCapabilities;
98 } TSG_PACKET_VERSIONCAPS;
99 
100 typedef struct
101 {
102  UINT32 flags;
103 } TSG_PACKET_QUARCONFIGREQUEST;
104 
105 typedef struct
106 {
107  UINT32 flags;
108  WCHAR* machineName;
109  UINT32 nameLength;
110  BYTE* data;
111  UINT32 dataLen;
112 } TSG_PACKET_QUARREQUEST;
113 
114 typedef struct
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;
125 
126 typedef struct
127 {
128  UINT32 flags;
129  UINT32 reserved;
130  BYTE* responseData;
131  UINT32 responseDataLen;
132  TSG_REDIRECTION_FLAGS redirectionFlags;
133 } TSG_PACKET_RESPONSE;
134 
135 typedef struct
136 {
137  UINT32 flags;
138  UINT32 certChainLen;
139  WCHAR* certChainData;
140  GUID nonce;
141  TSG_PACKET_VERSIONCAPS versionCaps;
142 } TSG_PACKET_QUARENC_RESPONSE;
143 
144 typedef struct
145 {
146  INT32 isDisplayMandatory;
147  INT32 isConsentMandatory;
148  UINT32 msgBytes;
149  WCHAR* msgBuffer;
150 } TSG_PACKET_STRING_MESSAGE;
151 
152 typedef struct
153 {
154  UINT64 tunnelContext;
155 } TSG_PACKET_REAUTH_MESSAGE;
156 
157 typedef struct
158 {
159  UINT32 msgID;
160  UINT32 msgType;
161  INT32 isMsgPresent;
162 } TSG_PACKET_MSG_RESPONSE;
163 
164 typedef struct
165 {
166  TSG_PACKET_QUARENC_RESPONSE pktQuarEncResponse;
167  TSG_PACKET_MSG_RESPONSE pktConsentMessage;
168 } TSG_PACKET_CAPS_RESPONSE;
169 
170 typedef struct
171 {
172  UINT32 maxMessagesPerBatch;
173 } TSG_PACKET_MSG_REQUEST;
174 
175 typedef struct
176 {
177  TSG_PACKET_VERSIONCAPS tsgVersionCaps;
178  UINT32 cookieLen;
179  BYTE* cookie;
180 } TSG_PACKET_AUTH;
181 
182 typedef union
183 {
184  TSG_PACKET_VERSIONCAPS packetVersionCaps;
185  TSG_PACKET_AUTH packetAuth;
186 } TSG_INITIAL_PACKET_TYPE_UNION;
187 
188 typedef struct
189 {
190  UINT64 tunnelContext;
191  UINT32 packetId;
192  TSG_INITIAL_PACKET_TYPE_UNION tsgInitialPacket;
193 } TSG_PACKET_REAUTH;
194 
195 typedef union
196 {
197  TSG_PACKET_HEADER packetHeader;
198  TSG_PACKET_VERSIONCAPS packetVersionCaps;
199  TSG_PACKET_QUARCONFIGREQUEST packetQuarConfigRequest;
200  TSG_PACKET_QUARREQUEST packetQuarRequest;
201  TSG_PACKET_RESPONSE packetResponse;
202  TSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse;
203  TSG_PACKET_CAPS_RESPONSE packetCapsResponse;
204  TSG_PACKET_MSG_REQUEST packetMsgRequest;
205  TSG_PACKET_MSG_RESPONSE packetMsgResponse;
206  TSG_PACKET_AUTH packetAuth;
207  TSG_PACKET_REAUTH packetReauth;
208 } TSG_PACKET_TYPE_UNION;
209 
210 typedef struct
211 {
212  UINT32 packetId;
213  TSG_PACKET_TYPE_UNION tsgPacket;
214 } TSG_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  wLog* log;
234 };
235 
236 static BOOL tsg_stream_align(wLog* log, wStream* s, size_t align);
237 
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 
271 static const char* tsg_component_id_to_string(UINT16 ComponentId, char* buffer, size_t bytelen)
272 {
273  const char* str = NULL;
274 
275 #define ENTRY(x) \
276  case x: \
277  str = #x; \
278  break
279  switch (ComponentId)
280  {
281  ENTRY(TS_GATEWAY_TRANSPORT);
282  default:
283  str = "TS_UNKNOWN";
284  break;
285  }
286 #undef ENTRY
287 
288  (void)_snprintf(buffer, bytelen, "%s [0x%04" PRIx16 "]", str, ComponentId);
289  return buffer;
290 }
291 
292 static const char* tsg_state_to_string(TSG_STATE state)
293 {
294  switch (state)
295  {
296  case TSG_STATE_INITIAL:
297  return "TSG_STATE_INITIAL";
298  case TSG_STATE_CONNECTED:
299  return "TSG_STATE_CONNECTED";
300  case TSG_STATE_AUTHORIZED:
301  return "TSG_STATE_AUTHORIZED";
302  case TSG_STATE_CHANNEL_CREATED:
303  return "TSG_STATE_CHANNEL_CREATED";
304  case TSG_STATE_PIPE_CREATED:
305  return "TSG_STATE_PIPE_CREATED";
306  case TSG_STATE_TUNNEL_CLOSE_PENDING:
307  return "TSG_STATE_TUNNEL_CLOSE_PENDING";
308  case TSG_STATE_CHANNEL_CLOSE_PENDING:
309  return "TSG_STATE_CHANNEL_CLOSE_PENDING";
310  case TSG_STATE_FINAL:
311  return "TSG_STATE_FINAL";
312  default:
313  return "TSG_STATE_UNKNOWN";
314  }
315 }
316 
317 static BOOL TsProxyReadTunnelContext(wLog* log, wStream* s, CONTEXT_HANDLE* tunnelContext)
318 {
319  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
320  return FALSE;
321 
322  WINPR_ASSERT(tunnelContext);
323  Stream_Read_UINT32(s, tunnelContext->ContextType); /* ContextType (4 bytes) */
324  Stream_Read(s, &tunnelContext->ContextUuid,
325  sizeof(tunnelContext->ContextUuid)); /* ContextUuid (16 bytes) */
326  return TRUE;
327 }
328 
329 static BOOL TsProxyWriteTunnelContext(wLog* log, wStream* s, const CONTEXT_HANDLE* tunnelContext)
330 {
331  if (!Stream_EnsureRemainingCapacity(s, 20))
332  return FALSE;
333 
334  Stream_Write_UINT32(s, tunnelContext->ContextType); /* ContextType (4 bytes) */
335  Stream_Write(s, &tunnelContext->ContextUuid,
336  sizeof(tunnelContext->ContextUuid)); /* ContextUuid (16 bytes) */
337  return TRUE;
338 }
339 
340 static BOOL tsg_ndr_pointer_write(wLog* log, wStream* s, UINT32* index, DWORD length)
341 {
342  WINPR_ASSERT(index);
343  const UINT32 ndrPtr = 0x20000 + (*index) * 4;
344 
345  if (!s)
346  return FALSE;
347  if (!Stream_EnsureRemainingCapacity(s, 4))
348  return FALSE;
349 
350  if (length > 0)
351  {
352  Stream_Write_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */
353  (*index) = (*index) + 1;
354  }
355  else
356  Stream_Write_UINT32(s, 0);
357  return TRUE;
358 }
359 
360 static BOOL tsg_ndr_pointer_read(wLog* log, wStream* s, UINT32* index, UINT32* ptrval,
361  BOOL required)
362 {
363  WINPR_ASSERT(index);
364  const UINT32 ndrPtr = 0x20000 + (*index) * 4;
365 
366  if (!s)
367  return FALSE;
368  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
369  return FALSE;
370 
371  DWORD val = 0;
372  Stream_Read_UINT32(s, val);
373  if (ptrval)
374  *ptrval = val;
375 
376  if (val != 0)
377  {
378  if (val != ndrPtr)
379  {
380  WLog_Print(log, WLOG_WARN, "Read NDR pointer 0x%04" PRIx32 " but expected 0x%04" PRIx32,
381  val, ndrPtr);
382  if ((val & 0xFFFF0000) != (ndrPtr & 0xFFFF0000))
383  return FALSE;
384  }
385  (*index)++;
386  }
387  else if (required)
388  {
389  WLog_Print(log, WLOG_ERROR, "NDR pointer == 0, but the field is required");
390  return FALSE;
391  }
392 
393  return TRUE;
394 }
395 
396 static BOOL tsg_ndr_write_string(wLog* log, wStream* s, const WCHAR* str, size_t length)
397 {
398  if (!Stream_EnsureRemainingCapacity(s, 12 + length) || (length > UINT32_MAX))
399  return FALSE;
400 
401  Stream_Write_UINT32(s, (UINT32)length); /* MaxCount (4 bytes) */
402  Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
403  Stream_Write_UINT32(s, (UINT32)length); /* ActualCount (4 bytes) */
404  Stream_Write_UTF16_String(s, str, length); /* Array */
405  return TRUE;
406 }
407 
408 static BOOL tsg_ndr_read_string(wLog* log, wStream* s, WCHAR** str, UINT32 lengthInBytes)
409 {
410  UINT32 MaxCount = 0;
411  UINT32 Offset = 0;
412  UINT32 ActualCount = 0;
413 
414  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12))
415  return FALSE;
416 
417  Stream_Read_UINT32(s, MaxCount); /* MaxCount (4 bytes) */
418  Stream_Read_UINT32(s, Offset); /* Offset (4 bytes) */
419  Stream_Read_UINT32(s, ActualCount); /* ActualCount (4 bytes) */
420  if (ActualCount > MaxCount)
421  {
422  WLog_Print(log, WLOG_ERROR,
423  "failed to read string, ActualCount (%" PRIu32 ") > MaxCount (%" PRIu32 ")",
424  ActualCount, MaxCount);
425  return FALSE;
426  }
427  if (Offset != 0)
428  {
429  WLog_Print(log, WLOG_ERROR, "Unsupported Offset (%" PRIu32 "), expected 0", Offset);
430  return FALSE;
431  }
432  if (ActualCount > lengthInBytes / sizeof(WCHAR))
433  {
434  WLog_Print(log, WLOG_ERROR,
435  "failed to read string, ActualCount (%" PRIu32
436  ") * sizeof(WCHAR) > lengthInBytes (%" PRIu32 ")",
437  ActualCount, lengthInBytes);
438  return FALSE;
439  }
440  if (str)
441  *str = Stream_PointerAs(s, WCHAR);
442 
443  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, MaxCount))
444  return FALSE;
445  Stream_Seek(s, MaxCount);
446  return TRUE;
447 }
448 
449 static BOOL tsg_ndr_read_packet_header(wLog* log, wStream* s, TSG_PACKET_HEADER* header)
450 {
451  const UINT32 ComponentId = TS_GATEWAY_TRANSPORT;
452 
453  WINPR_ASSERT(header);
454  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 2, sizeof(UINT16)))
455  return FALSE;
456  Stream_Read_UINT16(s, header->ComponentId);
457  Stream_Read_UINT16(s, header->PacketId);
458 
459  if (ComponentId != header->ComponentId)
460  {
461  char buffer[64] = { 0 };
462  char buffer2[64] = { 0 };
463  WLog_Print(log, WLOG_ERROR, "Unexpected ComponentId: %s, Expected %s",
464  tsg_component_id_to_string(header->ComponentId, buffer, sizeof(buffer)),
465  tsg_component_id_to_string(ComponentId, buffer2, sizeof(buffer2)));
466  return FALSE;
467  }
468 
469  return TRUE;
470 }
471 
472 static BOOL tsg_ndr_write_packet_header(wLog* log, wStream* s, const TSG_PACKET_HEADER* header)
473 {
474  WINPR_ASSERT(header);
475  if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16)))
476  return FALSE;
477  Stream_Write_UINT16(s, header->ComponentId);
478  Stream_Write_UINT16(s, header->PacketId);
479  return TRUE;
480 }
481 
482 static BOOL tsg_ndr_read_nap(wLog* log, wStream* s, TSG_CAPABILITY_NAP* nap)
483 {
484  WINPR_ASSERT(nap);
485 
486  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 1, sizeof(UINT32)))
487  return FALSE;
488  Stream_Read_UINT32(s, nap->capabilities);
489  return TRUE;
490 }
491 
492 static BOOL tsg_ndr_write_nap(wLog* log, wStream* s, const TSG_CAPABILITY_NAP* nap)
493 {
494  WINPR_ASSERT(nap);
495 
496  if (!Stream_EnsureRemainingCapacity(s, 1 * sizeof(UINT32)))
497  return FALSE;
498  Stream_Write_UINT32(s, nap->capabilities);
499  return TRUE;
500 }
501 
502 static BOOL tsg_ndr_read_tsg_caps(wLog* log, wStream* s, TSG_PACKET_CAPABILITIES* caps)
503 {
504  UINT32 capabilityType = 0;
505  UINT32 count = 0;
506  WINPR_ASSERT(caps);
507 
508  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 3, sizeof(UINT32)))
509  return FALSE;
510  Stream_Read_UINT32(s, count);
511  Stream_Read_UINT32(s, capabilityType);
512  Stream_Read_UINT32(s, caps->capabilityType);
513  if (capabilityType != caps->capabilityType)
514  {
515  WLog_Print(log, WLOG_ERROR, "Inconsistent data, capabilityType %s != %s",
516  tsg_packet_id_to_string(capabilityType),
517  tsg_packet_id_to_string(caps->capabilityType));
518  return FALSE;
519  }
520  switch (caps->capabilityType)
521  {
522  case TSG_CAPABILITY_TYPE_NAP:
523  return tsg_ndr_read_nap(log, s, &caps->tsgPacket.tsgCapNap);
524  default:
525  WLog_Print(log, WLOG_ERROR,
526  "unknown TSG_PACKET_CAPABILITIES::capabilityType 0x%04" PRIx32,
527  caps->capabilityType);
528  return FALSE;
529  }
530 }
531 
532 static BOOL tsg_ndr_write_tsg_caps(wLog* log, wStream* s, const TSG_PACKET_CAPABILITIES* caps)
533 {
534  WINPR_ASSERT(caps);
535 
536  if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT32)))
537  return FALSE;
538  Stream_Write_UINT32(s, caps->capabilityType);
539  Stream_Write_UINT32(s, caps->capabilityType);
540 
541  switch (caps->capabilityType)
542  {
543  case TSG_CAPABILITY_TYPE_NAP:
544  return tsg_ndr_write_nap(log, s, &caps->tsgPacket.tsgCapNap);
545  default:
546  WLog_Print(log, WLOG_ERROR,
547  "unknown TSG_PACKET_CAPABILITIES::capabilityType 0x%04" PRIx32,
548  caps->capabilityType);
549  return FALSE;
550  }
551 }
552 
553 static BOOL tsg_ndr_read_version_caps(wLog* log, wStream* s, UINT32* index,
554  TSG_PACKET_VERSIONCAPS* caps)
555 {
556  WINPR_ASSERT(caps);
557  if (!tsg_ndr_read_packet_header(log, s, &caps->tsgHeader))
558  return FALSE;
559 
560  UINT32 TSGCapsPtr = 0;
561  if (!tsg_ndr_pointer_read(log, s, index, &TSGCapsPtr, TRUE))
562  return FALSE;
563 
564  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 10))
565  return FALSE;
566  Stream_Read_UINT32(s, caps->numCapabilities);
567  Stream_Read_UINT16(s, caps->majorVersion);
568  Stream_Read_UINT16(s, caps->minorVersion);
569  Stream_Read_UINT16(s, caps->quarantineCapabilities);
570  /* 4-byte alignment */
571  if (!tsg_stream_align(log, s, 4))
572  return FALSE;
573 
574  return tsg_ndr_read_tsg_caps(log, s, &caps->tsgCaps);
575 }
576 
577 static BOOL tsg_ndr_write_version_caps(wLog* log, wStream* s, UINT32* index,
578  const TSG_PACKET_VERSIONCAPS* caps)
579 {
580  WINPR_ASSERT(caps);
581  if (!tsg_ndr_write_packet_header(log, s, &caps->tsgHeader))
582  return FALSE;
583 
584  if (!tsg_ndr_pointer_write(log, s, index, 1)) /* TsgCapsPtr (4 bytes) */
585  return FALSE;
586 
587  if (!Stream_EnsureRemainingCapacity(s, 10))
588  return FALSE;
589  Stream_Write_UINT32(s, caps->numCapabilities);
590  Stream_Write_UINT16(s, caps->majorVersion);
591  Stream_Write_UINT16(s, caps->minorVersion);
592  Stream_Write_UINT16(s, caps->quarantineCapabilities);
593 
594  /* 4-byte alignment (30 + 2) */
595  Stream_Write_UINT16(s, 0x0000); /* pad (2 bytes) */
596  Stream_Write_UINT32(s, caps->numCapabilities); /* MaxCount (4 bytes) */
597  return tsg_ndr_write_tsg_caps(log, s, &caps->tsgCaps);
598 }
599 
600 static BOOL tsg_ndr_read_quarenc_response(wLog* log, wStream* s, UINT32* index,
601  TSG_PACKET_QUARENC_RESPONSE* quarenc)
602 {
603  WINPR_ASSERT(quarenc);
604  UINT32 CertChainDataPtr = 0;
605  UINT32 VersionCapsPtr = 0;
606 
607  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
608  return FALSE;
609  Stream_Read_UINT32(s, quarenc->flags);
610  Stream_Read_UINT32(s, quarenc->certChainLen);
611 
612  if (!tsg_ndr_pointer_read(log, s, index, &CertChainDataPtr, quarenc->certChainLen != 0))
613  return FALSE;
614 
615  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 1, sizeof(quarenc->nonce)))
616  return FALSE;
617  Stream_Read(s, &quarenc->nonce, sizeof(quarenc->nonce));
618 
619  if (!tsg_ndr_pointer_read(log, s, index, &VersionCapsPtr, TRUE))
620  return FALSE;
621 
622  return TRUE;
623 }
624 
625 static BOOL tsg_ndr_read_quarenc_data(wLog* log, wStream* s, UINT32* index,
626  TSG_PACKET_QUARENC_RESPONSE* quarenc)
627 {
628  WINPR_ASSERT(quarenc);
629 
630  if (quarenc->certChainLen > 0)
631  {
632  /* [MS-TSGU] 2.2.9.2.1.6 TSG_PACKET_QUARENC_RESPONSE::certChainLen number of WCHAR */
633  if (!tsg_ndr_read_string(log, s, &quarenc->certChainData,
634  quarenc->certChainLen * sizeof(WCHAR)))
635  return FALSE;
636  /* 4-byte alignment */
637  if (!tsg_stream_align(log, s, 4))
638  return FALSE;
639  }
640 
641  return tsg_ndr_read_version_caps(log, s, index, &quarenc->versionCaps);
642 }
643 
644 static BOOL tsg_ndr_write_auth(wLog* log, wStream* s, UINT32* index, const TSG_PACKET_AUTH* auth)
645 {
646  WINPR_ASSERT(auth);
647 
648  if (!tsg_ndr_write_version_caps(log, s, index, &auth->tsgVersionCaps))
649  return FALSE;
650 
651  if (!Stream_EnsureRemainingCapacity(s, 4))
652  return FALSE;
653 
654  Stream_Write_UINT32(s, auth->cookieLen);
655  if (!tsg_ndr_pointer_write(log, s, index, auth->cookieLen))
656  return FALSE;
657 
658  if (!Stream_EnsureRemainingCapacity(s, auth->cookieLen))
659  return FALSE;
660  Stream_Write(s, auth->cookie, auth->cookieLen);
661  return TRUE;
662 }
663 
664 static BOOL tsg_ndr_write_reauth(wLog* log, wStream* s, UINT32* index,
665  const TSG_PACKET_REAUTH* auth)
666 {
667  WINPR_ASSERT(auth);
668 
669  if (!Stream_EnsureRemainingCapacity(s, 12))
670  return FALSE;
671 
672  Stream_Write_UINT64(s, auth->tunnelContext); /* TunnelContext (8 bytes) */
673  Stream_Write_UINT32(s, auth->packetId); /* PacketId (4 bytes) */
674 
675  switch (auth->packetId)
676  {
677  case TSG_PACKET_TYPE_VERSIONCAPS:
678  return tsg_ndr_write_version_caps(log, s, index,
679  &auth->tsgInitialPacket.packetVersionCaps);
680  case TSG_PACKET_TYPE_AUTH:
681  return tsg_ndr_write_auth(log, s, index, &auth->tsgInitialPacket.packetAuth);
682  default:
683  WLog_Print(log, WLOG_ERROR, "unexpected packetId %s",
684  tsg_packet_id_to_string(auth->packetId));
685  return FALSE;
686  }
687 }
688 
689 static BOOL tsg_ndr_read_packet_response(wLog* log, wStream* s, UINT32* index,
690  TSG_PACKET_RESPONSE* response)
691 {
692  UINT32 ResponseDataPtr = 0;
693  UINT32 MaxSizeValue = 0;
694  UINT32 MaxOffsetValue = 0;
695  UINT32 idleTimeout = 0;
696 
697  WINPR_ASSERT(response);
698 
699  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 2, sizeof(UINT32)))
700  return FALSE;
701  Stream_Read_UINT32(s, response->flags); /* Flags (4 bytes) */
702  Stream_Seek_UINT32(s); /* Reserved (4 bytes) */
703 
704  if (response->flags != TSG_PACKET_TYPE_QUARREQUEST)
705  {
706  WLog_Print(log, WLOG_ERROR,
707  "Unexpected Packet Response Flags: 0x%08" PRIX32
708  ", Expected TSG_PACKET_TYPE_QUARREQUEST",
709  response->flags);
710  return FALSE;
711  }
712 
713  if (!tsg_ndr_pointer_read(log, s, index, &ResponseDataPtr, TRUE))
714  return FALSE;
715 
716  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 10, sizeof(UINT32)))
717  return FALSE;
718 
719  Stream_Read_UINT32(s, response->responseDataLen); /* ResponseDataLength (4 bytes) */
720  Stream_Read_INT32(
721  s, response->redirectionFlags.enableAllRedirections); /* EnableAllRedirections (4 bytes) */
722  Stream_Read_INT32(
723  s,
724  response->redirectionFlags.disableAllRedirections); /* DisableAllRedirections (4 bytes) */
725  Stream_Read_INT32(s, response->redirectionFlags
726  .driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */
727  Stream_Read_INT32(s,
728  response->redirectionFlags
729  .printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */
730  Stream_Read_INT32(
731  s,
732  response->redirectionFlags.portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */
733  Stream_Read_INT32(s, response->redirectionFlags.reserved); /* Reserved (4 bytes) */
734  Stream_Read_INT32(
735  s, response->redirectionFlags
736  .clipboardRedirectionDisabled); /* ClipboardRedirectionDisabled (4 bytes) */
737  Stream_Read_INT32(
738  s,
739  response->redirectionFlags.pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */
740 
741  Stream_Read_UINT32(s, MaxSizeValue); /* (4 bytes) */
742  Stream_Read_UINT32(s, MaxOffsetValue); /* (4 bytes) */
743 
744  if (MaxSizeValue != response->responseDataLen)
745  {
746  WLog_Print(log, WLOG_ERROR, "Unexpected size value: %" PRIu32 ", expected: %" PRIu32 "",
747  MaxSizeValue, response->responseDataLen);
748  return FALSE;
749  }
750 
751  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, MaxSizeValue))
752  return FALSE;
753 
754  if (MaxSizeValue == 4)
755  Stream_Read_UINT32(s, idleTimeout);
756  else
757  Stream_Seek(s, MaxSizeValue); /* ResponseData */
758  return TRUE;
759 }
760 
761 WINPR_ATTR_FORMAT_ARG(3, 4)
762 static BOOL tsg_print(char** buffer, size_t* len, WINPR_FORMAT_ARG const char* fmt, ...)
763 {
764  int rc = 0;
765  va_list ap = { 0 };
766  if (!buffer || !len || !fmt)
767  return FALSE;
768  va_start(ap, fmt);
769  rc = vsnprintf(*buffer, *len, fmt, ap);
770  va_end(ap);
771  if ((rc < 0) || ((size_t)rc > *len))
772  return FALSE;
773  *len -= (size_t)rc;
774  *buffer += (size_t)rc;
775  return TRUE;
776 }
777 
778 static BOOL tsg_packet_header_to_string(char** buffer, size_t* length,
779  const TSG_PACKET_HEADER* header)
780 {
781  WINPR_ASSERT(buffer);
782  WINPR_ASSERT(length);
783  WINPR_ASSERT(header);
784 
785  return tsg_print(buffer, length,
786  "header { ComponentId=0x%04" PRIx16 ", PacketId=0x%04" PRIx16 " }",
787  header->ComponentId, header->PacketId);
788 }
789 
790 static BOOL tsg_type_capability_nap_to_string(char** buffer, size_t* length,
791  const TSG_CAPABILITY_NAP* cur)
792 {
793  WINPR_ASSERT(buffer);
794  WINPR_ASSERT(length);
795  WINPR_ASSERT(cur);
796 
797  return tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }",
798  tsg_packet_id_to_string(TSG_CAPABILITY_TYPE_NAP), cur->capabilities);
799 }
800 
801 static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
802  const TSG_PACKET_CAPABILITIES* caps, UINT32 numCaps)
803 {
804  WINPR_ASSERT(buffer);
805  WINPR_ASSERT(length);
806  WINPR_ASSERT(caps);
807 
808  if (!tsg_print(buffer, length, "capabilities { "))
809  return FALSE;
810 
811  for (UINT32 x = 0; x < numCaps; x++)
812  {
813  const TSG_PACKET_CAPABILITIES* cur = &caps[x];
814  switch (cur->capabilityType)
815  {
816  case TSG_CAPABILITY_TYPE_NAP:
817  if (!tsg_type_capability_nap_to_string(buffer, length, &cur->tsgPacket.tsgCapNap))
818  return FALSE;
819  break;
820  default:
821  if (!tsg_print(buffer, length, "TSG_UNKNOWN_CAPABILITY"))
822  return FALSE;
823  break;
824  }
825  }
826  return tsg_print(buffer, length, " }");
827 }
828 
829 static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length,
830  const TSG_PACKET_VERSIONCAPS* caps)
831 {
832  WINPR_ASSERT(buffer);
833  WINPR_ASSERT(length);
834  WINPR_ASSERT(caps);
835 
836  if (!tsg_print(buffer, length, "versioncaps { "))
837  return FALSE;
838  if (!tsg_packet_header_to_string(buffer, length, &caps->tsgHeader))
839  return FALSE;
840 
841  if (!tsg_print(buffer, length, " "))
842  return FALSE;
843 
844  if (!tsg_packet_capabilities_to_string(buffer, length, &caps->tsgCaps, caps->numCapabilities))
845  return FALSE;
846 
847  if (!tsg_print(buffer, length,
848  " numCapabilities=0x%08" PRIx32 ", majorVersion=0x%04" PRIx16
849  ", minorVersion=0x%04" PRIx16 ", quarantineCapabilities=0x%04" PRIx16,
850  caps->numCapabilities, caps->majorVersion, caps->minorVersion,
851  caps->quarantineCapabilities))
852  return FALSE;
853 
854  return tsg_print(buffer, length, " }");
855 }
856 
857 static BOOL tsg_packet_quarconfigrequest_to_string(char** buffer, size_t* length,
858  const TSG_PACKET_QUARCONFIGREQUEST* caps)
859 {
860  WINPR_ASSERT(buffer);
861  WINPR_ASSERT(length);
862  WINPR_ASSERT(caps);
863 
864  if (!tsg_print(buffer, length, "quarconfigrequest { "))
865  return FALSE;
866 
867  if (!tsg_print(buffer, length, " "))
868  return FALSE;
869 
870  if (!tsg_print(buffer, length, " flags=0x%08" PRIx32, caps->flags))
871  return FALSE;
872 
873  return tsg_print(buffer, length, " }");
874 }
875 
876 static BOOL tsg_packet_quarrequest_to_string(char** buffer, size_t* length,
877  const TSG_PACKET_QUARREQUEST* caps)
878 {
879  BOOL rc = FALSE;
880  char* name = NULL;
881  char* strdata = NULL;
882 
883  WINPR_ASSERT(buffer);
884  WINPR_ASSERT(length);
885  WINPR_ASSERT(caps);
886 
887  if (!tsg_print(buffer, length, "quarrequest { "))
888  return FALSE;
889 
890  if (!tsg_print(buffer, length, " "))
891  return FALSE;
892 
893  if (caps->nameLength > 0)
894  {
895  if (caps->nameLength > INT_MAX)
896  return FALSE;
897  name = ConvertWCharNToUtf8Alloc(caps->machineName, caps->nameLength, NULL);
898  if (!name)
899  return FALSE;
900  }
901 
902  strdata = winpr_BinToHexString(caps->data, caps->dataLen, TRUE);
903  if (strdata || (caps->dataLen == 0))
904  rc = tsg_print(buffer, length,
905  " flags=0x%08" PRIx32 ", machineName=%s [%" PRIu32 "], data[%" PRIu32 "]=%s",
906  caps->flags, name, caps->nameLength, caps->dataLen, strdata);
907  free(name);
908  free(strdata);
909  if (!rc)
910  return FALSE;
911 
912  return tsg_print(buffer, length, " }");
913 }
914 
915 static const char* tsg_bool_to_string(BOOL val)
916 {
917  if (val)
918  return "true";
919  return "false";
920 }
921 
922 static const char* tsg_redirection_flags_to_string(char* buffer, size_t size,
923  const TSG_REDIRECTION_FLAGS* flags)
924 {
925  WINPR_ASSERT(buffer || (size == 0));
926  WINPR_ASSERT(flags);
927 
928  (void)_snprintf(
929  buffer, size,
930  "enableAllRedirections=%s, disableAllRedirections=%s, driveRedirectionDisabled=%s, "
931  "printerRedirectionDisabled=%s, portRedirectionDisabled=%s, reserved=%s, "
932  "clipboardRedirectionDisabled=%s, pnpRedirectionDisabled=%s",
933  tsg_bool_to_string(flags->enableAllRedirections),
934  tsg_bool_to_string(flags->disableAllRedirections),
935  tsg_bool_to_string(flags->driveRedirectionDisabled),
936  tsg_bool_to_string(flags->printerRedirectionDisabled),
937  tsg_bool_to_string(flags->portRedirectionDisabled), tsg_bool_to_string(flags->reserved),
938  tsg_bool_to_string(flags->clipboardRedirectionDisabled),
939  tsg_bool_to_string(flags->pnpRedirectionDisabled));
940  return buffer;
941 }
942 
943 static BOOL tsg_packet_response_to_string(char** buffer, size_t* length,
944  const TSG_PACKET_RESPONSE* caps)
945 {
946  BOOL rc = FALSE;
947  char* strdata = NULL;
948  char tbuffer[8192] = { 0 };
949 
950  WINPR_ASSERT(buffer);
951  WINPR_ASSERT(length);
952  WINPR_ASSERT(caps);
953 
954  if (!tsg_print(buffer, length, "response { "))
955  return FALSE;
956 
957  if (!tsg_print(buffer, length, " "))
958  return FALSE;
959 
960  strdata = winpr_BinToHexString(caps->responseData, caps->responseDataLen, TRUE);
961  if (strdata || (caps->responseDataLen == 0))
962  rc = tsg_print(
963  buffer, length,
964  " flags=0x%08" PRIx32 ", reserved=0x%08" PRIx32 ", responseData[%" PRIu32
965  "]=%s, redirectionFlags={ %s }",
966  caps->flags, caps->reserved, caps->responseDataLen, strdata,
967  tsg_redirection_flags_to_string(tbuffer, ARRAYSIZE(tbuffer), &caps->redirectionFlags));
968  free(strdata);
969  if (!rc)
970  return FALSE;
971 
972  return tsg_print(buffer, length, " }");
973 }
974 
975 static BOOL tsg_packet_quarenc_response_to_string(char** buffer, size_t* length,
976  const TSG_PACKET_QUARENC_RESPONSE* caps)
977 {
978  BOOL rc = FALSE;
979  char* strdata = NULL;
980  RPC_CSTR uuid = NULL;
981  char tbuffer[8192] = { 0 };
982  size_t size = ARRAYSIZE(tbuffer);
983  char* ptbuffer = tbuffer;
984 
985  WINPR_ASSERT(buffer);
986  WINPR_ASSERT(length);
987  WINPR_ASSERT(caps);
988 
989  if (!tsg_print(buffer, length, "quarenc_response { "))
990  return FALSE;
991 
992  if (!tsg_print(buffer, length, " "))
993  return FALSE;
994 
995  if (caps->certChainLen > 0)
996  {
997  if (caps->certChainLen > INT_MAX)
998  return FALSE;
999  strdata = ConvertWCharNToUtf8Alloc(caps->certChainData, caps->certChainLen, NULL);
1000  if (!strdata)
1001  return FALSE;
1002  }
1003 
1004  tsg_packet_versioncaps_to_string(&ptbuffer, &size, &caps->versionCaps);
1005  UuidToStringA(&caps->nonce, &uuid);
1006  if (strdata || (caps->certChainLen == 0))
1007  rc =
1008  tsg_print(buffer, length,
1009  " flags=0x%08" PRIx32 ", certChain[%" PRIu32 "]=%s, nonce=%s, versionCaps=%s",
1010  caps->flags, caps->certChainLen, strdata, uuid, tbuffer);
1011  free(strdata);
1012  RpcStringFreeA(&uuid);
1013  if (!rc)
1014  return FALSE;
1015 
1016  return tsg_print(buffer, length, " }");
1017 }
1018 
1019 static BOOL tsg_packet_message_response_to_string(char** buffer, size_t* length,
1020  const TSG_PACKET_MSG_RESPONSE* caps)
1021 {
1022  WINPR_ASSERT(buffer);
1023  WINPR_ASSERT(length);
1024  WINPR_ASSERT(caps);
1025 
1026  if (!tsg_print(buffer, length, "msg_response { "))
1027  return FALSE;
1028 
1029  if (!tsg_print(buffer, length,
1030  " msgID=0x%08" PRIx32 ", msgType=0x%08" PRIx32 ", isMsgPresent=%" PRId32,
1031  caps->msgID, caps->msgType, caps->isMsgPresent))
1032  return FALSE;
1033 
1034  return tsg_print(buffer, length, " }");
1035 }
1036 
1037 static BOOL tsg_packet_caps_response_to_string(char** buffer, size_t* length,
1038  const TSG_PACKET_CAPS_RESPONSE* caps)
1039 {
1040  WINPR_ASSERT(buffer);
1041  WINPR_ASSERT(length);
1042  WINPR_ASSERT(caps);
1043 
1044  if (!tsg_print(buffer, length, "caps_response { "))
1045  return FALSE;
1046 
1047  if (!tsg_packet_quarenc_response_to_string(buffer, length, &caps->pktQuarEncResponse))
1048  return FALSE;
1049 
1050  if (!tsg_packet_message_response_to_string(buffer, length, &caps->pktConsentMessage))
1051  return FALSE;
1052 
1053  return tsg_print(buffer, length, " }");
1054 }
1055 
1056 static BOOL tsg_packet_message_request_to_string(char** buffer, size_t* length,
1057  const TSG_PACKET_MSG_REQUEST* caps)
1058 {
1059  WINPR_ASSERT(buffer);
1060  WINPR_ASSERT(length);
1061  WINPR_ASSERT(caps);
1062 
1063  if (!tsg_print(buffer, length, "caps_message_request { "))
1064  return FALSE;
1065 
1066  if (!tsg_print(buffer, length, " maxMessagesPerBatch=%" PRIu32, caps->maxMessagesPerBatch))
1067  return FALSE;
1068 
1069  return tsg_print(buffer, length, " }");
1070 }
1071 
1072 static BOOL tsg_packet_auth_to_string(char** buffer, size_t* length, const TSG_PACKET_AUTH* caps)
1073 {
1074  BOOL rc = FALSE;
1075  char* strdata = NULL;
1076  WINPR_ASSERT(buffer);
1077  WINPR_ASSERT(length);
1078  WINPR_ASSERT(caps);
1079 
1080  if (!tsg_print(buffer, length, "caps_message_request { "))
1081  return FALSE;
1082 
1083  if (!tsg_packet_versioncaps_to_string(buffer, length, &caps->tsgVersionCaps))
1084  return FALSE;
1085 
1086  strdata = winpr_BinToHexString(caps->cookie, caps->cookieLen, TRUE);
1087  if (strdata || (caps->cookieLen == 0))
1088  rc = tsg_print(buffer, length, " cookie[%" PRIu32 "]=%s", caps->cookieLen, strdata);
1089  free(strdata);
1090  if (!rc)
1091  return FALSE;
1092 
1093  return tsg_print(buffer, length, " }");
1094 }
1095 
1096 static BOOL tsg_packet_reauth_to_string(char** buffer, size_t* length,
1097  const TSG_PACKET_REAUTH* caps)
1098 {
1099  BOOL rc = FALSE;
1100  WINPR_ASSERT(buffer);
1101  WINPR_ASSERT(length);
1102  WINPR_ASSERT(caps);
1103 
1104  if (!tsg_print(buffer, length, "caps_message_request { "))
1105  return FALSE;
1106 
1107  if (!tsg_print(buffer, length, " tunnelContext=0x%016" PRIx64 ", packetId=%s [0x%08" PRIx32 "]",
1108  caps->tunnelContext, tsg_packet_id_to_string(caps->packetId), caps->packetId))
1109  return FALSE;
1110 
1111  switch (caps->packetId)
1112  {
1113  case TSG_PACKET_TYPE_VERSIONCAPS:
1114  rc = tsg_packet_versioncaps_to_string(buffer, length,
1115  &caps->tsgInitialPacket.packetVersionCaps);
1116  break;
1117  case TSG_PACKET_TYPE_AUTH:
1118  rc = tsg_packet_auth_to_string(buffer, length, &caps->tsgInitialPacket.packetAuth);
1119  break;
1120  default:
1121  rc = tsg_print(buffer, length, "TODO: Unhandled packet type %s [0x%08" PRIx32 "]",
1122  tsg_packet_id_to_string(caps->packetId), caps->packetId);
1123  break;
1124  }
1125 
1126  if (!rc)
1127  return FALSE;
1128 
1129  return tsg_print(buffer, length, " }");
1130 }
1131 
1132 static const char* tsg_packet_to_string(const TSG_PACKET* packet)
1133 {
1134  size_t len = 8192;
1135  static char sbuffer[8193] = { 0 };
1136  char* buffer = sbuffer;
1137 
1138  if (!tsg_print(&buffer, &len, "TSG_PACKET { packetId=%s [0x%08" PRIx32 "], ",
1139  tsg_packet_id_to_string(packet->packetId), packet->packetId))
1140  goto fail;
1141 
1142  switch (packet->packetId)
1143  {
1144  case TSG_PACKET_TYPE_HEADER:
1145  if (!tsg_packet_header_to_string(&buffer, &len, &packet->tsgPacket.packetHeader))
1146  goto fail;
1147  break;
1148  case TSG_PACKET_TYPE_VERSIONCAPS:
1149  if (!tsg_packet_versioncaps_to_string(&buffer, &len,
1150  &packet->tsgPacket.packetVersionCaps))
1151  goto fail;
1152  break;
1153  case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
1154  if (!tsg_packet_quarconfigrequest_to_string(&buffer, &len,
1155  &packet->tsgPacket.packetQuarConfigRequest))
1156  goto fail;
1157  break;
1158  case TSG_PACKET_TYPE_QUARREQUEST:
1159  if (!tsg_packet_quarrequest_to_string(&buffer, &len,
1160  &packet->tsgPacket.packetQuarRequest))
1161  goto fail;
1162  break;
1163  case TSG_PACKET_TYPE_RESPONSE:
1164  if (!tsg_packet_response_to_string(&buffer, &len, &packet->tsgPacket.packetResponse))
1165  goto fail;
1166  break;
1167  case TSG_PACKET_TYPE_QUARENC_RESPONSE:
1168  if (!tsg_packet_quarenc_response_to_string(&buffer, &len,
1169  &packet->tsgPacket.packetQuarEncResponse))
1170  goto fail;
1171  break;
1172  case TSG_PACKET_TYPE_CAPS_RESPONSE:
1173  if (!tsg_packet_caps_response_to_string(&buffer, &len,
1174  &packet->tsgPacket.packetCapsResponse))
1175  goto fail;
1176  break;
1177  case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
1178  if (!tsg_packet_message_request_to_string(&buffer, &len,
1179  &packet->tsgPacket.packetMsgRequest))
1180  goto fail;
1181  break;
1182  case TSG_PACKET_TYPE_MESSAGE_PACKET:
1183  if (!tsg_packet_message_response_to_string(&buffer, &len,
1184  &packet->tsgPacket.packetMsgResponse))
1185  goto fail;
1186  break;
1187  case TSG_PACKET_TYPE_AUTH:
1188  if (!tsg_packet_auth_to_string(&buffer, &len, &packet->tsgPacket.packetAuth))
1189  goto fail;
1190  break;
1191  case TSG_PACKET_TYPE_REAUTH:
1192  if (!tsg_packet_reauth_to_string(&buffer, &len, &packet->tsgPacket.packetReauth))
1193  goto fail;
1194  break;
1195  default:
1196  if (!tsg_print(&buffer, &len, "INVALID"))
1197  goto fail;
1198  break;
1199  }
1200 
1201  if (!tsg_print(&buffer, &len, " }"))
1202  goto fail;
1203 
1204 fail:
1205  return sbuffer;
1206 }
1207 
1208 static BOOL tsg_stream_align(wLog* log, wStream* s, size_t align)
1209 {
1210  size_t pos = 0;
1211  size_t offset = 0;
1212 
1213  if (!s)
1214  return FALSE;
1215 
1216  pos = Stream_GetPosition(s);
1217 
1218  if ((pos % align) != 0)
1219  offset = align - pos % align;
1220 
1221  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, offset))
1222  return FALSE;
1223  Stream_Seek(s, offset);
1224  return TRUE;
1225 }
1226 
1227 static BIO_METHOD* BIO_s_tsg(void);
1264 static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UINT32 count,
1265  const UINT32* lengths)
1266 {
1267  wStream* s = NULL;
1268  rdpTsg* tsg = NULL;
1269  size_t length = 0;
1270  const byte* buffer1 = NULL;
1271  const byte* buffer2 = NULL;
1272  const byte* buffer3 = NULL;
1273  UINT32 buffer1Length = 0;
1274  UINT32 buffer2Length = 0;
1275  UINT32 buffer3Length = 0;
1276  UINT32 numBuffers = 0;
1277  UINT32 totalDataBytes = 0;
1278  tsg = (rdpTsg*)IDL_handle;
1279  buffer1Length = buffer2Length = buffer3Length = 0;
1280 
1281  if (count > 0)
1282  {
1283  numBuffers++;
1284  buffer1 = &pRpcMessage[0];
1285  buffer1Length = lengths[0];
1286  totalDataBytes += lengths[0] + 4;
1287  }
1288 
1289  if (count > 1)
1290  {
1291  numBuffers++;
1292  buffer2 = &pRpcMessage[1];
1293  buffer2Length = lengths[1];
1294  totalDataBytes += lengths[1] + 4;
1295  }
1296 
1297  if (count > 2)
1298  {
1299  numBuffers++;
1300  buffer3 = &pRpcMessage[2];
1301  buffer3Length = lengths[2];
1302  totalDataBytes += lengths[2] + 4;
1303  }
1304 
1305  length = 28ull + totalDataBytes;
1306  if (length > INT_MAX)
1307  return -1;
1308  s = Stream_New(NULL, length);
1309 
1310  if (!s)
1311  {
1312  WLog_Print(tsg->log, WLOG_ERROR, "Stream_New failed!");
1313  return -1;
1314  }
1315 
1316  /* PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE_NR (20 bytes) */
1317  if (!TsProxyWriteTunnelContext(tsg->log, s, &tsg->ChannelContext))
1318  goto fail;
1319  Stream_Write_UINT32_BE(s, totalDataBytes); /* totalDataBytes (4 bytes) */
1320  Stream_Write_UINT32_BE(s, numBuffers); /* numBuffers (4 bytes) */
1321 
1322  if (buffer1Length > 0)
1323  Stream_Write_UINT32_BE(s, buffer1Length); /* buffer1Length (4 bytes) */
1324 
1325  if (buffer2Length > 0)
1326  Stream_Write_UINT32_BE(s, buffer2Length); /* buffer2Length (4 bytes) */
1327 
1328  if (buffer3Length > 0)
1329  Stream_Write_UINT32_BE(s, buffer3Length); /* buffer3Length (4 bytes) */
1330 
1331  if (buffer1Length > 0)
1332  Stream_Write(s, buffer1, buffer1Length); /* buffer1 (variable) */
1333 
1334  if (buffer2Length > 0)
1335  Stream_Write(s, buffer2, buffer2Length); /* buffer2 (variable) */
1336 
1337  if (buffer3Length > 0)
1338  Stream_Write(s, buffer3, buffer3Length); /* buffer3 (variable) */
1339 
1340  if (!rpc_client_write_call(tsg->rpc, s, TsProxySendToServerOpnum))
1341  return -1;
1342 
1343  return (int)length;
1344 fail:
1345  Stream_Free(s, TRUE);
1346  return -1;
1347 }
1348 
1360 static BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg, const TSG_PACKET* tsgPacket)
1361 {
1362  BOOL rc = FALSE;
1363  BOOL write = TRUE;
1364  UINT16 opnum = 0;
1365  wStream* s = NULL;
1366  rdpRpc* rpc = NULL;
1367 
1368  if (!tsg || !tsg->rpc)
1369  return FALSE;
1370 
1371  rpc = tsg->rpc;
1372  WLog_Print(tsg->log, WLOG_DEBUG, "%s", tsg_packet_to_string(tsgPacket));
1373  s = Stream_New(NULL, 108);
1374 
1375  if (!s)
1376  return FALSE;
1377 
1378  switch (tsgPacket->packetId)
1379  {
1380  case TSG_PACKET_TYPE_VERSIONCAPS:
1381  {
1382  UINT32 index = 0;
1383  const TSG_PACKET_VERSIONCAPS* packetVersionCaps =
1384  &tsgPacket->tsgPacket.packetVersionCaps;
1385 
1386  Stream_Write_UINT32(s, tsgPacket->packetId); /* PacketId (4 bytes) */
1387  Stream_Write_UINT32(s, tsgPacket->packetId); /* SwitchValue (4 bytes) */
1388  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* PacketVersionCapsPtr (4 bytes) */
1389  goto fail;
1390 
1391  if (!tsg_ndr_write_version_caps(tsg->log, s, &index, packetVersionCaps))
1392  goto fail;
1397  /*
1398  * 8-byte constant (8A E3 13 71 02 F4 36 71) also observed here:
1399  * http://lists.samba.org/archive/cifs-protocol/2010-July/001543.html
1400  */
1401  Stream_Write_UINT8(s, 0x8A);
1402  Stream_Write_UINT8(s, 0xE3);
1403  Stream_Write_UINT8(s, 0x13);
1404  Stream_Write_UINT8(s, 0x71);
1405  Stream_Write_UINT8(s, 0x02);
1406  Stream_Write_UINT8(s, 0xF4);
1407  Stream_Write_UINT8(s, 0x36);
1408  Stream_Write_UINT8(s, 0x71);
1409  Stream_Write_UINT32(s, 0x00040001); /* 1.4 (version?) */
1410  Stream_Write_UINT32(s, 0x00000001); /* 1 (element count?) */
1411  /* p_cont_list_t */
1412  Stream_Write_UINT8(s, 2); /* ncontext_elem */
1413  Stream_Write_UINT8(s, 0x40); /* reserved1 */
1414  Stream_Write_UINT16(s, 0x0028); /* reserved2 */
1415  /* p_syntax_id_t */
1416  Stream_Write(s, &TSGU_UUID, sizeof(p_uuid_t));
1417  Stream_Write_UINT32(s, TSGU_SYNTAX_IF_VERSION);
1418  /* p_syntax_id_t */
1419  Stream_Write(s, &NDR_UUID, sizeof(p_uuid_t));
1420  Stream_Write_UINT32(s, NDR_SYNTAX_IF_VERSION);
1421  opnum = TsProxyCreateTunnelOpnum;
1422  }
1423  break;
1424 
1425  case TSG_PACKET_TYPE_REAUTH:
1426  {
1427  const TSG_PACKET_REAUTH* packetReauth = &tsgPacket->tsgPacket.packetReauth;
1428  UINT32 index = 0;
1429  Stream_Write_UINT32(s, tsgPacket->packetId); /* PacketId (4 bytes) */
1430  Stream_Write_UINT32(s, tsgPacket->packetId); /* SwitchValue (4 bytes) */
1431  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* PacketReauthPtr (4 bytes) */
1432  goto fail;
1433  if (!tsg_ndr_write_reauth(tsg->log, s, &index, packetReauth))
1434  goto fail;
1435  opnum = TsProxyCreateTunnelOpnum;
1436  }
1437  break;
1438 
1439  default:
1440  WLog_Print(tsg->log, WLOG_WARN, "unexpected packetId %s",
1441  tsg_packet_id_to_string(tsgPacket->packetId));
1442  write = FALSE;
1443  break;
1444  }
1445 
1446  rc = TRUE;
1447 
1448  if (write)
1449  return rpc_client_write_call(rpc, s, opnum);
1450 fail:
1451  Stream_Free(s, TRUE);
1452  return rc;
1453 }
1454 
1455 static BOOL tsg_ndr_read_consent_message(wLog* log, rdpContext* context, wStream* s, UINT32* index)
1456 {
1457  TSG_PACKET_STRING_MESSAGE packetStringMessage = { 0 };
1458  UINT32 Pointer = 0;
1459 
1460  WINPR_ASSERT(context);
1461  WINPR_ASSERT(index);
1462 
1463  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12))
1464  return FALSE;
1465 
1466  Stream_Read_INT32(s, packetStringMessage.isDisplayMandatory);
1467  Stream_Read_INT32(s, packetStringMessage.isConsentMandatory);
1468  Stream_Read_UINT32(s, packetStringMessage.msgBytes);
1469 
1470  if (!tsg_ndr_pointer_read(log, s, index, &Pointer, FALSE))
1471  return FALSE;
1472 
1473  if (Pointer)
1474  {
1475  if (packetStringMessage.msgBytes > TSG_MESSAGING_MAX_MESSAGE_LENGTH)
1476  {
1477  WLog_Print(log, WLOG_ERROR, "Out of Spec Message Length %" PRIu32 "",
1478  packetStringMessage.msgBytes);
1479  return FALSE;
1480  }
1481  if (!tsg_ndr_read_string(log, s, &packetStringMessage.msgBuffer,
1482  packetStringMessage.msgBytes))
1483  return FALSE;
1484 
1485  if (context->instance)
1486  {
1487  return IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
1488  TSG_ASYNC_MESSAGE_CONSENT_MESSAGE
1489  ? GATEWAY_MESSAGE_CONSENT
1490  : TSG_ASYNC_MESSAGE_SERVICE_MESSAGE,
1491  packetStringMessage.isDisplayMandatory != 0,
1492  packetStringMessage.isConsentMandatory != 0,
1493  packetStringMessage.msgBytes, packetStringMessage.msgBuffer);
1494  }
1495  }
1496  return TRUE;
1497 }
1498 
1499 static BOOL tsg_ndr_read_tunnel_context(wLog* log, wStream* s, CONTEXT_HANDLE* tunnelContext,
1500  UINT32* tunnelId)
1501 {
1502 
1503  if (!tsg_stream_align(log, s, 4))
1504  return FALSE;
1505 
1506  /* TunnelContext (20 bytes) */
1507  if (!TsProxyReadTunnelContext(log, s, tunnelContext))
1508  return FALSE;
1509 
1510  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1511  return FALSE;
1512 
1513  WINPR_ASSERT(tunnelId);
1514  Stream_Read_UINT32(s, *tunnelId); /* TunnelId (4 bytes) */
1515 
1516  UINT32 ReturnValue = 0;
1517  Stream_Read_UINT32(s, ReturnValue); /* ReturnValue (4 bytes) */
1518  if (ReturnValue != NO_ERROR)
1519  WLog_WARN(TAG, "ReturnValue=%s", NtStatus2Tag(ReturnValue));
1520  return TRUE;
1521 }
1522 
1523 static BOOL tsg_ndr_read_caps_response(wLog* log, rdpContext* context, wStream* s, UINT32* index,
1524  UINT32 PacketPtr, TSG_PACKET_CAPS_RESPONSE* caps,
1525  CONTEXT_HANDLE* tunnelContext, UINT32* tunnelId)
1526 {
1527  UINT32 PacketQuarResponsePtr = 0;
1528  UINT32 MessageSwitchValue = 0;
1529  UINT32 MsgId = 0;
1530  UINT32 MsgType = 0;
1531  UINT32 IsMessagePresent = 0;
1532 
1533  WINPR_ASSERT(context);
1534  WINPR_ASSERT(index);
1535  WINPR_ASSERT(caps);
1536 
1537  if (!tsg_ndr_pointer_read(log, s, index, &PacketQuarResponsePtr, TRUE))
1538  goto fail;
1539 
1540  if (!tsg_ndr_read_quarenc_response(log, s, index, &caps->pktQuarEncResponse))
1541  goto fail;
1542 
1543  if (PacketPtr)
1544  {
1545  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
1546  goto fail;
1547 
1548  Stream_Read_UINT32(s, MsgId); /* MsgId (4 bytes) */
1549  Stream_Read_UINT32(s, MsgType); /* MsgType (4 bytes) */
1550  Stream_Read_UINT32(s, IsMessagePresent); /* IsMessagePresent (4 bytes) */
1551  Stream_Read_UINT32(s, MessageSwitchValue); /* MessageSwitchValue (4 bytes) */
1552  }
1553 
1554  {
1555  UINT32 MsgPtr = 0;
1556  if (!tsg_ndr_pointer_read(log, s, index, &MsgPtr, TRUE))
1557  return FALSE;
1558  }
1559  if (!tsg_ndr_read_quarenc_data(log, s, index, &caps->pktQuarEncResponse))
1560  goto fail;
1561 
1562  switch (MessageSwitchValue)
1563  {
1564  case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE:
1565  case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE:
1566  {
1567  if (!tsg_ndr_read_consent_message(log, context, s, index))
1568  goto fail;
1569  }
1570  break;
1571 
1572  case TSG_ASYNC_MESSAGE_REAUTH:
1573  {
1574  if (!tsg_stream_align(log, s, 8))
1575  goto fail;
1576 
1577  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1578  goto fail;
1579 
1580  Stream_Seek_UINT64(s); /* TunnelContext (8 bytes) */
1581  }
1582  break;
1583 
1584  default:
1585  WLog_Print(log, WLOG_ERROR, "Unexpected Message Type: 0x%" PRIX32 "",
1586  MessageSwitchValue);
1587  goto fail;
1588  }
1589 
1590  return tsg_ndr_read_tunnel_context(log, s, tunnelContext, tunnelId);
1591 fail:
1592  return FALSE;
1593 }
1594 
1595 static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu,
1596  CONTEXT_HANDLE* tunnelContext, UINT32* tunnelId)
1597 {
1598  BOOL rc = FALSE;
1599  UINT32 index = 0;
1600  TSG_PACKET packet = { 0 };
1601  UINT32 SwitchValue = 0;
1602  rdpContext* context = NULL;
1603  UINT32 PacketPtr = 0;
1604 
1605  WINPR_ASSERT(tsg);
1606  WINPR_ASSERT(tsg->rpc);
1607  WINPR_ASSERT(tsg->rpc->transport);
1608 
1609  context = transport_get_context(tsg->rpc->transport);
1610  WINPR_ASSERT(context);
1611 
1612  if (!pdu)
1613  return FALSE;
1614 
1615  if (!tsg_ndr_pointer_read(tsg->log, pdu->s, &index, &PacketPtr, TRUE))
1616  goto fail;
1617 
1618  if (!Stream_CheckAndLogRequiredLengthWLog(tsg->log, pdu->s, 8))
1619  goto fail;
1620  Stream_Read_UINT32(pdu->s, packet.packetId); /* PacketId (4 bytes) */
1621  Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1622 
1623  WLog_Print(tsg->log, WLOG_DEBUG, "%s", tsg_packet_id_to_string(packet.packetId));
1624 
1625  if ((packet.packetId == TSG_PACKET_TYPE_CAPS_RESPONSE) &&
1626  (SwitchValue == TSG_PACKET_TYPE_CAPS_RESPONSE))
1627  {
1628  if (!tsg_ndr_read_caps_response(tsg->log, context, pdu->s, &index, PacketPtr,
1629  &packet.tsgPacket.packetCapsResponse, tunnelContext,
1630  tunnelId))
1631  goto fail;
1632  }
1633  else if ((packet.packetId == TSG_PACKET_TYPE_QUARENC_RESPONSE) &&
1634  (SwitchValue == TSG_PACKET_TYPE_QUARENC_RESPONSE))
1635  {
1636  UINT32 PacketQuarResponsePtr = 0;
1637 
1638  if (!tsg_ndr_pointer_read(tsg->log, pdu->s, &index, &PacketQuarResponsePtr, TRUE))
1639  goto fail;
1640 
1641  if (!tsg_ndr_read_quarenc_response(tsg->log, pdu->s, &index,
1642  &packet.tsgPacket.packetQuarEncResponse))
1643  goto fail;
1644 
1645  if (!tsg_ndr_read_quarenc_data(tsg->log, pdu->s, &index,
1646  &packet.tsgPacket.packetQuarEncResponse))
1647  goto fail;
1648 
1649  if (!tsg_ndr_read_tunnel_context(tsg->log, pdu->s, tunnelContext, tunnelId))
1650  goto fail;
1651  }
1652  else
1653  {
1654  WLog_Print(tsg->log, WLOG_ERROR,
1655  "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_CAPS_RESPONSE "
1656  "or TSG_PACKET_TYPE_QUARENC_RESPONSE",
1657  packet.packetId);
1658  goto fail;
1659  }
1660 
1661  rc = TRUE;
1662 fail:
1663  return rc;
1664 }
1665 
1677 static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
1678 {
1679  size_t pad = 0;
1680  wStream* s = NULL;
1681  size_t count = 0;
1682  size_t offset = 0;
1683  rdpRpc* rpc = NULL;
1684 
1685  if (!tsg || !tsg->rpc || !tunnelContext || !tsg->MachineName)
1686  return FALSE;
1687 
1688  count = _wcslen(tsg->MachineName) + 1;
1689  if (count > UINT32_MAX)
1690  return FALSE;
1691 
1692  rpc = tsg->rpc;
1693  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyAuthorizeTunnelWriteRequest");
1694  s = Stream_New(NULL, 1024 + count * 2);
1695 
1696  if (!s)
1697  return FALSE;
1698 
1699  if (!TsProxyWriteTunnelContext(tsg->log, s, tunnelContext))
1700  {
1701  Stream_Free(s, TRUE);
1702  return FALSE;
1703  }
1704 
1705  /* 4-byte alignment */
1706  UINT32 index = 0;
1707  Stream_Write_UINT32(s, TSG_PACKET_TYPE_QUARREQUEST); /* PacketId (4 bytes) */
1708  Stream_Write_UINT32(s, TSG_PACKET_TYPE_QUARREQUEST); /* SwitchValue (4 bytes) */
1709  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* PacketQuarRequestPtr (4 bytes) */
1710  goto fail;
1711  Stream_Write_UINT32(s, 0x00000000); /* Flags (4 bytes) */
1712  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* MachineNamePtr (4 bytes) */
1713  goto fail;
1714  Stream_Write_UINT32(s, (UINT32)count); /* NameLength (4 bytes) */
1715  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* DataPtr (4 bytes) */
1716  goto fail;
1717  Stream_Write_UINT32(s, 0); /* DataLength (4 bytes) */
1718  /* MachineName */
1719  if (!tsg_ndr_write_string(tsg->log, s, tsg->MachineName, count))
1720  goto fail;
1721  /* 4-byte alignment */
1722  offset = Stream_GetPosition(s);
1723  pad = rpc_offset_align(&offset, 4);
1724  Stream_Zero(s, pad);
1725  Stream_Write_UINT32(s, 0x00000000); /* MaxCount (4 bytes) */
1726  Stream_SealLength(s);
1727  return rpc_client_write_call(rpc, s, TsProxyAuthorizeTunnelOpnum);
1728 fail:
1729  Stream_Free(s, TRUE);
1730  return FALSE;
1731 }
1732 
1733 static UINT32 tsg_redir_to_flags(const TSG_REDIRECTION_FLAGS* redirect)
1734 {
1735  UINT32 flags = 0;
1736  if (redirect->enableAllRedirections)
1737  flags |= HTTP_TUNNEL_REDIR_ENABLE_ALL;
1738  if (redirect->disableAllRedirections)
1739  flags |= HTTP_TUNNEL_REDIR_DISABLE_ALL;
1740 
1741  if (redirect->driveRedirectionDisabled)
1742  flags |= HTTP_TUNNEL_REDIR_DISABLE_DRIVE;
1743  if (redirect->printerRedirectionDisabled)
1744  flags |= HTTP_TUNNEL_REDIR_DISABLE_PRINTER;
1745  if (redirect->portRedirectionDisabled)
1746  flags |= HTTP_TUNNEL_REDIR_DISABLE_PORT;
1747  if (redirect->clipboardRedirectionDisabled)
1748  flags |= HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD;
1749  if (redirect->pnpRedirectionDisabled)
1750  flags |= HTTP_TUNNEL_REDIR_DISABLE_PNP;
1751  return flags;
1752 }
1753 
1754 static BOOL tsg_redirect_apply(rdpTsg* tsg, const TSG_REDIRECTION_FLAGS* redirect)
1755 {
1756  WINPR_ASSERT(tsg);
1757  WINPR_ASSERT(redirect);
1758 
1759  rdpTransport* transport = tsg->transport;
1760  WINPR_ASSERT(transport);
1761 
1762  rdpContext* context = transport_get_context(transport);
1763  UINT32 redirFlags = tsg_redir_to_flags(redirect);
1764  return utils_apply_gateway_policy(tsg->log, context, redirFlags, "TSG");
1765 }
1766 
1767 static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
1768 {
1769  BOOL rc = FALSE;
1770  UINT32 SwitchValue = 0;
1771  UINT32 index = 0;
1772  TSG_PACKET packet = { 0 };
1773  UINT32 PacketPtr = 0;
1774  UINT32 PacketResponsePtr = 0;
1775 
1776  WINPR_ASSERT(tsg);
1777  WINPR_ASSERT(pdu);
1778 
1779  wLog* log = tsg->log;
1780  WINPR_ASSERT(log);
1781 
1782  if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketPtr, TRUE))
1783  goto fail;
1784 
1785  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 8))
1786  goto fail;
1787  Stream_Read_UINT32(pdu->s, packet.packetId); /* PacketId (4 bytes) */
1788  Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1789 
1790  WLog_Print(log, WLOG_DEBUG, "%s", tsg_packet_id_to_string(packet.packetId));
1791 
1792  if (packet.packetId == E_PROXY_NAP_ACCESSDENIED)
1793  {
1794  WLog_Print(log, WLOG_ERROR, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)",
1795  E_PROXY_NAP_ACCESSDENIED);
1796  WLog_Print(log, WLOG_ERROR,
1797  "Ensure that the Gateway Connection Authorization Policy is correct");
1798  goto fail;
1799  }
1800 
1801  if ((packet.packetId != TSG_PACKET_TYPE_RESPONSE) || (SwitchValue != TSG_PACKET_TYPE_RESPONSE))
1802  {
1803  WLog_Print(log, WLOG_ERROR,
1804  "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_RESPONSE",
1805  packet.packetId);
1806  goto fail;
1807  }
1808 
1809  if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketResponsePtr, TRUE))
1810  goto fail;
1811 
1812  if (!tsg_ndr_read_packet_response(log, pdu->s, &index, &packet.tsgPacket.packetResponse))
1813  goto fail;
1814 
1815  rc = TRUE;
1816 
1817  if (packet.tsgPacket.packetResponse.flags & TSG_PACKET_TYPE_QUARREQUEST)
1818  rc = tsg_redirect_apply(tsg, &packet.tsgPacket.packetResponse.redirectionFlags);
1819 fail:
1820  return rc;
1821 }
1822 
1834 static BOOL TsProxyMakeTunnelCallWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext,
1835  UINT32 procId)
1836 {
1837  wStream* s = NULL;
1838  rdpRpc* rpc = NULL;
1839 
1840  if (!tsg || !tsg->rpc || !tunnelContext)
1841  return FALSE;
1842 
1843  rpc = tsg->rpc;
1844  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyMakeTunnelCallWriteRequest");
1845  s = Stream_New(NULL, 40);
1846 
1847  if (!s)
1848  return FALSE;
1849 
1850  /* TunnelContext (20 bytes) */
1851  UINT32 index = 0;
1852  if (!TsProxyWriteTunnelContext(tsg->log, s, tunnelContext))
1853  goto fail;
1854  Stream_Write_UINT32(s, procId); /* ProcId (4 bytes) */
1855  /* 4-byte alignment */
1856  Stream_Write_UINT32(s, TSG_PACKET_TYPE_MSGREQUEST_PACKET); /* PacketId (4 bytes) */
1857  Stream_Write_UINT32(s, TSG_PACKET_TYPE_MSGREQUEST_PACKET); /* SwitchValue (4 bytes) */
1858  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* PacketMsgRequestPtr (4 bytes) */
1859  goto fail;
1860  Stream_Write_UINT32(s, 0x00000001); /* MaxMessagesPerBatch (4 bytes) */
1861  return rpc_client_write_call(rpc, s, TsProxyMakeTunnelCallOpnum);
1862 fail:
1863  Stream_Free(s, TRUE);
1864  return FALSE;
1865 }
1866 
1867 static BOOL TsProxyReadPacketSTringMessage(rdpTsg* tsg, wStream* s, TSG_PACKET_STRING_MESSAGE* msg)
1868 {
1869  UINT32 ConsentMessagePtr = 0;
1870  UINT32 MsgPtr = 0;
1871  UINT32 index = 0;
1872 
1873  if (!tsg || !s || !msg)
1874  return FALSE;
1875 
1876  if (!Stream_CheckAndLogRequiredLengthWLog(tsg->log, s, 32))
1877  return FALSE;
1878 
1879  if (!tsg_ndr_pointer_read(tsg->log, s, &index, &ConsentMessagePtr, TRUE))
1880  return FALSE;
1881 
1882  Stream_Read_INT32(s, msg->isDisplayMandatory); /* IsDisplayMandatory (4 bytes) */
1883  Stream_Read_INT32(s, msg->isConsentMandatory); /* IsConsentMandatory (4 bytes) */
1884  Stream_Read_UINT32(s, msg->msgBytes); /* MsgBytes (4 bytes) */
1885 
1886  if (!tsg_ndr_pointer_read(tsg->log, s, &index, &MsgPtr, TRUE))
1887  return FALSE;
1888 
1889  return tsg_ndr_read_string(tsg->log, s, &msg->msgBuffer, msg->msgBytes);
1890 }
1891 
1892 static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
1893 {
1894  BOOL rc = FALSE;
1895  UINT32 index = 0;
1896  UINT32 SwitchValue = 0;
1897  TSG_PACKET packet;
1898  rdpContext* context = NULL;
1899  char* messageText = NULL;
1900  TSG_PACKET_MSG_RESPONSE packetMsgResponse = { 0 };
1901  TSG_PACKET_STRING_MESSAGE packetStringMessage = { 0 };
1902  TSG_PACKET_REAUTH_MESSAGE packetReauthMessage = { 0 };
1903  UINT32 PacketPtr = 0;
1904  UINT32 PacketMsgResponsePtr = 0;
1905 
1906  WINPR_ASSERT(tsg);
1907  WINPR_ASSERT(tsg->rpc);
1908 
1909  context = transport_get_context(tsg->rpc->transport);
1910  WINPR_ASSERT(context);
1911 
1912  /* This is an asynchronous response */
1913 
1914  if (!pdu)
1915  return FALSE;
1916 
1917  if (!Stream_CheckAndLogRequiredLengthWLog(tsg->log, pdu->s, 28))
1918  goto fail;
1919 
1920  if (!tsg_ndr_pointer_read(tsg->log, pdu->s, &index, &PacketPtr, TRUE))
1921  goto fail;
1922 
1923  Stream_Read_UINT32(pdu->s, packet.packetId); /* PacketId (4 bytes) */
1924  Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1925 
1926  WLog_Print(tsg->log, WLOG_DEBUG, "%s", tsg_packet_id_to_string(packet.packetId));
1927 
1928  if ((packet.packetId != TSG_PACKET_TYPE_MESSAGE_PACKET) ||
1929  (SwitchValue != TSG_PACKET_TYPE_MESSAGE_PACKET))
1930  {
1931  WLog_Print(tsg->log, WLOG_ERROR,
1932  "Unexpected PacketId: 0x%08" PRIX32 ", Expected TSG_PACKET_TYPE_MESSAGE_PACKET",
1933  packet.packetId);
1934  goto fail;
1935  }
1936 
1937  if (!tsg_ndr_pointer_read(tsg->log, pdu->s, &index, &PacketMsgResponsePtr, TRUE))
1938  goto fail;
1939 
1940  Stream_Read_UINT32(pdu->s, packetMsgResponse.msgID); /* MsgId (4 bytes) */
1941  Stream_Read_UINT32(pdu->s, packetMsgResponse.msgType); /* MsgType (4 bytes) */
1942  Stream_Read_INT32(pdu->s, packetMsgResponse.isMsgPresent); /* IsMsgPresent (4 bytes) */
1943 
1944  /* 2.2.9.2.1.9 TSG_PACKET_MSG_RESPONSE: Ignore empty message body. */
1945  if (!packetMsgResponse.isMsgPresent)
1946  {
1947  rc = TRUE;
1948  goto fail;
1949  }
1950 
1951  Stream_Read_UINT32(pdu->s, SwitchValue); /* SwitchValue (4 bytes) */
1952 
1953  switch (SwitchValue)
1954  {
1955  case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE:
1956  if (!TsProxyReadPacketSTringMessage(tsg, pdu->s, &packetStringMessage))
1957  goto fail;
1958 
1959  messageText = ConvertWCharNToUtf8Alloc(
1960  packetStringMessage.msgBuffer, packetStringMessage.msgBytes / sizeof(WCHAR), NULL);
1961  WLog_Print(tsg->log, WLOG_INFO, "Consent Message: %s", messageText);
1962  free(messageText);
1963 
1964  if (context->instance)
1965  {
1966  rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
1967  GATEWAY_MESSAGE_CONSENT,
1968  packetStringMessage.isDisplayMandatory != 0,
1969  packetStringMessage.isConsentMandatory != 0,
1970  packetStringMessage.msgBytes, packetStringMessage.msgBuffer);
1971  if (!rc)
1972  goto fail;
1973  }
1974 
1975  break;
1976 
1977  case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE:
1978  if (!TsProxyReadPacketSTringMessage(tsg, pdu->s, &packetStringMessage))
1979  goto fail;
1980 
1981  messageText = ConvertWCharNToUtf8Alloc(
1982  packetStringMessage.msgBuffer, packetStringMessage.msgBytes / sizeof(WCHAR), NULL);
1983  WLog_Print(tsg->log, WLOG_INFO, "Service Message: %s", messageText);
1984  free(messageText);
1985 
1986  if (context->instance)
1987  {
1988  rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
1989  GATEWAY_MESSAGE_SERVICE,
1990  packetStringMessage.isDisplayMandatory != 0,
1991  packetStringMessage.isConsentMandatory != 0,
1992  packetStringMessage.msgBytes, packetStringMessage.msgBuffer);
1993  if (!rc)
1994  goto fail;
1995  }
1996  break;
1997 
1998  case TSG_ASYNC_MESSAGE_REAUTH:
1999  {
2000  UINT32 ReauthMessagePtr = 0;
2001  if (!Stream_CheckAndLogRequiredLengthWLog(tsg->log, pdu->s, 20))
2002  goto fail;
2003 
2004  if (!tsg_ndr_pointer_read(tsg->log, pdu->s, &index, &ReauthMessagePtr, TRUE))
2005  goto fail;
2006  Stream_Seek_UINT32(pdu->s); /* alignment pad (4 bytes) */
2007  Stream_Read_UINT64(pdu->s,
2008  packetReauthMessage.tunnelContext); /* TunnelContext (8 bytes) */
2009  Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
2010  tsg->ReauthTunnelContext = packetReauthMessage.tunnelContext;
2011  }
2012  break;
2013 
2014  default:
2015  WLog_Print(tsg->log, WLOG_ERROR, "unexpected message type: %" PRIu32 "", SwitchValue);
2016  goto fail;
2017  }
2018 
2019  rc = TRUE;
2020 fail:
2021  return rc;
2022 }
2023 
2035 static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
2036 {
2037  WINPR_ASSERT(tsg);
2038  WINPR_ASSERT(tunnelContext);
2039 
2040  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCreateChannelWriteRequest");
2041 
2042  if (!tsg->rpc || !tsg->Hostname)
2043  return FALSE;
2044 
2045  rdpRpc* rpc = tsg->rpc;
2046  const size_t count = _wcslen(tsg->Hostname) + 1;
2047  if (count > UINT32_MAX)
2048  return FALSE;
2049 
2050  wStream* s = Stream_New(NULL, 60 + count * 2);
2051  if (!s)
2052  return FALSE;
2053 
2054  /* TunnelContext (20 bytes) */
2055  if (!TsProxyWriteTunnelContext(tsg->log, s, tunnelContext))
2056  goto fail;
2057 
2058  /* TSENDPOINTINFO */
2059  UINT32 index = 0;
2060  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1))
2061  goto fail;
2062  Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */
2063  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 0))
2064  goto fail;
2065  Stream_Write_UINT16(s, 0x0000); /* NumAlternateResourceNames (2 bytes) */
2066  Stream_Write_UINT16(s, 0x0000); /* Pad (2 bytes) */
2067  /* Port (4 bytes) */
2068  Stream_Write_UINT16(s, 0x0003); /* ProtocolId (RDP = 3) (2 bytes) */
2069  Stream_Write_UINT16(s, tsg->Port); /* PortNumber (0xD3D = 3389) (2 bytes) */
2070  Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */
2071  if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1))
2072  goto fail;
2073  if (!tsg_ndr_write_string(tsg->log, s, tsg->Hostname, (UINT32)count))
2074  goto fail;
2075  return rpc_client_write_call(rpc, s, TsProxyCreateChannelOpnum);
2076 
2077 fail:
2078  Stream_Free(s, TRUE);
2079  return FALSE;
2080 }
2081 
2082 static BOOL TsProxyCreateChannelReadResponse(wLog* log, const RPC_PDU* pdu,
2083  CONTEXT_HANDLE* channelContext, UINT32* channelId)
2084 {
2085  BOOL rc = FALSE;
2086 
2087  WINPR_ASSERT(log);
2088  WINPR_ASSERT(pdu);
2089  WINPR_ASSERT(channelId);
2090 
2091  WLog_Print(log, WLOG_DEBUG, "TsProxyCreateChannelReadResponse");
2092 
2093  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 28))
2094  goto fail;
2095 
2096  /* ChannelContext (20 bytes) */
2097  if (!TsProxyReadTunnelContext(log, pdu->s, channelContext))
2098  goto fail;
2099  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, pdu->s, 2, sizeof(UINT32)))
2100  goto fail;
2101  Stream_Read_UINT32(pdu->s, *channelId); /* ChannelId (4 bytes) */
2102  Stream_Seek_UINT32(pdu->s); /* ReturnValue (4 bytes) */
2103  rc = TRUE;
2104 fail:
2105  return rc;
2106 }
2107 
2114 static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
2115 {
2116  WINPR_ASSERT(tsg);
2117  WINPR_ASSERT(context);
2118 
2119  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseChannelWriteRequest");
2120 
2121  rdpRpc* rpc = tsg->rpc;
2122  WINPR_ASSERT(rpc);
2123 
2124  wStream* s = Stream_New(NULL, 20);
2125 
2126  if (!s)
2127  return FALSE;
2128 
2129  /* ChannelContext (20 bytes) */
2130  if (!TsProxyWriteTunnelContext(tsg->log, s, context))
2131  goto fail;
2132  return rpc_client_write_call(rpc, s, TsProxyCloseChannelOpnum);
2133 fail:
2134  Stream_Free(s, TRUE);
2135  return FALSE;
2136 }
2137 
2138 static BOOL TsProxyCloseChannelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
2139 {
2140  BOOL rc = FALSE;
2141  WLog_Print(log, WLOG_DEBUG, "TsProxyCloseChannelReadResponse");
2142 
2143  if (!pdu)
2144  return FALSE;
2145 
2146  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 24))
2147  goto fail;
2148 
2149  /* ChannelContext (20 bytes) */
2150  if (!TsProxyReadTunnelContext(log, pdu->s, context))
2151  goto fail;
2152 
2153  {
2154  const size_t len = sizeof(UINT32);
2155  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, len))
2156  goto fail;
2157  Stream_Seek(pdu->s, len); /* ReturnValue (4 bytes) */
2158  rc = TRUE;
2159  }
2160 fail:
2161  return rc;
2162 }
2163 
2170 static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, const CONTEXT_HANDLE* context)
2171 {
2172  WINPR_ASSERT(tsg);
2173  WINPR_ASSERT(context);
2174 
2175  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseTunnelWriteRequest");
2176 
2177  rdpRpc* rpc = tsg->rpc;
2178  WINPR_ASSERT(rpc);
2179 
2180  wStream* s = Stream_New(NULL, 20);
2181 
2182  if (!s)
2183  return FALSE;
2184 
2185  /* TunnelContext (20 bytes) */
2186  if (!TsProxyWriteTunnelContext(tsg->log, s, context))
2187  goto fail;
2188  return rpc_client_write_call(rpc, s, TsProxyCloseTunnelOpnum);
2189 fail:
2190  Stream_Free(s, TRUE);
2191  return FALSE;
2192 }
2193 
2194 static BOOL TsProxyCloseTunnelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
2195 {
2196  BOOL rc = FALSE;
2197 
2198  WINPR_ASSERT(log);
2199  WINPR_ASSERT(pdu);
2200  WINPR_ASSERT(context);
2201 
2202  WLog_Print(log, WLOG_DEBUG, "TsProxyCloseTunnelReadResponse");
2203 
2204  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 24))
2205  goto fail;
2206 
2207  /* TunnelContext (20 bytes) */
2208  if (!TsProxyReadTunnelContext(log, pdu->s, context))
2209  goto fail;
2210  {
2211  const size_t len = sizeof(UINT32);
2212  if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, len))
2213  goto fail;
2214  Stream_Seek(pdu->s, len); /* ReturnValue (4 bytes) */
2215  rc = TRUE;
2216  }
2217 fail:
2218  return rc;
2219 }
2220 
2229 static BOOL TsProxySetupReceivePipeWriteRequest(rdpTsg* tsg, const CONTEXT_HANDLE* channelContext)
2230 {
2231  wStream* s = NULL;
2232  rdpRpc* rpc = NULL;
2233  WLog_Print(tsg->log, WLOG_DEBUG, "TsProxySetupReceivePipeWriteRequest");
2234 
2235  WINPR_ASSERT(tsg);
2236  WINPR_ASSERT(tsg->rpc);
2237 
2238  if (!channelContext)
2239  return FALSE;
2240 
2241  rpc = tsg->rpc;
2242  s = Stream_New(NULL, 20);
2243 
2244  if (!s)
2245  return FALSE;
2246 
2247  /* ChannelContext (20 bytes) */
2248  if (!TsProxyWriteTunnelContext(tsg->log, s, channelContext))
2249  goto fail;
2250  return rpc_client_write_call(rpc, s, TsProxySetupReceivePipeOpnum);
2251 fail:
2252  Stream_Free(s, TRUE);
2253  return FALSE;
2254 }
2255 
2256 static BOOL tsg_transition_to_state(rdpTsg* tsg, TSG_STATE state)
2257 {
2258  WINPR_ASSERT(tsg);
2259  const char* oldState = tsg_state_to_string(tsg->state);
2260  const char* newState = tsg_state_to_string(state);
2261 
2262  WLog_Print(tsg->log, WLOG_DEBUG, "%s -> %s", oldState, newState);
2263  return tsg_set_state(tsg, state);
2264 }
2265 
2266 static BOOL tsg_initialize_version_caps(TSG_PACKET_VERSIONCAPS* packetVersionCaps)
2267 {
2268  WINPR_ASSERT(packetVersionCaps);
2269 
2270  packetVersionCaps->tsgHeader.ComponentId = TS_GATEWAY_TRANSPORT;
2271  packetVersionCaps->tsgHeader.PacketId = TSG_PACKET_TYPE_VERSIONCAPS;
2272  packetVersionCaps->numCapabilities = 1;
2273  packetVersionCaps->majorVersion = 1;
2274  packetVersionCaps->minorVersion = 1;
2275  packetVersionCaps->quarantineCapabilities = 0;
2276  packetVersionCaps->tsgCaps.capabilityType = TSG_CAPABILITY_TYPE_NAP;
2277  /*
2278  * Using reduced capabilities appears to trigger
2279  * TSG_PACKET_TYPE_QUARENC_RESPONSE instead of TSG_PACKET_TYPE_CAPS_RESPONSE
2280  *
2281  * However, reduced capabilities may break connectivity with servers enforcing features, such as
2282  * "Only allow connections from Remote Desktop Services clients that support RD Gateway
2283  * messaging"
2284  */
2285 
2286  packetVersionCaps->tsgCaps.tsgPacket.tsgCapNap.capabilities =
2287  TSG_NAP_CAPABILITY_QUAR_SOH | TSG_NAP_CAPABILITY_IDLE_TIMEOUT |
2288  TSG_MESSAGING_CAP_CONSENT_SIGN | TSG_MESSAGING_CAP_SERVICE_MSG | TSG_MESSAGING_CAP_REAUTH;
2289  return TRUE;
2290 }
2291 
2292 BOOL tsg_proxy_begin(rdpTsg* tsg)
2293 {
2294  TSG_PACKET tsgPacket = { 0 };
2295 
2296  WINPR_ASSERT(tsg);
2297 
2298  tsgPacket.packetId = TSG_PACKET_TYPE_VERSIONCAPS;
2299  if (!tsg_initialize_version_caps(&tsgPacket.tsgPacket.packetVersionCaps) ||
2300  !TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
2301  {
2302  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateTunnel failure");
2303  tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2304  return FALSE;
2305  }
2306 
2307  return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
2308 }
2309 
2310 static BOOL tsg_proxy_reauth(rdpTsg* tsg)
2311 {
2312  TSG_PACKET tsgPacket = { 0 };
2313 
2314  WINPR_ASSERT(tsg);
2315 
2316  tsg->reauthSequence = TRUE;
2317  TSG_PACKET_REAUTH* packetReauth = &tsgPacket.tsgPacket.packetReauth;
2318 
2319  tsgPacket.packetId = TSG_PACKET_TYPE_REAUTH;
2320  packetReauth->tunnelContext = tsg->ReauthTunnelContext;
2321  packetReauth->packetId = TSG_PACKET_TYPE_VERSIONCAPS;
2322 
2323  if (!tsg_initialize_version_caps(&packetReauth->tsgInitialPacket.packetVersionCaps))
2324  return FALSE;
2325 
2326  if (!TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
2327  {
2328  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateTunnel failure");
2329  tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2330  return FALSE;
2331  }
2332 
2333  if (!TsProxyMakeTunnelCallWriteRequest(tsg, &tsg->TunnelContext,
2334  TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST))
2335  {
2336  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyMakeTunnelCall failure");
2337  tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2338  return FALSE;
2339  }
2340 
2341  return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
2342 }
2343 
2344 BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu)
2345 {
2346  BOOL rc = FALSE;
2347  RpcClientCall* call = NULL;
2348  rdpRpc* rpc = NULL;
2349 
2350  WINPR_ASSERT(tsg);
2351  WINPR_ASSERT(pdu);
2352  WINPR_ASSERT(tsg->rpc);
2353 
2354  rpc = tsg->rpc;
2355 
2356  if (!(pdu->Flags & RPC_PDU_FLAG_STUB))
2357  {
2358  const size_t len = 24;
2359  if (!Stream_CheckAndLogRequiredLengthWLog(tsg->log, pdu->s, len))
2360  return FALSE;
2361  Stream_Seek(pdu->s, len);
2362  }
2363 
2364  switch (tsg->state)
2365  {
2366  case TSG_STATE_INITIAL:
2367  {
2368  CONTEXT_HANDLE* TunnelContext = NULL;
2369  TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
2370 
2371  if (!TsProxyCreateTunnelReadResponse(tsg, pdu, TunnelContext, &tsg->TunnelId))
2372  {
2373  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateTunnelReadResponse failure");
2374  return FALSE;
2375  }
2376 
2377  if (!tsg_transition_to_state(tsg, TSG_STATE_CONNECTED))
2378  return FALSE;
2379 
2380  if (!TsProxyAuthorizeTunnelWriteRequest(tsg, TunnelContext))
2381  {
2382  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyAuthorizeTunnel failure");
2383  return FALSE;
2384  }
2385 
2386  rc = TRUE;
2387  }
2388  break;
2389 
2390  case TSG_STATE_CONNECTED:
2391  {
2392  CONTEXT_HANDLE* TunnelContext =
2393  (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
2394 
2395  if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu))
2396  {
2397  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyAuthorizeTunnelReadResponse failure");
2398  return FALSE;
2399  }
2400 
2401  if (!tsg_transition_to_state(tsg, TSG_STATE_AUTHORIZED))
2402  return FALSE;
2403 
2404  if (!tsg->reauthSequence)
2405  {
2406  if (!TsProxyMakeTunnelCallWriteRequest(tsg, TunnelContext,
2407  TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST))
2408  {
2409  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyMakeTunnelCall failure");
2410  return FALSE;
2411  }
2412  }
2413 
2414  if (!TsProxyCreateChannelWriteRequest(tsg, TunnelContext))
2415  {
2416  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateChannel failure");
2417  return FALSE;
2418  }
2419 
2420  rc = TRUE;
2421  }
2422  break;
2423 
2424  case TSG_STATE_AUTHORIZED:
2425  call = rpc_client_call_find_by_id(rpc->client, pdu->CallId);
2426 
2427  if (!call)
2428  return FALSE;
2429 
2430  if (call->OpNum == TsProxyMakeTunnelCallOpnum)
2431  {
2432  if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu))
2433  {
2434  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyMakeTunnelCallReadResponse failure");
2435  return FALSE;
2436  }
2437 
2438  rc = TRUE;
2439  }
2440  else if (call->OpNum == TsProxyCreateChannelOpnum)
2441  {
2442  CONTEXT_HANDLE ChannelContext;
2443 
2444  if (!TsProxyCreateChannelReadResponse(tsg->log, pdu, &ChannelContext,
2445  &tsg->ChannelId))
2446  {
2447  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateChannelReadResponse failure");
2448  return FALSE;
2449  }
2450 
2451  if (!tsg->reauthSequence)
2452  CopyMemory(&tsg->ChannelContext, &ChannelContext, sizeof(CONTEXT_HANDLE));
2453  else
2454  CopyMemory(&tsg->NewChannelContext, &ChannelContext, sizeof(CONTEXT_HANDLE));
2455 
2456  if (!tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CREATED))
2457  return FALSE;
2458 
2459  if (!tsg->reauthSequence)
2460  {
2461  if (!TsProxySetupReceivePipeWriteRequest(tsg, &tsg->ChannelContext))
2462  {
2463  WLog_Print(tsg->log, WLOG_ERROR, "TsProxySetupReceivePipe failure");
2464  return FALSE;
2465  }
2466  }
2467  else
2468  {
2469  if (!TsProxyCloseChannelWriteRequest(tsg, &tsg->NewChannelContext))
2470  {
2471  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseChannelWriteRequest failure");
2472  return FALSE;
2473  }
2474 
2475  if (!TsProxyCloseTunnelWriteRequest(tsg, &tsg->NewTunnelContext))
2476  {
2477  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseTunnelWriteRequest failure");
2478  return FALSE;
2479  }
2480  }
2481 
2482  rc = tsg_transition_to_state(tsg, TSG_STATE_PIPE_CREATED);
2483  tsg->reauthSequence = FALSE;
2484  }
2485  else
2486  {
2487  WLog_Print(tsg->log, WLOG_ERROR,
2488  "TSG_STATE_AUTHORIZED unexpected OpNum: %" PRIu32 "\n", call->OpNum);
2489  }
2490 
2491  break;
2492 
2493  case TSG_STATE_CHANNEL_CREATED:
2494  break;
2495 
2496  case TSG_STATE_PIPE_CREATED:
2497  call = rpc_client_call_find_by_id(rpc->client, pdu->CallId);
2498 
2499  if (!call)
2500  return FALSE;
2501 
2502  if (call->OpNum == TsProxyMakeTunnelCallOpnum)
2503  {
2504  if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu))
2505  {
2506  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyMakeTunnelCallReadResponse failure");
2507  return FALSE;
2508  }
2509 
2510  rc = TRUE;
2511 
2512  if (tsg->ReauthTunnelContext)
2513  rc = tsg_proxy_reauth(tsg);
2514  }
2515  else if (call->OpNum == TsProxyCloseChannelOpnum)
2516  {
2517  CONTEXT_HANDLE ChannelContext;
2518 
2519  if (!TsProxyCloseChannelReadResponse(tsg->log, pdu, &ChannelContext))
2520  {
2521  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseChannelReadResponse failure");
2522  return FALSE;
2523  }
2524 
2525  rc = TRUE;
2526  }
2527  else if (call->OpNum == TsProxyCloseTunnelOpnum)
2528  {
2529  CONTEXT_HANDLE TunnelContext;
2530 
2531  if (!TsProxyCloseTunnelReadResponse(tsg->log, pdu, &TunnelContext))
2532  {
2533  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseTunnelReadResponse failure");
2534  return FALSE;
2535  }
2536 
2537  rc = TRUE;
2538  }
2539 
2540  break;
2541 
2542  case TSG_STATE_TUNNEL_CLOSE_PENDING:
2543  {
2544  CONTEXT_HANDLE ChannelContext;
2545 
2546  if (!TsProxyCloseChannelReadResponse(tsg->log, pdu, &ChannelContext))
2547  {
2548  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseChannelReadResponse failure");
2549  return FALSE;
2550  }
2551 
2552  if (!tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CLOSE_PENDING))
2553  return FALSE;
2554 
2555  if (!TsProxyCloseChannelWriteRequest(tsg, NULL))
2556  {
2557  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseChannelWriteRequest failure");
2558  return FALSE;
2559  }
2560 
2561  if (!TsProxyMakeTunnelCallWriteRequest(tsg, &tsg->TunnelContext,
2562  TSG_TUNNEL_CANCEL_ASYNC_MSG_REQUEST))
2563  {
2564  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyMakeTunnelCall failure");
2565  return FALSE;
2566  }
2567 
2568  rc = TRUE;
2569  }
2570  break;
2571 
2572  case TSG_STATE_CHANNEL_CLOSE_PENDING:
2573  {
2574  CONTEXT_HANDLE TunnelContext;
2575 
2576  if (!TsProxyCloseTunnelReadResponse(tsg->log, pdu, &TunnelContext))
2577  {
2578  WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCloseTunnelReadResponse failure");
2579  return FALSE;
2580  }
2581 
2582  rc = tsg_transition_to_state(tsg, TSG_STATE_FINAL);
2583  }
2584  break;
2585 
2586  case TSG_STATE_FINAL:
2587  break;
2588  default:
2589  break;
2590  }
2591 
2592  return rc;
2593 }
2594 
2595 BOOL tsg_check_event_handles(rdpTsg* tsg)
2596 {
2597  WINPR_ASSERT(tsg);
2598  if (rpc_client_in_channel_recv(tsg->rpc) < 0)
2599  return FALSE;
2600 
2601  if (rpc_client_out_channel_recv(tsg->rpc) < 0)
2602  return FALSE;
2603 
2604  return TRUE;
2605 }
2606 
2607 DWORD tsg_get_event_handles(rdpTsg* tsg, HANDLE* events, DWORD count)
2608 {
2609  UINT32 nCount = 0;
2610  rdpRpc* rpc = tsg->rpc;
2611  RpcVirtualConnection* connection = rpc->VirtualConnection;
2612 
2613  if (events && (nCount < count))
2614  {
2615  events[nCount] = rpc->client->PipeEvent;
2616  nCount++;
2617  }
2618  else
2619  return 0;
2620 
2621  if (connection->DefaultInChannel && connection->DefaultInChannel->common.tls)
2622  {
2623  if (events && (nCount < count))
2624  {
2625  BIO_get_event(connection->DefaultInChannel->common.tls->bio, &events[nCount]);
2626  nCount++;
2627  }
2628  else
2629  return 0;
2630  }
2631 
2632  if (connection->NonDefaultInChannel && connection->NonDefaultInChannel->common.tls)
2633  {
2634  if (events && (nCount < count))
2635  {
2636  BIO_get_event(connection->NonDefaultInChannel->common.tls->bio, &events[nCount]);
2637  nCount++;
2638  }
2639  else
2640  return 0;
2641  }
2642 
2643  if (connection->DefaultOutChannel && connection->DefaultOutChannel->common.tls)
2644  {
2645  if (events && (nCount < count))
2646  {
2647  BIO_get_event(connection->DefaultOutChannel->common.tls->bio, &events[nCount]);
2648  nCount++;
2649  }
2650  else
2651  return 0;
2652  }
2653 
2654  if (connection->NonDefaultOutChannel && connection->NonDefaultOutChannel->common.tls)
2655  {
2656  if (events && (nCount < count))
2657  {
2658  BIO_get_event(connection->NonDefaultOutChannel->common.tls->bio, &events[nCount]);
2659  nCount++;
2660  }
2661  else
2662  return 0;
2663  }
2664 
2665  return nCount;
2666 }
2667 
2668 static BOOL tsg_set_hostname(rdpTsg* tsg, const char* hostname)
2669 {
2670  WINPR_ASSERT(tsg);
2671  free(tsg->Hostname);
2672  tsg->Hostname = ConvertUtf8ToWCharAlloc(hostname, NULL);
2673  return tsg->Hostname != NULL;
2674 }
2675 
2676 static BOOL tsg_set_machine_name(rdpTsg* tsg, const char* machineName)
2677 {
2678  WINPR_ASSERT(tsg);
2679  free(tsg->MachineName);
2680  tsg->MachineName = ConvertUtf8ToWCharAlloc(machineName, NULL);
2681  return tsg->MachineName != NULL;
2682 }
2683 
2684 BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout)
2685 {
2686  UINT64 looptimeout = timeout * 1000ULL;
2687  DWORD nCount = 0;
2688  HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 };
2689  rdpRpc* rpc = NULL;
2690  rdpContext* context = NULL;
2691  rdpSettings* settings = NULL;
2692  rdpTransport* transport = NULL;
2693 
2694  WINPR_ASSERT(tsg);
2695 
2696  rpc = tsg->rpc;
2697  WINPR_ASSERT(rpc);
2698 
2699  transport = rpc->transport;
2700  context = transport_get_context(transport);
2701  WINPR_ASSERT(context);
2702 
2703  settings = context->settings;
2704 
2705  tsg->Port = port;
2706  tsg->transport = transport;
2707 
2708  if (!settings->GatewayPort)
2709  settings->GatewayPort = 443;
2710 
2711  if (!tsg_set_hostname(tsg, hostname))
2712  return FALSE;
2713 
2714  if (!tsg_set_machine_name(tsg, settings->ComputerName))
2715  return FALSE;
2716 
2717  if (!rpc_connect(rpc, timeout))
2718  {
2719  WLog_Print(tsg->log, WLOG_ERROR, "rpc_connect error!");
2720  return FALSE;
2721  }
2722 
2723  nCount = tsg_get_event_handles(tsg, events, ARRAYSIZE(events));
2724 
2725  if (nCount == 0)
2726  return FALSE;
2727 
2728  while (tsg->state != TSG_STATE_PIPE_CREATED)
2729  {
2730  const DWORD polltimeout = 250;
2731  DWORD status = WaitForMultipleObjects(nCount, events, FALSE, polltimeout);
2732  if (status == WAIT_TIMEOUT)
2733  {
2734  if (timeout > 0)
2735  {
2736  if (looptimeout < polltimeout)
2737  return FALSE;
2738  looptimeout -= polltimeout;
2739  }
2740  }
2741  else
2742  looptimeout = timeout * 1000ULL;
2743 
2744  if (!tsg_check_event_handles(tsg))
2745  {
2746  WLog_Print(tsg->log, WLOG_ERROR, "tsg_check failure");
2747  transport_set_layer(transport, TRANSPORT_LAYER_CLOSED);
2748  return FALSE;
2749  }
2750  }
2751 
2752  WLog_Print(tsg->log, WLOG_INFO, "TS Gateway Connection Success");
2753  tsg->bio = BIO_new(BIO_s_tsg());
2754 
2755  if (!tsg->bio)
2756  return FALSE;
2757 
2758  BIO_set_data(tsg->bio, (void*)tsg);
2759  return TRUE;
2760 }
2761 
2762 BOOL tsg_disconnect(rdpTsg* tsg)
2763 {
2783  if (!tsg)
2784  return FALSE;
2785 
2786  if (tsg->state != TSG_STATE_TUNNEL_CLOSE_PENDING)
2787  {
2788  if (!TsProxyCloseChannelWriteRequest(tsg, &tsg->ChannelContext))
2789  return FALSE;
2790 
2791  return tsg_transition_to_state(tsg, TSG_STATE_CHANNEL_CLOSE_PENDING);
2792  }
2793 
2794  return TRUE;
2795 }
2796 
2807 static int tsg_read(rdpTsg* tsg, BYTE* data, size_t length)
2808 {
2809  rdpRpc* rpc = NULL;
2810  int status = 0;
2811 
2812  if (!tsg || !data)
2813  return -1;
2814 
2815  rpc = tsg->rpc;
2816 
2817  if (transport_get_layer(rpc->transport) == TRANSPORT_LAYER_CLOSED)
2818  {
2819  WLog_Print(tsg->log, WLOG_ERROR, "tsg_read error: connection lost");
2820  return -1;
2821  }
2822 
2823  do
2824  {
2825  status = rpc_client_receive_pipe_read(rpc->client, data, length);
2826 
2827  if (status < 0)
2828  return -1;
2829 
2830  if (!status && !transport_get_blocking(rpc->transport))
2831  return 0;
2832 
2833  if (transport_get_layer(rpc->transport) == TRANSPORT_LAYER_CLOSED)
2834  {
2835  WLog_Print(tsg->log, WLOG_ERROR, "tsg_read error: connection lost");
2836  return -1;
2837  }
2838 
2839  if (status > 0)
2840  break;
2841 
2842  if (transport_get_blocking(rpc->transport))
2843  {
2844  while (WaitForSingleObject(rpc->client->PipeEvent, 0) != WAIT_OBJECT_0)
2845  {
2846  if (!tsg_check_event_handles(tsg))
2847  return -1;
2848 
2849  (void)WaitForSingleObject(rpc->client->PipeEvent, 100);
2850  }
2851  }
2852  } while (transport_get_blocking(rpc->transport));
2853 
2854  return status;
2855 }
2856 
2857 static int tsg_write(rdpTsg* tsg, const BYTE* data, UINT32 length)
2858 {
2859  int status = 0;
2860 
2861  if (!tsg || !data || !tsg->rpc || !tsg->rpc->transport)
2862  return -1;
2863 
2864  if (transport_get_layer(tsg->rpc->transport) == TRANSPORT_LAYER_CLOSED)
2865  {
2866  WLog_Print(tsg->log, WLOG_ERROR, "error, connection lost");
2867  return -1;
2868  }
2869 
2870  status = TsProxySendToServer((handle_t)tsg, data, 1, &length);
2871 
2872  if (status < 0)
2873  return -1;
2874 
2875  return (int)length;
2876 }
2877 
2878 rdpTsg* tsg_new(rdpTransport* transport)
2879 {
2880  rdpTsg* tsg = (rdpTsg*)calloc(1, sizeof(rdpTsg));
2881 
2882  if (!tsg)
2883  return NULL;
2884  tsg->log = WLog_Get(TAG);
2885  tsg->transport = transport;
2886  tsg->rpc = rpc_new(tsg->transport);
2887 
2888  if (!tsg->rpc)
2889  goto out_free;
2890 
2891  return tsg;
2892 out_free:
2893  free(tsg);
2894  return NULL;
2895 }
2896 
2897 void tsg_free(rdpTsg* tsg)
2898 {
2899  if (tsg)
2900  {
2901  rpc_free(tsg->rpc);
2902  free(tsg->Hostname);
2903  free(tsg->MachineName);
2904  free(tsg);
2905  }
2906 }
2907 
2908 static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
2909 {
2910  int status = 0;
2911  rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2912  BIO_clear_flags(bio, BIO_FLAGS_WRITE);
2913 
2914  if (num < 0)
2915  return -1;
2916  status = tsg_write(tsg, (const BYTE*)buf, (UINT32)num);
2917 
2918  if (status < 0)
2919  {
2920  BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2921  return -1;
2922  }
2923  else if (status == 0)
2924  {
2925  BIO_set_flags(bio, BIO_FLAGS_WRITE);
2926  WSASetLastError(WSAEWOULDBLOCK);
2927  }
2928  else
2929  {
2930  BIO_set_flags(bio, BIO_FLAGS_WRITE);
2931  }
2932 
2933  return status >= 0 ? status : -1;
2934 }
2935 
2936 static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
2937 {
2938  int status = 0;
2939  rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2940 
2941  if (!tsg || (size < 0))
2942  {
2943  BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2944  return -1;
2945  }
2946 
2947  BIO_clear_flags(bio, BIO_FLAGS_READ);
2948  status = tsg_read(tsg, (BYTE*)buf, (size_t)size);
2949 
2950  if (status < 0)
2951  {
2952  BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2953  return -1;
2954  }
2955  else if (status == 0)
2956  {
2957  BIO_set_flags(bio, BIO_FLAGS_READ);
2958  WSASetLastError(WSAEWOULDBLOCK);
2959  }
2960  else
2961  {
2962  BIO_set_flags(bio, BIO_FLAGS_READ);
2963  }
2964 
2965  return status > 0 ? status : -1;
2966 }
2967 
2968 static int transport_bio_tsg_puts(BIO* bio, const char* str)
2969 {
2970  WINPR_UNUSED(bio);
2971  WINPR_UNUSED(str);
2972  return 1;
2973 }
2974 
2975 // NOLINTNEXTLINE(readability-non-const-parameter)
2976 static int transport_bio_tsg_gets(BIO* bio, char* str, int size)
2977 {
2978  WINPR_UNUSED(bio);
2979  WINPR_UNUSED(str);
2980  WINPR_UNUSED(size);
2981  return 1;
2982 }
2983 
2984 static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
2985 {
2986  long status = -1;
2987  rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
2988  RpcVirtualConnection* connection = tsg->rpc->VirtualConnection;
2989  RpcInChannel* inChannel = connection->DefaultInChannel;
2990  RpcOutChannel* outChannel = connection->DefaultOutChannel;
2991 
2992  switch (cmd)
2993  {
2994  case BIO_CTRL_FLUSH:
2995  (void)BIO_flush(inChannel->common.tls->bio);
2996  (void)BIO_flush(outChannel->common.tls->bio);
2997  status = 1;
2998  break;
2999 
3000  case BIO_C_GET_EVENT:
3001  if (arg2)
3002  {
3003  *((HANDLE*)arg2) = tsg->rpc->client->PipeEvent;
3004  status = 1;
3005  }
3006 
3007  break;
3008 
3009  case BIO_C_SET_NONBLOCK:
3010  status = 1;
3011  break;
3012 
3013  case BIO_C_READ_BLOCKED:
3014  {
3015  BIO* cbio = outChannel->common.bio;
3016  status = BIO_read_blocked(cbio);
3017  }
3018  break;
3019 
3020  case BIO_C_WRITE_BLOCKED:
3021  {
3022  BIO* cbio = inChannel->common.bio;
3023  status = BIO_write_blocked(cbio);
3024  }
3025  break;
3026 
3027  case BIO_C_WAIT_READ:
3028  {
3029  int timeout = (int)arg1;
3030  BIO* cbio = outChannel->common.bio;
3031 
3032  if (BIO_read_blocked(cbio))
3033  return BIO_wait_read(cbio, timeout);
3034  else if (BIO_write_blocked(cbio))
3035  return BIO_wait_write(cbio, timeout);
3036  else
3037  status = 1;
3038  }
3039  break;
3040 
3041  case BIO_C_WAIT_WRITE:
3042  {
3043  int timeout = (int)arg1;
3044  BIO* cbio = inChannel->common.bio;
3045 
3046  if (BIO_write_blocked(cbio))
3047  status = BIO_wait_write(cbio, timeout);
3048  else if (BIO_read_blocked(cbio))
3049  status = BIO_wait_read(cbio, timeout);
3050  else
3051  status = 1;
3052  }
3053  break;
3054 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
3055  case BIO_CTRL_GET_KTLS_SEND:
3056  status = 0;
3057  break;
3058  case BIO_CTRL_GET_KTLS_RECV:
3059  status = 0;
3060  break;
3061 #endif
3062  default:
3063  break;
3064  }
3065 
3066  return status;
3067 }
3068 
3069 static int transport_bio_tsg_new(BIO* bio)
3070 {
3071  WINPR_ASSERT(bio);
3072  BIO_set_init(bio, 1);
3073  BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
3074  return 1;
3075 }
3076 
3077 static int transport_bio_tsg_free(BIO* bio)
3078 {
3079  WINPR_ASSERT(bio);
3080  WINPR_UNUSED(bio);
3081  return 1;
3082 }
3083 
3084 BIO_METHOD* BIO_s_tsg(void)
3085 {
3086  static BIO_METHOD* bio_methods = NULL;
3087 
3088  if (bio_methods == NULL)
3089  {
3090  if (!(bio_methods = BIO_meth_new(BIO_TYPE_TSG, "TSGateway")))
3091  return NULL;
3092 
3093  BIO_meth_set_write(bio_methods, transport_bio_tsg_write);
3094  BIO_meth_set_read(bio_methods, transport_bio_tsg_read);
3095  BIO_meth_set_puts(bio_methods, transport_bio_tsg_puts);
3096  BIO_meth_set_gets(bio_methods, transport_bio_tsg_gets);
3097  BIO_meth_set_ctrl(bio_methods, transport_bio_tsg_ctrl);
3098  BIO_meth_set_create(bio_methods, transport_bio_tsg_new);
3099  BIO_meth_set_destroy(bio_methods, transport_bio_tsg_free);
3100  }
3101 
3102  return bio_methods;
3103 }
3104 
3105 TSG_STATE tsg_get_state(rdpTsg* tsg)
3106 {
3107  if (!tsg)
3108  return TSG_STATE_INITIAL;
3109 
3110  return tsg->state;
3111 }
3112 
3113 BIO* tsg_get_bio(rdpTsg* tsg)
3114 {
3115  if (!tsg)
3116  return NULL;
3117 
3118  return tsg->bio;
3119 }
3120 
3121 BOOL tsg_set_state(rdpTsg* tsg, TSG_STATE state)
3122 {
3123  if (!tsg)
3124  return FALSE;
3125 
3126  tsg->state = state;
3127  return TRUE;
3128 }