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