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