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