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