FreeRDP
Loading...
Searching...
No Matches
rts.c
1
20#include <freerdp/config.h>
21
22#include <winpr/assert.h>
23#include <winpr/cast.h>
24#include <winpr/crt.h>
25#include <winpr/crypto.h>
26
27#include <freerdp/log.h>
28
29#include "ncacn_http.h"
30#include "rpc_client.h"
31#include "rts_signature.h"
32
33#include "rts.h"
34
35#define TAG FREERDP_TAG("core.gateway.rts")
36
70static int rts_destination_command_read(rdpRpc* rpc, wStream* buffer, UINT32* Destination);
71
72static const char* rts_command_to_string(UINT32 cmd, char* buffer, size_t len)
73{
74 const char* str = nullptr;
75
76#undef ENTRY
77#define ENTRY(x) \
78 case x: \
79 str = "#x"; \
80 break
81
82 switch (cmd)
83 {
84 ENTRY(RTS_CMD_RECEIVE_WINDOW_SIZE);
85 ENTRY(RTS_CMD_FLOW_CONTROL_ACK);
86 ENTRY(RTS_CMD_CONNECTION_TIMEOUT);
87 ENTRY(RTS_CMD_COOKIE);
88 ENTRY(RTS_CMD_CHANNEL_LIFETIME);
89 ENTRY(RTS_CMD_CLIENT_KEEPALIVE);
90 ENTRY(RTS_CMD_VERSION);
91 ENTRY(RTS_CMD_EMPTY);
92 ENTRY(RTS_CMD_PADDING);
93 ENTRY(RTS_CMD_NEGATIVE_ANCE);
94 ENTRY(RTS_CMD_ANCE);
95 ENTRY(RTS_CMD_CLIENT_ADDRESS);
96 ENTRY(RTS_CMD_ASSOCIATION_GROUP_ID);
97 ENTRY(RTS_CMD_DESTINATION);
98 ENTRY(RTS_CMD_PING_TRAFFIC_SENT_NOTIFY);
99 ENTRY(RTS_CMD_LAST_ID);
100 default:
101 str = "RTS_CMD_UNKNOWN";
102 break;
103 }
104
105#undef ENTRY
106
107 (void)_snprintf(buffer, len, "%s [0x%08" PRIx32 "]", str, cmd);
108 return buffer;
109}
110
111static const char* rts_pdu_ptype_to_string(UINT32 ptype)
112{
113 switch (ptype)
114 {
115 case PTYPE_REQUEST:
116 return "PTYPE_REQUEST";
117 case PTYPE_PING:
118 return "PTYPE_PING";
119 case PTYPE_RESPONSE:
120 return "PTYPE_RESPONSE";
121 case PTYPE_FAULT:
122 return "PTYPE_FAULT";
123 case PTYPE_WORKING:
124 return "PTYPE_WORKING";
125 case PTYPE_NOCALL:
126 return "PTYPE_NOCALL";
127 case PTYPE_REJECT:
128 return "PTYPE_REJECT";
129 case PTYPE_ACK:
130 return "PTYPE_ACK";
131 case PTYPE_CL_CANCEL:
132 return "PTYPE_CL_CANCEL";
133 case PTYPE_FACK:
134 return "PTYPE_FACK";
135 case PTYPE_CANCEL_ACK:
136 return "PTYPE_CANCEL_ACK";
137 case PTYPE_BIND:
138 return "PTYPE_BIND";
139 case PTYPE_BIND_ACK:
140 return "PTYPE_BIND_ACK";
141 case PTYPE_BIND_NAK:
142 return "PTYPE_BIND_NAK";
143 case PTYPE_ALTER_CONTEXT:
144 return "PTYPE_ALTER_CONTEXT";
145 case PTYPE_ALTER_CONTEXT_RESP:
146 return "PTYPE_ALTER_CONTEXT_RESP";
147 case PTYPE_RPC_AUTH_3:
148 return "PTYPE_RPC_AUTH_3";
149 case PTYPE_SHUTDOWN:
150 return "PTYPE_SHUTDOWN";
151 case PTYPE_CO_CANCEL:
152 return "PTYPE_CO_CANCEL";
153 case PTYPE_ORPHANED:
154 return "PTYPE_ORPHANED";
155 case PTYPE_RTS:
156 return "PTYPE_RTS";
157 default:
158 return "UNKNOWN";
159 }
160}
161
162static rpcconn_rts_hdr_t rts_pdu_header_init(void)
163{
164 rpcconn_rts_hdr_t header = WINPR_C_ARRAY_INIT;
165 header.header.rpc_vers = 5;
166 header.header.rpc_vers_minor = 0;
167 header.header.ptype = PTYPE_RTS;
168 header.header.packed_drep[0] = 0x10;
169 header.header.packed_drep[1] = 0x00;
170 header.header.packed_drep[2] = 0x00;
171 header.header.packed_drep[3] = 0x00;
172 header.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
173 header.header.auth_length = 0;
174 header.header.call_id = 0;
175
176 return header;
177}
178
179static BOOL rts_align_stream(wStream* s, size_t alignment, BOOL silent)
180{
181 size_t pos = 0;
182 size_t pad = 0;
183
184 WINPR_ASSERT(s);
185 WINPR_ASSERT(alignment > 0);
186
187 pos = Stream_GetPosition(s);
188 pad = rpc_offset_align(&pos, alignment);
189 return Stream_ConditionalSafeSeek(s, pad, silent);
190}
191
192static char* sdup(const void* src, size_t length)
193{
194 char* dst = nullptr;
195 WINPR_ASSERT(src || (length == 0));
196 if (length == 0)
197 return nullptr;
198
199 dst = calloc(length + 1, sizeof(char));
200 if (!dst)
201 return nullptr;
202 memcpy(dst, src, length);
203 return dst;
204}
205
206static BOOL rts_write_common_pdu_header(wStream* s, const rpcconn_common_hdr_t* header)
207{
208 WINPR_ASSERT(s);
209 WINPR_ASSERT(header);
210 if (!Stream_EnsureRemainingCapacity(s, sizeof(rpcconn_common_hdr_t)))
211 return FALSE;
212
213 Stream_Write_UINT8(s, header->rpc_vers);
214 Stream_Write_UINT8(s, header->rpc_vers_minor);
215 Stream_Write_UINT8(s, header->ptype);
216 Stream_Write_UINT8(s, header->pfc_flags);
217 Stream_Write(s, header->packed_drep, ARRAYSIZE(header->packed_drep));
218 Stream_Write_UINT16(s, header->frag_length);
219 Stream_Write_UINT16(s, header->auth_length);
220 Stream_Write_UINT32(s, header->call_id);
221 return TRUE;
222}
223
224rts_pdu_status_t rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header,
225 BOOL ignoreErrors)
226{
227 WINPR_ASSERT(s);
228 WINPR_ASSERT(header);
229
230 if (!ignoreErrors)
231 {
232 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(rpcconn_common_hdr_t)))
233 return RTS_PDU_INCOMPLETE;
234 }
235 else
236 {
237 const size_t sz = Stream_GetRemainingLength(s);
238 if (sz < sizeof(rpcconn_common_hdr_t))
239 return RTS_PDU_INCOMPLETE;
240 }
241
242 Stream_Read_UINT8(s, header->rpc_vers);
243 Stream_Read_UINT8(s, header->rpc_vers_minor);
244 Stream_Read_UINT8(s, header->ptype);
245 Stream_Read_UINT8(s, header->pfc_flags);
246 Stream_Read(s, header->packed_drep, ARRAYSIZE(header->packed_drep));
247 Stream_Read_UINT16(s, header->frag_length);
248 Stream_Read_UINT16(s, header->auth_length);
249 Stream_Read_UINT32(s, header->call_id);
250
251 if (header->frag_length < sizeof(rpcconn_common_hdr_t))
252 {
253 if (!ignoreErrors)
254 WLog_WARN(TAG, "Invalid header->frag_length of %" PRIu16 ", expected %" PRIuz,
255 header->frag_length, sizeof(rpcconn_common_hdr_t));
256 return RTS_PDU_FAIL;
257 }
258 if (header->auth_length > header->frag_length - 8ull)
259 {
260 if (!ignoreErrors)
261 WLog_WARN(TAG,
262 "Invalid header->auth_length(%" PRIu16 ") > header->frag_length(%" PRIu16
263 ") - 8ull",
264 header->frag_length, header->auth_length);
265 return RTS_PDU_FAIL;
266 }
267
268 if (!ignoreErrors)
269 {
270 if (!Stream_CheckAndLogRequiredLength(TAG, s,
271 header->frag_length - sizeof(rpcconn_common_hdr_t)))
272 return RTS_PDU_INCOMPLETE;
273 }
274 else
275 {
276 const size_t sz2 = Stream_GetRemainingLength(s);
277 if (sz2 < header->frag_length - sizeof(rpcconn_common_hdr_t))
278 return RTS_PDU_INCOMPLETE;
279 }
280 return RTS_PDU_VALID;
281}
282
283static BOOL rts_read_auth_verifier_no_checks(wStream* s, auth_verifier_co_t* auth,
284 const rpcconn_common_hdr_t* header, size_t* startPos,
285 BOOL silent)
286{
287 WINPR_ASSERT(s);
288 WINPR_ASSERT(auth);
289 WINPR_ASSERT(header);
290
291 WINPR_ASSERT(header->frag_length > header->auth_length + 8);
292
293 if (startPos)
294 *startPos = Stream_GetPosition(s);
295
296 /* Read the auth verifier and check padding matches frag_length */
297 {
298 const size_t expected = header->frag_length - header->auth_length - 8;
299
300 if (!Stream_SetPosition(s, expected))
301 return FALSE;
302 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 8, silent))
303 return FALSE;
304
305 Stream_Read_UINT8(s, auth->auth_type);
306 Stream_Read_UINT8(s, auth->auth_level);
307 Stream_Read_UINT8(s, auth->auth_pad_length);
308 Stream_Read_UINT8(s, auth->auth_reserved);
309 Stream_Read_UINT32(s, auth->auth_context_id);
310 }
311
312 if (header->auth_length != 0)
313 {
314 const void* ptr = Stream_Pointer(s);
315 if (!Stream_ConditionalSafeSeek(s, header->auth_length, silent))
316 return FALSE;
317 auth->auth_value = (BYTE*)sdup(ptr, header->auth_length);
318 if (auth->auth_value == nullptr)
319 return FALSE;
320 }
321
322 return TRUE;
323}
324
325static BOOL rts_read_auth_verifier(wStream* s, auth_verifier_co_t* auth,
326 const rpcconn_common_hdr_t* header, BOOL silent)
327{
328 size_t pos = 0;
329 WINPR_ASSERT(s);
330 WINPR_ASSERT(auth);
331 WINPR_ASSERT(header);
332
333 if (!rts_read_auth_verifier_no_checks(s, auth, header, &pos, silent))
334 return FALSE;
335
336 const size_t expected = header->frag_length - header->auth_length - 8;
337 return pos + auth->auth_pad_length == expected;
338}
339
340static BOOL rts_read_auth_verifier_with_stub(wStream* s, auth_verifier_co_t* auth,
341 rpcconn_common_hdr_t* header, BOOL silent)
342{
343 size_t pos = 0;
344 size_t alloc_hint = 0;
345 BYTE** ptr = nullptr;
346
347 if (!rts_read_auth_verifier_no_checks(s, auth, header, &pos, silent))
348 return FALSE;
349
350 switch (header->ptype)
351 {
352 case PTYPE_FAULT:
353 {
355 alloc_hint = hdr->alloc_hint;
356 ptr = &hdr->stub_data;
357 }
358 break;
359 case PTYPE_RESPONSE:
360 {
362 alloc_hint = hdr->alloc_hint;
363 ptr = &hdr->stub_data;
364 }
365 break;
366 case PTYPE_REQUEST:
367 {
369 alloc_hint = hdr->alloc_hint;
370 ptr = &hdr->stub_data;
371 }
372 break;
373 default:
374 return FALSE;
375 }
376
377 if (alloc_hint > 0)
378 {
379 const size_t off = header->auth_length + 8 + auth->auth_pad_length + pos;
380 const size_t size = header->frag_length - MIN(header->frag_length, off);
381 const void* src = Stream_Buffer(s) + pos;
382
383 if (off > header->frag_length)
384 WLog_WARN(TAG,
385 "Unexpected alloc_hint(%" PRIuz ") for PDU %s: size %" PRIuz
386 ", frag_length %" PRIu16 ", offset %" PRIuz,
387 alloc_hint, rts_pdu_ptype_to_string(header->ptype), size, header->frag_length,
388 off);
389
390 *ptr = nullptr;
391 if (size > 0)
392 {
393 *ptr = (BYTE*)sdup(src, size);
394 if (!*ptr)
395 return FALSE;
396 }
397 }
398
399 return TRUE;
400}
401
402static void rts_free_auth_verifier(auth_verifier_co_t* auth)
403{
404 if (!auth)
405 return;
406 free(auth->auth_value);
407}
408
409static BOOL rts_write_auth_verifier(wStream* s, const auth_verifier_co_t* auth,
410 const rpcconn_common_hdr_t* header)
411{
412 size_t pos = 0;
413 UINT8 auth_pad_length = 0;
414
415 WINPR_ASSERT(s);
416 WINPR_ASSERT(auth);
417 WINPR_ASSERT(header);
418
419 /* Align start to a multiple of 4 */
420 pos = Stream_GetPosition(s);
421 if ((pos % 4) != 0)
422 {
423 auth_pad_length = 4 - (pos % 4);
424 if (!Stream_EnsureRemainingCapacity(s, auth_pad_length))
425 return FALSE;
426 Stream_Zero(s, auth_pad_length);
427 }
428
429#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
430 WINPR_ASSERT(header->frag_length + 8ull > header->auth_length);
431 {
432 size_t apos = Stream_GetPosition(s);
433 size_t expected = header->frag_length - header->auth_length - 8;
434
435 WINPR_ASSERT(apos == expected);
436 }
437#endif
438
439 if (!Stream_EnsureRemainingCapacity(s, sizeof(auth_verifier_co_t)))
440 return FALSE;
441
442 Stream_Write_UINT8(s, auth->auth_type);
443 Stream_Write_UINT8(s, auth->auth_level);
444 Stream_Write_UINT8(s, auth_pad_length);
445 Stream_Write_UINT8(s, 0); /* auth->auth_reserved */
446 Stream_Write_UINT32(s, auth->auth_context_id);
447
448 if (!Stream_EnsureRemainingCapacity(s, header->auth_length))
449 return FALSE;
450 Stream_Write(s, auth->auth_value, header->auth_length);
451 return TRUE;
452}
453
454static BOOL rts_read_version(wStream* s, p_rt_version_t* version, BOOL silent)
455{
456 WINPR_ASSERT(s);
457 WINPR_ASSERT(version);
458
459 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 2 * sizeof(UINT8), silent))
460 return FALSE;
461 Stream_Read_UINT8(s, version->major);
462 Stream_Read_UINT8(s, version->minor);
463 return TRUE;
464}
465
466static void rts_free_supported_versions(p_rt_versions_supported_t* versions)
467{
468 if (!versions)
469 return;
470 free(versions->p_protocols);
471 versions->p_protocols = nullptr;
472}
473
474static BOOL rts_read_supported_versions(wStream* s, p_rt_versions_supported_t* versions,
475 BOOL silent)
476{
477 WINPR_ASSERT(s);
478 WINPR_ASSERT(versions);
479
480 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, sizeof(UINT8), silent))
481 return FALSE;
482
483 Stream_Read_UINT8(s, versions->n_protocols); /* count */
484
485 if (versions->n_protocols > 0)
486 {
487 versions->p_protocols = calloc(versions->n_protocols, sizeof(p_rt_version_t));
488 if (!versions->p_protocols)
489 return FALSE;
490 }
491 for (BYTE x = 0; x < versions->n_protocols; x++)
492 {
493 p_rt_version_t* version = &versions->p_protocols[x];
494 if (!rts_read_version(s, version, silent)) /* size_is(n_protocols) */
495 {
496 rts_free_supported_versions(versions);
497 return FALSE;
498 }
499 }
500
501 return TRUE;
502}
503
504static BOOL rts_read_port_any(wStream* s, port_any_t* port, BOOL silent)
505{
506 WINPR_ASSERT(s);
507 WINPR_ASSERT(port);
508
509 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, sizeof(UINT16), silent))
510 return FALSE;
511
512 Stream_Read_UINT16(s, port->length);
513 if (port->length == 0)
514 return TRUE;
515
516 const void* ptr = Stream_ConstPointer(s);
517 if (!Stream_ConditionalSafeSeek(s, port->length, silent))
518 return FALSE;
519 port->port_spec = sdup(ptr, port->length);
520 return port->port_spec != nullptr;
521}
522
523static void rts_free_port_any(port_any_t* port)
524{
525 if (!port)
526 return;
527 free(port->port_spec);
528}
529
530static BOOL rts_read_uuid(wStream* s, p_uuid_t* uuid, BOOL silent)
531{
532 WINPR_ASSERT(s);
533 WINPR_ASSERT(uuid);
534
535 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, sizeof(p_uuid_t), silent))
536 return FALSE;
537
538 Stream_Read_UINT32(s, uuid->time_low);
539 Stream_Read_UINT16(s, uuid->time_mid);
540 Stream_Read_UINT16(s, uuid->time_hi_and_version);
541 Stream_Read_UINT8(s, uuid->clock_seq_hi_and_reserved);
542 Stream_Read_UINT8(s, uuid->clock_seq_low);
543 Stream_Read(s, uuid->node, ARRAYSIZE(uuid->node));
544 return TRUE;
545}
546
547static BOOL rts_write_uuid(wStream* s, const p_uuid_t* uuid)
548{
549 WINPR_ASSERT(s);
550 WINPR_ASSERT(uuid);
551
552 if (!Stream_EnsureRemainingCapacity(s, sizeof(p_uuid_t)))
553 return FALSE;
554
555 Stream_Write_UINT32(s, uuid->time_low);
556 Stream_Write_UINT16(s, uuid->time_mid);
557 Stream_Write_UINT16(s, uuid->time_hi_and_version);
558 Stream_Write_UINT8(s, uuid->clock_seq_hi_and_reserved);
559 Stream_Write_UINT8(s, uuid->clock_seq_low);
560 Stream_Write(s, uuid->node, ARRAYSIZE(uuid->node));
561 return TRUE;
562}
563
564static p_syntax_id_t* rts_syntax_id_new(size_t count)
565{
566 return calloc(count, sizeof(p_syntax_id_t));
567}
568
569static void rts_syntax_id_free(p_syntax_id_t* ptr)
570{
571 free(ptr);
572}
573
574static BOOL rts_read_syntax_id(wStream* s, p_syntax_id_t* syntax_id, BOOL silent)
575{
576 WINPR_ASSERT(s);
577 WINPR_ASSERT(syntax_id);
578
579 if (!rts_read_uuid(s, &syntax_id->if_uuid, silent))
580 return FALSE;
581
582 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
583 return FALSE;
584
585 Stream_Read_UINT32(s, syntax_id->if_version);
586 return TRUE;
587}
588
589static BOOL rts_write_syntax_id(wStream* s, const p_syntax_id_t* syntax_id)
590{
591 WINPR_ASSERT(s);
592 WINPR_ASSERT(syntax_id);
593
594 if (!rts_write_uuid(s, &syntax_id->if_uuid))
595 return FALSE;
596
597 if (!Stream_EnsureRemainingCapacity(s, 4))
598 return FALSE;
599
600 Stream_Write_UINT32(s, syntax_id->if_version);
601 return TRUE;
602}
603
604static void rts_context_elem_free(p_cont_elem_t* ptr)
605{
606 if (!ptr)
607 return;
608 rts_syntax_id_free(ptr->transfer_syntaxes);
609 free(ptr);
610}
611
612WINPR_ATTR_MALLOC(rts_context_elem_free, 1)
613WINPR_ATTR_NODISCARD
614static p_cont_elem_t* rts_context_elem_new(size_t count)
615{
616 p_cont_elem_t* ctx = calloc(count, sizeof(p_cont_elem_t));
617 return ctx;
618}
619
620static BOOL rts_read_context_elem(wStream* s, p_cont_elem_t* element, BOOL silent)
621{
622 WINPR_ASSERT(s);
623 WINPR_ASSERT(element);
624
625 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
626 return FALSE;
627
628 Stream_Read_UINT16(s, element->p_cont_id);
629 Stream_Read_UINT8(s, element->n_transfer_syn); /* number of items */
630 Stream_Read_UINT8(s, element->reserved); /* alignment pad, m.b.z. */
631
632 if (!rts_read_syntax_id(s, &element->abstract_syntax, silent)) /* transfer syntax list */
633 return FALSE;
634
635 if (element->n_transfer_syn > 0)
636 {
637 element->transfer_syntaxes = rts_syntax_id_new(element->n_transfer_syn);
638 if (!element->transfer_syntaxes)
639 return FALSE;
640 for (BYTE x = 0; x < element->n_transfer_syn; x++)
641 {
642 p_syntax_id_t* syn = &element->transfer_syntaxes[x];
643 if (!rts_read_syntax_id(s, syn, silent)) /* size_is(n_transfer_syn) */
644 return FALSE;
645 }
646 }
647
648 return TRUE;
649}
650
651static BOOL rts_write_context_elem(wStream* s, const p_cont_elem_t* element)
652{
653 WINPR_ASSERT(s);
654 WINPR_ASSERT(element);
655
656 if (!Stream_EnsureRemainingCapacity(s, 4))
657 return FALSE;
658 Stream_Write_UINT16(s, element->p_cont_id);
659 Stream_Write_UINT8(s, element->n_transfer_syn); /* number of items */
660 Stream_Write_UINT8(s, element->reserved); /* alignment pad, m.b.z. */
661 if (!rts_write_syntax_id(s, &element->abstract_syntax)) /* transfer syntax list */
662 return FALSE;
663
664 for (BYTE x = 0; x < element->n_transfer_syn; x++)
665 {
666 const p_syntax_id_t* syn = &element->transfer_syntaxes[x];
667 if (!rts_write_syntax_id(s, syn)) /* size_is(n_transfer_syn) */
668 return FALSE;
669 }
670
671 return TRUE;
672}
673
674static BOOL rts_read_context_list(wStream* s, p_cont_list_t* list, BOOL silent)
675{
676 WINPR_ASSERT(s);
677 WINPR_ASSERT(list);
678
679 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
680 return FALSE;
681 Stream_Read_UINT8(s, list->n_context_elem); /* number of items */
682 Stream_Read_UINT8(s, list->reserved); /* alignment pad, m.b.z. */
683 Stream_Read_UINT16(s, list->reserved2); /* alignment pad, m.b.z. */
684
685 if (list->n_context_elem > 0)
686 {
687 list->p_cont_elem = rts_context_elem_new(list->n_context_elem);
688 if (!list->p_cont_elem)
689 return FALSE;
690 for (BYTE x = 0; x < list->n_context_elem; x++)
691 {
692 p_cont_elem_t* element = &list->p_cont_elem[x];
693 if (!rts_read_context_elem(s, element, silent))
694 return FALSE;
695 }
696 }
697 return TRUE;
698}
699
700static void rts_free_context_list(p_cont_list_t* list)
701{
702 if (!list)
703 return;
704 rts_context_elem_free(list->p_cont_elem);
705}
706
707static BOOL rts_write_context_list(wStream* s, const p_cont_list_t* list)
708{
709 WINPR_ASSERT(s);
710 WINPR_ASSERT(list);
711
712 if (!Stream_EnsureRemainingCapacity(s, 4))
713 return FALSE;
714 Stream_Write_UINT8(s, list->n_context_elem); /* number of items */
715 Stream_Write_UINT8(s, 0); /* alignment pad, m.b.z. */
716 Stream_Write_UINT16(s, 0); /* alignment pad, m.b.z. */
717
718 for (BYTE x = 0; x < list->n_context_elem; x++)
719 {
720 const p_cont_elem_t* element = &list->p_cont_elem[x];
721 if (!rts_write_context_elem(s, element))
722 return FALSE;
723 }
724 return TRUE;
725}
726
727static p_result_t* rts_result_new(size_t count)
728{
729 return calloc(count, sizeof(p_result_t));
730}
731
732static void rts_result_free(p_result_t* results)
733{
734 if (!results)
735 return;
736 free(results);
737}
738
739static BOOL rts_read_result(wStream* s, p_result_t* result, BOOL silent)
740{
741 WINPR_ASSERT(s);
742 WINPR_ASSERT(result);
743
744 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 2, silent))
745 return FALSE;
746
747 const UINT16 res = Stream_Get_UINT16(s);
748 switch (res)
749 {
750 case acceptance:
751 case user_rejection:
752 case provider_rejection:
753 case negotiate_ack:
754 break;
755 default:
756 WLog_ERR(TAG, "Invalid p_cont_def_result_t %" PRIu16, res);
757 return FALSE;
758 }
759 result->result = (p_cont_def_result_t)res;
760
761 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 2, silent))
762 return FALSE;
763
764 const UINT16 reason = Stream_Get_UINT16(s);
765 switch (reason)
766 {
767 case reason_not_specified:
768 case abstract_syntax_not_supported:
769 case proposed_transfer_syntaxes_not_supported:
770 case local_limit_exceeded:
771 break;
772 default:
773 WLog_ERR(TAG, "Invalid p_provider_reason_t %" PRIu16, reason);
774 return FALSE;
775 }
776 result->reason = (p_provider_reason_t)reason;
777 return rts_read_syntax_id(s, &result->transfer_syntax, silent);
778}
779
780static void rts_free_result(p_result_t* result)
781{
782 if (!result)
783 return;
784}
785
786static BOOL rts_read_result_list(wStream* s, p_result_list_t* list, BOOL silent)
787{
788 WINPR_ASSERT(s);
789 WINPR_ASSERT(list);
790
791 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
792 return FALSE;
793 Stream_Read_UINT8(s, list->n_results); /* count */
794 Stream_Read_UINT8(s, list->reserved); /* alignment pad, m.b.z. */
795 Stream_Read_UINT16(s, list->reserved2); /* alignment pad, m.b.z. */
796
797 if (list->n_results > 0)
798 {
799 list->p_results = rts_result_new(list->n_results);
800 if (!list->p_results)
801 return FALSE;
802
803 for (BYTE x = 0; x < list->n_results; x++)
804 {
805 p_result_t* result = &list->p_results[x]; /* size_is(n_results) */
806 if (!rts_read_result(s, result, silent))
807 return FALSE;
808 }
809 }
810
811 return TRUE;
812}
813
814static void rts_free_result_list(p_result_list_t* list)
815{
816 if (!list)
817 return;
818 for (BYTE x = 0; x < list->n_results; x++)
819 {
820 p_result_t* result = &list->p_results[x];
821 rts_free_result(result);
822 }
823 rts_result_free(list->p_results);
824}
825
826static void rts_free_pdu_alter_context(rpcconn_alter_context_hdr_t* ctx)
827{
828 if (!ctx)
829 return;
830
831 rts_free_context_list(&ctx->p_context_elem);
832 rts_free_auth_verifier(&ctx->auth_verifier);
833}
834
835static BOOL rts_read_pdu_alter_context(wStream* s, rpcconn_alter_context_hdr_t* ctx, BOOL silent)
836{
837 WINPR_ASSERT(s);
838 WINPR_ASSERT(ctx);
839
840 if (!Stream_ConditionalCheckAndLogRequiredLength(
841 TAG, s, sizeof(rpcconn_alter_context_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
842 return FALSE;
843
844 Stream_Read_UINT16(s, ctx->max_xmit_frag);
845 Stream_Read_UINT16(s, ctx->max_recv_frag);
846 Stream_Read_UINT32(s, ctx->assoc_group_id);
847
848 if (!rts_read_context_list(s, &ctx->p_context_elem, silent))
849 return FALSE;
850
851 if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent))
852 return FALSE;
853
854 return TRUE;
855}
856
857static BOOL rts_read_pdu_alter_context_response(wStream* s,
859 BOOL silent)
860{
861 WINPR_ASSERT(s);
862 WINPR_ASSERT(ctx);
863
864 if (!Stream_ConditionalCheckAndLogRequiredLength(
866 silent))
867 return FALSE;
868 Stream_Read_UINT16(s, ctx->max_xmit_frag);
869 Stream_Read_UINT16(s, ctx->max_recv_frag);
870 Stream_Read_UINT32(s, ctx->assoc_group_id);
871
872 if (!rts_read_port_any(s, &ctx->sec_addr, silent))
873 return FALSE;
874
875 if (!rts_align_stream(s, 4, silent))
876 return FALSE;
877
878 if (!rts_read_result_list(s, &ctx->p_result_list, silent))
879 return FALSE;
880
881 if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent))
882 return FALSE;
883
884 return TRUE;
885}
886
887static void rts_free_pdu_alter_context_response(rpcconn_alter_context_response_hdr_t* ctx)
888{
889 if (!ctx)
890 return;
891
892 rts_free_port_any(&ctx->sec_addr);
893 rts_free_result_list(&ctx->p_result_list);
894 rts_free_auth_verifier(&ctx->auth_verifier);
895}
896
897static BOOL rts_read_pdu_bind(wStream* s, rpcconn_bind_hdr_t* ctx, BOOL silent)
898{
899 WINPR_ASSERT(s);
900 WINPR_ASSERT(ctx);
901
902 if (!Stream_ConditionalCheckAndLogRequiredLength(
903 TAG, s, sizeof(rpcconn_bind_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
904 return FALSE;
905 Stream_Read_UINT16(s, ctx->max_xmit_frag);
906 Stream_Read_UINT16(s, ctx->max_recv_frag);
907 Stream_Read_UINT32(s, ctx->assoc_group_id);
908
909 if (!rts_read_context_list(s, &ctx->p_context_elem, silent))
910 return FALSE;
911
912 if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent))
913 return FALSE;
914
915 return TRUE;
916}
917
918static void rts_free_pdu_bind(rpcconn_bind_hdr_t* ctx)
919{
920 if (!ctx)
921 return;
922 rts_free_context_list(&ctx->p_context_elem);
923 rts_free_auth_verifier(&ctx->auth_verifier);
924}
925
926static BOOL rts_read_pdu_bind_ack(wStream* s, rpcconn_bind_ack_hdr_t* ctx, BOOL silent)
927{
928 WINPR_ASSERT(s);
929 WINPR_ASSERT(ctx);
930
931 if (!Stream_CheckAndLogRequiredLength(
932 TAG, s, sizeof(rpcconn_bind_ack_hdr_t) - sizeof(rpcconn_common_hdr_t)))
933 return FALSE;
934 Stream_Read_UINT16(s, ctx->max_xmit_frag);
935 Stream_Read_UINT16(s, ctx->max_recv_frag);
936 Stream_Read_UINT32(s, ctx->assoc_group_id);
937
938 if (!rts_read_port_any(s, &ctx->sec_addr, silent))
939 return FALSE;
940
941 if (!rts_align_stream(s, 4, silent))
942 return FALSE;
943
944 if (!rts_read_result_list(s, &ctx->p_result_list, silent))
945 return FALSE;
946
947 return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent);
948}
949
950static void rts_free_pdu_bind_ack(rpcconn_bind_ack_hdr_t* ctx)
951{
952 if (!ctx)
953 return;
954 rts_free_port_any(&ctx->sec_addr);
955 rts_free_result_list(&ctx->p_result_list);
956 rts_free_auth_verifier(&ctx->auth_verifier);
957}
958
959static BOOL rts_read_pdu_bind_nak(wStream* s, rpcconn_bind_nak_hdr_t* ctx, BOOL silent)
960{
961 WINPR_ASSERT(s);
962 WINPR_ASSERT(ctx);
963
964 if (!Stream_ConditionalCheckAndLogRequiredLength(
965 TAG, s, sizeof(rpcconn_bind_nak_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
966 return FALSE;
967 Stream_Read_UINT16(s, ctx->provider_reject_reason);
968 return rts_read_supported_versions(s, &ctx->versions, silent);
969}
970
971static void rts_free_pdu_bind_nak(rpcconn_bind_nak_hdr_t* ctx)
972{
973 if (!ctx)
974 return;
975
976 rts_free_supported_versions(&ctx->versions);
977}
978
979static BOOL rts_read_pdu_auth3(wStream* s, rpcconn_rpc_auth_3_hdr_t* ctx, BOOL silent)
980{
981 WINPR_ASSERT(s);
982 WINPR_ASSERT(ctx);
983
984 if (!Stream_ConditionalCheckAndLogRequiredLength(
985 TAG, s, sizeof(rpcconn_rpc_auth_3_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
986 return FALSE;
987 Stream_Read_UINT16(s, ctx->max_xmit_frag);
988 Stream_Read_UINT16(s, ctx->max_recv_frag);
989
990 return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent);
991}
992
993static void rts_free_pdu_auth3(rpcconn_rpc_auth_3_hdr_t* ctx)
994{
995 if (!ctx)
996 return;
997 rts_free_auth_verifier(&ctx->auth_verifier);
998}
999
1000static BOOL rts_read_pdu_fault(wStream* s, rpcconn_fault_hdr_t* ctx, BOOL silent)
1001{
1002 WINPR_ASSERT(s);
1003 WINPR_ASSERT(ctx);
1004
1005 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 12, silent))
1006 return FALSE;
1007 Stream_Read_UINT32(s, ctx->alloc_hint);
1008 Stream_Read_UINT16(s, ctx->p_cont_id);
1009 Stream_Read_UINT8(s, ctx->cancel_count);
1010 Stream_Read_UINT8(s, ctx->reserved);
1011 Stream_Read_UINT32(s, ctx->status);
1012
1013 WLog_WARN(TAG, "status=%s", Win32ErrorCode2Tag(ctx->status & 0xFFFF));
1014 return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header, silent);
1015}
1016
1017static void rts_free_pdu_fault(rpcconn_fault_hdr_t* ctx)
1018{
1019 if (!ctx)
1020 return;
1021 rts_free_auth_verifier(&ctx->auth_verifier);
1022}
1023
1024static BOOL rts_read_pdu_cancel_ack(wStream* s, rpcconn_cancel_hdr_t* ctx, BOOL silent)
1025{
1026 WINPR_ASSERT(s);
1027 WINPR_ASSERT(ctx);
1028
1029 if (!Stream_ConditionalCheckAndLogRequiredLength(
1030 TAG, s, sizeof(rpcconn_cancel_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
1031 return FALSE;
1032 return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent);
1033}
1034
1035static void rts_free_pdu_cancel_ack(rpcconn_cancel_hdr_t* ctx)
1036{
1037 if (!ctx)
1038 return;
1039 rts_free_auth_verifier(&ctx->auth_verifier);
1040}
1041
1042static BOOL rts_read_pdu_orphaned(wStream* s, rpcconn_orphaned_hdr_t* ctx, BOOL silent)
1043{
1044 WINPR_ASSERT(s);
1045 WINPR_ASSERT(ctx);
1046
1047 if (!Stream_ConditionalCheckAndLogRequiredLength(
1048 TAG, s, sizeof(rpcconn_orphaned_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
1049 return FALSE;
1050 return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header, silent);
1051}
1052
1053static void rts_free_pdu_orphaned(rpcconn_orphaned_hdr_t* ctx)
1054{
1055 if (!ctx)
1056 return;
1057 rts_free_auth_verifier(&ctx->auth_verifier);
1058}
1059
1060static BOOL rts_read_pdu_request(wStream* s, rpcconn_request_hdr_t* ctx, BOOL silent)
1061{
1062 WINPR_ASSERT(s);
1063 WINPR_ASSERT(ctx);
1064
1065 if (!Stream_ConditionalCheckAndLogRequiredLength(
1066 TAG, s, sizeof(rpcconn_request_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
1067 return FALSE;
1068 Stream_Read_UINT32(s, ctx->alloc_hint);
1069 Stream_Read_UINT16(s, ctx->p_cont_id);
1070 Stream_Read_UINT16(s, ctx->opnum);
1071 if (!rts_read_uuid(s, &ctx->object, silent))
1072 return FALSE;
1073
1074 return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header, silent);
1075}
1076
1077static void rts_free_pdu_request(rpcconn_request_hdr_t* ctx)
1078{
1079 if (!ctx)
1080 return;
1081 rts_free_auth_verifier(&ctx->auth_verifier);
1082}
1083
1084static BOOL rts_read_pdu_response(wStream* s, rpcconn_response_hdr_t* ctx, BOOL silent)
1085{
1086 WINPR_ASSERT(s);
1087 WINPR_ASSERT(ctx);
1088
1089 if (!Stream_ConditionalCheckAndLogRequiredLength(
1090 TAG, s, sizeof(rpcconn_response_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
1091 return FALSE;
1092 Stream_Read_UINT32(s, ctx->alloc_hint);
1093 Stream_Read_UINT16(s, ctx->p_cont_id);
1094 Stream_Read_UINT8(s, ctx->cancel_count);
1095 Stream_Read_UINT8(s, ctx->reserved);
1096
1097 if (!rts_align_stream(s, 8, silent))
1098 return FALSE;
1099
1100 return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header, silent);
1101}
1102
1103static void rts_free_pdu_response(rpcconn_response_hdr_t* ctx)
1104{
1105 if (!ctx)
1106 return;
1107 free(ctx->stub_data);
1108 rts_free_auth_verifier(&ctx->auth_verifier);
1109}
1110
1111static BOOL rts_read_pdu_rts(wStream* s, rpcconn_rts_hdr_t* ctx, BOOL silent)
1112{
1113 WINPR_ASSERT(s);
1114 WINPR_ASSERT(ctx);
1115
1116 if (!Stream_ConditionalCheckAndLogRequiredLength(
1117 TAG, s, sizeof(rpcconn_rts_hdr_t) - sizeof(rpcconn_common_hdr_t), silent))
1118 return FALSE;
1119
1120 Stream_Read_UINT16(s, ctx->Flags);
1121 Stream_Read_UINT16(s, ctx->NumberOfCommands);
1122 return TRUE;
1123}
1124
1125static void rts_free_pdu_rts(rpcconn_rts_hdr_t* ctx)
1126{
1127 WINPR_UNUSED(ctx);
1128}
1129
1130void rts_free_pdu_header(rpcconn_hdr_t* header, BOOL allocated)
1131{
1132 if (!header)
1133 return;
1134
1135 switch (header->common.ptype)
1136 {
1137 case PTYPE_ALTER_CONTEXT:
1138 rts_free_pdu_alter_context(&header->alter_context);
1139 break;
1140 case PTYPE_ALTER_CONTEXT_RESP:
1141 rts_free_pdu_alter_context_response(&header->alter_context_response);
1142 break;
1143 case PTYPE_BIND:
1144 rts_free_pdu_bind(&header->bind);
1145 break;
1146 case PTYPE_BIND_ACK:
1147 rts_free_pdu_bind_ack(&header->bind_ack);
1148 break;
1149 case PTYPE_BIND_NAK:
1150 rts_free_pdu_bind_nak(&header->bind_nak);
1151 break;
1152 case PTYPE_RPC_AUTH_3:
1153 rts_free_pdu_auth3(&header->rpc_auth_3);
1154 break;
1155 case PTYPE_CANCEL_ACK:
1156 rts_free_pdu_cancel_ack(&header->cancel);
1157 break;
1158 case PTYPE_FAULT:
1159 rts_free_pdu_fault(&header->fault);
1160 break;
1161 case PTYPE_ORPHANED:
1162 rts_free_pdu_orphaned(&header->orphaned);
1163 break;
1164 case PTYPE_REQUEST:
1165 rts_free_pdu_request(&header->request);
1166 break;
1167 case PTYPE_RESPONSE:
1168 rts_free_pdu_response(&header->response);
1169 break;
1170 case PTYPE_RTS:
1171 rts_free_pdu_rts(&header->rts);
1172 break;
1173 /* No extra fields */
1174 case PTYPE_SHUTDOWN:
1175 break;
1176
1177 /* not handled */
1178 case PTYPE_PING:
1179 case PTYPE_WORKING:
1180 case PTYPE_NOCALL:
1181 case PTYPE_REJECT:
1182 case PTYPE_ACK:
1183 case PTYPE_CL_CANCEL:
1184 case PTYPE_FACK:
1185 case PTYPE_CO_CANCEL:
1186 default:
1187 break;
1188 }
1189
1190 if (allocated)
1191 free(header);
1192}
1193
1194BOOL rts_read_pdu_header(wStream* s, rpcconn_hdr_t* header)
1195{
1196 return rts_read_pdu_header_ex(s, header, FALSE);
1197}
1198
1199BOOL rts_read_pdu_header_ex(wStream* s, rpcconn_hdr_t* header, BOOL silent)
1200{
1201 BOOL rc = FALSE;
1202 WINPR_ASSERT(s);
1203 WINPR_ASSERT(header);
1204
1205 const rts_pdu_status_t status = rts_read_common_pdu_header(s, &header->common, silent);
1206 if (status != RTS_PDU_VALID)
1207 return FALSE;
1208
1209 WLog_DBG(TAG, "Reading PDU type %s", rts_pdu_ptype_to_string(header->common.ptype));
1210
1211 switch (header->common.ptype)
1212 {
1213 case PTYPE_ALTER_CONTEXT:
1214 rc = rts_read_pdu_alter_context(s, &header->alter_context, silent);
1215 break;
1216 case PTYPE_ALTER_CONTEXT_RESP:
1217 rc = rts_read_pdu_alter_context_response(s, &header->alter_context_response, silent);
1218 break;
1219 case PTYPE_BIND:
1220 rc = rts_read_pdu_bind(s, &header->bind, silent);
1221 break;
1222 case PTYPE_BIND_ACK:
1223 rc = rts_read_pdu_bind_ack(s, &header->bind_ack, silent);
1224 break;
1225 case PTYPE_BIND_NAK:
1226 rc = rts_read_pdu_bind_nak(s, &header->bind_nak, silent);
1227 break;
1228 case PTYPE_RPC_AUTH_3:
1229 rc = rts_read_pdu_auth3(s, &header->rpc_auth_3, silent);
1230 break;
1231 case PTYPE_CANCEL_ACK:
1232 rc = rts_read_pdu_cancel_ack(s, &header->cancel, silent);
1233 break;
1234 case PTYPE_FAULT:
1235 rc = rts_read_pdu_fault(s, &header->fault, silent);
1236 break;
1237 case PTYPE_ORPHANED:
1238 rc = rts_read_pdu_orphaned(s, &header->orphaned, silent);
1239 break;
1240 case PTYPE_REQUEST:
1241 rc = rts_read_pdu_request(s, &header->request, silent);
1242 break;
1243 case PTYPE_RESPONSE:
1244 rc = rts_read_pdu_response(s, &header->response, silent);
1245 break;
1246 case PTYPE_RTS:
1247 rc = rts_read_pdu_rts(s, &header->rts, silent);
1248 break;
1249 case PTYPE_SHUTDOWN:
1250 rc = TRUE; /* No extra fields */
1251 break;
1252
1253 /* not handled */
1254 case PTYPE_PING:
1255 case PTYPE_WORKING:
1256 case PTYPE_NOCALL:
1257 case PTYPE_REJECT:
1258 case PTYPE_ACK:
1259 case PTYPE_CL_CANCEL:
1260 case PTYPE_FACK:
1261 case PTYPE_CO_CANCEL:
1262 default:
1263 break;
1264 }
1265
1266 return rc;
1267}
1268
1269static BOOL rts_write_pdu_header(wStream* s, const rpcconn_rts_hdr_t* header)
1270{
1271 WINPR_ASSERT(s);
1272 WINPR_ASSERT(header);
1273 if (!Stream_EnsureRemainingCapacity(s, sizeof(rpcconn_rts_hdr_t)))
1274 return FALSE;
1275
1276 if (!rts_write_common_pdu_header(s, &header->header))
1277 return FALSE;
1278
1279 Stream_Write_UINT16(s, header->Flags);
1280 Stream_Write_UINT16(s, header->NumberOfCommands);
1281 return TRUE;
1282}
1283
1284/* [MS-RPCH] 2.2.3.5.1 ReceiveWindowSize */
1285static BOOL rts_receive_window_size_command_read(rdpRpc* rpc, wStream* buffer,
1286 UINT32* ReceiveWindowSize)
1287{
1288 WINPR_ASSERT(rpc);
1289 WINPR_ASSERT(buffer);
1290
1291 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 8))
1292 return FALSE;
1293 const uint32_t CommandType = Stream_Get_UINT32(buffer);
1294 if (CommandType != RTS_CMD_RECEIVE_WINDOW_SIZE)
1295 {
1296 WLog_Print(rpc->log, WLOG_ERROR,
1297 "[MS-RPCH] 2.2.3.5.1 ReceiveWindowSize::CommandType must be 0x%08" PRIx32
1298 ", got "
1299 "0x%08" PRIx32,
1300 WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_RECEIVE_WINDOW_SIZE), CommandType);
1301 return FALSE;
1302 }
1303 const UINT32 val = Stream_Get_UINT32(buffer);
1304 if (ReceiveWindowSize)
1305 *ReceiveWindowSize = val; /* ReceiveWindowSize (4 bytes) */
1306
1307 return TRUE;
1308}
1309
1310/* [MS-RPCH] 2.2.3.5.1 ReceiveWindowSize */
1311static BOOL rts_receive_window_size_command_write(wStream* s, UINT32 ReceiveWindowSize)
1312{
1313 WINPR_ASSERT(s);
1314
1315 if (!Stream_EnsureRemainingCapacity(s, 2ull * sizeof(UINT32)))
1316 return FALSE;
1317
1318 Stream_Write_UINT32(s, RTS_CMD_RECEIVE_WINDOW_SIZE); /* CommandType (4 bytes) */
1319 Stream_Write_UINT32(s, ReceiveWindowSize); /* ReceiveWindowSize (4 bytes) */
1320
1321 return TRUE;
1322}
1323
1324/* [MS-RPCH] 2.2.3.5.2 FlowControlAck */
1325static int rts_flow_control_ack_command_read(rdpRpc* rpc, wStream* buffer, UINT32* BytesReceived,
1326 UINT32* AvailableWindow, BYTE* ChannelCookie)
1327{
1328 UINT32 val = 0;
1329 UINT32 Command = 0;
1330
1331 WINPR_ASSERT(rpc);
1332 WINPR_ASSERT(buffer);
1333
1334 int rc = rts_destination_command_read(rpc, buffer, &Command);
1335 if (rc < 0)
1336 return rc;
1337
1338 if (Command != RTS_CMD_FLOW_CONTROL_ACK)
1339 {
1340 char buffer1[64] = WINPR_C_ARRAY_INIT;
1341 char buffer2[64] = WINPR_C_ARRAY_INIT;
1342 WLog_Print(rpc->log, WLOG_ERROR, "got command %s, expected %s",
1343 rts_command_to_string(Command, buffer1, sizeof(buffer1)),
1344 rts_command_to_string(RTS_CMD_FLOW_CONTROL_ACK, buffer2, sizeof(buffer2)));
1345 return -1;
1346 }
1347
1348 /* Ack (24 bytes) */
1349 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 24))
1350 return -1;
1351
1352 Stream_Read_UINT32(buffer, val);
1353 if (BytesReceived)
1354 *BytesReceived = val; /* BytesReceived (4 bytes) */
1355
1356 Stream_Read_UINT32(buffer, val);
1357 if (AvailableWindow)
1358 *AvailableWindow = val; /* AvailableWindow (4 bytes) */
1359
1360 if (ChannelCookie)
1361 Stream_Read(buffer, ChannelCookie, 16); /* ChannelCookie (16 bytes) */
1362 else
1363 Stream_Seek(buffer, 16);
1364 return 24;
1365}
1366
1367/* [MS-RPCH] 2.2.3.5.2 FlowControlAck */
1368static BOOL rts_flow_control_ack_command_write(wStream* s, UINT32 BytesReceived,
1369 UINT32 AvailableWindow, BYTE* ChannelCookie)
1370{
1371 WINPR_ASSERT(s);
1372
1373 if (!Stream_EnsureRemainingCapacity(s, 28))
1374 return FALSE;
1375
1376 Stream_Write_UINT32(s, RTS_CMD_FLOW_CONTROL_ACK); /* CommandType (4 bytes) */
1377 Stream_Write_UINT32(s, BytesReceived); /* BytesReceived (4 bytes) */
1378 Stream_Write_UINT32(s, AvailableWindow); /* AvailableWindow (4 bytes) */
1379 Stream_Write(s, ChannelCookie, 16); /* ChannelCookie (16 bytes) */
1380
1381 return TRUE;
1382}
1383
1384/* [MS-RPCH] 2.2.3.5.3 ConnectionTimeout */
1385static BOOL rts_connection_timeout_command_read(WINPR_ATTR_UNUSED rdpRpc* rpc, wStream* buffer,
1386 UINT32* ConnectionTimeout)
1387{
1388 WINPR_ASSERT(rpc);
1389 WINPR_ASSERT(buffer);
1390
1391 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 8))
1392 return FALSE;
1393
1394 const uint32_t CommandType = Stream_Get_UINT32(buffer);
1395 if (CommandType != RTS_CMD_CONNECTION_TIMEOUT)
1396 {
1397 WLog_Print(rpc->log, WLOG_ERROR,
1398 "[MS-RPCH] 2.2.3.5.3 ConnectionTimeout::CommandType must be 0x%08" PRIx32
1399 ", got "
1400 "0x%08" PRIx32,
1401 WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_CONNECTION_TIMEOUT), CommandType);
1402 return FALSE;
1403 }
1404 const UINT32 val = Stream_Get_UINT32(buffer);
1405 if (ConnectionTimeout)
1406 *ConnectionTimeout = val; /* ConnectionTimeout (4 bytes) */
1407
1408 return TRUE;
1409}
1410
1411static BOOL rts_cookie_command_write(wStream* s, const BYTE* Cookie)
1412{
1413 WINPR_ASSERT(s);
1414
1415 if (!Stream_EnsureRemainingCapacity(s, 20))
1416 return FALSE;
1417
1418 Stream_Write_UINT32(s, RTS_CMD_COOKIE); /* CommandType (4 bytes) */
1419 Stream_Write(s, Cookie, 16); /* Cookie (16 bytes) */
1420
1421 return TRUE;
1422}
1423
1424static BOOL rts_channel_lifetime_command_write(wStream* s, UINT32 ChannelLifetime)
1425{
1426 WINPR_ASSERT(s);
1427
1428 if (!Stream_EnsureRemainingCapacity(s, 8))
1429 return FALSE;
1430 Stream_Write_UINT32(s, RTS_CMD_CHANNEL_LIFETIME); /* CommandType (4 bytes) */
1431 Stream_Write_UINT32(s, ChannelLifetime); /* ChannelLifetime (4 bytes) */
1432
1433 return TRUE;
1434}
1435
1436static BOOL rts_client_keepalive_command_write(wStream* s, UINT32 ClientKeepalive)
1437{
1438 WINPR_ASSERT(s);
1439
1440 if (!Stream_EnsureRemainingCapacity(s, 8))
1441 return FALSE;
1448 Stream_Write_UINT32(s, RTS_CMD_CLIENT_KEEPALIVE); /* CommandType (4 bytes) */
1449 Stream_Write_UINT32(s, ClientKeepalive); /* ClientKeepalive (4 bytes) */
1450
1451 return TRUE;
1452}
1453
1454/* [MS-RPCH] 2.2.3.5.7 Version */
1455static BOOL rts_version_command_read(rdpRpc* rpc, wStream* buffer, uint32_t* pversion)
1456{
1457 WINPR_ASSERT(rpc);
1458 WINPR_ASSERT(buffer);
1459
1460 if (!Stream_EnsureRemainingCapacity(buffer, 8))
1461 return FALSE;
1462
1463 const uint32_t CommandType = Stream_Get_UINT32(buffer); /* CommandType (4 bytes) */
1464 if (CommandType != RTS_CMD_VERSION)
1465 {
1466 WLog_Print(rpc->log, WLOG_ERROR,
1467 "[MS-RPCH] 2.2.3.5.7 Version::CommandType must be 0x%08" PRIx32 ", got "
1468 "0x%08" PRIx32,
1469 WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_VERSION), CommandType);
1470 return FALSE;
1471 }
1472 const uint32_t version = Stream_Get_UINT32(buffer); /* Version (4 bytes) */
1473 if (version != 1)
1474 {
1475 WLog_Print(rpc->log, WLOG_WARN,
1476 "[MS-RPCH] 2.2.3.5.7 Version::Version should be 0x00000001, got 0x%08" PRIx32,
1477 version);
1478 }
1479 if (pversion)
1480 *pversion = version;
1481
1482 return TRUE;
1483}
1484
1485/* [MS-RPCH] 2.2.3.5.7 Version */
1486static BOOL rts_version_command_write(wStream* buffer)
1487{
1488 WINPR_ASSERT(buffer);
1489
1490 if (!Stream_EnsureRemainingCapacity((buffer), 8))
1491 return FALSE;
1492
1493 Stream_Write_UINT32(buffer, RTS_CMD_VERSION); /* CommandType (4 bytes) */
1494 Stream_Write_UINT32(buffer, 1); /* Version (4 bytes) */
1495
1496 return TRUE;
1497}
1498
1499static BOOL rts_empty_command_write(wStream* s)
1500{
1501 WINPR_ASSERT(s);
1502
1503 if (!Stream_EnsureRemainingCapacity(s, 8))
1504 return FALSE;
1505
1506 Stream_Write_UINT32(s, RTS_CMD_EMPTY); /* CommandType (4 bytes) */
1507
1508 return TRUE;
1509}
1510
1511static BOOL rts_padding_command_read(wStream* s, size_t* length, BOOL silent)
1512{
1513 UINT32 ConformanceCount = 0;
1514 WINPR_ASSERT(s);
1515 WINPR_ASSERT(length);
1516 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
1517 return FALSE;
1518 Stream_Read_UINT32(s, ConformanceCount); /* ConformanceCount (4 bytes) */
1519 *length = ConformanceCount + 4;
1520 return TRUE;
1521}
1522
1523static BOOL rts_client_address_command_read(wStream* s, size_t* length, BOOL silent)
1524{
1525 UINT32 AddressType = 0;
1526
1527 WINPR_ASSERT(s);
1528 WINPR_ASSERT(length);
1529
1530 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
1531 return FALSE;
1532 Stream_Read_UINT32(s, AddressType); /* AddressType (4 bytes) */
1533
1534 if (AddressType == 0)
1535 {
1536 /* ClientAddress (4 bytes) */
1537 /* padding (12 bytes) */
1538 *length = 4 + 4 + 12;
1539 }
1540 else
1541 {
1542 /* ClientAddress (16 bytes) */
1543 /* padding (12 bytes) */
1544 *length = 4 + 16 + 12;
1545 }
1546 return TRUE;
1547}
1548
1549static BOOL rts_association_group_id_command_write(wStream* s, const BYTE* AssociationGroupId)
1550{
1551 WINPR_ASSERT(s);
1552
1553 if (!Stream_EnsureRemainingCapacity(s, 20))
1554 return FALSE;
1555
1556 Stream_Write_UINT32(s, RTS_CMD_ASSOCIATION_GROUP_ID); /* CommandType (4 bytes) */
1557 Stream_Write(s, AssociationGroupId, 16); /* AssociationGroupId (16 bytes) */
1558
1559 return TRUE;
1560}
1561
1562static int rts_destination_command_read(WINPR_ATTR_UNUSED rdpRpc* rpc, wStream* buffer,
1563 UINT32* Destination)
1564{
1565 UINT32 val = 0;
1566 WINPR_ASSERT(rpc);
1567 WINPR_ASSERT(buffer);
1568
1569 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 4))
1570 return -1;
1571 Stream_Read_UINT32(buffer, val);
1572 if (Destination)
1573 *Destination = val; /* Destination (4 bytes) */
1574
1575 return 4;
1576}
1577
1578static BOOL rts_destination_command_write(wStream* s, UINT32 Destination)
1579{
1580 WINPR_ASSERT(s);
1581
1582 if (!Stream_EnsureRemainingCapacity(s, 8))
1583 return FALSE;
1584
1585 Stream_Write_UINT32(s, RTS_CMD_DESTINATION); /* CommandType (4 bytes) */
1586 Stream_Write_UINT32(s, Destination); /* Destination (4 bytes) */
1587
1588 return TRUE;
1589}
1590
1591#define rts_send_buffer(channel, s, frag_length) \
1592 rts_send_buffer_int((channel), (s), (frag_length), __FILE__, __LINE__, __func__)
1593static BOOL rts_send_buffer_int(RpcChannel* channel, wStream* s, size_t frag_length,
1594 const char* file, size_t line, const char* fkt)
1595{
1596 BOOL status = FALSE;
1597 SSIZE_T rc = 0;
1598
1599 WINPR_ASSERT(channel);
1600 WINPR_ASSERT(channel->rpc);
1601 WINPR_ASSERT(s);
1602
1603 Stream_SealLength(s);
1604
1605 const DWORD level = WLOG_TRACE;
1606 if (WLog_IsLevelActive(channel->rpc->log, level))
1607 {
1608 WLog_PrintTextMessage(channel->rpc->log, level, line, file, fkt,
1609 "Sending [%s] %" PRIuz " bytes", fkt, Stream_Length(s));
1610 }
1611 if (Stream_Length(s) < sizeof(rpcconn_common_hdr_t))
1612 goto fail;
1613 if (Stream_Length(s) != frag_length)
1614 goto fail;
1615
1616 rc = rpc_channel_write(channel, Stream_Buffer(s), Stream_Length(s));
1617 if (rc < 0)
1618 goto fail;
1619 if ((size_t)rc != Stream_Length(s))
1620 goto fail;
1621 status = TRUE;
1622fail:
1623 return status;
1624}
1625
1626/* CONN/A Sequence */
1627
1628BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc)
1629{
1630 BOOL status = FALSE;
1631 wStream* buffer = nullptr;
1632 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1633 UINT32 ReceiveWindowSize = 0;
1634 BYTE* OUTChannelCookie = nullptr;
1635 BYTE* VirtualConnectionCookie = nullptr;
1636 RpcVirtualConnection* connection = nullptr;
1637 RpcOutChannel* outChannel = nullptr;
1638
1639 WINPR_ASSERT(rpc);
1640
1641 connection = rpc->VirtualConnection;
1642 WINPR_ASSERT(connection);
1643
1644 outChannel = connection->DefaultOutChannel;
1645 WINPR_ASSERT(outChannel);
1646
1647 header.header.frag_length = 76;
1648 header.Flags = RTS_FLAG_NONE;
1649 header.NumberOfCommands = 4;
1650
1651 WLog_DBG(TAG, "Sending CONN/A1 RTS PDU");
1652 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
1653 OUTChannelCookie = (BYTE*)&(outChannel->common.Cookie);
1654 ReceiveWindowSize = outChannel->ReceiveWindow;
1655
1656 buffer = Stream_New(nullptr, header.header.frag_length);
1657
1658 if (!buffer)
1659 return -1;
1660
1661 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1662 goto fail;
1663 status = rts_version_command_write(buffer); /* Version (8 bytes) */
1664 if (!status)
1665 goto fail;
1666 status = rts_cookie_command_write(
1667 buffer, VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */
1668 if (!status)
1669 goto fail;
1670 status = rts_cookie_command_write(buffer, OUTChannelCookie); /* OUTChannelCookie (20 bytes) */
1671 if (!status)
1672 goto fail;
1673 status = rts_receive_window_size_command_write(
1674 buffer, ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
1675 if (!status)
1676 goto fail;
1677 status = rts_send_buffer(&outChannel->common, buffer, header.header.frag_length);
1678fail:
1679 Stream_Free(buffer, TRUE);
1680 return status;
1681}
1682
1683BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer)
1684{
1685 BOOL rc = FALSE;
1686 UINT32 ConnectionTimeout = 0;
1687
1688 rpcconn_hdr_t header = WINPR_C_ARRAY_INIT;
1689 if (!rts_read_pdu_header(buffer, &header))
1690 goto fail;
1691
1692 if (header.rts.Flags != RTS_FLAG_NONE)
1693 {
1694 WLog_Print(rpc->log, WLOG_ERROR,
1695 "[MS-RPCH] 2.2.4.4 CONN/A3 RTS PDU unexpected Flags=0x%08" PRIx32
1696 ", expected 0x%08" PRIx32,
1697 header.rts.Flags, WINPR_CXX_COMPAT_CAST(UINT32, RTS_FLAG_NONE));
1698 goto fail;
1699 }
1700 if (header.rts.NumberOfCommands != 1)
1701 {
1702 WLog_Print(rpc->log, WLOG_ERROR,
1703 "[MS-RPCH] 2.2.4.4 CONN/A3 RTS PDU unexpected NumberOfCommands=%" PRIu32
1704 ", expected 1",
1705 header.rts.NumberOfCommands);
1706 goto fail;
1707 }
1708
1709 if (!rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout))
1710 goto fail;
1711
1712 WLog_Print(rpc->log, WLOG_DEBUG, "Receiving CONN/A3 RTS PDU: ConnectionTimeout: %" PRIu32 "",
1713 ConnectionTimeout);
1714
1715 WINPR_ASSERT(rpc);
1716 WINPR_ASSERT(rpc->VirtualConnection);
1717 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1718
1719 rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
1720
1721 rc = TRUE;
1722
1723fail:
1724 rts_free_pdu_header(&header, FALSE);
1725 return rc;
1726}
1727
1728/* CONN/B Sequence */
1729
1730BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc)
1731{
1732 BOOL status = FALSE;
1733 wStream* buffer = nullptr;
1734 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1735 BYTE* INChannelCookie = nullptr;
1736 BYTE* AssociationGroupId = nullptr;
1737 BYTE* VirtualConnectionCookie = nullptr;
1738 RpcVirtualConnection* connection = nullptr;
1739 RpcInChannel* inChannel = nullptr;
1740
1741 WINPR_ASSERT(rpc);
1742
1743 connection = rpc->VirtualConnection;
1744 WINPR_ASSERT(connection);
1745
1746 inChannel = connection->DefaultInChannel;
1747 WINPR_ASSERT(inChannel);
1748
1749 header.header.frag_length = 104;
1750 header.Flags = RTS_FLAG_NONE;
1751 header.NumberOfCommands = 6;
1752
1753 WLog_DBG(TAG, "Sending CONN/B1 RTS PDU");
1754
1755 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
1756 INChannelCookie = (BYTE*)&(inChannel->common.Cookie);
1757 AssociationGroupId = (BYTE*)&(connection->AssociationGroupId);
1758 buffer = Stream_New(nullptr, header.header.frag_length);
1759
1760 if (!buffer)
1761 goto fail;
1762 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1763 goto fail;
1764 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
1765 goto fail;
1766 if (!rts_cookie_command_write(buffer,
1767 VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */
1768 goto fail;
1769 if (!rts_cookie_command_write(buffer, INChannelCookie)) /* INChannelCookie (20 bytes) */
1770 goto fail;
1771 if (!rts_channel_lifetime_command_write(buffer,
1772 rpc->ChannelLifetime)) /* ChannelLifetime (8 bytes) */
1773 goto fail;
1774 if (!rts_client_keepalive_command_write(buffer,
1775 rpc->KeepAliveInterval)) /* ClientKeepalive (8 bytes) */
1776 goto fail;
1777 if (!rts_association_group_id_command_write(
1778 buffer, AssociationGroupId)) /* AssociationGroupId (20 bytes) */
1779 goto fail;
1780 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
1781fail:
1782 Stream_Free(buffer, TRUE);
1783 return status;
1784}
1785
1786/* [MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU */
1787
1788BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer)
1789{
1790 BOOL rc = FALSE;
1791 UINT32 ReceiveWindowSize = 0;
1792 UINT32 ConnectionTimeout = 0;
1793
1794 WINPR_ASSERT(rpc);
1795 WINPR_ASSERT(buffer);
1796
1797 rpcconn_hdr_t header = WINPR_C_ARRAY_INIT;
1798 if (!rts_read_pdu_header(buffer, &header))
1799 goto fail;
1800
1801 if (header.rts.Flags != RTS_FLAG_NONE)
1802 {
1803 WLog_Print(rpc->log, WLOG_ERROR,
1804 "[MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU unexpected Flags=0x%08" PRIx32
1805 ", expected 0x%08" PRIx32,
1806 header.rts.Flags, WINPR_CXX_COMPAT_CAST(UINT32, RTS_FLAG_NONE));
1807 goto fail;
1808 }
1809 if (header.rts.NumberOfCommands != 3)
1810 {
1811 WLog_Print(rpc->log, WLOG_ERROR,
1812 "[MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU unexpected NumberOfCommands=%" PRIu32
1813 ", expected 3",
1814 header.rts.NumberOfCommands);
1815 goto fail;
1816 }
1817 if (!rts_version_command_read(rpc, buffer, nullptr))
1818 goto fail;
1819
1820 if (!rts_receive_window_size_command_read(rpc, buffer, &ReceiveWindowSize))
1821 goto fail;
1822
1823 if (!rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout))
1824 goto fail;
1825
1826 WLog_Print(rpc->log, WLOG_DEBUG,
1827 "Receiving CONN/C2 RTS PDU: ConnectionTimeout: %" PRIu32
1828 " ReceiveWindowSize: %" PRIu32 "",
1829 ConnectionTimeout, ReceiveWindowSize);
1830
1831 WINPR_ASSERT(rpc);
1832 WINPR_ASSERT(rpc->VirtualConnection);
1833 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1834
1835 rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
1836 rpc->VirtualConnection->DefaultInChannel->PeerReceiveWindow = ReceiveWindowSize;
1837
1838 rc = TRUE;
1839
1840fail:
1841 rts_free_pdu_header(&header, FALSE);
1842 return rc;
1843}
1844
1845/* Out-of-Sequence PDUs */
1846
1847BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc)
1848{
1849 BOOL status = FALSE;
1850 wStream* buffer = nullptr;
1851 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1852 UINT32 BytesReceived = 0;
1853 UINT32 AvailableWindow = 0;
1854 BYTE* ChannelCookie = nullptr;
1855 RpcVirtualConnection* connection = nullptr;
1856 RpcInChannel* inChannel = nullptr;
1857 RpcOutChannel* outChannel = nullptr;
1858
1859 WINPR_ASSERT(rpc);
1860
1861 connection = rpc->VirtualConnection;
1862 WINPR_ASSERT(connection);
1863
1864 inChannel = connection->DefaultInChannel;
1865 WINPR_ASSERT(inChannel);
1866
1867 outChannel = connection->DefaultOutChannel;
1868 WINPR_ASSERT(outChannel);
1869
1870 header.header.frag_length = 56;
1871 header.Flags = RTS_FLAG_OTHER_CMD;
1872 header.NumberOfCommands = 2;
1873
1874 WLog_DBG(TAG, "Sending FlowControlAck RTS PDU");
1875
1876 BytesReceived = outChannel->BytesReceived;
1877 AvailableWindow = outChannel->AvailableWindowAdvertised;
1878 ChannelCookie = (BYTE*)&(outChannel->common.Cookie);
1879 outChannel->ReceiverAvailableWindow = outChannel->AvailableWindowAdvertised;
1880 buffer = Stream_New(nullptr, header.header.frag_length);
1881
1882 if (!buffer)
1883 goto fail;
1884
1885 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1886 goto fail;
1887 if (!rts_destination_command_write(buffer, FDOutProxy)) /* Destination Command (8 bytes) */
1888 goto fail;
1889
1890 /* FlowControlAck Command (28 bytes) */
1891 if (!rts_flow_control_ack_command_write(buffer, BytesReceived, AvailableWindow, ChannelCookie))
1892 goto fail;
1893
1894 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
1895fail:
1896 Stream_Free(buffer, TRUE);
1897 return status;
1898}
1899
1900static int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, wStream* buffer)
1901{
1902 int rc = 0;
1903 UINT32 BytesReceived = 0;
1904 UINT32 AvailableWindow = 0;
1905 BYTE ChannelCookie[16] = WINPR_C_ARRAY_INIT;
1906
1907 rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow,
1908 (BYTE*)&ChannelCookie);
1909 if (rc < 0)
1910 return rc;
1911 WLog_ERR(TAG,
1912 "Receiving FlowControlAck RTS PDU: BytesReceived: %" PRIu32
1913 " AvailableWindow: %" PRIu32 "",
1914 BytesReceived, AvailableWindow);
1915
1916 WINPR_ASSERT(rpc->VirtualConnection);
1917 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1918
1919 rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
1920 AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
1921 return 1;
1922}
1923
1924static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, wStream* buffer)
1925{
1926 UINT32 Command = 0;
1927 UINT32 Destination = 0;
1928 UINT32 BytesReceived = 0;
1929 UINT32 AvailableWindow = 0;
1930 BYTE ChannelCookie[16] = WINPR_C_ARRAY_INIT;
1948 int rc = rts_destination_command_read(rpc, buffer, &Command);
1949 if (rc < 0)
1950 return rc;
1951
1952 if (Command != RTS_CMD_DESTINATION)
1953 {
1954 char buffer1[64] = WINPR_C_ARRAY_INIT;
1955 char buffer2[64] = WINPR_C_ARRAY_INIT;
1956 WLog_Print(rpc->log, WLOG_ERROR, "got command %s, expected %s",
1957 rts_command_to_string(Command, buffer1, sizeof(buffer1)),
1958 rts_command_to_string(RTS_CMD_DESTINATION, buffer2, sizeof(buffer2)));
1959 return -1;
1960 }
1961
1962 rc = rts_destination_command_read(rpc, buffer, &Destination);
1963 if (rc < 0)
1964 return rc;
1965
1966 switch (Destination)
1967 {
1968 case FDClient:
1969 break;
1970 case FDInProxy:
1971 break;
1972 case FDServer:
1973 break;
1974 case FDOutProxy:
1975 break;
1976 default:
1977 WLog_Print(rpc->log, WLOG_ERROR,
1978 "got destination %" PRIu32
1979 ", expected one of [FDClient[0]|FDInProxy[1]|FDServer[2]|FDOutProxy[3]",
1980 Destination);
1981 return -1;
1982 }
1983
1984 rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow,
1985 ChannelCookie);
1986 if (rc < 0)
1987 return rc;
1988
1989 WLog_DBG(TAG,
1990 "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %" PRIu32
1991 " AvailableWindow: %" PRIu32 "",
1992 BytesReceived, AvailableWindow);
1993
1994 WINPR_ASSERT(rpc->VirtualConnection);
1995 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1996 rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
1997 AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
1998 return 1;
1999}
2000
2001BOOL rts_recv_ping_pdu(rdpRpc* rpc, wStream* s)
2002{
2003 BOOL rc = FALSE;
2004 rpcconn_hdr_t header = WINPR_C_ARRAY_INIT;
2005
2006 WINPR_ASSERT(rpc);
2007 WINPR_ASSERT(rpc->auth);
2008 WINPR_ASSERT(s);
2009
2010 if (!rts_read_pdu_header(s, &header))
2011 goto fail;
2012
2013 rc = TRUE;
2014 if (header.common.ptype != PTYPE_RTS)
2015 {
2016 WLog_Print(rpc->log, WLOG_ERROR, "received invalid ping PDU, type is 0x%" PRIx32,
2017 header.common.ptype);
2018 rc = FALSE;
2019 }
2020 if (header.rts.Flags != RTS_FLAG_PING)
2021 {
2022 WLog_Print(rpc->log, WLOG_ERROR, "received unexpected ping PDU::Flags 0x%" PRIx32,
2023 header.rts.Flags);
2024 rc = FALSE;
2025 }
2026fail:
2027 rts_free_pdu_header(&header, FALSE);
2028 return rc;
2029}
2030
2031static int rts_send_ping_pdu(rdpRpc* rpc)
2032{
2033 BOOL status = FALSE;
2034 wStream* buffer = nullptr;
2035 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2036 RpcInChannel* inChannel = nullptr;
2037
2038 WINPR_ASSERT(rpc);
2039 WINPR_ASSERT(rpc->VirtualConnection);
2040
2041 inChannel = rpc->VirtualConnection->DefaultInChannel;
2042 WINPR_ASSERT(inChannel);
2043
2044 header.header.frag_length = 20;
2045 header.Flags = RTS_FLAG_PING;
2046 header.NumberOfCommands = 0;
2047
2048 WLog_DBG(TAG, "Sending Ping RTS PDU");
2049 buffer = Stream_New(nullptr, header.header.frag_length);
2050
2051 if (!buffer)
2052 goto fail;
2053
2054 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2055 goto fail;
2056 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
2057fail:
2058 Stream_Free(buffer, TRUE);
2059 return (status) ? 1 : -1;
2060}
2061
2062BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length, BOOL silent)
2063{
2064 size_t padding = 0;
2065 size_t CommandLength = 0;
2066
2067 WINPR_ASSERT(s);
2068
2069 switch (CommandType)
2070 {
2071 case RTS_CMD_RECEIVE_WINDOW_SIZE:
2072 CommandLength = RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH;
2073 break;
2074
2075 case RTS_CMD_FLOW_CONTROL_ACK:
2076 CommandLength = RTS_CMD_FLOW_CONTROL_ACK_LENGTH;
2077 break;
2078
2079 case RTS_CMD_CONNECTION_TIMEOUT:
2080 CommandLength = RTS_CMD_CONNECTION_TIMEOUT_LENGTH;
2081 break;
2082
2083 case RTS_CMD_COOKIE:
2084 CommandLength = RTS_CMD_COOKIE_LENGTH;
2085 break;
2086
2087 case RTS_CMD_CHANNEL_LIFETIME:
2088 CommandLength = RTS_CMD_CHANNEL_LIFETIME_LENGTH;
2089 break;
2090
2091 case RTS_CMD_CLIENT_KEEPALIVE:
2092 CommandLength = RTS_CMD_CLIENT_KEEPALIVE_LENGTH;
2093 break;
2094
2095 case RTS_CMD_VERSION:
2096 CommandLength = RTS_CMD_VERSION_LENGTH;
2097 break;
2098
2099 case RTS_CMD_EMPTY:
2100 CommandLength = RTS_CMD_EMPTY_LENGTH;
2101 break;
2102
2103 case RTS_CMD_PADDING: /* variable-size */
2104 if (!rts_padding_command_read(s, &padding, silent))
2105 return FALSE;
2106 break;
2107
2108 case RTS_CMD_NEGATIVE_ANCE:
2109 CommandLength = RTS_CMD_NEGATIVE_ANCE_LENGTH;
2110 break;
2111
2112 case RTS_CMD_ANCE:
2113 CommandLength = RTS_CMD_ANCE_LENGTH;
2114 break;
2115
2116 case RTS_CMD_CLIENT_ADDRESS: /* variable-size */
2117 if (!rts_client_address_command_read(s, &CommandLength, silent))
2118 return FALSE;
2119 break;
2120
2121 case RTS_CMD_ASSOCIATION_GROUP_ID:
2122 CommandLength = RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH;
2123 break;
2124
2125 case RTS_CMD_DESTINATION:
2126 CommandLength = RTS_CMD_DESTINATION_LENGTH;
2127 break;
2128
2129 case RTS_CMD_PING_TRAFFIC_SENT_NOTIFY:
2130 CommandLength = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH;
2131 break;
2132
2133 default:
2134 WLog_ERR(TAG, "Error: Unknown RTS Command Type: 0x%" PRIx32 "", CommandType);
2135 return FALSE;
2136 }
2137
2138 CommandLength += padding;
2139 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, CommandLength, silent))
2140 return FALSE;
2141
2142 if (length)
2143 *length = CommandLength;
2144 return TRUE;
2145}
2146
2147static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
2148{
2149 BOOL status = FALSE;
2150 wStream* buffer = nullptr;
2151 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2152 BYTE* SuccessorChannelCookie = nullptr;
2153 RpcInChannel* inChannel = nullptr;
2154 RpcOutChannel* nextOutChannel = nullptr;
2155
2156 WINPR_ASSERT(rpc);
2157 WINPR_ASSERT(rpc->VirtualConnection);
2158
2159 inChannel = rpc->VirtualConnection->DefaultInChannel;
2160 WINPR_ASSERT(inChannel);
2161
2162 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
2163 WINPR_ASSERT(nextOutChannel);
2164
2165 header.header.frag_length = 56;
2166 header.Flags = RTS_FLAG_OUT_CHANNEL;
2167 header.NumberOfCommands = 3;
2168
2169 WLog_DBG(TAG, "Sending OUT_R2/A7 RTS PDU");
2170
2171 SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
2172 buffer = Stream_New(nullptr, header.header.frag_length);
2173
2174 if (!buffer)
2175 return -1;
2176
2177 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2178 goto fail;
2179 if (!rts_destination_command_write(buffer, FDServer)) /* Destination (8 bytes)*/
2180 goto fail;
2181 if (!rts_cookie_command_write(buffer,
2182 SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */
2183 goto fail;
2184 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
2185 goto fail;
2186 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
2187fail:
2188 Stream_Free(buffer, TRUE);
2189 return (status) ? 1 : -1;
2190}
2191
2192static int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
2193{
2194 BOOL status = FALSE;
2195 wStream* buffer = nullptr;
2196 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2197 RpcOutChannel* nextOutChannel = nullptr;
2198
2199 WINPR_ASSERT(rpc);
2200 WINPR_ASSERT(rpc->VirtualConnection);
2201
2202 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
2203 WINPR_ASSERT(nextOutChannel);
2204
2205 header.header.frag_length = 24;
2206 header.Flags = RTS_FLAG_PING;
2207 header.NumberOfCommands = 1;
2208
2209 WLog_DBG(TAG, "Sending OUT_R2/C1 RTS PDU");
2210 buffer = Stream_New(nullptr, header.header.frag_length);
2211
2212 if (!buffer)
2213 return -1;
2214
2215 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2216 goto fail;
2217
2218 if (!rts_empty_command_write(buffer)) /* Empty command (4 bytes) */
2219 goto fail;
2220 status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length);
2221fail:
2222 Stream_Free(buffer, TRUE);
2223 return (status) ? 1 : -1;
2224}
2225
2226BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
2227{
2228 BOOL status = FALSE;
2229 wStream* buffer = nullptr;
2230 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2231 UINT32 ReceiveWindowSize = 0;
2232 BYTE* VirtualConnectionCookie = nullptr;
2233 BYTE* PredecessorChannelCookie = nullptr;
2234 BYTE* SuccessorChannelCookie = nullptr;
2235 RpcVirtualConnection* connection = nullptr;
2236 RpcOutChannel* outChannel = nullptr;
2237 RpcOutChannel* nextOutChannel = nullptr;
2238
2239 WINPR_ASSERT(rpc);
2240
2241 connection = rpc->VirtualConnection;
2242 WINPR_ASSERT(connection);
2243
2244 outChannel = connection->DefaultOutChannel;
2245 WINPR_ASSERT(outChannel);
2246
2247 nextOutChannel = connection->NonDefaultOutChannel;
2248 WINPR_ASSERT(nextOutChannel);
2249
2250 header.header.frag_length = 96;
2251 header.Flags = RTS_FLAG_RECYCLE_CHANNEL;
2252 header.NumberOfCommands = 5;
2253
2254 WLog_DBG(TAG, "Sending OUT_R1/A3 RTS PDU");
2255
2256 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
2257 PredecessorChannelCookie = (BYTE*)&(outChannel->common.Cookie);
2258 SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
2259 ReceiveWindowSize = outChannel->ReceiveWindow;
2260 buffer = Stream_New(nullptr, header.header.frag_length);
2261
2262 if (!buffer)
2263 return -1;
2264
2265 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2266 goto fail;
2267 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
2268 goto fail;
2269 if (!rts_cookie_command_write(buffer,
2270 VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */
2271 goto fail;
2272 if (!rts_cookie_command_write(
2273 buffer, PredecessorChannelCookie)) /* PredecessorChannelCookie (20 bytes) */
2274 goto fail;
2275 if (!rts_cookie_command_write(buffer,
2276 SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */
2277 goto fail;
2278 if (!rts_receive_window_size_command_write(buffer,
2279 ReceiveWindowSize)) /* ReceiveWindowSize (8 bytes) */
2280 goto fail;
2281
2282 status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length);
2283fail:
2284 Stream_Free(buffer, TRUE);
2285 return status;
2286}
2287
2288static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, wStream* buffer)
2289{
2290 int status = 0;
2291 UINT32 Destination = 0;
2292 WINPR_ASSERT(rpc);
2293 WINPR_ASSERT(buffer);
2294
2295 RpcVirtualConnection* connection = rpc->VirtualConnection;
2296 WINPR_ASSERT(connection);
2297
2298 WLog_DBG(TAG, "Receiving OUT R1/A2 RTS PDU");
2299
2300 status = rts_destination_command_read(rpc, buffer, &Destination);
2301 if (status < 0)
2302 return status;
2303
2304 connection->NonDefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
2305
2306 if (!connection->NonDefaultOutChannel)
2307 return -1;
2308
2309 status = rpc_out_channel_replacement_connect(connection->NonDefaultOutChannel, 5000);
2310
2311 if (status < 0)
2312 {
2313 WLog_ERR(TAG, "rpc_out_channel_replacement_connect failure");
2314 return -1;
2315 }
2316
2317 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2318 CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
2319 return 1;
2320}
2321
2322static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, WINPR_ATTR_UNUSED wStream* buffer)
2323{
2324 int status = 0;
2325 RpcVirtualConnection* connection = nullptr;
2326
2327 WINPR_ASSERT(rpc);
2328 WINPR_ASSERT(buffer);
2329
2330 connection = rpc->VirtualConnection;
2331 WINPR_ASSERT(connection);
2332
2333 WLog_DBG(TAG, "Receiving OUT R2/A6 RTS PDU");
2334 status = rts_send_OUT_R2_C1_pdu(rpc);
2335
2336 if (status < 0)
2337 {
2338 WLog_ERR(TAG, "rts_send_OUT_R2_C1_pdu failure");
2339 return -1;
2340 }
2341
2342 status = rts_send_OUT_R2_A7_pdu(rpc);
2343
2344 if (status < 0)
2345 {
2346 WLog_ERR(TAG, "rts_send_OUT_R2_A7_pdu failure");
2347 return -1;
2348 }
2349
2350 rpc_out_channel_transition_to_state(connection->NonDefaultOutChannel,
2351 CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
2352 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2353 CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
2354 return 1;
2355}
2356
2357static int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, WINPR_ATTR_UNUSED wStream* buffer)
2358{
2359 RpcVirtualConnection* connection = nullptr;
2360
2361 WINPR_ASSERT(rpc);
2362 WINPR_ASSERT(buffer);
2363
2364 connection = rpc->VirtualConnection;
2365 WINPR_ASSERT(connection);
2366
2367 WLog_DBG(TAG, "Receiving OUT R2/B3 RTS PDU");
2368 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2369 CLIENT_OUT_CHANNEL_STATE_RECYCLED);
2370 return 1;
2371}
2372
2373BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer, const rpcconn_hdr_t* header)
2374{
2375 BOOL status = FALSE;
2376 size_t length = 0;
2377 RtsPduSignature signature = WINPR_C_ARRAY_INIT;
2378 RpcVirtualConnection* connection = nullptr;
2379
2380 WINPR_ASSERT(rpc);
2381 WINPR_ASSERT(buffer);
2382 WINPR_ASSERT(header);
2383
2384 wLog* log = WLog_Get(TAG);
2385
2386 const size_t total = Stream_Length(buffer);
2387 length = header->common.frag_length;
2388 if (total < length)
2389 {
2390 WLog_Print(log, WLOG_ERROR, "PDU length %" PRIuz " does not match available data %" PRIuz,
2391 length, total);
2392 return FALSE;
2393 }
2394
2395 connection = rpc->VirtualConnection;
2396
2397 if (!connection)
2398 {
2399 WLog_Print(log, WLOG_ERROR, "not connected, aborting");
2400 return FALSE;
2401 }
2402
2403 if (!rts_extract_pdu_signature(&signature, buffer, header))
2404 return FALSE;
2405
2406 rts_print_pdu_signature(log, WLOG_TRACE, &signature);
2407
2408 if (memcmp(&signature, &RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, sizeof(signature)) == 0)
2409 {
2410 status = rts_recv_flow_control_ack_pdu(rpc, buffer);
2411 }
2412 else if (memcmp(&signature, &RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE,
2413 sizeof(signature)) == 0)
2414 {
2415 status = rts_recv_flow_control_ack_with_destination_pdu(rpc, buffer);
2416 }
2417 else if (memcmp(&signature, &RTS_PDU_PING_SIGNATURE, sizeof(signature)) == 0)
2418 {
2419 status = rts_send_ping_pdu(rpc);
2420 }
2421 else
2422 {
2423 if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
2424 {
2425 if (memcmp(&signature, &RTS_PDU_OUT_R1_A2_SIGNATURE, sizeof(signature)) == 0)
2426 {
2427 status = rts_recv_OUT_R1_A2_pdu(rpc, buffer);
2428 }
2429 }
2430 else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_A6W)
2431 {
2432 if (memcmp(&signature, &RTS_PDU_OUT_R2_A6_SIGNATURE, sizeof(signature)) == 0)
2433 {
2434 status = rts_recv_OUT_R2_A6_pdu(rpc, buffer);
2435 }
2436 }
2437 else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_B3W)
2438 {
2439 if (memcmp(&signature, &RTS_PDU_OUT_R2_B3_SIGNATURE, sizeof(signature)) == 0)
2440 {
2441 status = rts_recv_OUT_R2_B3_pdu(rpc, buffer);
2442 }
2443 }
2444 }
2445
2446 if (!status)
2447 {
2448 const UINT32 SignatureId = rts_identify_pdu_signature(&signature, nullptr);
2449 WLog_Print(log, WLOG_ERROR, "error parsing RTS PDU with signature id: 0x%08" PRIX32 "",
2450 SignatureId);
2451 rts_print_pdu_signature(log, WLOG_ERROR, &signature);
2452 }
2453
2454 const size_t rem = Stream_GetRemainingLength(buffer);
2455 if (rem > 0)
2456 {
2457 WLog_Print(log, WLOG_ERROR, "%" PRIuz " bytes or %" PRIuz " total not parsed, aborting",
2458 rem, total);
2459 rts_print_pdu_signature(log, WLOG_ERROR, &signature);
2460 return FALSE;
2461 }
2462
2463 return status;
2464}
2465
2466BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth)
2467{
2468 WINPR_ASSERT(s);
2469 WINPR_ASSERT(auth);
2470
2471 if (!rts_write_common_pdu_header(s, &auth->header))
2472 return FALSE;
2473
2474 if (!Stream_EnsureRemainingCapacity(s, 2ull * sizeof(UINT16)))
2475 return FALSE;
2476
2477 Stream_Write_UINT16(s, auth->max_xmit_frag);
2478 Stream_Write_UINT16(s, auth->max_recv_frag);
2479
2480 return rts_write_auth_verifier(s, &auth->auth_verifier, &auth->header);
2481}
2482
2483BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind)
2484{
2485
2486 WINPR_ASSERT(s);
2487 WINPR_ASSERT(bind);
2488
2489 if (!rts_write_common_pdu_header(s, &bind->header))
2490 return FALSE;
2491
2492 if (!Stream_EnsureRemainingCapacity(s, 8))
2493 return FALSE;
2494
2495 Stream_Write_UINT16(s, bind->max_xmit_frag);
2496 Stream_Write_UINT16(s, bind->max_recv_frag);
2497 Stream_Write_UINT32(s, bind->assoc_group_id);
2498
2499 if (!rts_write_context_list(s, &bind->p_context_elem))
2500 return FALSE;
2501
2502 return rts_write_auth_verifier(s, &bind->auth_verifier, &bind->header);
2503}
2504
2505BOOL rts_conditional_check_and_log(const char* tag, wStream* s, size_t size, BOOL silent,
2506 const char* fkt, const char* file, size_t line)
2507{
2508 if (silent)
2509 {
2510 const size_t rem = Stream_GetRemainingLength(s);
2511 return (rem >= size);
2512 }
2513
2514 return Stream_CheckAndLogRequiredLengthEx(tag, WLOG_WARN, s, size, 1, "%s(%s:%" PRIuz ")", fkt,
2515 file, line);
2516}
2517
2518BOOL rts_conditional_safe_seek(wStream* s, size_t size, BOOL silent, const char* fkt,
2519 const char* file, size_t line)
2520{
2521 if (silent)
2522 {
2523 const size_t rem = Stream_GetRemainingLength(s);
2524 if (rem < size)
2525 return FALSE;
2526 }
2527 return Stream_SafeSeekEx(s, size, file, line, fkt);
2528}