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