FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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: %d", 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 INT16 statusCode = http_response_get_status_code(response);
650
651 if (statusCode != HTTP_STATUS_OK)
652 {
653 http_response_log_error_status(WLog_Get(TAG), WLOG_ERROR, response);
654
655 if (statusCode == HTTP_STATUS_DENIED)
656 {
657 rdpContext* context = transport_get_context(rpc->transport);
658 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
659 }
660
661 http_response_free(response);
662 return -1;
663 }
664
665 http_response_free(response);
666 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
667 VIRTUAL_CONNECTION_STATE_WAIT_A3W);
668 status = 1;
669 }
670 else
671 {
672 wStream* fragment = rpc->client->ReceiveFragment;
673
674 while (1)
675 {
676 size_t pos = 0;
677 rpcconn_common_hdr_t header = { 0 };
678
679 while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
680 {
681 status = rpc_channel_read(&outChannel->common, fragment,
682 RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
683
684 if (status < 0)
685 return -1;
686
687 if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
688 return 0;
689 }
690
691 pos = Stream_GetPosition(fragment);
692 Stream_SetPosition(fragment, 0);
693
694 /* Ignore errors, the PDU might not be complete. */
695 rts_read_common_pdu_header(fragment, &header, TRUE);
696 Stream_SetPosition(fragment, pos);
697
698 if (header.frag_length > rpc->max_recv_frag)
699 {
700 WLog_ERR(TAG,
701 "rpc_client_recv: invalid fragment size: %" PRIu16 " (max: %" PRIu16 ")",
702 header.frag_length, rpc->max_recv_frag);
703 winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
704 Stream_GetPosition(fragment));
705 return -1;
706 }
707
708 while (Stream_GetPosition(fragment) < header.frag_length)
709 {
710 status = rpc_channel_read(&outChannel->common, fragment,
711 header.frag_length - Stream_GetPosition(fragment));
712
713 if (status < 0)
714 {
715 WLog_ERR(TAG, "error reading fragment body");
716 return -1;
717 }
718
719 if (Stream_GetPosition(fragment) < header.frag_length)
720 return 0;
721 }
722
723 {
724 /* complete fragment received */
725 status = rpc_client_recv_fragment(rpc, fragment);
726
727 if (status < 0)
728 return status;
729
730 /* channel recycling may update channel pointers */
731 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
732 connection->NonDefaultOutChannel)
733 {
734 rpc_channel_free(&connection->DefaultOutChannel->common);
735 connection->DefaultOutChannel = connection->NonDefaultOutChannel;
736 connection->NonDefaultOutChannel = NULL;
737 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
738 CLIENT_OUT_CHANNEL_STATE_OPENED);
739 rpc_virtual_connection_transition_to_state(
740 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
741 return 0;
742 }
743
744 Stream_SetPosition(fragment, 0);
745 }
746 }
747 }
748
749 return status;
750}
751
752static SSIZE_T rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
753{
754 SSIZE_T status = -1;
755 HttpResponse* response = NULL;
756 RpcOutChannel* nextOutChannel = NULL;
757 HANDLE nextOutChannelEvent = NULL;
758 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
759 BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
760
761 if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
762 return 1;
763
764 response = http_response_recv(nextOutChannel->common.tls, TRUE);
765
766 if (response)
767 {
768 switch (nextOutChannel->State)
769 {
770 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
771 if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
772 {
773 if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
774 {
775 if (rpc_ncacn_http_is_final_request(&nextOutChannel->common))
776 {
777 rpc_ncacn_http_auth_uninit(&nextOutChannel->common);
778
779 if (rts_send_OUT_R1_A3_pdu(rpc))
780 {
781 status = 1;
782 rpc_out_channel_transition_to_state(
783 nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
784 }
785 else
786 {
787 WLog_ERR(TAG, "rts_send_OUT_R1/A3_pdu failure");
788 }
789 }
790 else
791 {
792 status = 1;
793 }
794 }
795 else
796 {
797 WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
798 }
799 }
800 else
801 {
802 WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
803 }
804
805 break;
806
807 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
808 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
809 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
810 default:
811 WLog_ERR(TAG,
812 "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
813 nextOutChannel->State);
814 status = -1;
815 }
816
817 http_response_free(response);
818 }
819
820 return status;
821}
822
823int rpc_client_out_channel_recv(rdpRpc* rpc)
824{
825 SSIZE_T status = 0;
826 RpcVirtualConnection* connection = rpc->VirtualConnection;
827
828 if (connection->DefaultOutChannel)
829 {
830 status = rpc_client_default_out_channel_recv(rpc);
831
832 if (status < 0)
833 return -1;
834 }
835
836 if (connection->NonDefaultOutChannel)
837 {
838 status = rpc_client_nondefault_out_channel_recv(rpc);
839
840 if (status < 0)
841 return -1;
842 }
843
844 return 1;
845}
846
847int rpc_client_in_channel_recv(rdpRpc* rpc)
848{
849 int status = 1;
850 HttpResponse* response = NULL;
851 RpcInChannel* inChannel = NULL;
852 RpcOutChannel* outChannel = NULL;
853 HANDLE InChannelEvent = NULL;
854 RpcVirtualConnection* connection = rpc->VirtualConnection;
855 inChannel = connection->DefaultInChannel;
856 outChannel = connection->DefaultOutChannel;
857 BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
858
859 if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
860 return 1;
861
862 if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
863 {
864 response = http_response_recv(inChannel->common.tls, TRUE);
865
866 if (!response)
867 return -1;
868
869 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
870 {
871 if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
872 {
873 WLog_ERR(TAG, "rpc_ncacn_http_recv_in_channel_response failure");
874 http_response_free(response);
875 return -1;
876 }
877
878 /* Send IN Channel Request */
879
880 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
881 {
882 WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
883 http_response_free(response);
884 return -1;
885 }
886
887 if (rpc_ncacn_http_is_final_request(&inChannel->common))
888 {
889 rpc_ncacn_http_auth_uninit(&inChannel->common);
890 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
891
892 /* Send CONN/B1 PDU over IN channel */
893
894 if (!rts_send_CONN_B1_pdu(rpc))
895 {
896 WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!");
897 http_response_free(response);
898 return -1;
899 }
900
901 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
902
903 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
904 {
905 rpc_virtual_connection_transition_to_state(
906 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
907 }
908 }
909
910 status = 1;
911 }
912
913 http_response_free(response);
914 }
915 else
916 {
917 response = http_response_recv(inChannel->common.tls, TRUE);
918
919 if (!response)
920 return -1;
921
922 /* We can receive an unauthorized HTTP response on the IN channel */
923 http_response_free(response);
924 }
925
926 return status;
927}
928
934RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId)
935{
936 RpcClientCall* clientCall = NULL;
937
938 if (!client)
939 return NULL;
940
941 ArrayList_Lock(client->ClientCallList);
942 const size_t count = ArrayList_Count(client->ClientCallList);
943
944 for (size_t index = 0; index < count; index++)
945 {
946 clientCall = (RpcClientCall*)ArrayList_GetItem(client->ClientCallList, index);
947
948 if (clientCall->CallId == CallId)
949 break;
950 }
951
952 ArrayList_Unlock(client->ClientCallList);
953 return clientCall;
954}
955
956RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
957{
958 RpcClientCall* clientCall = NULL;
959 clientCall = (RpcClientCall*)calloc(1, sizeof(RpcClientCall));
960
961 if (!clientCall)
962 return NULL;
963
964 clientCall->CallId = CallId;
965 clientCall->OpNum = OpNum;
966 clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
967 return clientCall;
968}
969
970void rpc_client_call_free(RpcClientCall* clientCall)
971{
972 free(clientCall);
973}
974
975static void rpc_array_client_call_free(void* call)
976{
977 rpc_client_call_free((RpcClientCall*)call);
978}
979
980int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer, size_t length)
981{
982 SSIZE_T status = 0;
983 RpcClientCall* clientCall = NULL;
984 wStream s;
985 rpcconn_common_hdr_t header = { 0 };
986
987 status = rpc_channel_write(&inChannel->common, buffer, length);
988
989 if (status <= 0)
990 return -1;
991
992 Stream_StaticConstInit(&s, buffer, length);
993 if (!rts_read_common_pdu_header(&s, &header, FALSE))
994 return -1;
995
996 clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id);
997 if (!clientCall)
998 return -1;
999
1000 clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
1001
1002 /*
1003 * This protocol specifies that only RPC PDUs are subject to the flow control abstract
1004 * data model. RTS PDUs and the HTTP request and response headers are not subject to flow
1005 * control. Implementations of this protocol MUST NOT include them when computing any of the
1006 * variables specified by this abstract data model.
1007 */
1008
1009 if (header.ptype == PTYPE_REQUEST)
1010 {
1011 const uint32_t ustatus = WINPR_ASSERTING_INT_CAST(uint32_t, status);
1012 inChannel->BytesSent += ustatus;
1013 inChannel->SenderAvailableWindow -= ustatus;
1014 }
1015
1016 if (status > INT32_MAX)
1017 return -1;
1018 return (int)status;
1019}
1020
1021BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
1022{
1023 size_t offset = 0;
1024 BYTE* buffer = NULL;
1025 size_t stub_data_pad = 0;
1026 SecBuffer plaintext;
1027 SecBuffer ciphertext = { 0 };
1028 RpcClientCall* clientCall = NULL;
1029 rdpCredsspAuth* auth = NULL;
1030 rpcconn_request_hdr_t request_pdu = { 0 };
1031 RpcVirtualConnection* connection = NULL;
1032 RpcInChannel* inChannel = NULL;
1033 BOOL rc = FALSE;
1034
1035 if (!s)
1036 return FALSE;
1037
1038 if (!rpc)
1039 goto fail;
1040
1041 auth = rpc->auth;
1042 connection = rpc->VirtualConnection;
1043
1044 if (!auth)
1045 {
1046 WLog_ERR(TAG, "invalid auth context");
1047 goto fail;
1048 }
1049
1050 if (!connection)
1051 goto fail;
1052
1053 inChannel = connection->DefaultInChannel;
1054
1055 if (!inChannel)
1056 goto fail;
1057
1058 Stream_SealLength(s);
1059 const size_t length = Stream_Length(s);
1060 if (length > UINT32_MAX)
1061 goto fail;
1062
1063 const size_t asize = credssp_auth_trailer_size(auth);
1064
1065 request_pdu.header = rpc_pdu_header_init(rpc);
1066 request_pdu.header.ptype = PTYPE_REQUEST;
1067 request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
1068 request_pdu.header.auth_length = (UINT16)asize;
1069 request_pdu.header.call_id = rpc->CallId++;
1070 request_pdu.alloc_hint = (UINT32)length;
1071 request_pdu.p_cont_id = 0x0000;
1072 request_pdu.opnum = opnum;
1073 clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
1074
1075 if (!clientCall)
1076 goto fail;
1077
1078 if (!ArrayList_Append(rpc->client->ClientCallList, clientCall))
1079 {
1080 rpc_client_call_free(clientCall);
1081 goto fail;
1082 }
1083
1084 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership of clientCall
1085 if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
1086 rpc->PipeCallId = request_pdu.header.call_id;
1087
1088 request_pdu.stub_data = Stream_Buffer(s);
1089 offset = 24;
1090 stub_data_pad = rpc_offset_align(&offset, 8);
1091 offset += length;
1092
1093 const size_t alg = rpc_offset_align(&offset, 4);
1094 WINPR_ASSERT(alg <= UINT8_MAX);
1095 request_pdu.auth_verifier.auth_pad_length = (UINT8)alg;
1096 request_pdu.auth_verifier.auth_type =
1097 rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
1098 request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
1099 request_pdu.auth_verifier.auth_reserved = 0x00;
1100 request_pdu.auth_verifier.auth_context_id = 0x00000000;
1101 offset += (8 + request_pdu.header.auth_length);
1102
1103 if (offset > UINT16_MAX)
1104 goto fail;
1105 request_pdu.header.frag_length = (UINT16)offset;
1106 buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
1107
1108 if (!buffer)
1109 goto fail;
1110
1111 CopyMemory(buffer, &request_pdu, 24);
1112 offset = 24;
1113 rpc_offset_pad(&offset, stub_data_pad);
1114 CopyMemory(&buffer[offset], request_pdu.stub_data, length);
1115 offset += length;
1116 rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
1117 CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
1118 offset += 8;
1119
1120 if (offset > request_pdu.header.frag_length)
1121 goto fail;
1122
1123 plaintext.pvBuffer = buffer;
1124 plaintext.cbBuffer = (UINT32)offset;
1125 plaintext.BufferType = SECBUFFER_READONLY;
1126
1127 size_t size = 0;
1128 if (!credssp_auth_encrypt(auth, &plaintext, &ciphertext, &size, rpc->SendSeqNum++))
1129 goto fail;
1130
1131 if (offset + size > request_pdu.header.frag_length)
1132 {
1133 sspi_SecBufferFree(&ciphertext);
1134 goto fail;
1135 }
1136
1137 CopyMemory(&buffer[offset], ciphertext.pvBuffer, size);
1138 offset += size;
1139
1140 sspi_SecBufferFree(&ciphertext);
1141
1142 if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
1143 goto fail;
1144
1145 rc = TRUE;
1146fail:
1147 free(buffer);
1148 Stream_Free(s, TRUE);
1149 return rc;
1150}
1151
1152static BOOL rpc_client_resolve_gateway(rdpSettings* settings, char** host, UINT16* port,
1153 BOOL* isProxy)
1154{
1155 struct addrinfo* result = NULL;
1156
1157 if (!settings || !host || !port || !isProxy)
1158 return FALSE;
1159 else
1160 {
1161 const char* peerHostname = freerdp_settings_get_string(settings, FreeRDP_GatewayHostname);
1162 const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername);
1163 const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_GatewayPassword);
1164 *port = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort);
1165 *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
1166 result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
1167
1168 if (!result)
1169 return FALSE;
1170
1171 *host =
1172 freerdp_tcp_address_to_string((const struct sockaddr_storage*)result->ai_addr, NULL);
1173 freeaddrinfo(result);
1174 return TRUE;
1175 }
1176}
1177
1178RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
1179{
1180 wObject* obj = NULL;
1181 RpcClient* client = (RpcClient*)calloc(1, sizeof(RpcClient));
1182
1183 if (!client)
1184 return NULL;
1185
1186 if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
1187 &client->isProxy))
1188 goto fail;
1189
1190 client->context = context;
1191
1192 if (!client->context)
1193 goto fail;
1194
1195 client->pdu = rpc_pdu_new();
1196
1197 if (!client->pdu)
1198 goto fail;
1199
1200 client->ReceiveFragment = Stream_New(NULL, max_recv_frag);
1201
1202 if (!client->ReceiveFragment)
1203 goto fail;
1204
1205 client->PipeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1206
1207 if (!client->PipeEvent)
1208 goto fail;
1209
1210 if (!ringbuffer_init(&(client->ReceivePipe), 4096))
1211 goto fail;
1212
1213 if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
1214 goto fail;
1215
1216 client->ClientCallList = ArrayList_New(TRUE);
1217
1218 if (!client->ClientCallList)
1219 goto fail;
1220
1221 obj = ArrayList_Object(client->ClientCallList);
1222 obj->fnObjectFree = rpc_array_client_call_free;
1223 return client;
1224fail:
1225 WINPR_PRAGMA_DIAG_PUSH
1226 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1227 rpc_client_free(client);
1228 WINPR_PRAGMA_DIAG_POP
1229 return NULL;
1230}
1231
1232void rpc_client_free(RpcClient* client)
1233{
1234 if (!client)
1235 return;
1236
1237 free(client->host);
1238
1239 if (client->ReceiveFragment)
1240 Stream_Free(client->ReceiveFragment, TRUE);
1241
1242 if (client->PipeEvent)
1243 (void)CloseHandle(client->PipeEvent);
1244
1245 ringbuffer_destroy(&(client->ReceivePipe));
1246 DeleteCriticalSection(&(client->PipeLock));
1247
1248 if (client->pdu)
1249 rpc_pdu_free(client->pdu);
1250
1251 if (client->ClientCallList)
1252 ArrayList_Free(client->ClientCallList);
1253
1254 free(client);
1255}
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