Gateway legacy parser fix (#7362)

* Implemented missing TSG debug functions

* Refactored RPC gateway parser

Utilize wStream instead of custom binary parsing code, add proper
input validation.
Reported by Sunglin from the Knownsec 404 team & 0103 sec team
This commit is contained in:
akallabeth 2021-10-15 11:45:08 +02:00 committed by GitHub
parent e72d502b8d
commit 07b789c880
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 2489 additions and 883 deletions

View File

@ -76,7 +76,7 @@ fail:
BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel)
{
wStream* s;
int status;
SSIZE_T status;
int contentLength;
BOOL continueNeeded = FALSE;
rdpNtlm* ntlm;
@ -156,6 +156,7 @@ BOOL rpc_ncacn_http_ntlm_init(rdpContext* context, RpcChannel* channel)
freerdp_set_last_error_log(instance->context,
FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
return TRUE;
case AUTH_FAILED:
default:
return FALSE;
}

View File

@ -619,7 +619,6 @@ static int rdg_websocket_handle_payload(BIO* bio, BYTE* pBuffer, size_t size,
return status;
}
break;
case WebsocketPingOpcode:
{
if (encodingContext->responseStreamBuffer == NULL)
@ -749,7 +748,6 @@ static int rdg_websocket_read(BIO* bio, BYTE* pBuffer, size_t size,
TAG, "Websocket Server sends data with masking key. This is against RFC 6455.");
return -1;
}
break;
case WebSocketStatePayload:
{
status = rdg_websocket_handle_payload(bio, pBuffer, size, encodingContext);
@ -889,7 +887,6 @@ static int rdg_socket_read(BIO* bio, BYTE* pBuffer, size_t size,
default:
return -1;
}
return -1; /* should not be reached */
}
static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size,
@ -1572,6 +1569,7 @@ static BOOL rdg_get_gateway_credentials(rdpContext* context)
freerdp_set_last_error_log(instance->context,
FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
return FALSE;
case AUTH_FAILED:
default:
return FALSE;
}
@ -1808,7 +1806,6 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
rdg->transferEncoding.context.websocket.responseStreamBuffer = NULL;
return TRUE;
break;
default:
return FALSE;
}
@ -2054,8 +2051,6 @@ static int rdg_write_data_packet(rdpRdg* rdg, const BYTE* buf, int isize)
}
else
return rdg_write_chunked_data_packet(rdg, buf, isize);
return -1;
}
static BOOL rdg_process_close_packet(rdpRdg* rdg, wStream* s)

View File

@ -24,6 +24,7 @@
#endif
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/tchar.h>
#include <winpr/synch.h>
#include <winpr/dsparse.h>
@ -46,6 +47,7 @@
#include "rpc_client.h"
#include "rpc.h"
#include "rts.h"
#define TAG FREERDP_TAG("core.gateway.rpc")
@ -88,8 +90,10 @@ static const char* PTYPE_STRINGS[] = { "PTYPE_REQUEST", "PTYPE_PING",
*
*/
void rpc_pdu_header_print(rpcconn_hdr_t* header)
void rpc_pdu_header_print(const rpcconn_hdr_t* header)
{
WINPR_ASSERT(header);
WLog_INFO(TAG, "rpc_vers: %" PRIu8 "", header->common.rpc_vers);
WLog_INFO(TAG, "rpc_vers_minor: %" PRIu8 "", header->common.rpc_vers_minor);
@ -139,26 +143,30 @@ void rpc_pdu_header_print(rpcconn_hdr_t* header)
}
}
void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header)
rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc)
{
header->rpc_vers = rpc->rpc_vers;
header->rpc_vers_minor = rpc->rpc_vers_minor;
header->packed_drep[0] = rpc->packed_drep[0];
header->packed_drep[1] = rpc->packed_drep[1];
header->packed_drep[2] = rpc->packed_drep[2];
header->packed_drep[3] = rpc->packed_drep[3];
rpcconn_common_hdr_t header = { 0 };
WINPR_ASSERT(rpc);
header.rpc_vers = rpc->rpc_vers;
header.rpc_vers_minor = rpc->rpc_vers_minor;
header.packed_drep[0] = rpc->packed_drep[0];
header.packed_drep[1] = rpc->packed_drep[1];
header.packed_drep[2] = rpc->packed_drep[2];
header.packed_drep[3] = rpc->packed_drep[3];
return header;
}
UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment)
size_t rpc_offset_align(size_t* offset, size_t alignment)
{
UINT32 pad;
size_t pad;
pad = *offset;
*offset = (*offset + alignment - 1) & ~(alignment - 1);
pad = *offset - pad;
return pad;
}
UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad)
size_t rpc_offset_pad(size_t* offset, size_t pad)
{
*offset += pad;
return pad;
@ -239,63 +247,67 @@ UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad)
*
*/
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length)
BOOL rpc_get_stub_data_info(const rpcconn_hdr_t* header, size_t* poffset, size_t* length)
{
UINT32 alloc_hint = 0;
rpcconn_hdr_t* header;
size_t used = 0;
size_t offset = 0;
BOOL rc = FALSE;
UINT32 frag_length;
UINT32 auth_length;
UINT32 auth_pad_length;
UINT32 auth_pad_length = 0;
UINT32 sec_trailer_offset;
rpc_sec_trailer* sec_trailer;
*offset = RPC_COMMON_FIELDS_LENGTH;
header = ((rpcconn_hdr_t*)buffer);
const rpc_sec_trailer* sec_trailer = NULL;
WINPR_ASSERT(header);
WINPR_ASSERT(poffset);
WINPR_ASSERT(length);
offset = RPC_COMMON_FIELDS_LENGTH;
switch (header->common.ptype)
{
case PTYPE_RESPONSE:
*offset += 8;
rpc_offset_align(offset, 8);
alloc_hint = header->response.alloc_hint;
offset += 8;
rpc_offset_align(&offset, 8);
sec_trailer = &header->response.auth_verifier;
break;
case PTYPE_REQUEST:
*offset += 4;
rpc_offset_align(offset, 8);
alloc_hint = header->request.alloc_hint;
offset += 4;
rpc_offset_align(&offset, 8);
sec_trailer = &header->request.auth_verifier;
break;
case PTYPE_RTS:
*offset += 4;
offset += 4;
break;
default:
WLog_ERR(TAG, "Unknown PTYPE: 0x%02" PRIX8 "", header->common.ptype);
return FALSE;
}
if (!length)
return TRUE;
if (header->common.ptype == PTYPE_REQUEST)
{
UINT32 csec_trailer_offset = header->common.frag_length - header->common.auth_length - 8;
*length = csec_trailer_offset - *offset;
return TRUE;
goto fail;
}
frag_length = header->common.frag_length;
auth_length = header->common.auth_length;
if (poffset)
*poffset = offset;
/* The fragment must be larger than the authentication trailer */
used = offset + auth_length + 8ull;
if (sec_trailer)
{
auth_pad_length = sec_trailer->auth_pad_length;
used += sec_trailer->auth_pad_length;
}
if (frag_length < used)
goto fail;
if (!length)
return TRUE;
sec_trailer_offset = frag_length - auth_length - 8;
sec_trailer = (rpc_sec_trailer*)&buffer[sec_trailer_offset];
auth_pad_length = sec_trailer->auth_pad_length;
#if 0
WLog_DBG(TAG,
"sec_trailer: type: %"PRIu8" level: %"PRIu8" pad_length: %"PRIu8" reserved: %"PRIu8" context_id: %"PRIu32"",
sec_trailer->auth_type, sec_trailer->auth_level,
sec_trailer->auth_pad_length, sec_trailer->auth_reserved,
sec_trailer->auth_context_id);
#endif
/**
* According to [MS-RPCE], auth_pad_length is the number of padding
@ -309,18 +321,21 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l
auth_length, (frag_length - (sec_trailer_offset + 8)));
}
*length = frag_length - auth_length - 24 - 8 - auth_pad_length;
return TRUE;
*length = sec_trailer_offset - auth_pad_length - offset;
rc = TRUE;
fail:
return rc;
}
SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length)
{
int status;
if (!channel)
if (!channel || (length > INT32_MAX))
return -1;
status = BIO_read(channel->tls->bio, Stream_Pointer(s), length);
status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
if (status > 0)
{
@ -339,10 +354,10 @@ SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length)
{
int status;
if (!channel)
if (!channel || (length > INT32_MAX))
return -1;
status = tls_write_all(channel->tls, data, length);
status = tls_write_all(channel->tls, data, (INT32)length);
return status;
}
@ -628,7 +643,7 @@ static void rpc_virtual_connection_free(RpcVirtualConnection* connection)
free(connection);
}
static BOOL rpc_channel_tls_connect(RpcChannel* channel, int timeout)
static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout)
{
int sockfd;
rdpTls* tls;
@ -718,7 +733,7 @@ static BOOL rpc_channel_tls_connect(RpcChannel* channel, int timeout)
return TRUE;
}
static int rpc_in_channel_connect(RpcInChannel* inChannel, int timeout)
static int rpc_in_channel_connect(RpcInChannel* inChannel, UINT32 timeout)
{
rdpContext* context;
@ -813,7 +828,7 @@ int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout)
return 1;
}
BOOL rpc_connect(rdpRpc* rpc, int timeout)
BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
{
RpcInChannel* inChannel;
RpcOutChannel* outChannel;

View File

@ -73,7 +73,6 @@ typedef struct _RPC_PDU
#include "../tcp.h"
#include "../transport.h"
#include "rts.h"
#include "http.h"
#include "ntlm.h"
@ -525,7 +524,8 @@ typedef struct
rpcconn_common_hdr_t header;
} rpcconn_shutdown_hdr_t;
typedef union {
typedef union
{
rpcconn_common_hdr_t common;
rpcconn_alter_context_hdr_t alter_context;
rpcconn_alter_context_response_hdr_t alter_context_response;
@ -765,14 +765,14 @@ struct rdp_rpc
RpcVirtualConnection* VirtualConnection;
};
FREERDP_LOCAL void rpc_pdu_header_print(rpcconn_hdr_t* header);
FREERDP_LOCAL void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header);
FREERDP_LOCAL void rpc_pdu_header_print(const rpcconn_hdr_t* header);
FREERDP_LOCAL rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc);
FREERDP_LOCAL UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment);
FREERDP_LOCAL UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad);
FREERDP_LOCAL size_t rpc_offset_align(size_t* offset, size_t alignment);
FREERDP_LOCAL size_t rpc_offset_pad(size_t* offset, size_t pad);
FREERDP_LOCAL BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* header, UINT32* offset,
UINT32* length);
FREERDP_LOCAL BOOL rpc_get_stub_data_info(const rpcconn_hdr_t* header, size_t* offset,
size_t* length);
FREERDP_LOCAL SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length);
@ -792,7 +792,7 @@ FREERDP_LOCAL BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc,
RpcVirtualConnection* connection,
VIRTUAL_CONNECTION_STATE state);
FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, int timeout);
FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout);
FREERDP_LOCAL rdpRpc* rpc_new(rdpTransport* transport);
FREERDP_LOCAL void rpc_free(rdpRpc* rpc);

View File

@ -22,11 +22,14 @@
#endif
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <freerdp/log.h>
#include "rpc_client.h"
#include "rts.h"
#include "rpc_bind.h"
#include "../utils.h"
@ -108,12 +111,11 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
auth_status rc;
BOOL continueNeeded = FALSE;
int status = -1;
BYTE* buffer = NULL;
wStream* buffer = NULL;
UINT32 offset;
UINT32 length;
RpcClientCall* clientCall;
p_cont_elem_t* p_cont_elem;
rpcconn_bind_hdr_t* bind_pdu = NULL;
rpcconn_bind_hdr_t bind_pdu = { 0 };
rdpContext* context;
rdpSettings* settings;
freerdp* instance;
@ -154,6 +156,7 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
freerdp_set_last_error_log(instance->context,
FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
return 0;
case AUTH_FAILED:
default:
return -1;
}
@ -171,36 +174,31 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
if (!continueNeeded)
goto fail;
bind_pdu = (rpcconn_bind_hdr_t*)calloc(1, sizeof(rpcconn_bind_hdr_t));
if (!bind_pdu)
goto fail;
sbuffer = ntlm_client_get_output_buffer(rpc->ntlm);
if (!sbuffer)
goto fail;
rpc_pdu_header_init(rpc, &bind_pdu->header);
bind_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer;
bind_pdu->auth_verifier.auth_value = sbuffer->pvBuffer;
bind_pdu->header.ptype = PTYPE_BIND;
bind_pdu->header.pfc_flags =
bind_pdu.header = rpc_pdu_header_init(rpc);
bind_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer;
bind_pdu.auth_verifier.auth_value = sbuffer->pvBuffer;
bind_pdu.header.ptype = PTYPE_BIND;
bind_pdu.header.pfc_flags =
PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
bind_pdu->header.call_id = 2;
bind_pdu->max_xmit_frag = rpc->max_xmit_frag;
bind_pdu->max_recv_frag = rpc->max_recv_frag;
bind_pdu->assoc_group_id = 0;
bind_pdu->p_context_elem.n_context_elem = 2;
bind_pdu->p_context_elem.reserved = 0;
bind_pdu->p_context_elem.reserved2 = 0;
bind_pdu->p_context_elem.p_cont_elem =
calloc(bind_pdu->p_context_elem.n_context_elem, sizeof(p_cont_elem_t));
bind_pdu.header.call_id = 2;
bind_pdu.max_xmit_frag = rpc->max_xmit_frag;
bind_pdu.max_recv_frag = rpc->max_recv_frag;
bind_pdu.assoc_group_id = 0;
bind_pdu.p_context_elem.n_context_elem = 2;
bind_pdu.p_context_elem.reserved = 0;
bind_pdu.p_context_elem.reserved2 = 0;
bind_pdu.p_context_elem.p_cont_elem =
calloc(bind_pdu.p_context_elem.n_context_elem, sizeof(p_cont_elem_t));
if (!bind_pdu->p_context_elem.p_cont_elem)
if (!bind_pdu.p_context_elem.p_cont_elem)
goto fail;
p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[0];
p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[0];
p_cont_elem->p_cont_id = 0;
p_cont_elem->n_transfer_syn = 1;
p_cont_elem->reserved = 0;
@ -213,7 +211,7 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &NDR_UUID, sizeof(p_uuid_t));
p_cont_elem->transfer_syntaxes[0].if_version = NDR_SYNTAX_IF_VERSION;
p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[1];
p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[1];
p_cont_elem->p_cont_id = 1;
p_cont_elem->n_transfer_syn = 1;
p_cont_elem->reserved = 0;
@ -227,32 +225,23 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &BTFN_UUID, sizeof(p_uuid_t));
p_cont_elem->transfer_syntaxes[0].if_version = BTFN_SYNTAX_IF_VERSION;
offset = 116;
bind_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
bind_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
bind_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
bind_pdu->auth_verifier.auth_reserved = 0x00;
bind_pdu->auth_verifier.auth_context_id = 0x00000000;
offset += (8 + bind_pdu->header.auth_length);
bind_pdu->header.frag_length = offset;
buffer = (BYTE*)malloc(bind_pdu->header.frag_length);
bind_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
bind_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
bind_pdu.auth_verifier.auth_reserved = 0x00;
bind_pdu.auth_verifier.auth_context_id = 0x00000000;
offset += (8 + bind_pdu.header.auth_length);
bind_pdu.header.frag_length = offset;
buffer = Stream_New(NULL, bind_pdu.header.frag_length);
if (!buffer)
goto fail;
CopyMemory(buffer, bind_pdu, 24);
CopyMemory(&buffer[24], &bind_pdu->p_context_elem, 4);
CopyMemory(&buffer[28], &bind_pdu->p_context_elem.p_cont_elem[0], 24);
CopyMemory(&buffer[52], bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes, 20);
CopyMemory(&buffer[72], &bind_pdu->p_context_elem.p_cont_elem[1], 24);
CopyMemory(&buffer[96], bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes, 20);
offset = 116;
rpc_offset_pad(&offset, bind_pdu->auth_verifier.auth_pad_length);
CopyMemory(&buffer[offset], &bind_pdu->auth_verifier.auth_type, 8);
CopyMemory(&buffer[offset + 8], bind_pdu->auth_verifier.auth_value,
bind_pdu->header.auth_length);
offset += (8 + bind_pdu->header.auth_length);
length = bind_pdu->header.frag_length;
clientCall = rpc_client_call_new(bind_pdu->header.call_id, 0);
if (!rts_write_pdu_bind(buffer, &bind_pdu))
goto fail;
clientCall = rpc_client_call_new(bind_pdu.header.call_id, 0);
if (!clientCall)
goto fail;
@ -263,22 +252,19 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
goto fail;
}
status = rpc_in_channel_send_pdu(inChannel, buffer, length);
Stream_SealLength(buffer);
status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer));
fail:
if (bind_pdu)
if (bind_pdu.p_context_elem.p_cont_elem)
{
if (bind_pdu->p_context_elem.p_cont_elem)
{
free(bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes);
free(bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes);
}
free(bind_pdu->p_context_elem.p_cont_elem);
free(bind_pdu.p_context_elem.p_cont_elem[0].transfer_syntaxes);
free(bind_pdu.p_context_elem.p_cont_elem[1].transfer_syntaxes);
}
free(bind_pdu);
free(buffer);
free(bind_pdu.p_context_elem.p_cont_elem);
Stream_Free(buffer, TRUE);
return (status > 0) ? 1 : -1;
}
@ -308,31 +294,47 @@ fail:
* example.
*/
int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s)
{
BOOL rc = FALSE;
BOOL continueNeeded = FALSE;
BYTE* auth_data;
rpcconn_hdr_t* header;
header = (rpcconn_hdr_t*)buffer;
const BYTE* auth_data;
size_t pos, end;
rpcconn_hdr_t header = { 0 };
WINPR_ASSERT(rpc);
WINPR_ASSERT(rpc->ntlm);
WINPR_ASSERT(s);
pos = Stream_GetPosition(s);
if (!rts_read_pdu_header(s, &header))
goto fail;
WLog_DBG(TAG, "Receiving BindAck PDU");
if (!rpc || !rpc->ntlm)
return -1;
rpc->max_recv_frag = header.bind_ack.max_xmit_frag;
rpc->max_xmit_frag = header.bind_ack.max_recv_frag;
rpc->max_recv_frag = header->bind_ack.max_xmit_frag;
rpc->max_xmit_frag = header->bind_ack.max_recv_frag;
auth_data = buffer + (header->common.frag_length - header->common.auth_length);
/* Get the correct offset in the input data and pass that on as input buffer.
* rts_read_pdu_header did already do consistency checks */
end = Stream_GetPosition(s);
Stream_SetPosition(s, pos + header.common.frag_length - header.common.auth_length);
auth_data = Stream_Pointer(s);
Stream_SetPosition(s, end);
if (!ntlm_client_set_input_buffer(rpc->ntlm, TRUE, auth_data, header->common.auth_length))
return -1;
if (!ntlm_client_set_input_buffer(rpc->ntlm, TRUE, auth_data, header.common.auth_length))
goto fail;
if (!ntlm_authenticate(rpc->ntlm, &continueNeeded))
return -1;
goto fail;
if (continueNeeded)
return -1;
goto fail;
return (int)length;
rc = TRUE;
fail:
rts_free_pdu_header(&header, FALSE);
return rc;
}
/**
@ -345,68 +347,63 @@ int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
{
int status = -1;
BYTE* buffer;
UINT32 offset;
UINT32 length;
wStream* buffer;
size_t offset;
const SecBuffer* sbuffer;
RpcClientCall* clientCall;
rpcconn_rpc_auth_3_hdr_t* auth_3_pdu;
RpcVirtualConnection* connection = rpc->VirtualConnection;
RpcInChannel* inChannel = connection->DefaultInChannel;
WLog_DBG(TAG, "Sending RpcAuth3 PDU");
auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*)calloc(1, sizeof(rpcconn_rpc_auth_3_hdr_t));
rpcconn_rpc_auth_3_hdr_t auth_3_pdu = { 0 };
RpcVirtualConnection* connection;
RpcInChannel* inChannel;
if (!auth_3_pdu)
return -1;
WINPR_ASSERT(rpc);
connection = rpc->VirtualConnection;
WINPR_ASSERT(connection);
inChannel = connection->DefaultInChannel;
WINPR_ASSERT(inChannel);
WLog_DBG(TAG, "Sending RpcAuth3 PDU");
sbuffer = ntlm_client_get_output_buffer(rpc->ntlm);
if (!sbuffer)
{
free(auth_3_pdu);
return -1;
}
rpc_pdu_header_init(rpc, &auth_3_pdu->header);
auth_3_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer;
auth_3_pdu->auth_verifier.auth_value = sbuffer->pvBuffer;
auth_3_pdu->header.ptype = PTYPE_RPC_AUTH_3;
auth_3_pdu->header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
auth_3_pdu->header.call_id = 2;
auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag;
auth_3_pdu->max_recv_frag = rpc->max_recv_frag;
auth_3_pdu.header = rpc_pdu_header_init(rpc);
auth_3_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer;
auth_3_pdu.auth_verifier.auth_value = sbuffer->pvBuffer;
auth_3_pdu.header.ptype = PTYPE_RPC_AUTH_3;
auth_3_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
auth_3_pdu.header.call_id = 2;
auth_3_pdu.max_xmit_frag = rpc->max_xmit_frag;
auth_3_pdu.max_recv_frag = rpc->max_recv_frag;
offset = 20;
auth_3_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
auth_3_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
auth_3_pdu->auth_verifier.auth_reserved = 0x00;
auth_3_pdu->auth_verifier.auth_context_id = 0x00000000;
offset += (8 + auth_3_pdu->header.auth_length);
auth_3_pdu->header.frag_length = offset;
buffer = (BYTE*)malloc(auth_3_pdu->header.frag_length);
auth_3_pdu.auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
auth_3_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
auth_3_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
auth_3_pdu.auth_verifier.auth_reserved = 0x00;
auth_3_pdu.auth_verifier.auth_context_id = 0x00000000;
offset += (8 + auth_3_pdu.header.auth_length);
auth_3_pdu.header.frag_length = offset;
buffer = Stream_New(NULL, auth_3_pdu.header.frag_length);
if (!buffer)
{
free(auth_3_pdu);
return -1;
}
CopyMemory(buffer, auth_3_pdu, 20);
offset = 20;
rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length);
CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8);
CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value,
auth_3_pdu->header.auth_length);
offset += (8 + auth_3_pdu->header.auth_length);
length = auth_3_pdu->header.frag_length;
clientCall = rpc_client_call_new(auth_3_pdu->header.call_id, 0);
if (!rts_write_pdu_auth3(buffer, &auth_3_pdu))
goto fail;
clientCall = rpc_client_call_new(auth_3_pdu.header.call_id, 0);
if (ArrayList_Append(rpc->client->ClientCallList, clientCall))
{
status = rpc_in_channel_send_pdu(inChannel, buffer, length);
Stream_SealLength(buffer);
status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer));
}
free(auth_3_pdu);
free(buffer);
fail:
Stream_Free(buffer, TRUE);
return (status > 0) ? 1 : -1;
}

View File

@ -35,7 +35,7 @@ FREERDP_LOCAL extern const p_uuid_t BTFN_UUID;
#define BTFN_SYNTAX_IF_VERSION 0x00000001
FREERDP_LOCAL int rpc_send_bind_pdu(rdpRpc* rpc);
FREERDP_LOCAL int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
FREERDP_LOCAL BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s);
FREERDP_LOCAL int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc);
#endif /* FREERDP_LIB_CORE_GATEWAY_RPC_BIND_H */

View File

@ -24,6 +24,7 @@
#include <freerdp/log.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/print.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
@ -35,6 +36,8 @@
#include "rpc_bind.h"
#include "rpc_fault.h"
#include "rpc_client.h"
#include "rts_signature.h"
#include "../rdp.h"
#include "../proxy.h"
@ -99,7 +102,7 @@ static int rpc_client_receive_pipe_write(RpcClient* client, const BYTE* buffer,
int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length)
{
int index = 0;
int status = 0;
size_t status = 0;
int nchunks = 0;
DataChunk chunks[2];
@ -122,7 +125,10 @@ int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length)
ResetEvent(client->PipeEvent);
LeaveCriticalSection(&(client->PipeLock));
return status;
if (status > INT_MAX)
return -1;
return (int)status;
}
static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
@ -173,12 +179,14 @@ static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
{
int status = -1;
rpcconn_rts_hdr_t* rts;
rdpTsg* tsg;
WINPR_ASSERT(rpc);
WINPR_ASSERT(pdu);
Stream_SealLength(pdu->s);
Stream_SetPosition(pdu->s, 0);
tsg = transport_get_tsg(rpc->transport);
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
@ -192,17 +200,13 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
break;
case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s);
if (!rts_match_pdu_signature(&RTS_PDU_CONN_A3_SIGNATURE, rts))
if (!rts_match_pdu_signature(&RTS_PDU_CONN_A3_SIGNATURE, pdu->s, NULL))
{
WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/A3");
return -1;
}
status = rts_recv_CONN_A3_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
if (status < 0)
if (!rts_recv_CONN_A3_pdu(rpc, pdu->s))
{
WLog_ERR(TAG, "rts_recv_CONN_A3_pdu failure");
return -1;
@ -214,17 +218,13 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
break;
case VIRTUAL_CONNECTION_STATE_WAIT_C2:
rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s);
if (!rts_match_pdu_signature(&RTS_PDU_CONN_C2_SIGNATURE, rts))
if (!rts_match_pdu_signature(&RTS_PDU_CONN_C2_SIGNATURE, pdu->s, NULL))
{
WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/C2");
return -1;
}
status = rts_recv_CONN_C2_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
if (status < 0)
if (!rts_recv_CONN_C2_pdu(rpc, pdu->s))
{
WLog_ERR(TAG, "rts_recv_CONN_C2_pdu failure");
return -1;
@ -257,7 +257,7 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
{
if (pdu->Type == PTYPE_BIND_ACK)
{
if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0)
if (!rpc_recv_bind_ack_pdu(rpc, pdu->s))
{
WLog_ERR(TAG, "rpc_recv_bind_ack_pdu failure");
return -1;
@ -306,39 +306,49 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
{
BYTE* buffer;
int rc = -1;
RPC_PDU* pdu;
UINT32 StubOffset;
UINT32 StubLength;
size_t StubOffset;
size_t StubLength;
RpcClientCall* call;
rpcconn_hdr_t* header;
pdu = rpc->client->pdu;
buffer = (BYTE*)Stream_Buffer(fragment);
header = (rpcconn_hdr_t*)Stream_Buffer(fragment);
rpcconn_hdr_t header = { 0 };
if (header->common.ptype == PTYPE_RESPONSE)
WINPR_ASSERT(rpc);
WINPR_ASSERT(rpc->client);
WINPR_ASSERT(fragment);
pdu = rpc->client->pdu;
WINPR_ASSERT(pdu);
Stream_SealLength(fragment);
Stream_SetPosition(fragment, 0);
if (!rts_read_pdu_header(fragment, &header))
goto fail;
if (header.common.ptype == PTYPE_RESPONSE)
{
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length;
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length;
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
header->common.frag_length;
header.common.frag_length;
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
(rpc->ReceiveWindow / 2))
{
if (rts_send_flow_control_ack_pdu(rpc) < 0)
return -1;
if (!rts_send_flow_control_ack_pdu(rpc))
goto fail;
}
if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength))
if (!rpc_get_stub_data_info(&header, &StubOffset, &StubLength))
{
WLog_ERR(TAG, "expected stub");
return -1;
goto fail;
}
if (StubLength == 4)
{
if ((header->common.call_id == rpc->PipeCallId) &&
(header->common.pfc_flags & PFC_LAST_FRAG))
if ((header.common.call_id == rpc->PipeCallId) &&
(header.common.pfc_flags & PFC_LAST_FRAG))
{
/* End of TsProxySetupReceivePipe */
TerminateEventArgs e;
@ -347,54 +357,66 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
WINPR_ASSERT(context);
rpc->result = *((UINT32*)&buffer[StubOffset]);
if (Stream_Length(fragment) < StubOffset + 4)
goto fail;
Stream_SetPosition(fragment, StubOffset);
Stream_Read_UINT32(fragment, rpc->result);
freerdp_abort_connect(context->instance);
tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
EventArgsInit(&e, "freerdp");
e.code = 0;
PubSub_OnTerminate(context->pubSub, context, &e);
return 0;
rc = 0;
goto success;
}
if (header->common.call_id != rpc->PipeCallId)
if (header.common.call_id != rpc->PipeCallId)
{
/* Ignoring non-TsProxySetupReceivePipe Response */
return 0;
rc = 0;
goto success;
}
}
if (rpc->StubFragCount == 0)
rpc->StubCallId = header->common.call_id;
rpc->StubCallId = header.common.call_id;
if (rpc->StubCallId != header->common.call_id)
if (rpc->StubCallId != header.common.call_id)
{
WLog_ERR(TAG,
"invalid call_id: actual: %" PRIu32 ", expected: %" PRIu32
", frag_count: %" PRIu32 "",
rpc->StubCallId, header->common.call_id, rpc->StubFragCount);
rpc->StubCallId, header.common.call_id, rpc->StubFragCount);
}
call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId);
if (!call)
return -1;
goto fail;
if (call->OpNum != TsProxySetupReceivePipeOpnum)
{
if (!Stream_EnsureCapacity(pdu->s, header->response.alloc_hint))
return -1;
const rpcconn_response_hdr_t* response =
(const rpcconn_response_hdr_t*)&header.response;
if (!Stream_EnsureCapacity(pdu->s, response->alloc_hint))
goto fail;
Stream_Write(pdu->s, &buffer[StubOffset], StubLength);
if (Stream_Length(fragment) < StubOffset + StubLength)
goto fail;
Stream_SetPosition(fragment, StubOffset);
Stream_Write(pdu->s, Stream_Pointer(fragment), StubLength);
rpc->StubFragCount++;
if (header->response.alloc_hint == StubLength)
if (response->alloc_hint == StubLength)
{
pdu->Flags = RPC_PDU_FLAG_STUB;
pdu->Type = PTYPE_RESPONSE;
pdu->CallId = rpc->StubCallId;
Stream_SealLength(pdu->s);
if (rpc_client_recv_pdu(rpc, pdu) < 0)
return -1;
goto fail;
rpc_pdu_reset(pdu);
rpc->StubFragCount = 0;
rpc->StubCallId = 0;
@ -402,75 +424,84 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
}
else
{
rpc_client_receive_pipe_write(rpc->client, &buffer[StubOffset], (size_t)StubLength);
const rpcconn_response_hdr_t* response = &header.response;
if (Stream_Length(fragment) < StubOffset + StubLength)
goto fail;
Stream_SetPosition(fragment, StubOffset);
rpc_client_receive_pipe_write(rpc->client, Stream_Pointer(fragment),
(size_t)StubLength);
rpc->StubFragCount++;
if (header->response.alloc_hint == StubLength)
if (response->alloc_hint == StubLength)
{
rpc->StubFragCount = 0;
rpc->StubCallId = 0;
}
}
return 1;
goto success;
}
else if (header->common.ptype == PTYPE_RTS)
else if (header.common.ptype == PTYPE_RTS)
{
if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
{
pdu->Flags = 0;
pdu->Type = header->common.ptype;
pdu->CallId = header->common.call_id;
pdu->Type = header.common.ptype;
pdu->CallId = header.common.call_id;
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
return -1;
goto fail;
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
Stream_SealLength(pdu->s);
Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment));
if (rpc_client_recv_pdu(rpc, pdu) < 0)
return -1;
goto fail;
rpc_pdu_reset(pdu);
}
else
{
if (rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length) < 0)
return -1;
if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header))
goto fail;
}
return 1;
goto success;
}
else if (header->common.ptype == PTYPE_BIND_ACK)
else if (header.common.ptype == PTYPE_BIND_ACK)
{
pdu->Flags = 0;
pdu->Type = header->common.ptype;
pdu->CallId = header->common.call_id;
pdu->Type = header.common.ptype;
pdu->CallId = header.common.call_id;
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
return -1;
goto fail;
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
Stream_SealLength(pdu->s);
Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment));
if (rpc_client_recv_pdu(rpc, pdu) < 0)
return -1;
goto fail;
rpc_pdu_reset(pdu);
return 1;
goto success;
}
else if (header->common.ptype == PTYPE_FAULT)
else if (header.common.ptype == PTYPE_FAULT)
{
rpc_recv_fault_pdu(header->fault.status);
return -1;
const rpcconn_fault_hdr_t* fault = (const rpcconn_fault_hdr_t*)&header.fault;
rpc_recv_fault_pdu(fault->status);
goto fail;
}
else
{
WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header->common.ptype);
return -1;
WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header.common.ptype);
goto fail;
}
return 1;
success:
rc = (rc < 0) ? 1 : 0; /* In case of default error return change to 1, otherwise we already set
the return code */
fail:
rts_free_pdu_header(&header, FALSE);
return rc;
}
static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
@ -520,7 +551,7 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
/* Send CONN/A1 PDU over OUT channel */
if (rts_send_CONN_A1_pdu(rpc) < 0)
if (!rts_send_CONN_A1_pdu(rpc))
{
http_response_free(response);
WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!");
@ -575,12 +606,13 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
}
else
{
wStream* fragment;
rpcconn_common_hdr_t* header;
fragment = rpc->client->ReceiveFragment;
wStream* fragment = rpc->client->ReceiveFragment;
while (1)
{
size_t pos;
rpcconn_common_hdr_t header = { 0 };
while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
{
status = rpc_channel_read(&outChannel->common, fragment,
@ -593,22 +625,27 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
return 0;
}
header = (rpcconn_common_hdr_t*)Stream_Buffer(fragment);
pos = Stream_GetPosition(fragment);
Stream_SetPosition(fragment, 0);
if (header->frag_length > rpc->max_recv_frag)
/* Ignore errors, the PDU might not be complete. */
rts_read_common_pdu_header(fragment, &header);
Stream_SetPosition(fragment, pos);
if (header.frag_length > rpc->max_recv_frag)
{
WLog_ERR(TAG,
"rpc_client_recv: invalid fragment size: %" PRIu16 " (max: %" PRIu16 ")",
header->frag_length, rpc->max_recv_frag);
header.frag_length, rpc->max_recv_frag);
winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
Stream_GetPosition(fragment));
return -1;
}
while (Stream_GetPosition(fragment) < header->frag_length)
while (Stream_GetPosition(fragment) < header.frag_length)
{
status = rpc_channel_read(&outChannel->common, fragment,
header->frag_length - Stream_GetPosition(fragment));
header.frag_length - Stream_GetPosition(fragment));
if (status < 0)
{
@ -616,14 +653,12 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc)
return -1;
}
if (Stream_GetPosition(fragment) < header->frag_length)
if (Stream_GetPosition(fragment) < header.frag_length)
return 0;
}
{
/* complete fragment received */
Stream_SealLength(fragment);
Stream_SetPosition(fragment, 0);
status = rpc_client_recv_fragment(rpc, fragment);
if (status < 0)
@ -675,10 +710,10 @@ static int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
{
rpc_ncacn_http_ntlm_uninit(&nextOutChannel->common);
status = rts_send_OUT_R1_A3_pdu(rpc);
if (status >= 0)
if (rts_send_OUT_R1_A3_pdu(rpc))
{
status = 1;
rpc_out_channel_transition_to_state(
nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
}
@ -699,6 +734,9 @@ static int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
break;
case CLIENT_OUT_CHANNEL_STATE_INITIAL:
case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
default:
WLog_ERR(TAG,
"rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
@ -781,7 +819,7 @@ int rpc_client_in_channel_recv(rdpRpc* rpc)
/* Send CONN/B1 PDU over IN channel */
if (rts_send_CONN_B1_pdu(rpc) < 0)
if (!rts_send_CONN_B1_pdu(rpc))
{
WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!");
http_response_free(response);
@ -822,8 +860,8 @@ int rpc_client_in_channel_recv(rdpRpc* rpc)
RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId)
{
int index;
int count;
size_t index;
size_t count;
RpcClientCall* clientCall = NULL;
if (!client)
@ -868,18 +906,23 @@ static void rpc_array_client_call_free(void* call)
rpc_client_call_free((RpcClientCall*)call);
}
int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length)
int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer, size_t length)
{
int status;
SSIZE_T status;
RpcClientCall* clientCall;
rpcconn_common_hdr_t* header;
wStream s;
rpcconn_common_hdr_t header = { 0 };
status = rpc_channel_write(&inChannel->common, buffer, length);
if (status <= 0)
return -1;
header = (rpcconn_common_hdr_t*)buffer;
clientCall = rpc_client_call_find_by_id(inChannel->common.client, header->call_id);
Stream_StaticInit(&s, buffer, length);
if (!rts_read_common_pdu_header(&s, &header))
return -1;
clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id);
clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
/*
@ -889,7 +932,7 @@ int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length
* variables specified by this abstract data model.
*/
if (header->ptype == PTYPE_REQUEST)
if (header.ptype == PTYPE_REQUEST)
{
inChannel->BytesSent += status;
inChannel->SenderAvailableWindow -= status;
@ -900,7 +943,7 @@ int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length
BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
{
UINT32 offset;
size_t offset;
BYTE* buffer = NULL;
UINT32 stub_data_pad;
SecBuffer Buffers[2] = { 0 };
@ -948,7 +991,7 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
if (size < 0)
goto fail;
rpc_pdu_header_init(rpc, &request_pdu.header);
request_pdu.header = rpc_pdu_header_init(rpc);
request_pdu.header.ptype = PTYPE_REQUEST;
request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
request_pdu.header.auth_length = (UINT16)size;
@ -1037,7 +1080,7 @@ static BOOL rpc_client_resolve_gateway(rdpSettings* settings, char** host, UINT1
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);
*port = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort);
*isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
result = freerdp_tcp_resolve_host(peerHostname, *port, 0);

View File

@ -31,7 +31,8 @@ FREERDP_LOCAL RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT3
FREERDP_LOCAL RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum);
FREERDP_LOCAL void rpc_client_call_free(RpcClientCall* client_call);
FREERDP_LOCAL int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length);
FREERDP_LOCAL int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer,
size_t length);
FREERDP_LOCAL int rpc_client_in_channel_recv(rdpRpc* rpc);
FREERDP_LOCAL int rpc_client_out_channel_recv(rdpRpc* rpc);

View File

@ -154,8 +154,7 @@ static const RPC_FAULT_CODE RPC_FAULT_CODES[] = {
DEFINE_RPC_FAULT_CODE(RPC_S_COOKIE_AUTH_FAILED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_GROUP_MEMBER_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(EPT_S_CANT_CREATE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_OBJECT, CAT_GATEWAY),
{ 0, NULL, NULL }
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_OBJECT, CAT_GATEWAY)
};
static const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[] = {
@ -207,8 +206,7 @@ static const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[] = {
{ HRESULT_CODE(E_PROXY_REAUTH_NAP_FAILED), "E_PROXY_REAUTH_NAP_FAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_CONNECTIONABORTED), "E_PROXY_CONNECTIONABORTED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_NOCERTAVAILABLE), "E_PROXY_NOCERTAVAILABLE", CAT_GATEWAY },
{ HRESULT_CODE(RPC_S_CALL_CANCELLED), "RPC_S_CALL_CANCELLED", CAT_GATEWAY },
{ 0, NULL, NULL }
{ HRESULT_CODE(RPC_S_CALL_CANCELLED), "RPC_S_CALL_CANCELLED", CAT_GATEWAY }
};
/**
@ -361,29 +359,32 @@ const char* rpc_error_to_string(UINT32 code)
size_t index;
static char buffer[1024];
for (index = 0; RPC_FAULT_CODES[index].name != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++)
{
if (RPC_FAULT_CODES[index].code == code)
const RPC_FAULT_CODE* const current = &RPC_FAULT_CODES[index];
if (current->code == code)
{
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_FAULT_CODES[index].name);
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
for (index = 0; RPC_TSG_FAULT_CODES[index].name != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
if (RPC_TSG_FAULT_CODES[index].code == code)
const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index];
if (current->code == code)
{
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_TSG_FAULT_CODES[index].name);
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
for (index = 0; RPC_TSG_FAULT_CODES[index].name != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
if (RPC_TSG_FAULT_CODES[index].code == HRESULT_CODE(code))
const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index];
if (current->code == HRESULT_CODE(code))
{
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_TSG_FAULT_CODES[index].name);
sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
@ -397,22 +398,25 @@ const char* rpc_error_to_category(UINT32 code)
{
size_t index;
for (index = 0; RPC_FAULT_CODES[index].category != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++)
{
if (RPC_FAULT_CODES[index].code == code)
return RPC_FAULT_CODES[index].category;
const RPC_FAULT_CODE* const current = &RPC_FAULT_CODES[index];
if (current->code == code)
return current->category;
}
for (index = 0; RPC_TSG_FAULT_CODES[index].category != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
if (RPC_TSG_FAULT_CODES[index].code == code)
return RPC_TSG_FAULT_CODES[index].category;
const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index];
if (current->code == code)
return current->category;
}
for (index = 0; RPC_TSG_FAULT_CODES[index].category != NULL; index++)
for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
if (RPC_TSG_FAULT_CODES[index].code == HRESULT_CODE(code))
return RPC_TSG_FAULT_CODES[index].category;
const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index];
if (current->code == HRESULT_CODE(code))
return current->category;
}
return "UNKNOWN";

File diff suppressed because it is too large Load Diff

View File

@ -24,12 +24,14 @@
#include "config.h"
#endif
#include "rpc.h"
#include <winpr/stream.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <freerdp/log.h>
#include "rpc.h"
#define RTS_FLAG_NONE 0x0000
#define RTS_FLAG_PING 0x0001
#define RTS_FLAG_OTHER_CMD 0x0002
@ -79,21 +81,28 @@
FREERDP_LOCAL void rts_generate_cookie(BYTE* cookie);
FREERDP_LOCAL SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length);
FREERDP_LOCAL BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth);
FREERDP_LOCAL BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind);
FREERDP_LOCAL int rts_send_CONN_A1_pdu(rdpRpc* rpc);
FREERDP_LOCAL int rts_recv_CONN_A3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
FREERDP_LOCAL BOOL rts_read_pdu_header(wStream* s, rpcconn_hdr_t* header);
FREERDP_LOCAL void rts_free_pdu_header(rpcconn_hdr_t* header, BOOL allocated);
FREERDP_LOCAL int rts_send_CONN_B1_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header);
FREERDP_LOCAL int rts_recv_CONN_C2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
FREERDP_LOCAL BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length);
FREERDP_LOCAL int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer);
FREERDP_LOCAL int rts_send_flow_control_ack_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc);
FREERDP_LOCAL int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
FREERDP_LOCAL BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer);
#include "rts_signature.h"
FREERDP_LOCAL BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc);
FREERDP_LOCAL BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer,
const rpcconn_hdr_t* header);
#endif /* FREERDP_LIB_CORE_GATEWAY_RTS_H */

View File

@ -17,6 +17,9 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <freerdp/log.h>
#include "rts_signature.h"
@ -276,90 +279,74 @@ static const RTS_PDU_SIGNATURE_ENTRY RTS_PDU_SIGNATURE_TABLE[] = {
{ RTS_PDU_PING, TRUE, &RTS_PDU_PING_SIGNATURE, "Ping" },
{ RTS_PDU_FLOW_CONTROL_ACK, TRUE, &RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, "FlowControlAck" },
{ RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION, TRUE,
&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, "FlowControlAckWithDestination" },
{ 0, FALSE, NULL, NULL }
&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, "FlowControlAckWithDestination" }
};
BOOL rts_match_pdu_signature(const RtsPduSignature* signature, const rpcconn_rts_hdr_t* rts)
BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header)
{
UINT16 i;
int status;
const BYTE* buffer;
UINT32 length;
UINT32 offset;
UINT32 CommandType;
UINT32 CommandLength;
RtsPduSignature extracted = { 0 };
if (!signature || !rts)
WINPR_ASSERT(signature);
WINPR_ASSERT(src);
if (!rts_extract_pdu_signature(&extracted, src, header))
return FALSE;
if (rts->Flags != signature->Flags)
return FALSE;
if (rts->NumberOfCommands != signature->NumberOfCommands)
return FALSE;
buffer = (const BYTE*)rts;
offset = RTS_PDU_HEADER_LENGTH;
length = rts->header.frag_length - offset;
for (i = 0; i < rts->NumberOfCommands; i++)
{
CommandType = *((const UINT32*)&buffer[offset]); /* CommandType (4 bytes) */
offset += 4;
if (CommandType != signature->CommandTypes[i])
return FALSE;
status = rts_command_length(CommandType, &buffer[offset], length);
if (status < 0)
return FALSE;
CommandLength = (UINT32)status;
offset += CommandLength;
length = rts->header.frag_length - offset;
}
return TRUE;
return memcmp(signature, &extracted, sizeof(extracted)) == 0;
}
BOOL rts_extract_pdu_signature(RtsPduSignature* signature, const rpcconn_rts_hdr_t* rts)
BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header)
{
int i;
int status;
const BYTE* buffer;
UINT32 length;
UINT32 offset;
UINT32 CommandType;
UINT32 CommandLength;
BOOL rc = FALSE;
UINT16 i;
wStream tmp;
rpcconn_hdr_t rheader = { 0 };
const rpcconn_rts_hdr_t* rts;
if (!signature || !rts)
return FALSE;
WINPR_ASSERT(signature);
WINPR_ASSERT(src);
Stream_StaticInit(&tmp, Stream_Pointer(src), Stream_GetRemainingLength(src));
if (!header)
{
if (!rts_read_pdu_header(&tmp, &rheader))
goto fail;
header = &rheader;
}
rts = &header->rts;
if (rts->header.frag_length < sizeof(rpcconn_rts_hdr_t))
goto fail;
signature->Flags = rts->Flags;
signature->NumberOfCommands = rts->NumberOfCommands;
buffer = (const BYTE*)rts;
offset = RTS_PDU_HEADER_LENGTH;
length = rts->header.frag_length - offset;
for (i = 0; i < rts->NumberOfCommands; i++)
{
CommandType = *((const UINT32*)&buffer[offset]); /* CommandType (4 bytes) */
offset += 4;
signature->CommandTypes[i] = CommandType;
status = rts_command_length(CommandType, &buffer[offset], length);
UINT32 CommandType;
size_t CommandLength;
if (status < 0)
return FALSE;
if (Stream_GetRemainingLength(&tmp) < 4)
goto fail;
CommandLength = (UINT32)status;
offset += CommandLength;
length = rts->header.frag_length - offset;
Stream_Read_UINT32(&tmp, CommandType); /* CommandType (4 bytes) */
/* We only need this for comparison against known command types */
if (i < ARRAYSIZE(signature->CommandTypes))
signature->CommandTypes[i] = CommandType;
if (!rts_command_length(CommandType, &tmp, &CommandLength))
goto fail;
if (!Stream_SafeSeek(&tmp, CommandLength))
goto fail;
}
return TRUE;
rc = TRUE;
fail:
rts_free_pdu_header(&rheader, FALSE);
Stream_Free(&tmp, FALSE);
return rc;
}
UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
@ -367,11 +354,15 @@ UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
{
size_t i, j;
for (i = 0; RTS_PDU_SIGNATURE_TABLE[i].SignatureId != 0; i++)
{
const RtsPduSignature* pSignature = RTS_PDU_SIGNATURE_TABLE[i].Signature;
if (entry)
*entry = NULL;
if (!RTS_PDU_SIGNATURE_TABLE[i].SignatureClient)
for (i = 0; i < ARRAYSIZE(RTS_PDU_SIGNATURE_TABLE); i++)
{
const RTS_PDU_SIGNATURE_ENTRY* current = &RTS_PDU_SIGNATURE_TABLE[i];
const RtsPduSignature* pSignature = current->Signature;
if (!current->SignatureClient)
continue;
if (signature->Flags != pSignature->Flags)
@ -387,9 +378,9 @@ UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
}
if (entry)
*entry = &RTS_PDU_SIGNATURE_TABLE[i];
*entry = current;
return RTS_PDU_SIGNATURE_TABLE[i].SignatureId;
return current->SignatureId;
}
return 0;

View File

@ -178,10 +178,10 @@ FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_PING_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE;
FREERDP_LOCAL BOOL rts_match_pdu_signature(const RtsPduSignature* signature,
const rpcconn_rts_hdr_t* rts);
FREERDP_LOCAL BOOL rts_extract_pdu_signature(RtsPduSignature* signature,
const rpcconn_rts_hdr_t* rts);
FREERDP_LOCAL BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header);
FREERDP_LOCAL BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header);
FREERDP_LOCAL UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
const RTS_PDU_SIGNATURE_ENTRY** entry);
FREERDP_LOCAL BOOL rts_print_pdu_signature(const RtsPduSignature* signature);

View File

@ -24,6 +24,7 @@
#include "config.h"
#endif
#include <winpr/assert.h>
#include <winpr/crt.h>
#include <winpr/ndr.h>
#include <winpr/error.h>
@ -39,13 +40,14 @@
#define TAG FREERDP_TAG("core.gateway.tsg")
#define TSG_CAPABILITY_TYPE_NAP 0x00000001
#define TSG_PACKET_TYPE_HEADER 0x00004844
#define TSG_PACKET_TYPE_VERSIONCAPS 0x00005643
#define TSG_PACKET_TYPE_QUARCONFIGREQUEST 0x00005143
#define TSG_PACKET_TYPE_QUARREQUEST 0x00005152
#define TSG_PACKET_TYPE_RESPONSE 0x00005052
#define TSG_PACKET_TYPE_QUARENC_RESPONSE 0x00004552
#define TSG_CAPABILITY_TYPE_NAP 0x00000001
#define TSG_PACKET_TYPE_CAPS_RESPONSE 0x00004350
#define TSG_PACKET_TYPE_MSGREQUEST_PACKET 0x00004752
#define TSG_PACKET_TYPE_MESSAGE_PACKET 0x00004750
@ -310,16 +312,35 @@ static BOOL tsg_print(char** buffer, size_t* len, const char* fmt, ...)
static BOOL tsg_packet_header_to_string(char** buffer, size_t* length,
const TSG_PACKET_HEADER* header)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(header);
return tsg_print(buffer, length,
"header { ComponentId=0x%04" PRIx16 ", PacketId=0x%04" PRIx16 " }",
header->ComponentId, header->PacketId);
}
static BOOL tsg_type_capability_nap_to_string(char** buffer, size_t* length,
const TSG_CAPABILITY_NAP* cur)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(cur);
return tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }",
tsg_packet_id_to_string(TSG_CAPABILITY_TYPE_NAP), cur->capabilities);
}
static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
const TSG_PACKET_CAPABILITIES* caps, UINT32 numCaps)
{
UINT32 x;
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "capabilities { "))
return FALSE;
@ -329,9 +350,7 @@ static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
switch (cur->capabilityType)
{
case TSG_CAPABILITY_TYPE_NAP:
if (!tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }",
tsg_packet_id_to_string(cur->capabilityType),
cur->tsgPacket.tsgCapNap.capabilities))
if (!tsg_type_capability_nap_to_string(buffer, length, &cur->tsgPacket.tsgCapNap))
return FALSE;
break;
default:
@ -346,6 +365,10 @@ static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length,
const TSG_PACKET_VERSIONCAPS* caps)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "versioncaps { "))
return FALSE;
if (!tsg_packet_header_to_string(buffer, length, &caps->tsgHeader))
@ -367,6 +390,281 @@ static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length,
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_quarconfigrequest_to_string(char** buffer, size_t* length,
const TSG_PACKET_QUARCONFIGREQUEST* caps)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "quarconfigrequest { "))
return FALSE;
if (!tsg_print(buffer, length, " "))
return FALSE;
if (!tsg_print(buffer, length, " flags=0x%08" PRIx32, caps->flags))
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_quarrequest_to_string(char** buffer, size_t* length,
const TSG_PACKET_QUARREQUEST* caps)
{
BOOL rc = FALSE;
char* name = NULL;
char* strdata = NULL;
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "quarrequest { "))
return FALSE;
if (!tsg_print(buffer, length, " "))
return FALSE;
if (caps->nameLength > 0)
{
if (caps->nameLength > INT_MAX)
return FALSE;
if (ConvertFromUnicode(CP_UTF8, 0, caps->machineName, (int)caps->nameLength, &name, 0, NULL,
NULL) < 0)
return FALSE;
}
strdata = winpr_BinToHexString(caps->data, caps->dataLen, TRUE);
if (strdata || (caps->dataLen == 0))
rc = tsg_print(buffer, length,
" flags=0x%08" PRIx32 ", machineName=%s [%" PRIu32 "], data[%" PRIu32 "]=%s",
caps->flags, name, caps->nameLength, caps->dataLen, strdata);
free(name);
free(strdata);
if (!rc)
return FALSE;
return tsg_print(buffer, length, " }");
}
static const char* tsg_bool_to_string(BOOL val)
{
if (val)
return "true";
return "false";
}
static const char* tsg_redirection_flags_to_string(char* buffer, size_t size,
const TSG_REDIRECTION_FLAGS* flags)
{
WINPR_ASSERT(buffer || (size == 0));
WINPR_ASSERT(flags);
_snprintf(buffer, size,
"enableAllRedirections=%s, disableAllRedirections=%s, driveRedirectionDisabled=%s, "
"printerRedirectionDisabled=%s, portRedirectionDisabled=%s, reserved=%s, "
"clipboardRedirectionDisabled=%s, pnpRedirectionDisabled=%s",
tsg_bool_to_string(flags->enableAllRedirections),
tsg_bool_to_string(flags->disableAllRedirections),
tsg_bool_to_string(flags->driveRedirectionDisabled),
tsg_bool_to_string(flags->printerRedirectionDisabled),
tsg_bool_to_string(flags->portRedirectionDisabled),
tsg_bool_to_string(flags->reserved),
tsg_bool_to_string(flags->clipboardRedirectionDisabled),
tsg_bool_to_string(flags->pnpRedirectionDisabled));
return buffer;
}
static BOOL tsg_packet_response_to_string(char** buffer, size_t* length,
const TSG_PACKET_RESPONSE* caps)
{
BOOL rc = FALSE;
char* strdata = NULL;
char tbuffer[8192] = { 0 };
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "response { "))
return FALSE;
if (!tsg_print(buffer, length, " "))
return FALSE;
strdata = winpr_BinToHexString(caps->responseData, caps->responseDataLen, TRUE);
if (strdata || (caps->responseDataLen == 0))
rc = tsg_print(
buffer, length,
" flags=0x%08" PRIx32 ", reserved=0x%08" PRIx32 ", responseData[%" PRIu32
"]=%s, redirectionFlags={ %s }",
caps->flags, caps->reserved, caps->responseDataLen, strdata,
tsg_redirection_flags_to_string(tbuffer, ARRAYSIZE(tbuffer), &caps->redirectionFlags));
free(strdata);
if (!rc)
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_quarenc_response_to_string(char** buffer, size_t* length,
const TSG_PACKET_QUARENC_RESPONSE* caps)
{
BOOL rc = FALSE;
char* strdata = NULL;
RPC_CSTR uuid;
char tbuffer[8192] = { 0 };
size_t size = ARRAYSIZE(tbuffer);
char* ptbuffer = tbuffer;
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "quarenc_response { "))
return FALSE;
if (!tsg_print(buffer, length, " "))
return FALSE;
if (caps->certChainLen > 0)
{
if (caps->certChainLen > INT_MAX)
return FALSE;
if (ConvertFromUnicode(CP_UTF8, 0, caps->certChainData, (int)caps->certChainLen, &strdata,
0, NULL, NULL) <= 0)
return FALSE;
}
tsg_packet_versioncaps_to_string(&ptbuffer, &size, caps->versionCaps);
UuidToStringA(&caps->nonce, &uuid);
if (strdata || (caps->certChainLen == 0))
rc =
tsg_print(buffer, length,
" flags=0x%08" PRIx32 ", certChain[%" PRIu32 "]=%s, nonce=%s, versionCaps=%s",
caps->flags, caps->certChainLen, strdata, uuid, tbuffer);
free(strdata);
free(uuid);
if (!rc)
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_message_response_to_string(char** buffer, size_t* length,
const TSG_PACKET_MSG_RESPONSE* caps)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "msg_response { "))
return FALSE;
if (!tsg_print(buffer, length,
" msgID=0x%08" PRIx32 ", msgType=0x%08" PRIx32 ", isMsgPresent=%" PRId32,
caps->msgID, caps->msgType, caps->isMsgPresent))
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_caps_response_to_string(char** buffer, size_t* length,
const TSG_PACKET_CAPS_RESPONSE* caps)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "caps_response { "))
return FALSE;
if (!tsg_packet_quarenc_response_to_string(buffer, length, &caps->pktQuarEncResponse))
return FALSE;
if (!tsg_packet_message_response_to_string(buffer, length, &caps->pktConsentMessage))
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_message_request_to_string(char** buffer, size_t* length,
const TSG_PACKET_MSG_REQUEST* caps)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "caps_message_request { "))
return FALSE;
if (!tsg_print(buffer, length, " maxMessagesPerBatch=%" PRIu32, caps->maxMessagesPerBatch))
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_auth_to_string(char** buffer, size_t* length, const TSG_PACKET_AUTH* caps)
{
BOOL rc = FALSE;
char* strdata = NULL;
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "caps_message_request { "))
return FALSE;
if (!tsg_packet_versioncaps_to_string(buffer, length, &caps->tsgVersionCaps))
return FALSE;
strdata = winpr_BinToHexString(caps->cookie, caps->cookieLen, TRUE);
if (strdata || (caps->cookieLen == 0))
rc = tsg_print(buffer, length, " cookie[%" PRIu32 "]=%s", caps->cookieLen, strdata);
free(strdata);
if (!rc)
return FALSE;
return tsg_print(buffer, length, " }");
}
static BOOL tsg_packet_reauth_to_string(char** buffer, size_t* length,
const TSG_PACKET_REAUTH* caps)
{
BOOL rc = FALSE;
WINPR_ASSERT(buffer);
WINPR_ASSERT(length);
WINPR_ASSERT(caps);
if (!tsg_print(buffer, length, "caps_message_request { "))
return FALSE;
if (!tsg_print(buffer, length, " tunnelContext=0x%016" PRIx64 ", packetId=%s [0x%08" PRIx32 "]",
caps->tunnelContext, tsg_packet_id_to_string(caps->packetId), caps->packetId))
return FALSE;
switch (caps->packetId)
{
case TSG_PACKET_TYPE_VERSIONCAPS:
rc = tsg_packet_versioncaps_to_string(buffer, length,
caps->tsgInitialPacket.packetVersionCaps);
break;
case TSG_PACKET_TYPE_AUTH:
rc = tsg_packet_auth_to_string(buffer, length, caps->tsgInitialPacket.packetAuth);
break;
default:
rc = tsg_print(buffer, length, "TODO: Unhandled packet type %s [0x%08" PRIx32 "]",
tsg_packet_id_to_string(caps->packetId), caps->packetId);
break;
}
if (!rc)
return FALSE;
return tsg_print(buffer, length, " }");
}
static const char* tsg_packet_to_string(const TSG_PACKET* packet)
{
size_t len = 8192;
@ -389,43 +687,45 @@ static const char* tsg_packet_to_string(const TSG_PACKET* packet)
goto fail;
break;
case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_quarconfigrequest_to_string(&buffer, &len,
packet->tsgPacket.packetQuarConfigRequest))
goto fail;
break;
case TSG_PACKET_TYPE_QUARREQUEST:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_quarrequest_to_string(&buffer, &len,
packet->tsgPacket.packetQuarRequest))
goto fail;
break;
case TSG_PACKET_TYPE_RESPONSE:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_response_to_string(&buffer, &len, packet->tsgPacket.packetResponse))
goto fail;
break;
case TSG_PACKET_TYPE_QUARENC_RESPONSE:
if (!tsg_print(&buffer, &len, "TODO"))
goto fail;
break;
case TSG_CAPABILITY_TYPE_NAP:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_quarenc_response_to_string(&buffer, &len,
packet->tsgPacket.packetQuarEncResponse))
goto fail;
break;
case TSG_PACKET_TYPE_CAPS_RESPONSE:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_caps_response_to_string(&buffer, &len,
packet->tsgPacket.packetCapsResponse))
goto fail;
break;
case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_message_request_to_string(&buffer, &len,
packet->tsgPacket.packetMsgRequest))
goto fail;
break;
case TSG_PACKET_TYPE_MESSAGE_PACKET:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_message_response_to_string(&buffer, &len,
packet->tsgPacket.packetMsgResponse))
goto fail;
break;
case TSG_PACKET_TYPE_AUTH:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_auth_to_string(&buffer, &len, packet->tsgPacket.packetAuth))
goto fail;
break;
case TSG_PACKET_TYPE_REAUTH:
if (!tsg_print(&buffer, &len, "TODO"))
if (!tsg_packet_reauth_to_string(&buffer, &len, packet->tsgPacket.packetReauth))
goto fail;
break;
default:
@ -499,7 +799,7 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI
{
wStream* s;
rdpTsg* tsg;
int length;
size_t length;
const byte* buffer1 = NULL;
const byte* buffer2 = NULL;
const byte* buffer3 = NULL;
@ -535,7 +835,9 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI
totalDataBytes += lengths[2] + 4;
}
length = 28 + totalDataBytes;
length = 28ull + totalDataBytes;
if (length > INT_MAX)
return -1;
s = Stream_New(NULL, length);
if (!s)
@ -571,7 +873,7 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI
if (!rpc_client_write_call(tsg->rpc, s, TsProxySendToServerOpnum))
return -1;
return length;
return (int)length;
}
/**
@ -884,8 +1186,8 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
if (Stream_GetRemainingLength(pdu->s) < 16)
goto fail;
Stream_Read_UINT32(pdu->s, packetStringMessage.isDisplayMandatory);
Stream_Read_UINT32(pdu->s, packetStringMessage.isConsentMandatory);
Stream_Read_INT32(pdu->s, packetStringMessage.isDisplayMandatory);
Stream_Read_INT32(pdu->s, packetStringMessage.isConsentMandatory);
Stream_Read_UINT32(pdu->s, packetStringMessage.msgBytes);
Stream_Read_UINT32(pdu->s, Pointer);
@ -1085,16 +1387,19 @@ fail:
static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
{
UINT32 pad;
size_t pad;
wStream* s;
size_t count;
UINT32 offset;
size_t offset;
rdpRpc* rpc;
if (!tsg || !tsg->rpc || !tunnelContext || !tsg->MachineName)
return FALSE;
count = _wcslen(tsg->MachineName) + 1;
if (count > UINT32_MAX)
return FALSE;
rpc = tsg->rpc;
WLog_DBG(TAG, "TsProxyAuthorizeTunnelWriteRequest");
s = Stream_New(NULL, 1024 + count * 2);
@ -1111,13 +1416,13 @@ static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunn
Stream_Write_UINT32(s, 0x00020000); /* PacketQuarRequestPtr (4 bytes) */
Stream_Write_UINT32(s, 0x00000000); /* Flags (4 bytes) */
Stream_Write_UINT32(s, 0x00020004); /* MachineNamePtr (4 bytes) */
Stream_Write_UINT32(s, count); /* NameLength (4 bytes) */
Stream_Write_UINT32(s, (UINT32)count); /* NameLength (4 bytes) */
Stream_Write_UINT32(s, 0x00020008); /* DataPtr (4 bytes) */
Stream_Write_UINT32(s, 0); /* DataLength (4 bytes) */
/* MachineName */
Stream_Write_UINT32(s, count); /* MaxCount (4 bytes) */
Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */
Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
Stream_Write_UINT32(s, count); /* ActualCount (4 bytes) */
Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */
Stream_Write_UTF16_String(s, tsg->MachineName, count); /* Array */
/* 4-byte alignment */
offset = Stream_GetPosition(s);
@ -1128,7 +1433,7 @@ static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunn
return rpc_client_write_call(rpc, s, TsProxyAuthorizeTunnelOpnum);
}
static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
static BOOL TsProxyAuthorizeTunnelReadResponse(RPC_PDU* pdu)
{
BOOL rc = FALSE;
UINT32 Pointer;
@ -1190,25 +1495,24 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
Stream_Seek_UINT32(pdu->s); /* Reserved (4 bytes) */
Stream_Read_UINT32(pdu->s, Pointer); /* ResponseDataPtr (4 bytes) */
Stream_Read_UINT32(pdu->s, packetResponse->responseDataLen); /* ResponseDataLength (4 bytes) */
Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags
.enableAllRedirections); /* EnableAllRedirections (4 bytes) */
Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags
.disableAllRedirections); /* DisableAllRedirections (4 bytes) */
Stream_Read_UINT32(pdu->s,
packetResponse->redirectionFlags
.driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */
Stream_Read_UINT32(pdu->s,
packetResponse->redirectionFlags
.printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */
Stream_Read_UINT32(pdu->s,
packetResponse->redirectionFlags
.portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */
Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags.reserved); /* Reserved (4 bytes) */
Stream_Read_UINT32(
Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
.enableAllRedirections); /* EnableAllRedirections (4 bytes) */
Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
.disableAllRedirections); /* DisableAllRedirections (4 bytes) */
Stream_Read_INT32(pdu->s,
packetResponse->redirectionFlags
.driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */
Stream_Read_INT32(pdu->s,
packetResponse->redirectionFlags
.printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */
Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
.portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */
Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags.reserved); /* Reserved (4 bytes) */
Stream_Read_INT32(
pdu->s, packetResponse->redirectionFlags
.clipboardRedirectionDisabled); /* ClipboardRedirectionDisabled (4 bytes) */
Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags
.pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */
Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags
.pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */
Stream_Read_UINT32(pdu->s, SizeValue); /* (4 bytes) */
if (SizeValue != packetResponse->responseDataLen)
@ -1445,6 +1749,8 @@ static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnel
rpc = tsg->rpc;
count = _wcslen(tsg->Hostname) + 1;
if (count > UINT32_MAX)
return FALSE;
s = Stream_New(NULL, 60 + count * 2);
if (!s)
@ -1464,15 +1770,15 @@ static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnel
Stream_Write_UINT16(s, tsg->Port); /* PortNumber (0xD3D = 3389) (2 bytes) */
Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */
Stream_Write_UINT32(s, 0x00020004); /* ResourceNamePtr (4 bytes) */
Stream_Write_UINT32(s, count); /* MaxCount (4 bytes) */
Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */
Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
Stream_Write_UINT32(s, count); /* ActualCount (4 bytes) */
Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */
Stream_Write_UTF16_String(s, tsg->Hostname, count); /* Array */
return rpc_client_write_call(rpc, s, TsProxyCreateChannelOpnum);
}
static BOOL TsProxyCreateChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
CONTEXT_HANDLE* channelContext, UINT32* channelId)
static BOOL TsProxyCreateChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* channelContext,
UINT32* channelId)
{
BOOL rc = FALSE;
WLog_DBG(TAG, "TsProxyCreateChannelReadResponse");
@ -1520,7 +1826,7 @@ static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context
return rpc_client_write_call(rpc, s, TsProxyCloseChannelOpnum);
}
static BOOL TsProxyCloseChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, CONTEXT_HANDLE* context)
static BOOL TsProxyCloseChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
WLog_DBG(TAG, "TsProxyCloseChannelReadResponse");
@ -1567,7 +1873,7 @@ static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
return rpc_client_write_call(rpc, s, TsProxyCloseTunnelOpnum);
}
static BOOL TsProxyCloseTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, CONTEXT_HANDLE* context)
static BOOL TsProxyCloseTunnelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
WLog_DBG(TAG, "TsProxyCloseTunnelReadResponse");
@ -1718,8 +2024,6 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
return FALSE;
rpc = tsg->rpc;
Stream_SealLength(pdu->s);
Stream_SetPosition(pdu->s, 0);
if (!(pdu->Flags & RPC_PDU_FLAG_STUB))
{
@ -1758,7 +2062,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
CONTEXT_HANDLE* TunnelContext;
TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu))
if (!TsProxyAuthorizeTunnelReadResponse(pdu))
{
WLog_ERR(TAG, "TsProxyAuthorizeTunnelReadResponse failure");
return FALSE;
@ -1807,7 +2111,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
{
CONTEXT_HANDLE ChannelContext;
if (!TsProxyCreateChannelReadResponse(tsg, pdu, &ChannelContext, &tsg->ChannelId))
if (!TsProxyCreateChannelReadResponse(pdu, &ChannelContext, &tsg->ChannelId))
{
WLog_ERR(TAG, "TsProxyCreateChannelReadResponse failure");
return FALSE;
@ -1880,7 +2184,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
{
CONTEXT_HANDLE ChannelContext;
if (!TsProxyCloseChannelReadResponse(tsg, pdu, &ChannelContext))
if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext))
{
WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure");
return FALSE;
@ -1892,7 +2196,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
{
CONTEXT_HANDLE TunnelContext;
if (!TsProxyCloseTunnelReadResponse(tsg, pdu, &TunnelContext))
if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext))
{
WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure");
return FALSE;
@ -1907,7 +2211,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
{
CONTEXT_HANDLE ChannelContext;
if (!TsProxyCloseChannelReadResponse(tsg, pdu, &ChannelContext))
if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext))
{
WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure");
return FALSE;
@ -1937,7 +2241,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
{
CONTEXT_HANDLE TunnelContext;
if (!TsProxyCloseTunnelReadResponse(tsg, pdu, &TunnelContext))
if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext))
{
WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure");
return FALSE;
@ -2164,7 +2468,7 @@ BOOL tsg_disconnect(rdpTsg* tsg)
* @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 bytes to read
*/
static int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length)
static int tsg_read(rdpTsg* tsg, BYTE* data, size_t length)
{
rdpRpc* rpc;
int status = 0;
@ -2182,7 +2486,7 @@ static int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length)
do
{
status = rpc_client_receive_pipe_read(rpc->client, data, (size_t)length);
status = rpc_client_receive_pipe_read(rpc->client, data, length);
if (status < 0)
return -1;
@ -2232,7 +2536,7 @@ static int tsg_write(rdpTsg* tsg, const BYTE* data, UINT32 length)
if (status < 0)
return -1;
return length;
return (int)length;
}
rdpTsg* tsg_new(rdpTransport* transport)
@ -2271,7 +2575,10 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
int status;
rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
status = tsg_write(tsg, (const BYTE*)buf, num);
if (num < 0)
return -1;
status = tsg_write(tsg, (const BYTE*)buf, (UINT32)num);
if (status < 0)
{
@ -2303,7 +2610,7 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
}
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = tsg_read(tsg, (BYTE*)buf, size);
status = tsg_read(tsg, (BYTE*)buf, (size_t)size);
if (status < 0)
{
@ -2325,17 +2632,22 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
static int transport_bio_tsg_puts(BIO* bio, const char* str)
{
WINPR_UNUSED(bio);
WINPR_UNUSED(str);
return 1;
}
static int transport_bio_tsg_gets(BIO* bio, char* str, int size)
{
WINPR_UNUSED(bio);
WINPR_UNUSED(str);
WINPR_UNUSED(size);
return 1;
}
static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
int status = -1;
long status = -1;
rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio);
RpcVirtualConnection* connection = tsg->rpc->VirtualConnection;
RpcInChannel* inChannel = connection->DefaultInChannel;
@ -2413,6 +2725,7 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
static int transport_bio_tsg_new(BIO* bio)
{
WINPR_ASSERT(bio);
BIO_set_init(bio, 1);
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return 1;
@ -2420,6 +2733,8 @@ static int transport_bio_tsg_new(BIO* bio)
static int transport_bio_tsg_free(BIO* bio)
{
WINPR_ASSERT(bio);
WINPR_UNUSED(bio);
return 1;
}