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