FreeRDP
Loading...
Searching...
No Matches
rpc_client.c
1
20#include <freerdp/config.h>
21
22#include <freerdp/log.h>
23
24#include <winpr/crt.h>
25#include <winpr/wtypes.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
28#include <winpr/print.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
32
33#include "http.h"
34#include "ncacn_http.h"
35
36#include "rpc_bind.h"
37#include "rpc_fault.h"
38#include "rpc_client.h"
39#include "rts_signature.h"
40
41#include "../utils.h"
42#include "../rdp.h"
43#include "../proxy.h"
44
45#define TAG FREERDP_TAG("core.gateway.rpc")
46
47WINPR_ATTR_NODISCARD
48static const char* rpc_client_state_str(RPC_CLIENT_STATE state)
49{
50 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
51 const char* str = "RPC_CLIENT_STATE_UNKNOWN";
52
53 switch (state)
54 {
55 case RPC_CLIENT_STATE_INITIAL:
56 str = "RPC_CLIENT_STATE_INITIAL";
57 break;
58
59 case RPC_CLIENT_STATE_ESTABLISHED:
60 str = "RPC_CLIENT_STATE_ESTABLISHED";
61 break;
62
63 case RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK:
64 str = "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK";
65 break;
66
67 case RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK:
68 str = "RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK";
69 break;
70
71 case RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE:
72 str = "RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE";
73 break;
74
75 case RPC_CLIENT_STATE_CONTEXT_NEGOTIATED:
76 str = "RPC_CLIENT_STATE_CONTEXT_NEGOTIATED";
77 break;
78
79 case RPC_CLIENT_STATE_WAIT_RESPONSE:
80 str = "RPC_CLIENT_STATE_WAIT_RESPONSE";
81 break;
82
83 case RPC_CLIENT_STATE_FINAL:
84 str = "RPC_CLIENT_STATE_FINAL";
85 break;
86 default:
87 break;
88 }
89 return str;
90}
91
92WINPR_ATTR_NODISCARD
93static BOOL rpc_pdu_reset(RPC_PDU* pdu)
94{
95 WINPR_ASSERT(pdu);
96 pdu->Type = 0;
97 pdu->Flags = 0;
98 pdu->CallId = 0;
99 Stream_ResetPosition(pdu->s);
100 return Stream_SetLength(pdu->s, 0);
101}
102
103static void rpc_pdu_free(RPC_PDU* pdu)
104{
105 if (!pdu)
106 return;
107
108 Stream_Free(pdu->s, TRUE);
109 free(pdu);
110}
111
112WINPR_ATTR_MALLOC(rpc_pdu_free, 1)
113static RPC_PDU* rpc_pdu_new(void)
114{
115 RPC_PDU* pdu = (RPC_PDU*)calloc(1, sizeof(RPC_PDU));
116
117 if (!pdu)
118 return nullptr;
119
120 pdu->s = Stream_New(nullptr, 4096);
121
122 if (!pdu->s)
123 goto fail;
124
125 if (!rpc_pdu_reset(pdu))
126 goto fail;
127
128 return pdu;
129
130fail:
131 rpc_pdu_free(pdu);
132 return nullptr;
133}
134
135WINPR_ATTR_NODISCARD
136static int rpc_client_receive_pipe_write(RpcClient* client, const BYTE* buffer, size_t length)
137{
138 int status = 0;
139
140 if (!client || !buffer)
141 return -1;
142
143 EnterCriticalSection(&(client->PipeLock));
144
145 if (ringbuffer_write(&(client->ReceivePipe), buffer, length))
146 status += (int)length;
147
148 if (ringbuffer_used(&(client->ReceivePipe)) > 0)
149 (void)SetEvent(client->PipeEvent);
150
151 LeaveCriticalSection(&(client->PipeLock));
152 return status;
153}
154
155int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length)
156{
157 size_t status = 0;
158 int nchunks = 0;
159 DataChunk chunks[2];
160
161 if (!client || !buffer)
162 return -1;
163
164 EnterCriticalSection(&(client->PipeLock));
165 nchunks = ringbuffer_peek(&(client->ReceivePipe), chunks, length);
166
167 for (int index = 0; index < nchunks; index++)
168 {
169 CopyMemory(&buffer[status], chunks[index].data, chunks[index].size);
170 status += chunks[index].size;
171 }
172
173 if (status > 0)
174 ringbuffer_commit_read_bytes(&(client->ReceivePipe), status);
175
176 if (ringbuffer_used(&(client->ReceivePipe)) < 1)
177 (void)ResetEvent(client->PipeEvent);
178
179 LeaveCriticalSection(&(client->PipeLock));
180
181 if (status > INT_MAX)
182 return -1;
183 return (int)status;
184}
185
186static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
187{
188 int status = 1;
189
190 rpc->State = state;
191 WLog_DBG(TAG, "%s", rpc_client_state_str(state));
192 return status;
193}
194
195WINPR_ATTR_NODISCARD
196static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu)
197{
198 int status = -1;
199 RtsPduSignature found = WINPR_C_ARRAY_INIT;
200
201 WINPR_ASSERT(rpc);
202 WINPR_ASSERT(pdu);
203
204 rdpTsg* tsg = transport_get_tsg(rpc->transport);
205
206 WLog_Print(rpc->log, WLOG_TRACE, "client state %s, vc state %s",
207 rpc_client_state_str(rpc->State), rpc_vc_state_str(rpc->VirtualConnection->State));
208
209 const BOOL rc =
210 rts_match_pdu_signature_ex(&RTS_PDU_PING_SIGNATURE, pdu->s, nullptr, &found, TRUE);
211 rts_print_pdu_signature(rpc->log, WLOG_TRACE, &found);
212 if (rc)
213 return rts_recv_ping_pdu(rpc, pdu->s);
214
215 if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
216 {
217 switch (rpc->VirtualConnection->State)
218 {
219 case VIRTUAL_CONNECTION_STATE_INITIAL:
220 break;
221
222 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
223 break;
224
225 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
226 if (memcmp(&found, &RTS_PDU_CONN_A3_SIGNATURE, sizeof(found)) != 0)
227 {
228 WLog_Print(rpc->log, WLOG_ERROR, "unexpected RTS PDU: Expected CONN/A3");
229 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
230 return -1;
231 }
232
233 if (!rts_recv_CONN_A3_pdu(rpc, pdu->s))
234 {
235 WLog_Print(rpc->log, WLOG_ERROR, "rts_recv_CONN_A3_pdu failure");
236 return -1;
237 }
238
239 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
240 VIRTUAL_CONNECTION_STATE_WAIT_C2);
241 status = 1;
242 break;
243
244 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
245 if (memcmp(&found, &RTS_PDU_CONN_C2_SIGNATURE, sizeof(found)) != 0)
246 {
247 WLog_Print(rpc->log, WLOG_ERROR, "unexpected RTS PDU: Expected CONN/C2");
248 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
249 return -1;
250 }
251
252 if (!rts_recv_CONN_C2_pdu(rpc, pdu->s))
253 {
254 WLog_Print(rpc->log, WLOG_ERROR, "rts_recv_CONN_C2_pdu failure");
255 return -1;
256 }
257
258 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
259 VIRTUAL_CONNECTION_STATE_OPENED);
260 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_ESTABLISHED);
261
262 if (rpc_send_bind_pdu(rpc, TRUE) < 0)
263 {
264 WLog_Print(rpc->log, WLOG_ERROR, "rpc_send_bind_pdu failure");
265 return -1;
266 }
267
268 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK);
269 status = 1;
270 break;
271
272 case VIRTUAL_CONNECTION_STATE_OPENED:
273 break;
274
275 case VIRTUAL_CONNECTION_STATE_FINAL:
276 break;
277 default:
278 break;
279 }
280 }
281 else if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
282 {
283 if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
284 {
285 if (pdu->Type == PTYPE_BIND_ACK || pdu->Type == PTYPE_ALTER_CONTEXT_RESP)
286 {
287 if (!rpc_recv_bind_ack_pdu(rpc, pdu->s))
288 {
289 WLog_Print(rpc->log, WLOG_ERROR, "rpc_recv_bind_ack_pdu failure");
290 return -1;
291 }
292 }
293 else
294 {
295 WLog_Print(rpc->log, WLOG_ERROR,
296 "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK unexpected pdu type: 0x%08" PRIX32
297 "",
298 pdu->Type);
299 return -1;
300 }
301
302 switch (rpc_bind_state(rpc))
303 {
304 case RPC_BIND_STATE_INCOMPLETE:
305 if (rpc_send_bind_pdu(rpc, FALSE) < 0)
306 {
307 WLog_Print(rpc->log, WLOG_ERROR, "rpc_send_bind_pdu failure");
308 return -1;
309 }
310 break;
311 case RPC_BIND_STATE_LAST_LEG:
312 if (rpc_send_rpc_auth_3_pdu(rpc) < 0)
313 {
314 WLog_Print(rpc->log, WLOG_ERROR,
315 "rpc_secure_bind: error sending rpc_auth_3 pdu!");
316 return -1;
317 }
318 /* fallthrough */
319 WINPR_FALLTHROUGH
320 case RPC_BIND_STATE_COMPLETE:
321 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
322
323 if (!tsg_proxy_begin(tsg))
324 {
325 WLog_Print(rpc->log, WLOG_ERROR, "tsg_proxy_begin failure");
326 return -1;
327 }
328 break;
329 default:
330 break;
331 }
332
333 status = 1;
334 }
335 else
336 {
337 WLog_Print(rpc->log, WLOG_ERROR, "invalid rpc->State: %u", rpc->State);
338 }
339 }
340 else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
341 {
342 if (!tsg_recv_pdu(tsg, pdu))
343 status = -1;
344 else
345 status = 1;
346 }
347
348 return status;
349}
350
351WINPR_ATTR_NODISCARD
352static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
353{
354 WINPR_ASSERT(rpc);
355 WINPR_ASSERT(pdu);
356
357 Stream_SealLength(pdu->s);
358 Stream_ResetPosition(pdu->s);
359
360 const size_t before = Stream_GetRemainingLength(pdu->s);
361 WLog_Print(rpc->log, WLOG_TRACE, "RPC PDU parsing %" PRIuz " bytes", before);
362 const int rc = rpc_client_recv_pdu_int(rpc, pdu);
363 if (rc < 0)
364 return rc;
365 const size_t after = Stream_GetRemainingLength(pdu->s);
366 if (after > 0)
367 {
368 /* Just log so we do not fail if we have some unprocessed padding bytes */
369 WLog_Print(rpc->log, WLOG_WARN, "Incompletely parsed RPC PDU (%" PRIuz " bytes remain)",
370 after);
371 }
372
373 return rc;
374}
375
376WINPR_ATTR_NODISCARD
377static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
378{
379 int rc = -1;
380 size_t StubOffset = 0;
381 size_t StubLength = 0;
382 RpcClientCall* call = nullptr;
383 rpcconn_hdr_t header = WINPR_C_ARRAY_INIT;
384
385 WINPR_ASSERT(rpc);
386 WINPR_ASSERT(rpc->client);
387 WINPR_ASSERT(fragment);
388
389 RPC_PDU* pdu = rpc->client->pdu;
390 WINPR_ASSERT(pdu);
391
392 Stream_SealLength(fragment);
393 Stream_ResetPosition(fragment);
394
395 if (!rts_read_pdu_header(fragment, &header))
396 goto fail;
397
398 if (header.common.ptype == PTYPE_RESPONSE)
399 {
400 rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length;
401 rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
402 header.common.frag_length;
403
404 if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
405 (rpc->ReceiveWindow / 2))
406 {
407 if (!rts_send_flow_control_ack_pdu(rpc))
408 goto fail;
409 }
410
411 if (!rpc_get_stub_data_info(rpc, &header, &StubOffset, &StubLength))
412 {
413 WLog_ERR(TAG, "expected stub");
414 goto fail;
415 }
416
417 if (StubLength == 4)
418 {
419 if ((header.common.call_id == rpc->PipeCallId) &&
420 (header.common.pfc_flags & PFC_LAST_FRAG))
421 {
422 /* End of TsProxySetupReceivePipe */
423 TerminateEventArgs e;
424 rdpContext* context = transport_get_context(rpc->transport);
425 rdpTsg* tsg = transport_get_tsg(rpc->transport);
426
427 WINPR_ASSERT(context);
428
429 if (Stream_Length(fragment) < StubOffset + 4)
430 goto fail;
431 if (!Stream_SetPosition(fragment, StubOffset))
432 goto fail;
433 Stream_Read_UINT32(fragment, rpc->result);
434
435 utils_abort_connect(context->rdp);
436 tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
437 EventArgsInit(&e, "freerdp");
438 e.code = 0;
439 rc = PubSub_OnTerminate(context->rdp->pubSub, context, &e) >= 0 ? 0 : -1;
440 goto success;
441 }
442
443 if (header.common.call_id != rpc->PipeCallId)
444 {
445 /* Ignoring non-TsProxySetupReceivePipe Response */
446 rc = 0;
447 goto success;
448 }
449 }
450
451 if (rpc->StubFragCount == 0)
452 rpc->StubCallId = header.common.call_id;
453
454 if (rpc->StubCallId != header.common.call_id)
455 {
456 WLog_ERR(TAG,
457 "invalid call_id: actual: %" PRIu32 ", expected: %" PRIu32
458 ", frag_count: %" PRIu32 "",
459 rpc->StubCallId, header.common.call_id, rpc->StubFragCount);
460 }
461
462 call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId);
463
464 if (!call)
465 goto fail;
466
467 if (call->OpNum != TsProxySetupReceivePipeOpnum)
468 {
469 const rpcconn_response_hdr_t* response =
470 (const rpcconn_response_hdr_t*)&header.response;
471 if (!Stream_EnsureRemainingCapacity(pdu->s, StubLength))
472 goto fail;
473
474 if (Stream_Length(fragment) < StubOffset + StubLength)
475 goto fail;
476
477 if (!Stream_SetPosition(fragment, StubOffset))
478 goto fail;
479
480 Stream_Write(pdu->s, Stream_ConstPointer(fragment), StubLength);
481 rpc->StubFragCount++;
482
483 if (response->alloc_hint == StubLength)
484 {
485 pdu->Flags = RPC_PDU_FLAG_STUB;
486 pdu->Type = PTYPE_RESPONSE;
487 pdu->CallId = rpc->StubCallId;
488
489 if (rpc_client_recv_pdu(rpc, pdu) < 0)
490 goto fail;
491 if (!rpc_pdu_reset(pdu))
492 goto fail;
493 rpc->StubFragCount = 0;
494 rpc->StubCallId = 0;
495 }
496 }
497 else
498 {
499 const rpcconn_response_hdr_t* response = &header.response;
500 if (Stream_Length(fragment) < StubOffset + StubLength)
501 goto fail;
502 if (!Stream_SetPosition(fragment, StubOffset))
503 goto fail;
504 if (rpc_client_receive_pipe_write(rpc->client, Stream_ConstPointer(fragment),
505 StubLength) < 0)
506 goto fail;
507 rpc->StubFragCount++;
508
509 if (response->alloc_hint == StubLength)
510 {
511 rpc->StubFragCount = 0;
512 rpc->StubCallId = 0;
513 }
514 }
515
516 goto success;
517 }
518 else if (header.common.ptype == PTYPE_RTS)
519 {
520 if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
521 {
522 pdu->Flags = 0;
523 pdu->Type = header.common.ptype;
524 pdu->CallId = header.common.call_id;
525
526 const size_t len = Stream_Length(fragment);
527 if (!Stream_EnsureRemainingCapacity(pdu->s, len))
528 goto fail;
529
530 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
531
532 if (rpc_client_recv_pdu(rpc, pdu) < 0)
533 goto fail;
534
535 if (!rpc_pdu_reset(pdu))
536 goto fail;
537 }
538 else
539 {
540 if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header))
541 goto fail;
542 }
543
544 goto success;
545 }
546 else if (header.common.ptype == PTYPE_BIND_ACK ||
547 header.common.ptype == PTYPE_ALTER_CONTEXT_RESP)
548 {
549 pdu->Flags = 0;
550 pdu->Type = header.common.ptype;
551 pdu->CallId = header.common.call_id;
552
553 const size_t len = Stream_Length(fragment);
554 if (!Stream_EnsureRemainingCapacity(pdu->s, len))
555 goto fail;
556
557 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
558
559 if (rpc_client_recv_pdu(rpc, pdu) < 0)
560 goto fail;
561
562 if (!rpc_pdu_reset(pdu))
563 goto fail;
564 goto success;
565 }
566 else if (header.common.ptype == PTYPE_FAULT)
567 {
568 const rpcconn_fault_hdr_t* fault = (const rpcconn_fault_hdr_t*)&header.fault;
569 rpc_recv_fault_pdu(fault->status);
570 goto fail;
571 }
572 else
573 {
574 WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header.common.ptype);
575 goto fail;
576 }
577
578success:
579 rc = (rc < 0) ? 1 : 0; /* In case of default error return change to 1, otherwise we already set
580 the return code */
581fail:
582 rts_free_pdu_header(&header, FALSE);
583 return rc;
584}
585
586WINPR_ATTR_NODISCARD
587static SSIZE_T rpc_client_default_out_channel_recv(rdpRpc* rpc)
588{
589 SSIZE_T status = -1;
590 HttpResponse* response = nullptr;
591 RpcInChannel* inChannel = nullptr;
592 RpcOutChannel* outChannel = nullptr;
593 HANDLE outChannelEvent = nullptr;
594 RpcVirtualConnection* connection = rpc->VirtualConnection;
595 inChannel = connection->DefaultInChannel;
596 outChannel = connection->DefaultOutChannel;
597 BIO_get_event(outChannel->common.tls->bio, &outChannelEvent);
598
599 if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
600 {
601 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
602 return 1;
603
604 response = http_response_recv(outChannel->common.tls, TRUE);
605
606 if (!response)
607 return -1;
608
609 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
610 {
611 /* Receive OUT Channel Response */
612 if (!rpc_ncacn_http_recv_out_channel_response(&outChannel->common, response))
613 {
614 http_response_free(response);
615 WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
616 return -1;
617 }
618
619 /* Send OUT Channel Request */
620
621 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
622 {
623 http_response_free(response);
624 WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
625 return -1;
626 }
627
628 if (rpc_ncacn_http_is_final_request(&outChannel->common))
629 {
630 rpc_ncacn_http_auth_uninit(&outChannel->common);
631 rpc_out_channel_transition_to_state(outChannel,
632 CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
633
634 /* Send CONN/A1 PDU over OUT channel */
635
636 if (!rts_send_CONN_A1_pdu(rpc))
637 {
638 http_response_free(response);
639 WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!");
640 return -1;
641 }
642
643 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
644
645 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_OPENED)
646 {
647 rpc_virtual_connection_transition_to_state(
648 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
649 }
650 }
651
652 status = 1;
653 }
654
655 http_response_free(response);
656 }
657 else if (connection->State == VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT)
658 {
659 /* Receive OUT channel response */
660 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
661 return 1;
662
663 response = http_response_recv(outChannel->common.tls, FALSE);
664
665 if (!response)
666 return -1;
667
668 const UINT16 statusCode = http_response_get_status_code(response);
669 if (statusCode != HTTP_STATUS_OK)
670 {
671 http_response_log_error_status(WLog_Get(TAG), WLOG_ERROR, response);
672
673 if (statusCode == HTTP_STATUS_DENIED)
674 {
675 rdpContext* context = transport_get_context(rpc->transport);
676 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
677 }
678
679 http_response_free(response);
680 return -1;
681 }
682
683 http_response_free(response);
684 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
685 VIRTUAL_CONNECTION_STATE_WAIT_A3W);
686 status = 1;
687 }
688 else
689 {
690 wStream* fragment = rpc->client->ReceiveFragment;
691
692 while (1)
693 {
694 size_t pos = 0;
695 rpcconn_common_hdr_t header = WINPR_C_ARRAY_INIT;
696
697 while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
698 {
699 status = rpc_channel_read(&outChannel->common, fragment,
700 RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
701
702 if (status < 0)
703 return -1;
704
705 if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
706 return 0;
707 }
708
709 pos = Stream_GetPosition(fragment);
710 Stream_ResetPosition(fragment);
711
712 /* Ignore errors, the PDU might not be complete. */
713 const rts_pdu_status_t rc = rts_read_common_pdu_header(fragment, &header, TRUE);
714 if (rc == RTS_PDU_FAIL)
715 return -1;
716
717 if (!Stream_SetPosition(fragment, pos))
718 return -1;
719
720 if (header.frag_length >= rpc->max_recv_frag)
721 {
722 WLog_ERR(TAG,
723 "rpc_client_recv: invalid fragment size: %" PRIu16 " (max: %" PRIu16 ")",
724 header.frag_length, rpc->max_recv_frag);
725 winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
726 Stream_GetPosition(fragment));
727 return -1;
728 }
729
730 while (Stream_GetPosition(fragment) < header.frag_length)
731 {
732 status = rpc_channel_read(&outChannel->common, fragment,
733 header.frag_length - Stream_GetPosition(fragment));
734
735 if (status < 0)
736 {
737 WLog_ERR(TAG, "error reading fragment body");
738 return -1;
739 }
740
741 if (Stream_GetPosition(fragment) < header.frag_length)
742 return 0;
743 }
744
745 {
746 /* complete fragment received */
747 status = rpc_client_recv_fragment(rpc, fragment);
748
749 if (status < 0)
750 return status;
751
752 /* channel recycling may update channel pointers */
753 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
754 connection->NonDefaultOutChannel)
755 {
756 rpc_channel_free(&connection->DefaultOutChannel->common);
757 connection->DefaultOutChannel = connection->NonDefaultOutChannel;
758 connection->NonDefaultOutChannel = nullptr;
759 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
760 CLIENT_OUT_CHANNEL_STATE_OPENED);
761 rpc_virtual_connection_transition_to_state(
762 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
763 return 0;
764 }
765
766 Stream_ResetPosition(fragment);
767 }
768 }
769 }
770
771 return status;
772}
773
774WINPR_ATTR_NODISCARD
775static SSIZE_T rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
776{
777 SSIZE_T status = -1;
778 HttpResponse* response = nullptr;
779 RpcOutChannel* nextOutChannel = nullptr;
780 HANDLE nextOutChannelEvent = nullptr;
781 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
782 BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
783
784 if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
785 return 1;
786
787 response = http_response_recv(nextOutChannel->common.tls, TRUE);
788
789 if (response)
790 {
791 switch (nextOutChannel->State)
792 {
793 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
794 if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
795 {
796 if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
797 {
798 if (rpc_ncacn_http_is_final_request(&nextOutChannel->common))
799 {
800 rpc_ncacn_http_auth_uninit(&nextOutChannel->common);
801
802 if (rts_send_OUT_R1_A3_pdu(rpc))
803 {
804 status = 1;
805 rpc_out_channel_transition_to_state(
806 nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
807 }
808 else
809 {
810 WLog_ERR(TAG, "rts_send_OUT_R1/A3_pdu failure");
811 }
812 }
813 else
814 {
815 status = 1;
816 }
817 }
818 else
819 {
820 WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
821 }
822 }
823 else
824 {
825 WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
826 }
827
828 break;
829
830 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
831 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
832 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
833 default:
834 WLog_ERR(TAG,
835 "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
836 nextOutChannel->State);
837 status = -1;
838 }
839
840 http_response_free(response);
841 }
842
843 return status;
844}
845
846int rpc_client_out_channel_recv(rdpRpc* rpc)
847{
848 SSIZE_T status = 0;
849 RpcVirtualConnection* connection = rpc->VirtualConnection;
850
851 if (connection->DefaultOutChannel)
852 {
853 status = rpc_client_default_out_channel_recv(rpc);
854
855 if (status < 0)
856 return -1;
857 }
858
859 if (connection->NonDefaultOutChannel)
860 {
861 status = rpc_client_nondefault_out_channel_recv(rpc);
862
863 if (status < 0)
864 return -1;
865 }
866
867 return 1;
868}
869
870int rpc_client_in_channel_recv(rdpRpc* rpc)
871{
872 int status = 1;
873 HttpResponse* response = nullptr;
874 RpcInChannel* inChannel = nullptr;
875 RpcOutChannel* outChannel = nullptr;
876 HANDLE InChannelEvent = nullptr;
877 RpcVirtualConnection* connection = rpc->VirtualConnection;
878 inChannel = connection->DefaultInChannel;
879 outChannel = connection->DefaultOutChannel;
880 BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
881
882 if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
883 return 1;
884
885 if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
886 {
887 response = http_response_recv(inChannel->common.tls, TRUE);
888
889 if (!response)
890 return -1;
891
892 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
893 {
894 if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
895 {
896 WLog_ERR(TAG, "rpc_ncacn_http_recv_in_channel_response failure");
897 http_response_free(response);
898 return -1;
899 }
900
901 /* Send IN Channel Request */
902
903 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
904 {
905 WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
906 http_response_free(response);
907 return -1;
908 }
909
910 if (rpc_ncacn_http_is_final_request(&inChannel->common))
911 {
912 rpc_ncacn_http_auth_uninit(&inChannel->common);
913 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
914
915 /* Send CONN/B1 PDU over IN channel */
916
917 if (!rts_send_CONN_B1_pdu(rpc))
918 {
919 WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!");
920 http_response_free(response);
921 return -1;
922 }
923
924 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
925
926 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
927 {
928 rpc_virtual_connection_transition_to_state(
929 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
930 }
931 }
932
933 status = 1;
934 }
935
936 http_response_free(response);
937 }
938 else
939 {
940 response = http_response_recv(inChannel->common.tls, TRUE);
941
942 if (!response)
943 return -1;
944
945 /* We can receive an unauthorized HTTP response on the IN channel */
946 http_response_free(response);
947 }
948
949 return status;
950}
951
957RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId)
958{
959 RpcClientCall* clientCall = nullptr;
960
961 if (!client)
962 return nullptr;
963
964 ArrayList_Lock(client->ClientCallList);
965 const size_t count = ArrayList_Count(client->ClientCallList);
966
967 for (size_t index = 0; index < count; index++)
968 {
969 clientCall = (RpcClientCall*)ArrayList_GetItem(client->ClientCallList, index);
970
971 if (clientCall->CallId == CallId)
972 break;
973 }
974
975 ArrayList_Unlock(client->ClientCallList);
976 return clientCall;
977}
978
979RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
980{
981 RpcClientCall* clientCall = nullptr;
982 clientCall = (RpcClientCall*)calloc(1, sizeof(RpcClientCall));
983
984 if (!clientCall)
985 return nullptr;
986
987 clientCall->CallId = CallId;
988 clientCall->OpNum = OpNum;
989 clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
990 return clientCall;
991}
992
993void rpc_client_call_free(RpcClientCall* clientCall)
994{
995 free(clientCall);
996}
997
998static void rpc_array_client_call_free(void* call)
999{
1000 rpc_client_call_free((RpcClientCall*)call);
1001}
1002
1003int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer, size_t length)
1004{
1005 RpcClientCall* clientCall = nullptr;
1006 wStream s = Stream_Init();
1007 rpcconn_common_hdr_t header = WINPR_C_ARRAY_INIT;
1008
1009 SSIZE_T status = rpc_channel_write(&inChannel->common, buffer, length);
1010
1011 if (status <= 0)
1012 return -1;
1013
1014 Stream_StaticConstInit(&s, buffer, length);
1015 const rts_pdu_status_t rc = rts_read_common_pdu_header(&s, &header, FALSE);
1016 if (rc != RTS_PDU_VALID)
1017 return FALSE;
1018
1019 clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id);
1020 if (!clientCall)
1021 return -1;
1022
1023 clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
1024
1025 /*
1026 * This protocol specifies that only RPC PDUs are subject to the flow control abstract
1027 * data model. RTS PDUs and the HTTP request and response headers are not subject to flow
1028 * control. Implementations of this protocol MUST NOT include them when computing any of the
1029 * variables specified by this abstract data model.
1030 */
1031
1032 if (header.ptype == PTYPE_REQUEST)
1033 {
1034 const uint32_t ustatus = WINPR_ASSERTING_INT_CAST(uint32_t, status);
1035 inChannel->BytesSent += ustatus;
1036 inChannel->SenderAvailableWindow -= ustatus;
1037 }
1038
1039 if (status > INT32_MAX)
1040 return -1;
1041 return (int)status;
1042}
1043
1044BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
1045{
1046 size_t offset = 0;
1047 BYTE* buffer = nullptr;
1048 size_t stub_data_pad = 0;
1049 SecBuffer plaintext;
1050 SecBuffer ciphertext = WINPR_C_ARRAY_INIT;
1051 RpcClientCall* clientCall = nullptr;
1052 rdpCredsspAuth* auth = nullptr;
1053 rpcconn_request_hdr_t request_pdu = WINPR_C_ARRAY_INIT;
1054 RpcVirtualConnection* connection = nullptr;
1055 RpcInChannel* inChannel = nullptr;
1056 BOOL rc = FALSE;
1057
1058 if (!s)
1059 return FALSE;
1060
1061 if (!rpc)
1062 goto fail;
1063
1064 auth = rpc->auth;
1065 connection = rpc->VirtualConnection;
1066
1067 if (!auth)
1068 {
1069 WLog_ERR(TAG, "invalid auth context");
1070 goto fail;
1071 }
1072
1073 if (!connection)
1074 goto fail;
1075
1076 inChannel = connection->DefaultInChannel;
1077
1078 if (!inChannel)
1079 goto fail;
1080
1081 Stream_SealLength(s);
1082
1083 {
1084 const size_t length = Stream_Length(s);
1085 if (length > UINT32_MAX)
1086 goto fail;
1087
1088 {
1089 const size_t asize = credssp_auth_trailer_size(auth);
1090 request_pdu.header = rpc_pdu_header_init(rpc);
1091 request_pdu.header.ptype = PTYPE_REQUEST;
1092 request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
1093 request_pdu.header.auth_length = (UINT16)asize;
1094 }
1095 request_pdu.header.call_id = rpc->CallId++;
1096 request_pdu.alloc_hint = (UINT32)length;
1097 request_pdu.p_cont_id = 0x0000;
1098 request_pdu.opnum = opnum;
1099 clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
1100
1101 if (!clientCall)
1102 goto fail;
1103
1104 if (!ArrayList_Append(rpc->client->ClientCallList, clientCall))
1105 {
1106 rpc_client_call_free(clientCall);
1107 goto fail;
1108 }
1109
1110 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership
1111 if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
1112 rpc->PipeCallId = request_pdu.header.call_id;
1113
1114 request_pdu.stub_data = Stream_Buffer(s);
1115 offset = 24;
1116 stub_data_pad = rpc_offset_align(&offset, 8);
1117 offset += length;
1118
1119 {
1120 const size_t alg = rpc_offset_align(&offset, 4);
1121 WINPR_ASSERT(alg <= UINT8_MAX);
1122 request_pdu.auth_verifier.auth_pad_length = (UINT8)alg;
1123 }
1124 request_pdu.auth_verifier.auth_type =
1125 rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
1126 request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
1127 request_pdu.auth_verifier.auth_reserved = 0x00;
1128 request_pdu.auth_verifier.auth_context_id = 0x00000000;
1129 offset += (8 + request_pdu.header.auth_length);
1130
1131 if (offset > UINT16_MAX)
1132 goto fail;
1133 request_pdu.header.frag_length = (UINT16)offset;
1134 buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
1135
1136 if (!buffer)
1137 goto fail;
1138
1139 CopyMemory(buffer, &request_pdu, 24);
1140 offset = 24;
1141 rpc_offset_pad(&offset, stub_data_pad);
1142 CopyMemory(&buffer[offset], request_pdu.stub_data, length);
1143 offset += length;
1144 }
1145
1146 rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
1147 CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
1148 offset += 8;
1149
1150 if (offset > request_pdu.header.frag_length)
1151 goto fail;
1152
1153 plaintext.pvBuffer = buffer;
1154 plaintext.cbBuffer = (UINT32)offset;
1155 plaintext.BufferType = SECBUFFER_READONLY;
1156
1157 {
1158 size_t size = 0;
1159 if (!credssp_auth_encrypt(auth, &plaintext, &ciphertext, &size, rpc->SendSeqNum++))
1160 goto fail;
1161
1162 if (offset + size > request_pdu.header.frag_length)
1163 {
1164 sspi_SecBufferFree(&ciphertext);
1165 goto fail;
1166 }
1167
1168 CopyMemory(&buffer[offset], ciphertext.pvBuffer, size);
1169 offset += size;
1170 }
1171
1172 sspi_SecBufferFree(&ciphertext);
1173
1174 if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
1175 goto fail;
1176
1177 rc = TRUE;
1178fail:
1179 free(buffer);
1180 Stream_Free(s, TRUE);
1181 return rc;
1182}
1183
1184WINPR_ATTR_NODISCARD
1185static BOOL rpc_client_resolve_gateway(rdpSettings* settings, char** host, UINT16* port,
1186 BOOL* isProxy)
1187{
1188 struct addrinfo* result = nullptr;
1189
1190 if (!settings || !host || !port || !isProxy)
1191 return FALSE;
1192 else
1193 {
1194 const char* peerHostname = freerdp_settings_get_string(settings, FreeRDP_GatewayHostname);
1195 const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername);
1196 const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_GatewayPassword);
1197 *port = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort);
1198 *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
1199 result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
1200
1201 if (!result)
1202 return FALSE;
1203
1204 *host = freerdp_tcp_address_to_string(
1205 WINPR_PACKED_ALIGN_CAST(const struct sockaddr_storage*, result->ai_addr), nullptr);
1206 freeaddrinfo(result);
1207 return TRUE;
1208 }
1209}
1210
1211RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
1212{
1213 wObject* obj = nullptr;
1214 RpcClient* client = (RpcClient*)calloc(1, sizeof(RpcClient));
1215
1216 if (!client)
1217 return nullptr;
1218
1219 if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
1220 &client->isProxy))
1221 goto fail;
1222
1223 client->context = context;
1224
1225 if (!client->context)
1226 goto fail;
1227
1228 client->pdu = rpc_pdu_new();
1229
1230 if (!client->pdu)
1231 goto fail;
1232
1233 client->ReceiveFragment = Stream_New(nullptr, max_recv_frag);
1234
1235 if (!client->ReceiveFragment)
1236 goto fail;
1237
1238 client->PipeEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1239
1240 if (!client->PipeEvent)
1241 goto fail;
1242
1243 if (!ringbuffer_init(&(client->ReceivePipe), 4096))
1244 goto fail;
1245
1246 if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
1247 goto fail;
1248
1249 client->ClientCallList = ArrayList_New(TRUE);
1250
1251 if (!client->ClientCallList)
1252 goto fail;
1253
1254 obj = ArrayList_Object(client->ClientCallList);
1255 obj->fnObjectFree = rpc_array_client_call_free;
1256 return client;
1257fail:
1258 WINPR_PRAGMA_DIAG_PUSH
1259 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1260 rpc_client_free(client);
1261 WINPR_PRAGMA_DIAG_POP
1262 return nullptr;
1263}
1264
1265void rpc_client_free(RpcClient* client)
1266{
1267 if (!client)
1268 return;
1269
1270 free(client->host);
1271
1272 if (client->ReceiveFragment)
1273 Stream_Free(client->ReceiveFragment, TRUE);
1274
1275 if (client->PipeEvent)
1276 (void)CloseHandle(client->PipeEvent);
1277
1278 ringbuffer_destroy(&(client->ReceivePipe));
1279 DeleteCriticalSection(&(client->PipeLock));
1280
1281 if (client->pdu)
1282 rpc_pdu_free(client->pdu);
1283
1284 if (client->ClientCallList)
1285 ArrayList_Free(client->ClientCallList);
1286
1287 free(client);
1288}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
a piece of data in the ring buffer, exactly like a glibc iovec
Definition ringbuffer.h:44
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59