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