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