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