FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 0x08" PRIx32 ", got "
1258 "0x%08" PRIx32,
1259 RTS_CMD_RECEIVE_WINDOW_SIZE, CommandType);
1260 return FALSE;
1261 }
1262 const UINT32 val = Stream_Get_UINT32(buffer);
1263 if (ReceiveWindowSize)
1264 *ReceiveWindowSize = val; /* ReceiveWindowSize (4 bytes) */
1265
1266 return TRUE;
1267}
1268
1269/* [MS-RPCH] 2.2.3.5.1 ReceiveWindowSize */
1270static BOOL rts_receive_window_size_command_write(wStream* s, UINT32 ReceiveWindowSize)
1271{
1272 WINPR_ASSERT(s);
1273
1274 if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT32)))
1275 return FALSE;
1276
1277 Stream_Write_UINT32(s, RTS_CMD_RECEIVE_WINDOW_SIZE); /* CommandType (4 bytes) */
1278 Stream_Write_UINT32(s, ReceiveWindowSize); /* ReceiveWindowSize (4 bytes) */
1279
1280 return TRUE;
1281}
1282
1283/* [MS-RPCH] 2.2.3.5.2 FlowControlAck */
1284static int rts_flow_control_ack_command_read(rdpRpc* rpc, wStream* buffer, UINT32* BytesReceived,
1285 UINT32* AvailableWindow, BYTE* ChannelCookie)
1286{
1287 UINT32 val = 0;
1288 UINT32 Command = 0;
1289
1290 WINPR_ASSERT(rpc);
1291 WINPR_ASSERT(buffer);
1292
1293 int rc = rts_destination_command_read(rpc, buffer, &Command);
1294 if (rc < 0)
1295 return rc;
1296
1297 if (Command != RTS_CMD_FLOW_CONTROL_ACK)
1298 {
1299 char buffer1[64] = { 0 };
1300 char buffer2[64] = { 0 };
1301 WLog_Print(rpc->log, WLOG_ERROR, "got command %s, expected %s",
1302 rts_command_to_string(Command, buffer1, sizeof(buffer1)),
1303 rts_command_to_string(RTS_CMD_FLOW_CONTROL_ACK, buffer2, sizeof(buffer2)));
1304 return -1;
1305 }
1306
1307 /* Ack (24 bytes) */
1308 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 24))
1309 return -1;
1310
1311 Stream_Read_UINT32(buffer, val);
1312 if (BytesReceived)
1313 *BytesReceived = val; /* BytesReceived (4 bytes) */
1314
1315 Stream_Read_UINT32(buffer, val);
1316 if (AvailableWindow)
1317 *AvailableWindow = val; /* AvailableWindow (4 bytes) */
1318
1319 if (ChannelCookie)
1320 Stream_Read(buffer, ChannelCookie, 16); /* ChannelCookie (16 bytes) */
1321 else
1322 Stream_Seek(buffer, 16);
1323 return 24;
1324}
1325
1326/* [MS-RPCH] 2.2.3.5.2 FlowControlAck */
1327static BOOL rts_flow_control_ack_command_write(wStream* s, UINT32 BytesReceived,
1328 UINT32 AvailableWindow, BYTE* ChannelCookie)
1329{
1330 WINPR_ASSERT(s);
1331
1332 if (!Stream_EnsureRemainingCapacity(s, 28))
1333 return FALSE;
1334
1335 Stream_Write_UINT32(s, RTS_CMD_FLOW_CONTROL_ACK); /* CommandType (4 bytes) */
1336 Stream_Write_UINT32(s, BytesReceived); /* BytesReceived (4 bytes) */
1337 Stream_Write_UINT32(s, AvailableWindow); /* AvailableWindow (4 bytes) */
1338 Stream_Write(s, ChannelCookie, 16); /* ChannelCookie (16 bytes) */
1339
1340 return TRUE;
1341}
1342
1343/* [MS-RPCH] 2.2.3.5.3 ConnectionTimeout */
1344static BOOL rts_connection_timeout_command_read(WINPR_ATTR_UNUSED rdpRpc* rpc, wStream* buffer,
1345 UINT32* ConnectionTimeout)
1346{
1347 WINPR_ASSERT(rpc);
1348 WINPR_ASSERT(buffer);
1349
1350 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 8))
1351 return FALSE;
1352
1353 const uint32_t CommandType = Stream_Get_UINT32(buffer);
1354 if (CommandType != RTS_CMD_CONNECTION_TIMEOUT)
1355 {
1356 WLog_Print(rpc->log, WLOG_ERROR,
1357 "[MS-RPCH] 2.2.3.5.3 ConnectionTimeout::CommandType must be 0x08" PRIx32 ", got "
1358 "0x%08" PRIx32,
1359 RTS_CMD_CONNECTION_TIMEOUT, CommandType);
1360 return FALSE;
1361 }
1362 const UINT32 val = Stream_Get_UINT32(buffer);
1363 if (ConnectionTimeout)
1364 *ConnectionTimeout = val; /* ConnectionTimeout (4 bytes) */
1365
1366 return TRUE;
1367}
1368
1369static BOOL rts_cookie_command_write(wStream* s, const BYTE* Cookie)
1370{
1371 WINPR_ASSERT(s);
1372
1373 if (!Stream_EnsureRemainingCapacity(s, 20))
1374 return FALSE;
1375
1376 Stream_Write_UINT32(s, RTS_CMD_COOKIE); /* CommandType (4 bytes) */
1377 Stream_Write(s, Cookie, 16); /* Cookie (16 bytes) */
1378
1379 return TRUE;
1380}
1381
1382static BOOL rts_channel_lifetime_command_write(wStream* s, UINT32 ChannelLifetime)
1383{
1384 WINPR_ASSERT(s);
1385
1386 if (!Stream_EnsureRemainingCapacity(s, 8))
1387 return FALSE;
1388 Stream_Write_UINT32(s, RTS_CMD_CHANNEL_LIFETIME); /* CommandType (4 bytes) */
1389 Stream_Write_UINT32(s, ChannelLifetime); /* ChannelLifetime (4 bytes) */
1390
1391 return TRUE;
1392}
1393
1394static BOOL rts_client_keepalive_command_write(wStream* s, UINT32 ClientKeepalive)
1395{
1396 WINPR_ASSERT(s);
1397
1398 if (!Stream_EnsureRemainingCapacity(s, 8))
1399 return FALSE;
1406 Stream_Write_UINT32(s, RTS_CMD_CLIENT_KEEPALIVE); /* CommandType (4 bytes) */
1407 Stream_Write_UINT32(s, ClientKeepalive); /* ClientKeepalive (4 bytes) */
1408
1409 return TRUE;
1410}
1411
1412/* [MS-RPCH] 2.2.3.5.7 Version */
1413static BOOL rts_version_command_read(rdpRpc* rpc, wStream* buffer, uint32_t* pversion)
1414{
1415 WINPR_ASSERT(rpc);
1416 WINPR_ASSERT(buffer);
1417
1418 if (!Stream_EnsureRemainingCapacity(buffer, 8))
1419 return FALSE;
1420
1421 const uint32_t CommandType = Stream_Get_UINT32(buffer); /* CommandType (4 bytes) */
1422 if (CommandType != RTS_CMD_VERSION)
1423 {
1424 WLog_Print(rpc->log, WLOG_ERROR,
1425 "[MS-RPCH] 2.2.3.5.7 Version::CommandType must be 0x08" PRIx32 ", got "
1426 "0x%08" PRIx32,
1427 RTS_CMD_VERSION, CommandType);
1428 return FALSE;
1429 }
1430 const uint32_t version = Stream_Get_UINT32(buffer); /* Version (4 bytes) */
1431 if (version != 1)
1432 {
1433 WLog_Print(rpc->log, WLOG_WARN,
1434 "[MS-RPCH] 2.2.3.5.7 Version::Version should be 0x00000001, got 0x%08" PRIx32,
1435 version);
1436 }
1437 if (pversion)
1438 *pversion = version;
1439
1440 return TRUE;
1441}
1442
1443/* [MS-RPCH] 2.2.3.5.7 Version */
1444static BOOL rts_version_command_write(wStream* buffer)
1445{
1446 WINPR_ASSERT(buffer);
1447
1448 if (!Stream_EnsureRemainingCapacity((buffer), 8))
1449 return FALSE;
1450
1451 Stream_Write_UINT32(buffer, RTS_CMD_VERSION); /* CommandType (4 bytes) */
1452 Stream_Write_UINT32(buffer, 1); /* Version (4 bytes) */
1453
1454 return TRUE;
1455}
1456
1457static BOOL rts_empty_command_write(wStream* s)
1458{
1459 WINPR_ASSERT(s);
1460
1461 if (!Stream_EnsureRemainingCapacity(s, 8))
1462 return FALSE;
1463
1464 Stream_Write_UINT32(s, RTS_CMD_EMPTY); /* CommandType (4 bytes) */
1465
1466 return TRUE;
1467}
1468
1469static BOOL rts_padding_command_read(wStream* s, size_t* length, BOOL silent)
1470{
1471 UINT32 ConformanceCount = 0;
1472 WINPR_ASSERT(s);
1473 WINPR_ASSERT(length);
1474 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
1475 return FALSE;
1476 Stream_Read_UINT32(s, ConformanceCount); /* ConformanceCount (4 bytes) */
1477 *length = ConformanceCount + 4;
1478 return TRUE;
1479}
1480
1481static BOOL rts_client_address_command_read(wStream* s, size_t* length, BOOL silent)
1482{
1483 UINT32 AddressType = 0;
1484
1485 WINPR_ASSERT(s);
1486 WINPR_ASSERT(length);
1487
1488 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
1489 return FALSE;
1490 Stream_Read_UINT32(s, AddressType); /* AddressType (4 bytes) */
1491
1492 if (AddressType == 0)
1493 {
1494 /* ClientAddress (4 bytes) */
1495 /* padding (12 bytes) */
1496 *length = 4 + 4 + 12;
1497 }
1498 else
1499 {
1500 /* ClientAddress (16 bytes) */
1501 /* padding (12 bytes) */
1502 *length = 4 + 16 + 12;
1503 }
1504 return TRUE;
1505}
1506
1507static BOOL rts_association_group_id_command_write(wStream* s, const BYTE* AssociationGroupId)
1508{
1509 WINPR_ASSERT(s);
1510
1511 if (!Stream_EnsureRemainingCapacity(s, 20))
1512 return FALSE;
1513
1514 Stream_Write_UINT32(s, RTS_CMD_ASSOCIATION_GROUP_ID); /* CommandType (4 bytes) */
1515 Stream_Write(s, AssociationGroupId, 16); /* AssociationGroupId (16 bytes) */
1516
1517 return TRUE;
1518}
1519
1520static int rts_destination_command_read(WINPR_ATTR_UNUSED rdpRpc* rpc, wStream* buffer,
1521 UINT32* Destination)
1522{
1523 UINT32 val = 0;
1524 WINPR_ASSERT(rpc);
1525 WINPR_ASSERT(buffer);
1526
1527 if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 4))
1528 return -1;
1529 Stream_Read_UINT32(buffer, val);
1530 if (Destination)
1531 *Destination = val; /* Destination (4 bytes) */
1532
1533 return 4;
1534}
1535
1536static BOOL rts_destination_command_write(wStream* s, UINT32 Destination)
1537{
1538 WINPR_ASSERT(s);
1539
1540 if (!Stream_EnsureRemainingCapacity(s, 8))
1541 return FALSE;
1542
1543 Stream_Write_UINT32(s, RTS_CMD_DESTINATION); /* CommandType (4 bytes) */
1544 Stream_Write_UINT32(s, Destination); /* Destination (4 bytes) */
1545
1546 return TRUE;
1547}
1548
1549void rts_generate_cookie(BYTE* cookie)
1550{
1551 WINPR_ASSERT(cookie);
1552 winpr_RAND(cookie, 16);
1553}
1554
1555#define rts_send_buffer(channel, s, frag_length) \
1556 rts_send_buffer_int((channel), (s), (frag_length), __FILE__, __LINE__, __func__)
1557static BOOL rts_send_buffer_int(RpcChannel* channel, wStream* s, size_t frag_length,
1558 const char* file, size_t line, const char* fkt)
1559{
1560 BOOL status = FALSE;
1561 SSIZE_T rc = 0;
1562
1563 WINPR_ASSERT(channel);
1564 WINPR_ASSERT(channel->rpc);
1565 WINPR_ASSERT(s);
1566
1567 Stream_SealLength(s);
1568
1569 const DWORD level = WLOG_TRACE;
1570 if (WLog_IsLevelActive(channel->rpc->log, level))
1571 {
1572 WLog_PrintMessage(channel->rpc->log, WLOG_MESSAGE_TEXT, level, line, file, fkt,
1573 "Sending [%s] %" PRIuz " bytes", fkt, Stream_Length(s));
1574 }
1575 if (Stream_Length(s) < sizeof(rpcconn_common_hdr_t))
1576 goto fail;
1577 if (Stream_Length(s) != frag_length)
1578 goto fail;
1579
1580 rc = rpc_channel_write(channel, Stream_Buffer(s), Stream_Length(s));
1581 if (rc < 0)
1582 goto fail;
1583 if ((size_t)rc != Stream_Length(s))
1584 goto fail;
1585 status = TRUE;
1586fail:
1587 return status;
1588}
1589
1590/* CONN/A Sequence */
1591
1592BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc)
1593{
1594 BOOL status = FALSE;
1595 wStream* buffer = NULL;
1596 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1597 UINT32 ReceiveWindowSize = 0;
1598 BYTE* OUTChannelCookie = NULL;
1599 BYTE* VirtualConnectionCookie = NULL;
1600 RpcVirtualConnection* connection = NULL;
1601 RpcOutChannel* outChannel = NULL;
1602
1603 WINPR_ASSERT(rpc);
1604
1605 connection = rpc->VirtualConnection;
1606 WINPR_ASSERT(connection);
1607
1608 outChannel = connection->DefaultOutChannel;
1609 WINPR_ASSERT(outChannel);
1610
1611 header.header.frag_length = 76;
1612 header.Flags = RTS_FLAG_NONE;
1613 header.NumberOfCommands = 4;
1614
1615 WLog_DBG(TAG, "Sending CONN/A1 RTS PDU");
1616 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
1617 OUTChannelCookie = (BYTE*)&(outChannel->common.Cookie);
1618 ReceiveWindowSize = outChannel->ReceiveWindow;
1619
1620 buffer = Stream_New(NULL, header.header.frag_length);
1621
1622 if (!buffer)
1623 return -1;
1624
1625 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1626 goto fail;
1627 status = rts_version_command_write(buffer); /* Version (8 bytes) */
1628 if (!status)
1629 goto fail;
1630 status = rts_cookie_command_write(
1631 buffer, VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */
1632 if (!status)
1633 goto fail;
1634 status = rts_cookie_command_write(buffer, OUTChannelCookie); /* OUTChannelCookie (20 bytes) */
1635 if (!status)
1636 goto fail;
1637 status = rts_receive_window_size_command_write(
1638 buffer, ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
1639 if (!status)
1640 goto fail;
1641 status = rts_send_buffer(&outChannel->common, buffer, header.header.frag_length);
1642fail:
1643 Stream_Free(buffer, TRUE);
1644 return status;
1645}
1646
1647BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer)
1648{
1649 BOOL rc = FALSE;
1650 UINT32 ConnectionTimeout = 0;
1651
1652 rpcconn_hdr_t header = { 0 };
1653 if (!rts_read_pdu_header(buffer, &header))
1654 goto fail;
1655
1656 if (header.rts.Flags != RTS_FLAG_NONE)
1657 {
1658 WLog_Print(rpc->log, WLOG_ERROR,
1659 "[MS-RPCH] 2.2.4.4 CONN/A3 RTS PDU unexpected Flags=0x%08" PRIx32
1660 ", expected 0x%08" PRIx32,
1661 header.rts.Flags, RTS_FLAG_NONE);
1662 goto fail;
1663 }
1664 if (header.rts.NumberOfCommands != 1)
1665 {
1666 WLog_Print(rpc->log, WLOG_ERROR,
1667 "[MS-RPCH] 2.2.4.4 CONN/A3 RTS PDU unexpected NumberOfCommands=%" PRIu32
1668 ", expected 1",
1669 header.rts.NumberOfCommands);
1670 goto fail;
1671 }
1672
1673 if (!rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout))
1674 goto fail;
1675
1676 WLog_Print(rpc->log, WLOG_DEBUG, "Receiving CONN/A3 RTS PDU: ConnectionTimeout: %" PRIu32 "",
1677 ConnectionTimeout);
1678
1679 WINPR_ASSERT(rpc);
1680 WINPR_ASSERT(rpc->VirtualConnection);
1681 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1682
1683 rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
1684
1685 rc = TRUE;
1686
1687fail:
1688 rts_free_pdu_header(&header, FALSE);
1689 return rc;
1690}
1691
1692/* CONN/B Sequence */
1693
1694BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc)
1695{
1696 BOOL status = FALSE;
1697 wStream* buffer = NULL;
1698 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1699 BYTE* INChannelCookie = NULL;
1700 BYTE* AssociationGroupId = NULL;
1701 BYTE* VirtualConnectionCookie = NULL;
1702 RpcVirtualConnection* connection = NULL;
1703 RpcInChannel* inChannel = NULL;
1704
1705 WINPR_ASSERT(rpc);
1706
1707 connection = rpc->VirtualConnection;
1708 WINPR_ASSERT(connection);
1709
1710 inChannel = connection->DefaultInChannel;
1711 WINPR_ASSERT(inChannel);
1712
1713 header.header.frag_length = 104;
1714 header.Flags = RTS_FLAG_NONE;
1715 header.NumberOfCommands = 6;
1716
1717 WLog_DBG(TAG, "Sending CONN/B1 RTS PDU");
1718
1719 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
1720 INChannelCookie = (BYTE*)&(inChannel->common.Cookie);
1721 AssociationGroupId = (BYTE*)&(connection->AssociationGroupId);
1722 buffer = Stream_New(NULL, header.header.frag_length);
1723
1724 if (!buffer)
1725 goto fail;
1726 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1727 goto fail;
1728 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
1729 goto fail;
1730 if (!rts_cookie_command_write(buffer,
1731 VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */
1732 goto fail;
1733 if (!rts_cookie_command_write(buffer, INChannelCookie)) /* INChannelCookie (20 bytes) */
1734 goto fail;
1735 if (!rts_channel_lifetime_command_write(buffer,
1736 rpc->ChannelLifetime)) /* ChannelLifetime (8 bytes) */
1737 goto fail;
1738 if (!rts_client_keepalive_command_write(buffer,
1739 rpc->KeepAliveInterval)) /* ClientKeepalive (8 bytes) */
1740 goto fail;
1741 if (!rts_association_group_id_command_write(
1742 buffer, AssociationGroupId)) /* AssociationGroupId (20 bytes) */
1743 goto fail;
1744 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
1745fail:
1746 Stream_Free(buffer, TRUE);
1747 return status;
1748}
1749
1750/* [MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU */
1751
1752BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer)
1753{
1754 BOOL rc = FALSE;
1755 UINT32 ReceiveWindowSize = 0;
1756 UINT32 ConnectionTimeout = 0;
1757
1758 WINPR_ASSERT(rpc);
1759 WINPR_ASSERT(buffer);
1760
1761 rpcconn_hdr_t header = { 0 };
1762 if (!rts_read_pdu_header(buffer, &header))
1763 goto fail;
1764
1765 if (header.rts.Flags != RTS_FLAG_NONE)
1766 {
1767 WLog_Print(rpc->log, WLOG_ERROR,
1768 "[MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU unexpected Flags=0x%08" PRIx32
1769 ", expected 0x%08" PRIx32,
1770 header.rts.Flags, RTS_FLAG_NONE);
1771 goto fail;
1772 }
1773 if (header.rts.NumberOfCommands != 3)
1774 {
1775 WLog_Print(rpc->log, WLOG_ERROR,
1776 "[MS-RPCH] 2.2.4.9 CONN/C2 RTS PDU unexpected NumberOfCommands=%" PRIu32
1777 ", expected 3",
1778 header.rts.NumberOfCommands);
1779 goto fail;
1780 }
1781 if (!rts_version_command_read(rpc, buffer, NULL))
1782 goto fail;
1783
1784 if (!rts_receive_window_size_command_read(rpc, buffer, &ReceiveWindowSize))
1785 goto fail;
1786
1787 if (!rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout))
1788 goto fail;
1789
1790 WLog_Print(rpc->log, WLOG_DEBUG,
1791 "Receiving CONN/C2 RTS PDU: ConnectionTimeout: %" PRIu32
1792 " ReceiveWindowSize: %" PRIu32 "",
1793 ConnectionTimeout, ReceiveWindowSize);
1794
1795 WINPR_ASSERT(rpc);
1796 WINPR_ASSERT(rpc->VirtualConnection);
1797 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1798
1799 rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout;
1800 rpc->VirtualConnection->DefaultInChannel->PeerReceiveWindow = ReceiveWindowSize;
1801
1802 rc = TRUE;
1803
1804fail:
1805 rts_free_pdu_header(&header, FALSE);
1806 return rc;
1807}
1808
1809/* Out-of-Sequence PDUs */
1810
1811BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc)
1812{
1813 BOOL status = FALSE;
1814 wStream* buffer = NULL;
1815 rpcconn_rts_hdr_t header = rts_pdu_header_init();
1816 UINT32 BytesReceived = 0;
1817 UINT32 AvailableWindow = 0;
1818 BYTE* ChannelCookie = NULL;
1819 RpcVirtualConnection* connection = NULL;
1820 RpcInChannel* inChannel = NULL;
1821 RpcOutChannel* outChannel = NULL;
1822
1823 WINPR_ASSERT(rpc);
1824
1825 connection = rpc->VirtualConnection;
1826 WINPR_ASSERT(connection);
1827
1828 inChannel = connection->DefaultInChannel;
1829 WINPR_ASSERT(inChannel);
1830
1831 outChannel = connection->DefaultOutChannel;
1832 WINPR_ASSERT(outChannel);
1833
1834 header.header.frag_length = 56;
1835 header.Flags = RTS_FLAG_OTHER_CMD;
1836 header.NumberOfCommands = 2;
1837
1838 WLog_DBG(TAG, "Sending FlowControlAck RTS PDU");
1839
1840 BytesReceived = outChannel->BytesReceived;
1841 AvailableWindow = outChannel->AvailableWindowAdvertised;
1842 ChannelCookie = (BYTE*)&(outChannel->common.Cookie);
1843 outChannel->ReceiverAvailableWindow = outChannel->AvailableWindowAdvertised;
1844 buffer = Stream_New(NULL, header.header.frag_length);
1845
1846 if (!buffer)
1847 goto fail;
1848
1849 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
1850 goto fail;
1851 if (!rts_destination_command_write(buffer, FDOutProxy)) /* Destination Command (8 bytes) */
1852 goto fail;
1853
1854 /* FlowControlAck Command (28 bytes) */
1855 if (!rts_flow_control_ack_command_write(buffer, BytesReceived, AvailableWindow, ChannelCookie))
1856 goto fail;
1857
1858 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
1859fail:
1860 Stream_Free(buffer, TRUE);
1861 return status;
1862}
1863
1864static int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, wStream* buffer)
1865{
1866 int rc = 0;
1867 UINT32 BytesReceived = 0;
1868 UINT32 AvailableWindow = 0;
1869 BYTE ChannelCookie[16] = { 0 };
1870
1871 rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow,
1872 (BYTE*)&ChannelCookie);
1873 if (rc < 0)
1874 return rc;
1875 WLog_ERR(TAG,
1876 "Receiving FlowControlAck RTS PDU: BytesReceived: %" PRIu32
1877 " AvailableWindow: %" PRIu32 "",
1878 BytesReceived, AvailableWindow);
1879
1880 WINPR_ASSERT(rpc->VirtualConnection);
1881 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1882
1883 rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
1884 AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
1885 return 1;
1886}
1887
1888static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, wStream* buffer)
1889{
1890 UINT32 Command = 0;
1891 UINT32 Destination = 0;
1892 UINT32 BytesReceived = 0;
1893 UINT32 AvailableWindow = 0;
1894 BYTE ChannelCookie[16] = { 0 };
1912 int rc = rts_destination_command_read(rpc, buffer, &Command);
1913 if (rc < 0)
1914 return rc;
1915
1916 if (Command != RTS_CMD_DESTINATION)
1917 {
1918 char buffer1[64] = { 0 };
1919 char buffer2[64] = { 0 };
1920 WLog_Print(rpc->log, WLOG_ERROR, "got command %s, expected %s",
1921 rts_command_to_string(Command, buffer1, sizeof(buffer1)),
1922 rts_command_to_string(RTS_CMD_DESTINATION, buffer2, sizeof(buffer2)));
1923 return -1;
1924 }
1925
1926 rc = rts_destination_command_read(rpc, buffer, &Destination);
1927 if (rc < 0)
1928 return rc;
1929
1930 switch (Destination)
1931 {
1932 case FDClient:
1933 break;
1934 case FDInProxy:
1935 break;
1936 case FDServer:
1937 break;
1938 case FDOutProxy:
1939 break;
1940 default:
1941 WLog_Print(rpc->log, WLOG_ERROR,
1942 "got destination %" PRIu32
1943 ", expected one of [FDClient[0]|FDInProxy[1]|FDServer[2]|FDOutProxy[3]",
1944 Destination);
1945 return -1;
1946 }
1947
1948 rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow,
1949 ChannelCookie);
1950 if (rc < 0)
1951 return rc;
1952
1953 WLog_DBG(TAG,
1954 "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %" PRIu32
1955 " AvailableWindow: %" PRIu32 "",
1956 BytesReceived, AvailableWindow);
1957
1958 WINPR_ASSERT(rpc->VirtualConnection);
1959 WINPR_ASSERT(rpc->VirtualConnection->DefaultInChannel);
1960 rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =
1961 AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived);
1962 return 1;
1963}
1964
1965BOOL rts_recv_ping_pdu(rdpRpc* rpc, wStream* s)
1966{
1967 BOOL rc = FALSE;
1968 rpcconn_hdr_t header = { 0 };
1969
1970 WINPR_ASSERT(rpc);
1971 WINPR_ASSERT(rpc->auth);
1972 WINPR_ASSERT(s);
1973
1974 if (!rts_read_pdu_header(s, &header))
1975 goto fail;
1976
1977 rc = TRUE;
1978 if (header.common.ptype != PTYPE_RTS)
1979 {
1980 WLog_Print(rpc->log, WLOG_ERROR, "received invalid ping PDU, type is 0x%" PRIx32,
1981 header.common.ptype);
1982 rc = FALSE;
1983 }
1984 if (header.rts.Flags != RTS_FLAG_PING)
1985 {
1986 WLog_Print(rpc->log, WLOG_ERROR, "received unexpected ping PDU::Flags 0x%" PRIx32,
1987 header.rts.Flags);
1988 rc = FALSE;
1989 }
1990fail:
1991 rts_free_pdu_header(&header, FALSE);
1992 return rc;
1993}
1994
1995static int rts_send_ping_pdu(rdpRpc* rpc)
1996{
1997 BOOL status = FALSE;
1998 wStream* buffer = NULL;
1999 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2000 RpcInChannel* inChannel = NULL;
2001
2002 WINPR_ASSERT(rpc);
2003 WINPR_ASSERT(rpc->VirtualConnection);
2004
2005 inChannel = rpc->VirtualConnection->DefaultInChannel;
2006 WINPR_ASSERT(inChannel);
2007
2008 header.header.frag_length = 20;
2009 header.Flags = RTS_FLAG_PING;
2010 header.NumberOfCommands = 0;
2011
2012 WLog_DBG(TAG, "Sending Ping RTS PDU");
2013 buffer = Stream_New(NULL, header.header.frag_length);
2014
2015 if (!buffer)
2016 goto fail;
2017
2018 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2019 goto fail;
2020 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
2021fail:
2022 Stream_Free(buffer, TRUE);
2023 return (status) ? 1 : -1;
2024}
2025
2026BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length, BOOL silent)
2027{
2028 size_t padding = 0;
2029 size_t CommandLength = 0;
2030
2031 WINPR_ASSERT(s);
2032
2033 switch (CommandType)
2034 {
2035 case RTS_CMD_RECEIVE_WINDOW_SIZE:
2036 CommandLength = RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH;
2037 break;
2038
2039 case RTS_CMD_FLOW_CONTROL_ACK:
2040 CommandLength = RTS_CMD_FLOW_CONTROL_ACK_LENGTH;
2041 break;
2042
2043 case RTS_CMD_CONNECTION_TIMEOUT:
2044 CommandLength = RTS_CMD_CONNECTION_TIMEOUT_LENGTH;
2045 break;
2046
2047 case RTS_CMD_COOKIE:
2048 CommandLength = RTS_CMD_COOKIE_LENGTH;
2049 break;
2050
2051 case RTS_CMD_CHANNEL_LIFETIME:
2052 CommandLength = RTS_CMD_CHANNEL_LIFETIME_LENGTH;
2053 break;
2054
2055 case RTS_CMD_CLIENT_KEEPALIVE:
2056 CommandLength = RTS_CMD_CLIENT_KEEPALIVE_LENGTH;
2057 break;
2058
2059 case RTS_CMD_VERSION:
2060 CommandLength = RTS_CMD_VERSION_LENGTH;
2061 break;
2062
2063 case RTS_CMD_EMPTY:
2064 CommandLength = RTS_CMD_EMPTY_LENGTH;
2065 break;
2066
2067 case RTS_CMD_PADDING: /* variable-size */
2068 if (!rts_padding_command_read(s, &padding, silent))
2069 return FALSE;
2070 break;
2071
2072 case RTS_CMD_NEGATIVE_ANCE:
2073 CommandLength = RTS_CMD_NEGATIVE_ANCE_LENGTH;
2074 break;
2075
2076 case RTS_CMD_ANCE:
2077 CommandLength = RTS_CMD_ANCE_LENGTH;
2078 break;
2079
2080 case RTS_CMD_CLIENT_ADDRESS: /* variable-size */
2081 if (!rts_client_address_command_read(s, &CommandLength, silent))
2082 return FALSE;
2083 break;
2084
2085 case RTS_CMD_ASSOCIATION_GROUP_ID:
2086 CommandLength = RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH;
2087 break;
2088
2089 case RTS_CMD_DESTINATION:
2090 CommandLength = RTS_CMD_DESTINATION_LENGTH;
2091 break;
2092
2093 case RTS_CMD_PING_TRAFFIC_SENT_NOTIFY:
2094 CommandLength = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH;
2095 break;
2096
2097 default:
2098 WLog_ERR(TAG, "Error: Unknown RTS Command Type: 0x%" PRIx32 "", CommandType);
2099 return FALSE;
2100 }
2101
2102 CommandLength += padding;
2103 if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, CommandLength, silent))
2104 return FALSE;
2105
2106 if (length)
2107 *length = CommandLength;
2108 return TRUE;
2109}
2110
2111static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
2112{
2113 BOOL status = FALSE;
2114 wStream* buffer = NULL;
2115 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2116 BYTE* SuccessorChannelCookie = NULL;
2117 RpcInChannel* inChannel = NULL;
2118 RpcOutChannel* nextOutChannel = NULL;
2119
2120 WINPR_ASSERT(rpc);
2121 WINPR_ASSERT(rpc->VirtualConnection);
2122
2123 inChannel = rpc->VirtualConnection->DefaultInChannel;
2124 WINPR_ASSERT(inChannel);
2125
2126 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
2127 WINPR_ASSERT(nextOutChannel);
2128
2129 header.header.frag_length = 56;
2130 header.Flags = RTS_FLAG_OUT_CHANNEL;
2131 header.NumberOfCommands = 3;
2132
2133 WLog_DBG(TAG, "Sending OUT_R2/A7 RTS PDU");
2134
2135 SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
2136 buffer = Stream_New(NULL, header.header.frag_length);
2137
2138 if (!buffer)
2139 return -1;
2140
2141 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2142 goto fail;
2143 if (!rts_destination_command_write(buffer, FDServer)) /* Destination (8 bytes)*/
2144 goto fail;
2145 if (!rts_cookie_command_write(buffer,
2146 SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */
2147 goto fail;
2148 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
2149 goto fail;
2150 status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length);
2151fail:
2152 Stream_Free(buffer, TRUE);
2153 return (status) ? 1 : -1;
2154}
2155
2156static int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
2157{
2158 BOOL status = FALSE;
2159 wStream* buffer = NULL;
2160 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2161 RpcOutChannel* nextOutChannel = NULL;
2162
2163 WINPR_ASSERT(rpc);
2164 WINPR_ASSERT(rpc->VirtualConnection);
2165
2166 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
2167 WINPR_ASSERT(nextOutChannel);
2168
2169 header.header.frag_length = 24;
2170 header.Flags = RTS_FLAG_PING;
2171 header.NumberOfCommands = 1;
2172
2173 WLog_DBG(TAG, "Sending OUT_R2/C1 RTS PDU");
2174 buffer = Stream_New(NULL, header.header.frag_length);
2175
2176 if (!buffer)
2177 return -1;
2178
2179 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2180 goto fail;
2181
2182 if (!rts_empty_command_write(buffer)) /* Empty command (4 bytes) */
2183 goto fail;
2184 status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length);
2185fail:
2186 Stream_Free(buffer, TRUE);
2187 return (status) ? 1 : -1;
2188}
2189
2190BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
2191{
2192 BOOL status = FALSE;
2193 wStream* buffer = NULL;
2194 rpcconn_rts_hdr_t header = rts_pdu_header_init();
2195 UINT32 ReceiveWindowSize = 0;
2196 BYTE* VirtualConnectionCookie = NULL;
2197 BYTE* PredecessorChannelCookie = NULL;
2198 BYTE* SuccessorChannelCookie = NULL;
2199 RpcVirtualConnection* connection = NULL;
2200 RpcOutChannel* outChannel = NULL;
2201 RpcOutChannel* nextOutChannel = NULL;
2202
2203 WINPR_ASSERT(rpc);
2204
2205 connection = rpc->VirtualConnection;
2206 WINPR_ASSERT(connection);
2207
2208 outChannel = connection->DefaultOutChannel;
2209 WINPR_ASSERT(outChannel);
2210
2211 nextOutChannel = connection->NonDefaultOutChannel;
2212 WINPR_ASSERT(nextOutChannel);
2213
2214 header.header.frag_length = 96;
2215 header.Flags = RTS_FLAG_RECYCLE_CHANNEL;
2216 header.NumberOfCommands = 5;
2217
2218 WLog_DBG(TAG, "Sending OUT_R1/A3 RTS PDU");
2219
2220 VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
2221 PredecessorChannelCookie = (BYTE*)&(outChannel->common.Cookie);
2222 SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
2223 ReceiveWindowSize = outChannel->ReceiveWindow;
2224 buffer = Stream_New(NULL, header.header.frag_length);
2225
2226 if (!buffer)
2227 return -1;
2228
2229 if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */
2230 goto fail;
2231 if (!rts_version_command_write(buffer)) /* Version (8 bytes) */
2232 goto fail;
2233 if (!rts_cookie_command_write(buffer,
2234 VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */
2235 goto fail;
2236 if (!rts_cookie_command_write(
2237 buffer, PredecessorChannelCookie)) /* PredecessorChannelCookie (20 bytes) */
2238 goto fail;
2239 if (!rts_cookie_command_write(buffer,
2240 SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */
2241 goto fail;
2242 if (!rts_receive_window_size_command_write(buffer,
2243 ReceiveWindowSize)) /* ReceiveWindowSize (8 bytes) */
2244 goto fail;
2245
2246 status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length);
2247fail:
2248 Stream_Free(buffer, TRUE);
2249 return status;
2250}
2251
2252static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, wStream* buffer)
2253{
2254 int status = 0;
2255 UINT32 Destination = 0;
2256 RpcVirtualConnection* connection = NULL;
2257 WINPR_ASSERT(rpc);
2258 WINPR_ASSERT(buffer);
2259
2260 connection = rpc->VirtualConnection;
2261 WINPR_ASSERT(connection);
2262
2263 WLog_DBG(TAG, "Receiving OUT R1/A2 RTS PDU");
2264
2265 status = rts_destination_command_read(rpc, buffer, &Destination);
2266 if (status < 0)
2267 return status;
2268
2269 connection->NonDefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
2270
2271 if (!connection->NonDefaultOutChannel)
2272 return -1;
2273
2274 status = rpc_out_channel_replacement_connect(connection->NonDefaultOutChannel, 5000);
2275
2276 if (status < 0)
2277 {
2278 WLog_ERR(TAG, "rpc_out_channel_replacement_connect failure");
2279 return -1;
2280 }
2281
2282 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2283 CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
2284 return 1;
2285}
2286
2287static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, WINPR_ATTR_UNUSED wStream* buffer)
2288{
2289 int status = 0;
2290 RpcVirtualConnection* connection = NULL;
2291
2292 WINPR_ASSERT(rpc);
2293 WINPR_ASSERT(buffer);
2294
2295 connection = rpc->VirtualConnection;
2296 WINPR_ASSERT(connection);
2297
2298 WLog_DBG(TAG, "Receiving OUT R2/A6 RTS PDU");
2299 status = rts_send_OUT_R2_C1_pdu(rpc);
2300
2301 if (status < 0)
2302 {
2303 WLog_ERR(TAG, "rts_send_OUT_R2_C1_pdu failure");
2304 return -1;
2305 }
2306
2307 status = rts_send_OUT_R2_A7_pdu(rpc);
2308
2309 if (status < 0)
2310 {
2311 WLog_ERR(TAG, "rts_send_OUT_R2_A7_pdu failure");
2312 return -1;
2313 }
2314
2315 rpc_out_channel_transition_to_state(connection->NonDefaultOutChannel,
2316 CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
2317 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2318 CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
2319 return 1;
2320}
2321
2322static int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, WINPR_ATTR_UNUSED wStream* buffer)
2323{
2324 RpcVirtualConnection* connection = NULL;
2325
2326 WINPR_ASSERT(rpc);
2327 WINPR_ASSERT(buffer);
2328
2329 connection = rpc->VirtualConnection;
2330 WINPR_ASSERT(connection);
2331
2332 WLog_DBG(TAG, "Receiving OUT R2/B3 RTS PDU");
2333 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
2334 CLIENT_OUT_CHANNEL_STATE_RECYCLED);
2335 return 1;
2336}
2337
2338BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer, const rpcconn_hdr_t* header)
2339{
2340 BOOL status = FALSE;
2341 size_t length = 0;
2342 RtsPduSignature signature = { 0 };
2343 RpcVirtualConnection* connection = NULL;
2344
2345 WINPR_ASSERT(rpc);
2346 WINPR_ASSERT(buffer);
2347 WINPR_ASSERT(header);
2348
2349 wLog* log = WLog_Get(TAG);
2350
2351 const size_t total = Stream_Length(buffer);
2352 length = header->common.frag_length;
2353 if (total < length)
2354 {
2355 WLog_Print(log, WLOG_ERROR, "PDU length %" PRIuz " does not match available data %" PRIuz,
2356 length, total);
2357 return FALSE;
2358 }
2359
2360 connection = rpc->VirtualConnection;
2361
2362 if (!connection)
2363 {
2364 WLog_Print(log, WLOG_ERROR, "not connected, aborting");
2365 return FALSE;
2366 }
2367
2368 if (!rts_extract_pdu_signature(&signature, buffer, header))
2369 return FALSE;
2370
2371 rts_print_pdu_signature(log, WLOG_TRACE, &signature);
2372
2373 if (memcmp(&signature, &RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, sizeof(signature)) == 0)
2374 {
2375 status = rts_recv_flow_control_ack_pdu(rpc, buffer);
2376 }
2377 else if (memcmp(&signature, &RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE,
2378 sizeof(signature)) == 0)
2379 {
2380 status = rts_recv_flow_control_ack_with_destination_pdu(rpc, buffer);
2381 }
2382 else if (memcmp(&signature, &RTS_PDU_PING_SIGNATURE, sizeof(signature)) == 0)
2383 {
2384 status = rts_send_ping_pdu(rpc);
2385 }
2386 else
2387 {
2388 if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
2389 {
2390 if (memcmp(&signature, &RTS_PDU_OUT_R1_A2_SIGNATURE, sizeof(signature)) == 0)
2391 {
2392 status = rts_recv_OUT_R1_A2_pdu(rpc, buffer);
2393 }
2394 }
2395 else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_A6W)
2396 {
2397 if (memcmp(&signature, &RTS_PDU_OUT_R2_A6_SIGNATURE, sizeof(signature)) == 0)
2398 {
2399 status = rts_recv_OUT_R2_A6_pdu(rpc, buffer);
2400 }
2401 }
2402 else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_B3W)
2403 {
2404 if (memcmp(&signature, &RTS_PDU_OUT_R2_B3_SIGNATURE, sizeof(signature)) == 0)
2405 {
2406 status = rts_recv_OUT_R2_B3_pdu(rpc, buffer);
2407 }
2408 }
2409 }
2410
2411 if (!status)
2412 {
2413 const UINT32 SignatureId = rts_identify_pdu_signature(&signature, NULL);
2414 WLog_Print(log, WLOG_ERROR, "error parsing RTS PDU with signature id: 0x%08" PRIX32 "",
2415 SignatureId);
2416 rts_print_pdu_signature(log, WLOG_ERROR, &signature);
2417 }
2418
2419 const size_t rem = Stream_GetRemainingLength(buffer);
2420 if (rem > 0)
2421 {
2422 WLog_Print(log, WLOG_ERROR, "%" PRIuz " bytes or %" PRIuz " total not parsed, aborting",
2423 rem, total);
2424 rts_print_pdu_signature(log, WLOG_ERROR, &signature);
2425 return FALSE;
2426 }
2427
2428 return status;
2429}
2430
2431BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth)
2432{
2433 WINPR_ASSERT(s);
2434 WINPR_ASSERT(auth);
2435
2436 if (!rts_write_common_pdu_header(s, &auth->header))
2437 return FALSE;
2438
2439 if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16)))
2440 return FALSE;
2441
2442 Stream_Write_UINT16(s, auth->max_xmit_frag);
2443 Stream_Write_UINT16(s, auth->max_recv_frag);
2444
2445 return rts_write_auth_verifier(s, &auth->auth_verifier, &auth->header);
2446}
2447
2448BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind)
2449{
2450
2451 WINPR_ASSERT(s);
2452 WINPR_ASSERT(bind);
2453
2454 if (!rts_write_common_pdu_header(s, &bind->header))
2455 return FALSE;
2456
2457 if (!Stream_EnsureRemainingCapacity(s, 8))
2458 return FALSE;
2459
2460 Stream_Write_UINT16(s, bind->max_xmit_frag);
2461 Stream_Write_UINT16(s, bind->max_recv_frag);
2462 Stream_Write_UINT32(s, bind->assoc_group_id);
2463
2464 if (!rts_write_context_list(s, &bind->p_context_elem))
2465 return FALSE;
2466
2467 return rts_write_auth_verifier(s, &bind->auth_verifier, &bind->header);
2468}
2469
2470BOOL rts_conditional_check_and_log(const char* tag, wStream* s, size_t size, BOOL silent,
2471 const char* fkt, const char* file, size_t line)
2472{
2473 if (silent)
2474 {
2475 const size_t rem = Stream_GetRemainingLength(s);
2476 if (rem < size)
2477 return FALSE;
2478 return TRUE;
2479 }
2480
2481 return Stream_CheckAndLogRequiredLengthEx(tag, WLOG_WARN, s, size, 1, "%s(%s:%" PRIuz ")", fkt,
2482 file, line);
2483}
2484
2485BOOL rts_conditional_safe_seek(wStream* s, size_t size, BOOL silent, const char* fkt,
2486 const char* file, size_t line)
2487{
2488 if (silent)
2489 {
2490 const size_t rem = Stream_GetRemainingLength(s);
2491 if (rem < size)
2492 return FALSE;
2493 }
2494 return Stream_SafeSeekEx(s, size, file, line, fkt);
2495}