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