20 #include <freerdp/config.h>
22 #include <freerdp/log.h>
24 #include <winpr/crt.h>
25 #include <winpr/wtypes.h>
26 #include <winpr/assert.h>
27 #include <winpr/print.h>
28 #include <winpr/synch.h>
29 #include <winpr/thread.h>
30 #include <winpr/stream.h>
33 #include "ncacn_http.h"
36 #include "rpc_fault.h"
37 #include "rpc_client.h"
38 #include "rts_signature.h"
44 #define TAG FREERDP_TAG("core.gateway.rpc")
46 static const char* rpc_client_state_str(RPC_CLIENT_STATE state)
49 const char* str =
"RPC_CLIENT_STATE_UNKNOWN";
53 case RPC_CLIENT_STATE_INITIAL:
54 str =
"RPC_CLIENT_STATE_INITIAL";
57 case RPC_CLIENT_STATE_ESTABLISHED:
58 str =
"RPC_CLIENT_STATE_ESTABLISHED";
61 case RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK:
62 str =
"RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK";
65 case RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK:
66 str =
"RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK";
69 case RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE:
70 str =
"RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE";
73 case RPC_CLIENT_STATE_CONTEXT_NEGOTIATED:
74 str =
"RPC_CLIENT_STATE_CONTEXT_NEGOTIATED";
77 case RPC_CLIENT_STATE_WAIT_RESPONSE:
78 str =
"RPC_CLIENT_STATE_WAIT_RESPONSE";
81 case RPC_CLIENT_STATE_FINAL:
82 str =
"RPC_CLIENT_STATE_FINAL";
90 static void rpc_pdu_reset(
RPC_PDU* pdu)
95 Stream_SetPosition(pdu->s, 0);
96 Stream_SetLength(pdu->s, 0);
99 static RPC_PDU* rpc_pdu_new(
void)
107 pdu->s = Stream_New(NULL, 4096);
119 static void rpc_pdu_free(
RPC_PDU* pdu)
124 Stream_Free(pdu->s, TRUE);
128 static int rpc_client_receive_pipe_write(
RpcClient* client,
const BYTE* buffer,
size_t length)
132 if (!client || !buffer)
135 EnterCriticalSection(&(client->PipeLock));
137 if (ringbuffer_write(&(client->ReceivePipe), buffer, length))
138 status += (int)length;
140 if (ringbuffer_used(&(client->ReceivePipe)) > 0)
141 (
void)SetEvent(client->PipeEvent);
143 LeaveCriticalSection(&(client->PipeLock));
147 int rpc_client_receive_pipe_read(
RpcClient* client, BYTE* buffer,
size_t length)
153 if (!client || !buffer)
156 EnterCriticalSection(&(client->PipeLock));
157 nchunks = ringbuffer_peek(&(client->ReceivePipe), chunks, length);
159 for (
int index = 0; index < nchunks; index++)
161 CopyMemory(&buffer[status], chunks[index].data, chunks[index].size);
162 status += chunks[index].size;
166 ringbuffer_commit_read_bytes(&(client->ReceivePipe), status);
168 if (ringbuffer_used(&(client->ReceivePipe)) < 1)
169 (void)ResetEvent(client->PipeEvent);
171 LeaveCriticalSection(&(client->PipeLock));
173 if (status > INT_MAX)
178 static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
183 WLog_DBG(TAG,
"%s", rpc_client_state_str(state));
187 static int rpc_client_recv_pdu_int(rdpRpc* rpc,
RPC_PDU* pdu)
195 rdpTsg* tsg = transport_get_tsg(rpc->transport);
197 WLog_VRB(TAG,
"client state %s, vc state %s", rpc_client_state_str(rpc->State),
198 rpc_vc_state_str(rpc->VirtualConnection->State));
200 const BOOL rc = rts_match_pdu_signature_ex(&RTS_PDU_PING_SIGNATURE, pdu->s, NULL, &found, TRUE);
201 rts_print_pdu_signature(rpc->log, WLOG_TRACE, &found);
203 return rts_recv_ping_pdu(rpc, pdu->s);
205 if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
207 switch (rpc->VirtualConnection->State)
209 case VIRTUAL_CONNECTION_STATE_INITIAL:
212 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
215 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
216 if (memcmp(&found, &RTS_PDU_CONN_A3_SIGNATURE,
sizeof(found)) != 0)
218 wLog* log = WLog_Get(TAG);
219 WLog_Print(log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/A3");
220 rts_print_pdu_signature(log, WLOG_ERROR, &found);
224 if (!rts_recv_CONN_A3_pdu(rpc, pdu->s))
226 WLog_ERR(TAG,
"rts_recv_CONN_A3_pdu failure");
230 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
231 VIRTUAL_CONNECTION_STATE_WAIT_C2);
235 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
236 if (memcmp(&found, &RTS_PDU_CONN_C2_SIGNATURE,
sizeof(found)) != 0)
238 wLog* log = WLog_Get(TAG);
239 WLog_Print(log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/C2");
240 rts_print_pdu_signature(log, WLOG_ERROR, &found);
244 if (!rts_recv_CONN_C2_pdu(rpc, pdu->s))
246 WLog_ERR(TAG,
"rts_recv_CONN_C2_pdu failure");
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);
254 if (rpc_send_bind_pdu(rpc, TRUE) < 0)
256 WLog_ERR(TAG,
"rpc_send_bind_pdu failure");
260 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK);
264 case VIRTUAL_CONNECTION_STATE_OPENED:
267 case VIRTUAL_CONNECTION_STATE_FINAL:
273 else if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
275 if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
277 if (pdu->Type == PTYPE_BIND_ACK || pdu->Type == PTYPE_ALTER_CONTEXT_RESP)
279 if (!rpc_recv_bind_ack_pdu(rpc, pdu->s))
281 WLog_ERR(TAG,
"rpc_recv_bind_ack_pdu failure");
288 "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK unexpected pdu type: 0x%08" PRIX32
294 switch (rpc_bind_state(rpc))
296 case RPC_BIND_STATE_INCOMPLETE:
297 if (rpc_send_bind_pdu(rpc, FALSE) < 0)
299 WLog_ERR(TAG,
"rpc_send_bind_pdu failure");
303 case RPC_BIND_STATE_LAST_LEG:
304 if (rpc_send_rpc_auth_3_pdu(rpc) < 0)
306 WLog_ERR(TAG,
"rpc_secure_bind: error sending rpc_auth_3 pdu!");
311 case RPC_BIND_STATE_COMPLETE:
312 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
314 if (!tsg_proxy_begin(tsg))
316 WLog_ERR(TAG,
"tsg_proxy_begin failure");
328 WLog_ERR(TAG,
"invalid rpc->State: %d", rpc->State);
331 else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
333 if (!tsg_recv_pdu(tsg, pdu))
342 static int rpc_client_recv_pdu(rdpRpc* rpc,
RPC_PDU* pdu)
347 Stream_SealLength(pdu->s);
348 Stream_SetPosition(pdu->s, 0);
350 const size_t before = Stream_GetRemainingLength(pdu->s);
351 WLog_VRB(TAG,
"RPC PDU parsing %" PRIuz
" bytes", before);
352 const int rc = rpc_client_recv_pdu_int(rpc, pdu);
355 const size_t after = Stream_GetRemainingLength(pdu->s);
359 WLog_WARN(TAG,
"Incompletely parsed RPC PDU (%" PRIuz
" bytes remain)", after);
365 static int rpc_client_recv_fragment(rdpRpc* rpc,
wStream* fragment)
369 size_t StubOffset = 0;
370 size_t StubLength = 0;
375 WINPR_ASSERT(rpc->client);
376 WINPR_ASSERT(fragment);
378 pdu = rpc->client->pdu;
381 Stream_SealLength(fragment);
382 Stream_SetPosition(fragment, 0);
384 if (!rts_read_pdu_header(fragment, &header))
387 if (header.common.ptype == PTYPE_RESPONSE)
389 rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length;
390 rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
391 header.common.frag_length;
393 if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
394 (rpc->ReceiveWindow / 2))
396 if (!rts_send_flow_control_ack_pdu(rpc))
400 if (!rpc_get_stub_data_info(rpc, &header, &StubOffset, &StubLength))
402 WLog_ERR(TAG,
"expected stub");
408 if ((header.common.call_id == rpc->PipeCallId) &&
409 (header.common.pfc_flags & PFC_LAST_FRAG))
412 TerminateEventArgs e;
413 rdpContext* context = transport_get_context(rpc->transport);
414 rdpTsg* tsg = transport_get_tsg(rpc->transport);
416 WINPR_ASSERT(context);
418 if (Stream_Length(fragment) < StubOffset + 4)
420 Stream_SetPosition(fragment, StubOffset);
421 Stream_Read_UINT32(fragment, rpc->result);
423 utils_abort_connect(context->rdp);
424 tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
425 EventArgsInit(&e,
"freerdp");
427 PubSub_OnTerminate(context->rdp->pubSub, context, &e);
432 if (header.common.call_id != rpc->PipeCallId)
440 if (rpc->StubFragCount == 0)
441 rpc->StubCallId = header.common.call_id;
443 if (rpc->StubCallId != header.common.call_id)
446 "invalid call_id: actual: %" PRIu32
", expected: %" PRIu32
447 ", frag_count: %" PRIu32
"",
448 rpc->StubCallId, header.common.call_id, rpc->StubFragCount);
451 call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId);
456 if (call->OpNum != TsProxySetupReceivePipeOpnum)
460 if (!Stream_EnsureCapacity(pdu->s, response->alloc_hint))
463 if (Stream_Length(fragment) < StubOffset + StubLength)
466 Stream_SetPosition(fragment, StubOffset);
467 Stream_Write(pdu->s, Stream_ConstPointer(fragment), StubLength);
468 rpc->StubFragCount++;
470 if (response->alloc_hint == StubLength)
472 pdu->Flags = RPC_PDU_FLAG_STUB;
473 pdu->Type = PTYPE_RESPONSE;
474 pdu->CallId = rpc->StubCallId;
476 if (rpc_client_recv_pdu(rpc, pdu) < 0)
479 rpc->StubFragCount = 0;
486 if (Stream_Length(fragment) < StubOffset + StubLength)
488 Stream_SetPosition(fragment, StubOffset);
489 rpc_client_receive_pipe_write(rpc->client, Stream_ConstPointer(fragment), StubLength);
490 rpc->StubFragCount++;
492 if (response->alloc_hint == StubLength)
494 rpc->StubFragCount = 0;
501 else if (header.common.ptype == PTYPE_RTS)
503 if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
506 pdu->Type = header.common.ptype;
507 pdu->CallId = header.common.call_id;
509 const size_t len = Stream_Length(fragment);
510 if (!Stream_EnsureCapacity(pdu->s, len))
513 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
515 if (rpc_client_recv_pdu(rpc, pdu) < 0)
522 if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header))
528 else if (header.common.ptype == PTYPE_BIND_ACK ||
529 header.common.ptype == PTYPE_ALTER_CONTEXT_RESP)
532 pdu->Type = header.common.ptype;
533 pdu->CallId = header.common.call_id;
535 const size_t len = Stream_Length(fragment);
536 if (!Stream_EnsureCapacity(pdu->s, len))
539 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
541 if (rpc_client_recv_pdu(rpc, pdu) < 0)
547 else if (header.common.ptype == PTYPE_FAULT)
550 rpc_recv_fault_pdu(fault->status);
555 WLog_ERR(TAG,
"unexpected RPC PDU type 0x%02" PRIX8
"", header.common.ptype);
560 rc = (rc < 0) ? 1 : 0;
563 rts_free_pdu_header(&header, FALSE);
567 static SSIZE_T rpc_client_default_out_channel_recv(rdpRpc* rpc)
570 UINT32 statusCode = 0;
571 HttpResponse* response = NULL;
574 HANDLE outChannelEvent = NULL;
576 inChannel = connection->DefaultInChannel;
577 outChannel = connection->DefaultOutChannel;
578 BIO_get_event(outChannel->common.tls->bio, &outChannelEvent);
580 if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
582 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
585 response = http_response_recv(outChannel->common.tls, TRUE);
590 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
593 if (!rpc_ncacn_http_recv_out_channel_response(&outChannel->common, response))
595 http_response_free(response);
596 WLog_ERR(TAG,
"rpc_ncacn_http_recv_out_channel_response failure");
602 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
604 http_response_free(response);
605 WLog_ERR(TAG,
"rpc_ncacn_http_send_out_channel_request failure");
609 if (rpc_ncacn_http_is_final_request(&outChannel->common))
611 rpc_ncacn_http_auth_uninit(&outChannel->common);
612 rpc_out_channel_transition_to_state(outChannel,
613 CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
617 if (!rts_send_CONN_A1_pdu(rpc))
619 http_response_free(response);
620 WLog_ERR(TAG,
"rpc_send_CONN_A1_pdu error!");
624 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
626 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_OPENED)
628 rpc_virtual_connection_transition_to_state(
629 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
636 http_response_free(response);
638 else if (connection->State == VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT)
641 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
644 response = http_response_recv(outChannel->common.tls, FALSE);
649 statusCode = http_response_get_status_code(response);
651 if (statusCode != HTTP_STATUS_OK)
653 http_response_log_error_status(WLog_Get(TAG), WLOG_ERROR, response);
655 if (statusCode == HTTP_STATUS_DENIED)
657 rdpContext* context = transport_get_context(rpc->transport);
658 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
661 http_response_free(response);
665 http_response_free(response);
666 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
667 VIRTUAL_CONNECTION_STATE_WAIT_A3W);
672 wStream* fragment = rpc->client->ReceiveFragment;
679 while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
681 status = rpc_channel_read(&outChannel->common, fragment,
682 RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
687 if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
691 pos = Stream_GetPosition(fragment);
692 Stream_SetPosition(fragment, 0);
695 rts_read_common_pdu_header(fragment, &header, TRUE);
696 Stream_SetPosition(fragment, pos);
698 if (header.frag_length > rpc->max_recv_frag)
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));
708 while (Stream_GetPosition(fragment) < header.frag_length)
710 status = rpc_channel_read(&outChannel->common, fragment,
711 header.frag_length - Stream_GetPosition(fragment));
715 WLog_ERR(TAG,
"error reading fragment body");
719 if (Stream_GetPosition(fragment) < header.frag_length)
725 status = rpc_client_recv_fragment(rpc, fragment);
731 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
732 connection->NonDefaultOutChannel)
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);
744 Stream_SetPosition(fragment, 0);
752 static SSIZE_T rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
755 HttpResponse* response = NULL;
757 HANDLE nextOutChannelEvent = NULL;
758 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
759 BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
761 if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
764 response = http_response_recv(nextOutChannel->common.tls, TRUE);
768 switch (nextOutChannel->State)
770 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
771 if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
773 if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
775 if (rpc_ncacn_http_is_final_request(&nextOutChannel->common))
777 rpc_ncacn_http_auth_uninit(&nextOutChannel->common);
779 if (rts_send_OUT_R1_A3_pdu(rpc))
782 rpc_out_channel_transition_to_state(
783 nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
787 WLog_ERR(TAG,
"rts_send_OUT_R1/A3_pdu failure");
797 WLog_ERR(TAG,
"rpc_ncacn_http_send_out_channel_request failure");
802 WLog_ERR(TAG,
"rpc_ncacn_http_recv_out_channel_response failure");
807 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
808 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
809 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
812 "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
813 nextOutChannel->State);
817 http_response_free(response);
823 int rpc_client_out_channel_recv(rdpRpc* rpc)
828 if (connection->DefaultOutChannel)
830 status = rpc_client_default_out_channel_recv(rpc);
836 if (connection->NonDefaultOutChannel)
838 status = rpc_client_nondefault_out_channel_recv(rpc);
847 int rpc_client_in_channel_recv(rdpRpc* rpc)
850 HttpResponse* response = NULL;
853 HANDLE InChannelEvent = NULL;
855 inChannel = connection->DefaultInChannel;
856 outChannel = connection->DefaultOutChannel;
857 BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
859 if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
862 if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
864 response = http_response_recv(inChannel->common.tls, TRUE);
869 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
871 if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
873 WLog_ERR(TAG,
"rpc_ncacn_http_recv_in_channel_response failure");
874 http_response_free(response);
880 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
882 WLog_ERR(TAG,
"rpc_ncacn_http_send_in_channel_request failure");
883 http_response_free(response);
887 if (rpc_ncacn_http_is_final_request(&inChannel->common))
889 rpc_ncacn_http_auth_uninit(&inChannel->common);
890 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
894 if (!rts_send_CONN_B1_pdu(rpc))
896 WLog_ERR(TAG,
"rpc_send_CONN_B1_pdu error!");
897 http_response_free(response);
901 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
903 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
905 rpc_virtual_connection_transition_to_state(
906 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
913 http_response_free(response);
917 response = http_response_recv(inChannel->common.tls, TRUE);
923 http_response_free(response);
941 ArrayList_Lock(client->ClientCallList);
942 const size_t count = ArrayList_Count(client->ClientCallList);
944 for (
size_t index = 0; index < count; index++)
946 clientCall = (
RpcClientCall*)ArrayList_GetItem(client->ClientCallList, index);
948 if (clientCall->CallId == CallId)
952 ArrayList_Unlock(client->ClientCallList);
956 RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
964 clientCall->CallId = CallId;
965 clientCall->OpNum = OpNum;
966 clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
975 static void rpc_array_client_call_free(
void* call)
980 int rpc_in_channel_send_pdu(
RpcInChannel* inChannel,
const BYTE* buffer,
size_t length)
987 status = rpc_channel_write(&inChannel->common, buffer, length);
992 Stream_StaticConstInit(&s, buffer, length);
993 if (!rts_read_common_pdu_header(&s, &header, FALSE))
996 clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id);
1000 clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
1009 if (header.ptype == PTYPE_REQUEST)
1011 inChannel->BytesSent += status;
1012 inChannel->SenderAvailableWindow -= status;
1015 if (status > INT32_MAX)
1020 BOOL rpc_client_write_call(rdpRpc* rpc,
wStream* s, UINT16 opnum)
1023 BYTE* buffer = NULL;
1024 size_t stub_data_pad = 0;
1028 rdpCredsspAuth* auth = NULL;
1041 connection = rpc->VirtualConnection;
1045 WLog_ERR(TAG,
"invalid auth context");
1052 inChannel = connection->DefaultInChannel;
1057 Stream_SealLength(s);
1058 const size_t length = Stream_Length(s);
1059 if (length > UINT32_MAX)
1062 const size_t asize = credssp_auth_trailer_size(auth);
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);
1077 if (!ArrayList_Append(rpc->client->ClientCallList, clientCall))
1079 rpc_client_call_free(clientCall);
1084 if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
1085 rpc->PipeCallId = request_pdu.header.call_id;
1087 request_pdu.stub_data = Stream_Buffer(s);
1089 stub_data_pad = rpc_offset_align(&offset, 8);
1091 request_pdu.auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
1092 request_pdu.auth_verifier.auth_type =
1093 rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
1094 request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
1095 request_pdu.auth_verifier.auth_reserved = 0x00;
1096 request_pdu.auth_verifier.auth_context_id = 0x00000000;
1097 offset += (8 + request_pdu.header.auth_length);
1099 if (offset > UINT32_MAX)
1101 request_pdu.header.frag_length = (UINT32)offset;
1102 buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
1107 CopyMemory(buffer, &request_pdu, 24);
1109 rpc_offset_pad(&offset, stub_data_pad);
1110 CopyMemory(&buffer[offset], request_pdu.stub_data, length);
1112 rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
1113 CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
1116 if (offset > UINT32_MAX)
1119 plaintext.pvBuffer = buffer;
1120 plaintext.cbBuffer = (UINT32)offset;
1121 plaintext.BufferType = SECBUFFER_READONLY;
1124 if (!credssp_auth_encrypt(auth, &plaintext, &ciphertext, &size, rpc->SendSeqNum++))
1127 CopyMemory(&buffer[offset], ciphertext.pvBuffer, size);
1130 sspi_SecBufferFree(&ciphertext);
1132 if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
1138 Stream_Free(s, TRUE);
1142 static BOOL rpc_client_resolve_gateway(rdpSettings* settings,
char** host, UINT16* port,
1145 struct addrinfo* result = NULL;
1147 if (!settings || !host || !port || !isProxy)
1155 *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
1156 result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
1162 freerdp_tcp_address_to_string((
const struct sockaddr_storage*)result->ai_addr, NULL);
1163 freeaddrinfo(result);
1168 RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
1176 if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
1180 client->context = context;
1182 if (!client->context)
1185 client->pdu = rpc_pdu_new();
1190 client->ReceiveFragment = Stream_New(NULL, max_recv_frag);
1192 if (!client->ReceiveFragment)
1195 client->PipeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1197 if (!client->PipeEvent)
1200 if (!ringbuffer_init(&(client->ReceivePipe), 4096))
1203 if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
1206 client->ClientCallList = ArrayList_New(TRUE);
1208 if (!client->ClientCallList)
1211 obj = ArrayList_Object(client->ClientCallList);
1212 obj->fnObjectFree = rpc_array_client_call_free;
1215 WINPR_PRAGMA_DIAG_PUSH
1216 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1217 rpc_client_free(client);
1218 WINPR_PRAGMA_DIAG_POP
1229 if (client->ReceiveFragment)
1230 Stream_Free(client->ReceiveFragment, TRUE);
1232 if (client->PipeEvent)
1233 (void)CloseHandle(client->PipeEvent);
1235 ringbuffer_destroy(&(client->ReceivePipe));
1236 DeleteCriticalSection(&(client->PipeLock));
1239 rpc_pdu_free(client->pdu);
1241 if (client->ClientCallList)
1242 ArrayList_Free(client->ClientCallList);
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
This struct contains function pointer to initialize/free objects.