2012-11-28 21:47:04 +04:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* RPC Client
|
|
|
|
*
|
|
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
#include <freerdp/log.h>
|
2013-12-21 03:22:29 +04:00
|
|
|
|
2012-11-28 21:47:04 +04:00
|
|
|
#include <winpr/crt.h>
|
2012-12-13 00:55:42 +04:00
|
|
|
#include <winpr/print.h>
|
2012-11-28 21:47:04 +04:00
|
|
|
#include <winpr/synch.h>
|
|
|
|
#include <winpr/thread.h>
|
2012-12-11 00:43:07 +04:00
|
|
|
#include <winpr/stream.h>
|
2012-11-28 21:47:04 +04:00
|
|
|
|
2015-02-04 01:17:17 +03:00
|
|
|
#include "http.h"
|
|
|
|
#include "ncacn_http.h"
|
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
#include "rpc_bind.h"
|
2012-12-12 04:17:57 +04:00
|
|
|
#include "rpc_fault.h"
|
2012-11-28 21:47:04 +04:00
|
|
|
#include "rpc_client.h"
|
2013-05-22 12:58:11 +04:00
|
|
|
#include "../rdp.h"
|
2018-09-27 17:42:27 +03:00
|
|
|
#include "../proxy.h"
|
2013-05-22 12:58:11 +04:00
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
#define TAG FREERDP_TAG("core.gateway.rpc")
|
2012-12-12 09:49:15 +04:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
static void rpc_pdu_reset(RPC_PDU* pdu)
|
|
|
|
{
|
|
|
|
pdu->Type = 0;
|
|
|
|
pdu->Flags = 0;
|
|
|
|
pdu->CallId = 0;
|
|
|
|
Stream_SetPosition(pdu->s, 0);
|
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static RPC_PDU* rpc_pdu_new(void)
|
2012-12-12 09:49:15 +04:00
|
|
|
{
|
2015-02-02 04:47:43 +03:00
|
|
|
RPC_PDU* pdu;
|
2019-11-06 17:24:51 +03:00
|
|
|
pdu = (RPC_PDU*)malloc(sizeof(RPC_PDU));
|
2012-12-12 09:49:15 +04:00
|
|
|
|
|
|
|
if (!pdu)
|
2015-02-02 04:47:43 +03:00
|
|
|
return NULL;
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2015-02-02 04:47:43 +03:00
|
|
|
pdu->s = Stream_New(NULL, 4096);
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2015-02-02 04:47:43 +03:00
|
|
|
if (!pdu->s)
|
|
|
|
{
|
|
|
|
free(pdu);
|
|
|
|
return NULL;
|
2012-12-12 09:49:15 +04:00
|
|
|
}
|
2012-12-12 04:17:57 +04:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
rpc_pdu_reset(pdu);
|
2015-02-02 04:47:43 +03:00
|
|
|
return pdu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rpc_pdu_free(RPC_PDU* pdu)
|
|
|
|
{
|
|
|
|
if (!pdu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Stream_Free(pdu->s, TRUE);
|
|
|
|
free(pdu);
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
static int rpc_client_receive_pipe_write(RpcClient* client, const BYTE* buffer, size_t length)
|
2015-02-01 00:56:25 +03:00
|
|
|
{
|
2015-02-01 21:09:28 +03:00
|
|
|
int status = 0;
|
2018-09-27 17:23:01 +03:00
|
|
|
|
|
|
|
if (!client || !buffer)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
EnterCriticalSection(&(client->PipeLock));
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
if (ringbuffer_write(&(client->ReceivePipe), buffer, length))
|
2019-11-06 17:24:51 +03:00
|
|
|
status += (int)length;
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
if (ringbuffer_used(&(client->ReceivePipe)) > 0)
|
|
|
|
SetEvent(client->PipeEvent);
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
LeaveCriticalSection(&(client->PipeLock));
|
2015-02-01 21:09:28 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length)
|
2015-02-01 21:09:28 +03:00
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
int status = 0;
|
|
|
|
int nchunks = 0;
|
|
|
|
DataChunk chunks[2];
|
2018-09-27 17:23:01 +03:00
|
|
|
|
|
|
|
if (!client || !buffer)
|
|
|
|
return -1;
|
|
|
|
|
2015-02-01 21:09:28 +03:00
|
|
|
EnterCriticalSection(&(client->PipeLock));
|
|
|
|
nchunks = ringbuffer_peek(&(client->ReceivePipe), chunks, length);
|
|
|
|
|
|
|
|
for (index = 0; index < nchunks; index++)
|
|
|
|
{
|
|
|
|
CopyMemory(&buffer[status], chunks[index].data, chunks[index].size);
|
|
|
|
status += chunks[index].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status > 0)
|
|
|
|
ringbuffer_commit_read_bytes(&(client->ReceivePipe), status);
|
|
|
|
|
|
|
|
if (ringbuffer_used(&(client->ReceivePipe)) < 1)
|
|
|
|
ResetEvent(client->PipeEvent);
|
|
|
|
|
|
|
|
LeaveCriticalSection(&(client->PipeLock));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
|
2015-02-03 02:50:26 +03:00
|
|
|
{
|
|
|
|
int status = 1;
|
|
|
|
const char* str = "RPC_CLIENT_STATE_UNKNOWN";
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
{
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_INITIAL:
|
|
|
|
str = "RPC_CLIENT_STATE_INITIAL";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_ESTABLISHED:
|
|
|
|
str = "RPC_CLIENT_STATE_ESTABLISHED";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK:
|
|
|
|
str = "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK:
|
|
|
|
str = "RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE:
|
|
|
|
str = "RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_CONTEXT_NEGOTIATED:
|
|
|
|
str = "RPC_CLIENT_STATE_CONTEXT_NEGOTIATED";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_WAIT_RESPONSE:
|
|
|
|
str = "RPC_CLIENT_STATE_WAIT_RESPONSE";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case RPC_CLIENT_STATE_FINAL:
|
|
|
|
str = "RPC_CLIENT_STATE_FINAL";
|
|
|
|
break;
|
2015-02-03 02:50:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
rpc->State = state;
|
|
|
|
WLog_DBG(TAG, "%s", str);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
|
2015-02-01 21:09:28 +03:00
|
|
|
{
|
2015-02-03 02:50:26 +03:00
|
|
|
int status = -1;
|
2015-02-02 16:19:07 +03:00
|
|
|
rpcconn_rts_hdr_t* rts;
|
|
|
|
rdpTsg* tsg = rpc->transport->tsg;
|
|
|
|
|
2015-02-04 00:33:45 +03:00
|
|
|
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
|
|
|
switch (rpc->VirtualConnection->State)
|
|
|
|
{
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_INITIAL:
|
|
|
|
break;
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
|
|
|
|
break;
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
|
2019-11-06 17:24:51 +03:00
|
|
|
rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s);
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2018-09-28 13:08:27 +03:00
|
|
|
if (!rts_match_pdu_signature(&RTS_PDU_CONN_A3_SIGNATURE, rts))
|
2017-02-20 20:31:58 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/A3");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
status = rts_recv_CONN_A3_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rts_recv_CONN_A3_pdu failure");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
|
|
|
|
VIRTUAL_CONNECTION_STATE_WAIT_C2);
|
2017-02-20 20:31:58 +03:00
|
|
|
status = 1;
|
|
|
|
break;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_WAIT_C2:
|
2019-11-06 17:24:51 +03:00
|
|
|
rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s);
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2018-09-28 13:08:27 +03:00
|
|
|
if (!rts_match_pdu_signature(&RTS_PDU_CONN_C2_SIGNATURE, rts))
|
2017-02-20 20:31:58 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/C2");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
status = rts_recv_CONN_C2_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rts_recv_CONN_C2_pdu failure");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
|
|
|
|
VIRTUAL_CONNECTION_STATE_OPENED);
|
2017-02-20 20:31:58 +03:00
|
|
|
rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_ESTABLISHED);
|
2015-02-03 02:50:26 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
if (rpc_send_bind_pdu(rpc) < 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_send_bind_pdu failure");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK);
|
|
|
|
status = 1;
|
|
|
|
break;
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_OPENED:
|
|
|
|
break;
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
case VIRTUAL_CONNECTION_STATE_FINAL:
|
|
|
|
break;
|
2015-02-02 16:19:07 +03:00
|
|
|
}
|
|
|
|
}
|
2015-02-03 02:50:26 +03:00
|
|
|
else if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
2015-02-03 02:50:26 +03:00
|
|
|
if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
2015-02-03 02:50:26 +03:00
|
|
|
if (pdu->Type == PTYPE_BIND_ACK)
|
|
|
|
{
|
|
|
|
if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_recv_bind_ack_pdu failure");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG,
|
|
|
|
"RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK unexpected pdu type: 0x%08" PRIX32
|
|
|
|
"",
|
2017-02-20 20:31:58 +03:00
|
|
|
pdu->Type);
|
2015-02-02 16:19:07 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-04 01:17:17 +03:00
|
|
|
if (rpc_send_rpc_auth_3_pdu(rpc) < 0)
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2018-09-28 09:43:43 +03:00
|
|
|
if (!tsg_proxy_begin(tsg))
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
2015-02-16 23:35:51 +03:00
|
|
|
WLog_ERR(TAG, "tsg_proxy_begin failure");
|
2015-02-02 16:19:07 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
status = 1;
|
2015-02-02 16:19:07 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_client_recv_pdu: invalid rpc->State: %d", rpc->State);
|
|
|
|
}
|
|
|
|
}
|
2015-02-03 02:50:26 +03:00
|
|
|
else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
|
2015-02-02 16:19:07 +03:00
|
|
|
{
|
2018-09-28 09:43:43 +03:00
|
|
|
if (!tsg_recv_pdu(tsg, pdu))
|
|
|
|
status = -1;
|
|
|
|
else
|
|
|
|
status = 1;
|
2015-02-02 16:19:07 +03:00
|
|
|
}
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
return status;
|
2015-02-01 00:56:25 +03:00
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
|
2012-12-12 04:17:57 +04:00
|
|
|
{
|
2014-08-18 21:34:47 +04:00
|
|
|
BYTE* buffer;
|
2015-02-01 23:58:32 +03:00
|
|
|
RPC_PDU* pdu;
|
2012-12-12 04:17:57 +04:00
|
|
|
UINT32 StubOffset;
|
|
|
|
UINT32 StubLength;
|
2015-02-01 23:58:32 +03:00
|
|
|
RpcClientCall* call;
|
2014-08-18 21:34:47 +04:00
|
|
|
rpcconn_hdr_t* header;
|
2015-02-02 16:19:07 +03:00
|
|
|
pdu = rpc->client->pdu;
|
2019-11-06 17:24:51 +03:00
|
|
|
buffer = (BYTE*)Stream_Buffer(fragment);
|
|
|
|
header = (rpcconn_hdr_t*)Stream_Buffer(fragment);
|
2012-12-12 08:34:51 +04:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (header->common.ptype == PTYPE_RESPONSE)
|
2012-12-12 04:17:57 +04:00
|
|
|
{
|
2015-02-01 23:58:32 +03:00
|
|
|
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length;
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
|
|
|
|
header->common.frag_length;
|
2012-12-12 04:17:57 +04:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
|
|
|
|
(rpc->ReceiveWindow / 2))
|
2015-02-01 23:58:32 +03:00
|
|
|
{
|
2015-05-26 16:49:38 +03:00
|
|
|
if (rts_send_flow_control_ack_pdu(rpc) < 0)
|
|
|
|
return -1;
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
2014-08-19 20:26:39 +04:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "expected stub");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StubLength == 4)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if ((header->common.call_id == rpc->PipeCallId) &&
|
|
|
|
(header->common.pfc_flags & PFC_LAST_FRAG))
|
2014-05-21 19:32:14 +04:00
|
|
|
{
|
2015-04-11 00:09:54 +03:00
|
|
|
/* End of TsProxySetupReceivePipe */
|
2015-02-01 23:58:32 +03:00
|
|
|
TerminateEventArgs e;
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc->result = *((UINT32*)&buffer[StubOffset]);
|
2015-09-05 15:57:30 +03:00
|
|
|
freerdp_abort_connect(rpc->context->instance);
|
2018-09-28 09:43:43 +03:00
|
|
|
tsg_set_state(rpc->transport->tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
|
2015-02-01 23:58:32 +03:00
|
|
|
EventArgsInit(&e, "freerdp");
|
|
|
|
e.code = 0;
|
|
|
|
PubSub_OnTerminate(rpc->context->pubSub, rpc->context, &e);
|
2015-04-11 00:09:54 +03:00
|
|
|
return 0;
|
2014-05-21 19:32:14 +04:00
|
|
|
}
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2015-04-11 00:09:54 +03:00
|
|
|
if (header->common.call_id != rpc->PipeCallId)
|
|
|
|
{
|
|
|
|
/* Ignoring non-TsProxySetupReceivePipe Response */
|
|
|
|
return 0;
|
|
|
|
}
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
2015-01-13 21:50:46 +03:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (rpc->StubFragCount == 0)
|
|
|
|
rpc->StubCallId = header->common.call_id;
|
2015-01-13 21:50:46 +03:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (rpc->StubCallId != header->common.call_id)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG,
|
|
|
|
"invalid call_id: actual: %" PRIu32 ", expected: %" PRIu32
|
|
|
|
", frag_count: %" PRIu32 "",
|
2017-02-20 20:31:58 +03:00
|
|
|
rpc->StubCallId, header->common.call_id, rpc->StubFragCount);
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
2015-01-13 21:50:46 +03:00
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId);
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
|
|
if (!call)
|
2014-05-21 19:32:14 +04:00
|
|
|
return -1;
|
2012-12-12 08:34:51 +04:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (call->OpNum != TsProxySetupReceivePipeOpnum)
|
|
|
|
{
|
2015-03-30 18:15:45 +03:00
|
|
|
if (!Stream_EnsureCapacity(pdu->s, header->response.alloc_hint))
|
2015-03-26 19:09:47 +03:00
|
|
|
return -1;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
Stream_Write(pdu->s, &buffer[StubOffset], StubLength);
|
|
|
|
rpc->StubFragCount++;
|
2012-12-12 08:34:51 +04:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
if (header->response.alloc_hint == StubLength)
|
|
|
|
{
|
|
|
|
pdu->Flags = RPC_PDU_FLAG_STUB;
|
|
|
|
pdu->Type = PTYPE_RESPONSE;
|
|
|
|
pdu->CallId = rpc->StubCallId;
|
|
|
|
Stream_SealLength(pdu->s);
|
2021-01-27 11:44:19 +03:00
|
|
|
if (rpc_client_recv_pdu(rpc, pdu) < 0)
|
|
|
|
return -1;
|
2015-02-02 16:19:07 +03:00
|
|
|
rpc_pdu_reset(pdu);
|
2015-02-01 23:58:32 +03:00
|
|
|
rpc->StubFragCount = 0;
|
|
|
|
rpc->StubCallId = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2013-06-19 00:55:23 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_client_receive_pipe_write(rpc->client, &buffer[StubOffset], (size_t)StubLength);
|
2015-02-01 23:58:32 +03:00
|
|
|
rpc->StubFragCount++;
|
|
|
|
|
|
|
|
if (header->response.alloc_hint == StubLength)
|
|
|
|
{
|
|
|
|
rpc->StubFragCount = 0;
|
|
|
|
rpc->StubCallId = 0;
|
|
|
|
}
|
2013-06-19 00:55:23 +04:00
|
|
|
}
|
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
return 1;
|
2012-12-12 08:34:51 +04:00
|
|
|
}
|
2015-02-01 23:58:32 +03:00
|
|
|
else if (header->common.ptype == PTYPE_RTS)
|
2012-12-12 04:17:57 +04:00
|
|
|
{
|
2015-02-01 23:58:32 +03:00
|
|
|
if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
|
|
|
|
{
|
|
|
|
pdu->Flags = 0;
|
|
|
|
pdu->Type = header->common.ptype;
|
|
|
|
pdu->CallId = header->common.call_id;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-03-30 18:15:45 +03:00
|
|
|
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
|
2015-03-26 19:09:47 +03:00
|
|
|
return -1;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
|
|
|
|
Stream_SealLength(pdu->s);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-26 16:49:38 +03:00
|
|
|
if (rpc_client_recv_pdu(rpc, pdu) < 0)
|
|
|
|
return -1;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
rpc_pdu_reset(pdu);
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-26 16:49:38 +03:00
|
|
|
if (rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length) < 0)
|
|
|
|
return -1;
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
2015-02-02 16:19:07 +03:00
|
|
|
|
|
|
|
return 1;
|
2012-12-12 04:17:57 +04:00
|
|
|
}
|
2015-02-01 23:58:32 +03:00
|
|
|
else if (header->common.ptype == PTYPE_BIND_ACK)
|
2012-12-12 04:17:57 +04:00
|
|
|
{
|
2015-02-01 23:58:32 +03:00
|
|
|
pdu->Flags = 0;
|
|
|
|
pdu->Type = header->common.ptype;
|
|
|
|
pdu->CallId = header->common.call_id;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-04-10 23:50:17 +03:00
|
|
|
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
|
2015-03-26 19:09:47 +03:00
|
|
|
return -1;
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
|
|
|
|
Stream_SealLength(pdu->s);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2015-05-26 16:49:38 +03:00
|
|
|
if (rpc_client_recv_pdu(rpc, pdu) < 0)
|
|
|
|
return -1;
|
2015-02-02 16:19:07 +03:00
|
|
|
|
2017-02-20 20:31:58 +03:00
|
|
|
rpc_pdu_reset(pdu);
|
2015-02-02 16:19:07 +03:00
|
|
|
return 1;
|
2012-12-12 04:17:57 +04:00
|
|
|
}
|
2015-02-01 23:58:32 +03:00
|
|
|
else if (header->common.ptype == PTYPE_FAULT)
|
|
|
|
{
|
2018-11-16 17:41:19 +03:00
|
|
|
rpc_recv_fault_pdu(header->fault.status);
|
2015-02-01 23:58:32 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header->common.ptype);
|
2015-02-02 16:19:07 +03:00
|
|
|
return -1;
|
2015-02-01 23:58:32 +03:00
|
|
|
}
|
2012-12-12 04:17:57 +04:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
return 1;
|
2012-12-12 04:17:57 +04:00
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
|
|
|
int status = -1;
|
2015-03-19 18:44:47 +03:00
|
|
|
UINT32 statusCode;
|
2015-02-04 01:17:17 +03:00
|
|
|
HttpResponse* response;
|
2015-02-04 04:39:47 +03:00
|
|
|
RpcInChannel* inChannel;
|
2015-02-04 01:17:17 +03:00
|
|
|
RpcOutChannel* outChannel;
|
2015-03-19 18:44:47 +03:00
|
|
|
HANDLE outChannelEvent = NULL;
|
2015-02-19 23:06:57 +03:00
|
|
|
RpcVirtualConnection* connection = rpc->VirtualConnection;
|
|
|
|
inChannel = connection->DefaultInChannel;
|
|
|
|
outChannel = connection->DefaultOutChannel;
|
2018-09-27 17:05:14 +03:00
|
|
|
BIO_get_event(outChannel->common.tls->bio, &outChannelEvent);
|
2015-03-19 18:44:47 +03:00
|
|
|
|
2015-02-04 04:39:47 +03:00
|
|
|
if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
2015-03-19 18:44:47 +03:00
|
|
|
if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
|
|
|
|
return 1;
|
|
|
|
|
2018-11-12 17:40:10 +03:00
|
|
|
response = http_response_recv(outChannel->common.tls, TRUE);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
if (!response)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
|
|
|
|
{
|
|
|
|
/* Receive OUT Channel Response */
|
2018-09-27 17:05:14 +03:00
|
|
|
if (!rpc_ncacn_http_recv_out_channel_response(&outChannel->common, response))
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
2018-08-17 17:00:19 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send OUT Channel Request */
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
2018-08-17 17:00:19 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
rpc_ncacn_http_ntlm_uninit(&outChannel->common);
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
/* Send CONN/A1 PDU over OUT channel */
|
|
|
|
|
|
|
|
if (rts_send_CONN_A1_pdu(rpc) < 0)
|
|
|
|
{
|
2018-08-17 17:00:19 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
|
2015-02-04 04:39:47 +03:00
|
|
|
|
2015-02-04 19:18:27 +03:00
|
|
|
if (inChannel->State == CLIENT_IN_CHANNEL_STATE_OPENED)
|
2015-02-04 04:39:47 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_virtual_connection_transition_to_state(
|
|
|
|
rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
|
2015-02-04 04:39:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
status = 1;
|
2015-02-04 01:17:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
http_response_free(response);
|
|
|
|
}
|
2015-02-19 23:06:57 +03:00
|
|
|
else if (connection->State == VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT)
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
|
|
|
/* Receive OUT channel response */
|
2015-03-19 18:44:47 +03:00
|
|
|
if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
|
|
|
|
return 1;
|
|
|
|
|
2018-11-12 17:40:10 +03:00
|
|
|
response = http_response_recv(outChannel->common.tls, FALSE);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
if (!response)
|
|
|
|
return -1;
|
|
|
|
|
2018-09-27 16:04:41 +03:00
|
|
|
statusCode = http_response_get_status_code(response);
|
2015-03-19 18:44:47 +03:00
|
|
|
|
|
|
|
if (statusCode != HTTP_STATUS_OK)
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG, "error! Status Code: %" PRIu32 "", statusCode);
|
2015-02-04 01:17:17 +03:00
|
|
|
http_response_print(response);
|
|
|
|
|
2015-03-19 18:44:47 +03:00
|
|
|
if (statusCode == HTTP_STATUS_DENIED)
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
2020-01-09 12:34:27 +03:00
|
|
|
freerdp_set_last_error_if_not(rpc->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
|
2015-02-04 01:17:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-15 18:50:01 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
http_response_free(response);
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
|
|
|
|
VIRTUAL_CONNECTION_STATE_WAIT_A3W);
|
2015-02-04 04:39:47 +03:00
|
|
|
status = 1;
|
2015-02-04 01:17:17 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-12 22:08:38 +03:00
|
|
|
wStream* fragment;
|
|
|
|
rpcconn_common_hdr_t* header;
|
|
|
|
fragment = rpc->client->ReceiveFragment;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
|
|
|
|
{
|
2018-09-27 17:05:14 +03:00
|
|
|
status = rpc_channel_read(&outChannel->common, fragment,
|
|
|
|
RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
return -1;
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
|
2015-02-12 22:08:38 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:34:41 +03:00
|
|
|
header = (rpcconn_common_hdr_t*)Stream_Buffer(fragment);
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (header->frag_length > rpc->max_recv_frag)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG,
|
|
|
|
"rpc_client_recv: invalid fragment size: %" PRIu16 " (max: %" PRIu16 ")",
|
2017-02-20 20:31:58 +03:00
|
|
|
header->frag_length, rpc->max_recv_frag);
|
2019-11-06 17:24:51 +03:00
|
|
|
winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
|
|
|
|
Stream_GetPosition(fragment));
|
2015-02-12 22:08:38 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (Stream_GetPosition(fragment) < header->frag_length)
|
|
|
|
{
|
2018-09-27 17:05:14 +03:00
|
|
|
status = rpc_channel_read(&outChannel->common, fragment,
|
|
|
|
header->frag_length - Stream_GetPosition(fragment));
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "error reading fragment body");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
if (Stream_GetPosition(fragment) < header->frag_length)
|
2015-02-12 22:08:38 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
/* complete fragment received */
|
|
|
|
Stream_SealLength(fragment);
|
|
|
|
Stream_SetPosition(fragment, 0);
|
|
|
|
status = rpc_client_recv_fragment(rpc, fragment);
|
|
|
|
|
2015-02-24 23:34:41 +03:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2015-02-19 23:06:57 +03:00
|
|
|
/* channel recycling may update channel pointers */
|
2019-11-06 17:24:51 +03:00
|
|
|
if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
|
|
|
|
connection->NonDefaultOutChannel)
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2018-09-27 17:05:14 +03:00
|
|
|
rpc_channel_free(&connection->DefaultOutChannel->common);
|
2015-02-24 23:34:41 +03:00
|
|
|
connection->DefaultOutChannel = connection->NonDefaultOutChannel;
|
|
|
|
connection->NonDefaultOutChannel = NULL;
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
|
|
|
|
CLIENT_OUT_CHANNEL_STATE_OPENED);
|
|
|
|
rpc_virtual_connection_transition_to_state(
|
|
|
|
rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
|
2015-02-24 23:34:41 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
Stream_SetPosition(fragment, 0);
|
|
|
|
}
|
|
|
|
}
|
2015-02-04 01:17:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-01-15 14:43:37 +03:00
|
|
|
static int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
|
|
|
int status = -1;
|
|
|
|
HttpResponse* response;
|
|
|
|
RpcOutChannel* nextOutChannel;
|
2015-03-19 18:44:47 +03:00
|
|
|
HANDLE nextOutChannelEvent = NULL;
|
2015-02-24 23:34:41 +03:00
|
|
|
nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
|
2018-09-27 17:05:14 +03:00
|
|
|
BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
|
2015-03-19 18:44:47 +03:00
|
|
|
|
|
|
|
if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
|
|
|
|
return 1;
|
|
|
|
|
2018-11-12 17:40:10 +03:00
|
|
|
response = http_response_recv(nextOutChannel->common.tls, TRUE);
|
2015-03-19 18:44:47 +03:00
|
|
|
|
2015-02-24 23:34:41 +03:00
|
|
|
if (response)
|
|
|
|
{
|
2018-12-06 12:07:15 +03:00
|
|
|
switch (nextOutChannel->State)
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
case CLIENT_OUT_CHANNEL_STATE_SECURITY:
|
2018-12-06 12:07:15 +03:00
|
|
|
if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2018-12-06 12:07:15 +03:00
|
|
|
if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2018-12-06 12:07:15 +03:00
|
|
|
rpc_ncacn_http_ntlm_uninit(&nextOutChannel->common);
|
|
|
|
status = rts_send_OUT_R1_A3_pdu(rpc);
|
|
|
|
|
|
|
|
if (status >= 0)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_out_channel_transition_to_state(
|
|
|
|
nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
|
2018-12-06 12:07:15 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rts_send_OUT_R1/A3_pdu failure");
|
|
|
|
}
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-06 12:07:15 +03:00
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-06 12:07:15 +03:00
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
2018-12-06 12:07:15 +03:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-11-06 17:24:51 +03:00
|
|
|
WLog_ERR(TAG,
|
|
|
|
"rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
|
2018-12-06 12:07:15 +03:00
|
|
|
nextOutChannel->State);
|
|
|
|
return -1;
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
http_response_free(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpc_client_out_channel_recv(rdpRpc* rpc)
|
|
|
|
{
|
2015-03-19 18:44:47 +03:00
|
|
|
int status;
|
2015-02-24 23:34:41 +03:00
|
|
|
RpcVirtualConnection* connection = rpc->VirtualConnection;
|
|
|
|
|
2015-03-19 18:44:47 +03:00
|
|
|
if (connection->DefaultOutChannel)
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2015-03-19 18:44:47 +03:00
|
|
|
status = rpc_client_default_out_channel_recv(rpc);
|
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
return -1;
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
|
2015-03-19 18:44:47 +03:00
|
|
|
if (connection->NonDefaultOutChannel)
|
2015-02-24 23:34:41 +03:00
|
|
|
{
|
2015-03-19 18:44:47 +03:00
|
|
|
status = rpc_client_nondefault_out_channel_recv(rpc);
|
2015-02-24 23:34:41 +03:00
|
|
|
|
2015-03-19 18:44:47 +03:00
|
|
|
if (status < 0)
|
|
|
|
return -1;
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
|
2015-03-19 18:44:47 +03:00
|
|
|
return 1;
|
2015-02-24 23:34:41 +03:00
|
|
|
}
|
|
|
|
|
2015-02-04 01:17:17 +03:00
|
|
|
int rpc_client_in_channel_recv(rdpRpc* rpc)
|
|
|
|
{
|
2015-03-19 18:44:47 +03:00
|
|
|
int status = 1;
|
2015-02-04 01:17:17 +03:00
|
|
|
HttpResponse* response;
|
|
|
|
RpcInChannel* inChannel;
|
2015-02-04 04:39:47 +03:00
|
|
|
RpcOutChannel* outChannel;
|
2015-02-04 01:17:17 +03:00
|
|
|
HANDLE InChannelEvent = NULL;
|
2015-02-19 23:06:57 +03:00
|
|
|
RpcVirtualConnection* connection = rpc->VirtualConnection;
|
|
|
|
inChannel = connection->DefaultInChannel;
|
|
|
|
outChannel = connection->DefaultOutChannel;
|
2018-09-27 17:05:14 +03:00
|
|
|
BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
|
|
|
|
{
|
2018-11-12 17:40:10 +03:00
|
|
|
response = http_response_recv(inChannel->common.tls, TRUE);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
if (!response)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
|
|
|
|
{
|
2018-09-27 17:05:14 +03:00
|
|
|
if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_recv_in_channel_response failure");
|
2018-01-15 18:50:01 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send IN Channel Request */
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
|
2015-02-04 01:17:17 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
|
2018-01-15 18:50:01 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:05:14 +03:00
|
|
|
rpc_ncacn_http_ntlm_uninit(&inChannel->common);
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
/* Send CONN/B1 PDU over IN channel */
|
|
|
|
|
|
|
|
if (rts_send_CONN_B1_pdu(rpc) < 0)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!");
|
2018-01-15 18:50:01 +03:00
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
|
2015-02-04 01:17:17 +03:00
|
|
|
|
2015-02-04 19:18:27 +03:00
|
|
|
if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
|
2015-02-04 04:39:47 +03:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rpc_virtual_connection_transition_to_state(
|
|
|
|
rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
|
2015-02-04 04:39:47 +03:00
|
|
|
}
|
|
|
|
|
2015-02-04 01:17:17 +03:00
|
|
|
status = 1;
|
|
|
|
}
|
2015-02-04 19:18:27 +03:00
|
|
|
|
|
|
|
http_response_free(response);
|
2015-02-04 01:17:17 +03:00
|
|
|
}
|
2015-03-19 18:44:47 +03:00
|
|
|
else
|
|
|
|
{
|
2018-11-12 17:40:10 +03:00
|
|
|
response = http_response_recv(inChannel->common.tls, TRUE);
|
2015-03-19 18:44:47 +03:00
|
|
|
|
|
|
|
if (!response)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* We can receive an unauthorized HTTP response on the IN channel */
|
|
|
|
http_response_free(response);
|
|
|
|
}
|
2015-02-04 01:17:17 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2012-12-08 06:09:55 +04:00
|
|
|
/**
|
|
|
|
* [MS-RPCE] Client Call:
|
|
|
|
* http://msdn.microsoft.com/en-us/library/gg593159/
|
|
|
|
*/
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId)
|
2012-12-08 06:09:55 +04:00
|
|
|
{
|
|
|
|
int index;
|
|
|
|
int count;
|
2015-01-28 22:54:03 +03:00
|
|
|
RpcClientCall* clientCall = NULL;
|
2018-09-27 17:23:01 +03:00
|
|
|
|
|
|
|
if (!client)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ArrayList_Lock(client->ClientCallList);
|
|
|
|
count = ArrayList_Count(client->ClientCallList);
|
2012-12-08 06:09:55 +04:00
|
|
|
|
|
|
|
for (index = 0; index < count; index++)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
clientCall = (RpcClientCall*)ArrayList_GetItem(client->ClientCallList, index);
|
2012-12-08 06:09:55 +04:00
|
|
|
|
2012-12-12 09:49:15 +04:00
|
|
|
if (clientCall->CallId == CallId)
|
2012-12-08 06:09:55 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
ArrayList_Unlock(client->ClientCallList);
|
2012-12-12 09:49:15 +04:00
|
|
|
return clientCall;
|
2012-12-08 06:09:55 +04:00
|
|
|
}
|
|
|
|
|
2014-08-18 21:34:47 +04:00
|
|
|
RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
|
2012-12-08 06:09:55 +04:00
|
|
|
{
|
2014-08-18 21:34:47 +04:00
|
|
|
RpcClientCall* clientCall;
|
2019-11-06 17:24:51 +03:00
|
|
|
clientCall = (RpcClientCall*)calloc(1, sizeof(RpcClientCall));
|
2012-12-08 06:09:55 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
if (!clientCall)
|
|
|
|
return NULL;
|
2012-12-08 06:09:55 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
clientCall->CallId = CallId;
|
|
|
|
clientCall->OpNum = OpNum;
|
|
|
|
clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
|
2012-12-12 09:49:15 +04:00
|
|
|
return clientCall;
|
2012-12-08 06:09:55 +04:00
|
|
|
}
|
|
|
|
|
2014-08-18 21:34:47 +04:00
|
|
|
void rpc_client_call_free(RpcClientCall* clientCall)
|
2012-12-08 06:09:55 +04:00
|
|
|
{
|
2012-12-12 09:49:15 +04:00
|
|
|
free(clientCall);
|
2012-12-08 06:09:55 +04:00
|
|
|
}
|
|
|
|
|
2018-10-18 10:09:30 +03:00
|
|
|
static void rpc_array_client_call_free(void* call)
|
|
|
|
{
|
|
|
|
rpc_client_call_free((RpcClientCall*)call);
|
|
|
|
}
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length)
|
2012-11-28 21:47:04 +04:00
|
|
|
{
|
2013-12-21 03:22:29 +04:00
|
|
|
int status;
|
2014-08-18 21:34:47 +04:00
|
|
|
RpcClientCall* clientCall;
|
|
|
|
rpcconn_common_hdr_t* header;
|
2018-09-27 17:05:14 +03:00
|
|
|
status = rpc_channel_write(&inChannel->common, buffer, length);
|
2012-11-28 22:38:01 +04:00
|
|
|
|
2015-02-03 22:44:31 +03:00
|
|
|
if (status <= 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
header = (rpcconn_common_hdr_t*)buffer;
|
2018-09-27 17:42:27 +03:00
|
|
|
clientCall = rpc_client_call_find_by_id(inChannel->common.client, header->call_id);
|
2012-12-12 09:49:15 +04:00
|
|
|
clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
|
2012-11-28 21:47:04 +04:00
|
|
|
|
|
|
|
/*
|
2017-02-20 20:31:58 +03:00
|
|
|
* This protocol specifies that only RPC PDUs are subject to the flow control abstract
|
2019-11-06 17:24:51 +03:00
|
|
|
* data model. RTS PDUs and the HTTP request and response headers are not subject to flow
|
|
|
|
* control. Implementations of this protocol MUST NOT include them when computing any of the
|
|
|
|
* variables specified by this abstract data model.
|
2017-02-20 20:31:58 +03:00
|
|
|
*/
|
2012-12-13 07:03:40 +04:00
|
|
|
|
|
|
|
if (header->ptype == PTYPE_REQUEST)
|
|
|
|
{
|
2014-05-21 19:32:14 +04:00
|
|
|
inChannel->BytesSent += status;
|
|
|
|
inChannel->SenderAvailableWindow -= status;
|
2012-12-13 07:03:40 +04:00
|
|
|
}
|
2012-11-28 21:47:04 +04:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-09-28 09:43:43 +03:00
|
|
|
BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
|
2015-02-12 22:08:38 +03:00
|
|
|
{
|
|
|
|
UINT32 offset;
|
|
|
|
BYTE* buffer = NULL;
|
|
|
|
UINT32 stub_data_pad;
|
2018-10-09 15:19:05 +03:00
|
|
|
SecBuffer Buffers[2] = { 0 };
|
2015-02-12 22:08:38 +03:00
|
|
|
SecBufferDesc Message;
|
2018-09-28 09:43:43 +03:00
|
|
|
RpcClientCall* clientCall = NULL;
|
|
|
|
rdpNtlm* ntlm;
|
2020-06-17 09:41:21 +03:00
|
|
|
rpcconn_request_hdr_t request_pdu = { 0 };
|
2018-09-28 09:43:43 +03:00
|
|
|
RpcVirtualConnection* connection;
|
|
|
|
RpcInChannel* inChannel;
|
|
|
|
size_t length;
|
2018-09-28 13:29:29 +03:00
|
|
|
SSIZE_T size;
|
2018-10-17 14:19:33 +03:00
|
|
|
BOOL rc = FALSE;
|
2018-09-28 09:43:43 +03:00
|
|
|
|
2018-10-09 15:19:05 +03:00
|
|
|
if (!s)
|
2018-09-28 09:43:43 +03:00
|
|
|
return FALSE;
|
|
|
|
|
2018-10-09 15:19:05 +03:00
|
|
|
if (!rpc)
|
|
|
|
goto fail;
|
|
|
|
|
2018-09-28 09:43:43 +03:00
|
|
|
ntlm = rpc->ntlm;
|
|
|
|
connection = rpc->VirtualConnection;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2018-09-28 13:29:29 +03:00
|
|
|
if (!ntlm)
|
2015-02-12 22:08:38 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "invalid ntlm context");
|
2018-10-09 15:19:05 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
}
|
|
|
|
|
2018-09-28 09:43:43 +03:00
|
|
|
if (!connection)
|
2018-10-09 15:19:05 +03:00
|
|
|
goto fail;
|
2018-09-28 09:43:43 +03:00
|
|
|
|
|
|
|
inChannel = connection->DefaultInChannel;
|
|
|
|
|
|
|
|
if (!inChannel)
|
2018-10-09 15:19:05 +03:00
|
|
|
goto fail;
|
2018-09-28 09:43:43 +03:00
|
|
|
|
|
|
|
Stream_SealLength(s);
|
|
|
|
length = Stream_Length(s);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2018-09-28 13:29:29 +03:00
|
|
|
if (ntlm_client_query_auth_size(ntlm) < 0)
|
2018-10-09 15:19:05 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2018-09-28 13:29:29 +03:00
|
|
|
size = ntlm_client_get_context_max_size(ntlm);
|
|
|
|
|
|
|
|
if (size < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2020-06-17 09:41:21 +03:00
|
|
|
rpc_pdu_header_init(rpc, &request_pdu.header);
|
|
|
|
request_pdu.header.ptype = PTYPE_REQUEST;
|
|
|
|
request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
|
|
|
|
request_pdu.header.auth_length = (UINT16)size;
|
|
|
|
request_pdu.header.call_id = rpc->CallId++;
|
|
|
|
request_pdu.alloc_hint = length;
|
|
|
|
request_pdu.p_cont_id = 0x0000;
|
|
|
|
request_pdu.opnum = opnum;
|
|
|
|
clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (!clientCall)
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (ArrayList_Add(rpc->client->ClientCallList, clientCall) < 0)
|
2018-10-17 14:19:33 +03:00
|
|
|
{
|
|
|
|
rpc_client_call_free(clientCall);
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2018-10-17 14:19:33 +03:00
|
|
|
}
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2020-06-17 09:41:21 +03:00
|
|
|
if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
|
|
|
|
rpc->PipeCallId = request_pdu.header.call_id;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2020-06-17 09:41:21 +03:00
|
|
|
request_pdu.stub_data = Stream_Buffer(s);
|
2015-02-12 22:08:38 +03:00
|
|
|
offset = 24;
|
|
|
|
stub_data_pad = rpc_offset_align(&offset, 8);
|
|
|
|
offset += length;
|
2020-06-17 09:41:21 +03:00
|
|
|
request_pdu.auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
|
|
|
|
request_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
|
|
|
|
request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
|
|
|
|
request_pdu.auth_verifier.auth_reserved = 0x00;
|
|
|
|
request_pdu.auth_verifier.auth_context_id = 0x00000000;
|
|
|
|
offset += (8 + request_pdu.header.auth_length);
|
|
|
|
request_pdu.header.frag_length = offset;
|
|
|
|
buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
if (!buffer)
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2020-06-17 09:41:21 +03:00
|
|
|
CopyMemory(buffer, &request_pdu, 24);
|
2015-02-12 22:08:38 +03:00
|
|
|
offset = 24;
|
|
|
|
rpc_offset_pad(&offset, stub_data_pad);
|
2020-06-17 09:41:21 +03:00
|
|
|
CopyMemory(&buffer[offset], request_pdu.stub_data, length);
|
2015-02-12 22:08:38 +03:00
|
|
|
offset += length;
|
2020-06-17 09:41:21 +03:00
|
|
|
rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
|
|
|
|
CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
|
2015-02-12 22:08:38 +03:00
|
|
|
offset += 8;
|
2020-06-17 13:10:33 +03:00
|
|
|
Buffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; /* auth_data */
|
2021-01-27 11:44:19 +03:00
|
|
|
Buffers[1].BufferType = SECBUFFER_TOKEN; /* signature */
|
2015-02-12 22:08:38 +03:00
|
|
|
Buffers[0].pvBuffer = buffer;
|
|
|
|
Buffers[0].cbBuffer = offset;
|
2018-09-28 13:29:29 +03:00
|
|
|
Buffers[1].cbBuffer = size;
|
2015-02-12 22:08:38 +03:00
|
|
|
Buffers[1].pvBuffer = calloc(1, Buffers[1].cbBuffer);
|
|
|
|
|
|
|
|
if (!Buffers[1].pvBuffer)
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
Message.cBuffers = 2;
|
|
|
|
Message.ulVersion = SECBUFFER_VERSION;
|
2019-11-06 17:24:51 +03:00
|
|
|
Message.pBuffers = (PSecBuffer)&Buffers;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2018-09-28 13:29:29 +03:00
|
|
|
if (!ntlm_client_encrypt(ntlm, 0, &Message, rpc->SendSeqNum++))
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
|
|
CopyMemory(&buffer[offset], Buffers[1].pvBuffer, Buffers[1].cbBuffer);
|
|
|
|
offset += Buffers[1].cbBuffer;
|
|
|
|
|
2020-06-17 09:41:21 +03:00
|
|
|
if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
|
2018-09-28 09:43:43 +03:00
|
|
|
goto fail;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
2018-10-17 14:19:33 +03:00
|
|
|
rc = TRUE;
|
2018-09-28 09:43:43 +03:00
|
|
|
fail:
|
2015-02-12 22:08:38 +03:00
|
|
|
free(buffer);
|
|
|
|
free(Buffers[1].pvBuffer);
|
2018-09-28 09:43:43 +03:00
|
|
|
Stream_Free(s, TRUE);
|
2018-10-17 14:19:33 +03:00
|
|
|
return rc;
|
2015-02-12 22:08:38 +03:00
|
|
|
}
|
|
|
|
|
2018-09-27 17:42:27 +03:00
|
|
|
static BOOL rpc_client_resolve_gateway(rdpSettings* settings, char** host, UINT16* port,
|
|
|
|
BOOL* isProxy)
|
|
|
|
{
|
|
|
|
struct addrinfo* result;
|
|
|
|
|
|
|
|
if (!settings || !host || !port || !isProxy)
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
{
|
2020-08-04 09:49:46 +03:00
|
|
|
const char* peerHostname = freerdp_settings_get_string(settings, FreeRDP_GatewayHostname);
|
|
|
|
const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername);
|
|
|
|
const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_GatewayPassword);
|
|
|
|
*port = freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort);
|
2018-09-27 17:42:27 +03:00
|
|
|
*isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
|
|
|
|
result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
return FALSE;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
*host =
|
|
|
|
freerdp_tcp_address_to_string((const struct sockaddr_storage*)result->ai_addr, NULL);
|
2018-09-27 17:42:27 +03:00
|
|
|
freeaddrinfo(result);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
|
2012-11-28 21:47:04 +04:00
|
|
|
{
|
2020-05-12 18:16:14 +03:00
|
|
|
wObject* obj;
|
2019-11-06 17:24:51 +03:00
|
|
|
RpcClient* client = (RpcClient*)calloc(1, sizeof(RpcClient));
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2018-09-27 17:42:27 +03:00
|
|
|
if (!client)
|
|
|
|
return NULL;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
|
|
|
|
&client->isProxy))
|
2018-09-27 17:42:27 +03:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
client->context = context;
|
|
|
|
|
|
|
|
if (!client->context)
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2012-11-28 21:47:04 +04:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
client->pdu = rpc_pdu_new();
|
2015-02-01 00:56:25 +03:00
|
|
|
|
2015-02-02 16:19:07 +03:00
|
|
|
if (!client->pdu)
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2012-12-11 03:56:53 +04:00
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
client->ReceiveFragment = Stream_New(NULL, max_recv_frag);
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
if (!client->ReceiveFragment)
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
client->PipeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
|
|
|
if (!client->PipeEvent)
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
if (!ringbuffer_init(&(client->ReceivePipe), 4096))
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2015-02-01 21:09:28 +03:00
|
|
|
|
|
|
|
if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
client->ClientCallList = ArrayList_New(TRUE);
|
2017-02-20 20:31:58 +03:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
if (!client->ClientCallList)
|
2018-09-27 17:23:01 +03:00
|
|
|
goto fail;
|
2014-08-18 19:22:43 +04:00
|
|
|
|
2020-05-12 18:16:14 +03:00
|
|
|
obj = ArrayList_Object(client->ClientCallList);
|
|
|
|
if (!obj)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
obj->fnObjectFree = rpc_array_client_call_free;
|
2018-09-27 17:23:01 +03:00
|
|
|
return client;
|
|
|
|
fail:
|
|
|
|
rpc_client_free(client);
|
|
|
|
return NULL;
|
2012-12-12 08:34:51 +04:00
|
|
|
}
|
|
|
|
|
2018-09-27 17:23:01 +03:00
|
|
|
void rpc_client_free(RpcClient* client)
|
2012-12-12 08:34:51 +04:00
|
|
|
{
|
2014-05-21 19:32:14 +04:00
|
|
|
if (!client)
|
2015-02-02 16:19:07 +03:00
|
|
|
return;
|
2014-05-21 19:32:14 +04:00
|
|
|
|
2018-09-27 17:42:27 +03:00
|
|
|
free(client->host);
|
|
|
|
|
2015-02-01 21:09:28 +03:00
|
|
|
if (client->ReceiveFragment)
|
|
|
|
Stream_Free(client->ReceiveFragment, TRUE);
|
|
|
|
|
|
|
|
if (client->PipeEvent)
|
|
|
|
CloseHandle(client->PipeEvent);
|
|
|
|
|
|
|
|
ringbuffer_destroy(&(client->ReceivePipe));
|
|
|
|
DeleteCriticalSection(&(client->PipeLock));
|
2012-12-13 07:03:40 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
if (client->pdu)
|
|
|
|
rpc_pdu_free(client->pdu);
|
2012-12-13 05:02:56 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
if (client->ClientCallList)
|
2012-12-13 05:02:56 +04:00
|
|
|
ArrayList_Free(client->ClientCallList);
|
2012-12-12 09:49:15 +04:00
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
free(client);
|
2012-12-12 08:34:51 +04:00
|
|
|
}
|