2012-03-26 10:45:01 +04:00
|
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2012-03-26 20:20:38 +04:00
|
|
|
|
* RPC over HTTP
|
2012-03-26 10:45:01 +04:00
|
|
|
|
*
|
2012-03-26 20:20:38 +04:00
|
|
|
|
* Copyright 2012 Fujitsu Technology Solutions GmbH
|
|
|
|
|
* Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
|
2012-11-01 04:38:48 +04:00
|
|
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2012-03-26 10:45:01 +04:00
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-08-15 01:09:01 +04:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
2012-03-26 10:45:01 +04:00
|
|
|
|
#include "config.h"
|
2012-08-15 01:09:01 +04:00
|
|
|
|
#endif
|
|
|
|
|
|
2012-09-09 00:45:06 +04:00
|
|
|
|
#include <winpr/crt.h>
|
2012-10-29 06:16:21 +04:00
|
|
|
|
#include <winpr/tchar.h>
|
2012-11-28 22:38:01 +04:00
|
|
|
|
#include <winpr/synch.h>
|
2012-10-29 04:55:19 +04:00
|
|
|
|
#include <winpr/dsparse.h>
|
2014-09-12 16:36:29 +04:00
|
|
|
|
|
2014-08-19 20:26:39 +04:00
|
|
|
|
#include <freerdp/log.h>
|
2012-10-29 04:55:19 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
#include <openssl/bio.h>
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
|
|
|
|
#include <valgrind/memcheck.h>
|
|
|
|
|
#endif
|
2012-03-26 10:45:01 +04:00
|
|
|
|
|
2012-04-14 22:19:31 +04:00
|
|
|
|
#include "http.h"
|
2012-11-15 19:00:07 +04:00
|
|
|
|
#include "ntlm.h"
|
2012-11-28 07:03:05 +04:00
|
|
|
|
#include "ncacn_http.h"
|
2012-11-28 09:32:12 +04:00
|
|
|
|
#include "rpc_bind.h"
|
|
|
|
|
#include "rpc_fault.h"
|
2012-11-28 21:47:04 +04:00
|
|
|
|
#include "rpc_client.h"
|
2012-04-14 22:19:31 +04:00
|
|
|
|
|
|
|
|
|
#include "rpc.h"
|
2012-03-26 10:45:01 +04:00
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
|
#define TAG FREERDP_TAG("core.gateway.rpc")
|
2014-09-12 16:36:29 +04:00
|
|
|
|
|
2012-11-18 01:46:30 +04:00
|
|
|
|
/* Security Verification Trailer Signature */
|
|
|
|
|
|
|
|
|
|
rpc_sec_verification_trailer RPC_SEC_VERIFICATION_TRAILER =
|
2014-08-19 20:26:39 +04:00
|
|
|
|
{ { 0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71 } };
|
2012-11-18 01:46:30 +04:00
|
|
|
|
|
2012-10-30 21:01:54 +04:00
|
|
|
|
static char* PTYPE_STRINGS[] =
|
|
|
|
|
{
|
|
|
|
|
"PTYPE_REQUEST",
|
|
|
|
|
"PTYPE_PING",
|
|
|
|
|
"PTYPE_RESPONSE",
|
|
|
|
|
"PTYPE_FAULT",
|
|
|
|
|
"PTYPE_WORKING",
|
|
|
|
|
"PTYPE_NOCALL",
|
|
|
|
|
"PTYPE_REJECT",
|
|
|
|
|
"PTYPE_ACK",
|
|
|
|
|
"PTYPE_CL_CANCEL",
|
|
|
|
|
"PTYPE_FACK",
|
|
|
|
|
"PTYPE_CANCEL_ACK",
|
|
|
|
|
"PTYPE_BIND",
|
|
|
|
|
"PTYPE_BIND_ACK",
|
|
|
|
|
"PTYPE_BIND_NAK",
|
|
|
|
|
"PTYPE_ALTER_CONTEXT",
|
|
|
|
|
"PTYPE_ALTER_CONTEXT_RESP",
|
|
|
|
|
"PTYPE_RPC_AUTH_3",
|
|
|
|
|
"PTYPE_SHUTDOWN",
|
|
|
|
|
"PTYPE_CO_CANCEL",
|
|
|
|
|
"PTYPE_ORPHANED",
|
|
|
|
|
"PTYPE_RTS",
|
|
|
|
|
""
|
|
|
|
|
};
|
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
const RPC_SECURITY_PROVIDER_INFO RPC_SECURITY_PROVIDER_INFO_TABLE[] =
|
2012-10-31 18:52:04 +04:00
|
|
|
|
{
|
2012-11-28 09:32:12 +04:00
|
|
|
|
{ RPC_C_AUTHN_NONE, TRUE, -1 },
|
|
|
|
|
{ RPC_C_AUTHN_GSS_NEGOTIATE, TRUE, -1 },
|
|
|
|
|
{ RPC_C_AUTHN_WINNT, FALSE, 3 },
|
|
|
|
|
{ RPC_C_AUTHN_GSS_SCHANNEL, TRUE, -1 },
|
|
|
|
|
{ RPC_C_AUTHN_GSS_KERBEROS, TRUE, -1 },
|
|
|
|
|
{ RPC_C_AUTHN_DEFAULT, -1, -1 },
|
|
|
|
|
{ 0, -1, -1 }
|
2012-10-31 18:52:04 +04:00
|
|
|
|
};
|
|
|
|
|
|
2015-02-04 19:18:27 +03:00
|
|
|
|
/**
|
|
|
|
|
* [MS-RPCH]: Remote Procedure Call over HTTP Protocol Specification:
|
|
|
|
|
* http://msdn.microsoft.com/en-us/library/cc243950/
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Connection Establishment\n
|
|
|
|
|
*
|
|
|
|
|
* Client Outbound Proxy Inbound Proxy Server\n
|
|
|
|
|
* | | | |\n
|
|
|
|
|
* |-----------------IN Channel Request--------------->| |\n
|
|
|
|
|
* |---OUT Channel Request-->| |<-Legacy Server Response-|\n
|
|
|
|
|
* | |<--------------Legacy Server Response--------------|\n
|
|
|
|
|
* | | | |\n
|
|
|
|
|
* |---------CONN_A1-------->| | |\n
|
|
|
|
|
* |----------------------CONN_B1--------------------->| |\n
|
|
|
|
|
* | |----------------------CONN_A2--------------------->|\n
|
|
|
|
|
* | | | |\n
|
|
|
|
|
* |<--OUT Channel Response--| |---------CONN_B2-------->|\n
|
|
|
|
|
* |<--------CONN_A3---------| | |\n
|
|
|
|
|
* | |<---------------------CONN_C1----------------------|\n
|
|
|
|
|
* | | |<--------CONN_B3---------|\n
|
|
|
|
|
* |<--------CONN_C2---------| | |\n
|
|
|
|
|
* | | | |\n
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
void rpc_pdu_header_print(rpcconn_hdr_t* header)
|
2012-10-30 21:01:54 +04:00
|
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, "rpc_vers: %d", header->common.rpc_vers);
|
|
|
|
|
WLog_INFO(TAG, "rpc_vers_minor: %d", header->common.rpc_vers_minor);
|
2012-10-30 21:01:54 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.ptype > PTYPE_RTS)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, "ptype: %s (%d)", "PTYPE_UNKNOWN", header->common.ptype);
|
2012-10-30 21:01:54 +04:00
|
|
|
|
else
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, "ptype: %s (%d)", PTYPE_STRINGS[header->common.ptype], header->common.ptype);
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, "pfc_flags (0x%02X) = {", header->common.pfc_flags);
|
2012-10-30 21:01:54 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_FIRST_FRAG)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_FIRST_FRAG");
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_LAST_FRAG)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_LAST_FRAG");
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_PENDING_CANCEL)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_PENDING_CANCEL");
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_RESERVED_1)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_RESERVED_1");
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_CONC_MPX)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_CONC_MPX");
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_DID_NOT_EXECUTE");
|
2012-10-30 21:01:54 +04:00
|
|
|
|
|
2014-08-19 20:26:39 +04:00
|
|
|
|
if (header->common.pfc_flags & PFC_OBJECT_UUID)
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " PFC_OBJECT_UUID");
|
2012-10-30 21:01:54 +04:00
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, " }");
|
|
|
|
|
WLog_INFO(TAG, "packed_drep[4]: %02X %02X %02X %02X",
|
|
|
|
|
header->common.packed_drep[0], header->common.packed_drep[1],
|
|
|
|
|
header->common.packed_drep[2], header->common.packed_drep[3]);
|
|
|
|
|
WLog_INFO(TAG, "frag_length: %d", header->common.frag_length);
|
|
|
|
|
WLog_INFO(TAG, "auth_length: %d", header->common.auth_length);
|
|
|
|
|
WLog_INFO(TAG, "call_id: %d", header->common.call_id);
|
2012-11-09 14:04:39 +04:00
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
if (header->common.ptype == PTYPE_RESPONSE)
|
2012-11-09 14:04:39 +04:00
|
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
|
WLog_INFO(TAG, "alloc_hint: %d", header->response.alloc_hint);
|
|
|
|
|
WLog_INFO(TAG, "p_cont_id: %d", header->response.p_cont_id);
|
|
|
|
|
WLog_INFO(TAG, "cancel_count: %d", header->response.cancel_count);
|
|
|
|
|
WLog_INFO(TAG, "reserved: %d", header->response.reserved);
|
2012-11-09 14:04:39 +04:00
|
|
|
|
}
|
2012-10-30 21:01:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header)
|
2012-10-30 00:41:20 +04:00
|
|
|
|
{
|
2012-11-16 01:25:22 +04:00
|
|
|
|
header->common.rpc_vers = rpc->rpc_vers;
|
|
|
|
|
header->common.rpc_vers_minor = rpc->rpc_vers_minor;
|
|
|
|
|
header->common.packed_drep[0] = rpc->packed_drep[0];
|
|
|
|
|
header->common.packed_drep[1] = rpc->packed_drep[1];
|
|
|
|
|
header->common.packed_drep[2] = rpc->packed_drep[2];
|
|
|
|
|
header->common.packed_drep[3] = rpc->packed_drep[3];
|
2012-10-30 00:41:20 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-30 02:46:32 +04:00
|
|
|
|
UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment)
|
|
|
|
|
{
|
|
|
|
|
UINT32 pad;
|
|
|
|
|
pad = *offset;
|
|
|
|
|
*offset = (*offset + alignment - 1) & ~(alignment - 1);
|
|
|
|
|
pad = *offset - pad;
|
|
|
|
|
return pad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad)
|
|
|
|
|
{
|
|
|
|
|
*offset += pad;
|
|
|
|
|
return pad;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-08 02:41:12 +04:00
|
|
|
|
/**
|
|
|
|
|
* PDU Segments:
|
|
|
|
|
* ________________________________
|
|
|
|
|
* | |
|
|
|
|
|
* | PDU Header |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
* | |
|
|
|
|
|
* | |
|
|
|
|
|
* | PDU Body |
|
|
|
|
|
* | |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
* | |
|
|
|
|
|
* | Security Trailer |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
* | |
|
|
|
|
|
* | Authentication Token |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-18 01:46:30 +04:00
|
|
|
|
/**
|
|
|
|
|
* PDU Structure with verification trailer
|
|
|
|
|
*
|
|
|
|
|
* MUST only appear in a request PDU!
|
|
|
|
|
* ________________________________
|
|
|
|
|
* | |
|
|
|
|
|
* | PDU Header |
|
|
|
|
|
* |________________________________| _______
|
|
|
|
|
* | | /|\
|
|
|
|
|
* | | |
|
|
|
|
|
* | Stub Data | |
|
|
|
|
|
* | | |
|
|
|
|
|
* |________________________________| |
|
|
|
|
|
* | | PDU Body
|
|
|
|
|
* | Stub Pad | |
|
|
|
|
|
* |________________________________| |
|
|
|
|
|
* | | |
|
|
|
|
|
* | Verification Trailer | |
|
|
|
|
|
* |________________________________| |
|
|
|
|
|
* | | |
|
|
|
|
|
* | Authentication Pad | |
|
|
|
|
|
* |________________________________| __\|/__
|
|
|
|
|
* | |
|
|
|
|
|
* | Security Trailer |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
* | |
|
|
|
|
|
* | Authentication Token |
|
|
|
|
|
* |________________________________|
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2012-12-08 02:41:12 +04:00
|
|
|
|
/**
|
|
|
|
|
* Security Trailer:
|
|
|
|
|
*
|
|
|
|
|
* The sec_trailer structure MUST be placed at the end of the PDU, including past stub data,
|
|
|
|
|
* when present. The sec_trailer structure MUST be 4-byte aligned with respect to the beginning
|
|
|
|
|
* of the PDU. Padding octets MUST be used to align the sec_trailer structure if its natural
|
|
|
|
|
* beginning is not already 4-byte aligned.
|
|
|
|
|
*
|
|
|
|
|
* All PDUs that carry sec_trailer information share certain common fields:
|
|
|
|
|
* frag_length and auth_length. The beginning of the sec_trailer structure for each PDU MUST be
|
|
|
|
|
* calculated to start from offset (frag_length – auth_length – 8) from the beginning of the PDU.
|
|
|
|
|
*
|
|
|
|
|
* Immediately after the sec_trailer structure, there MUST be a BLOB carrying the authentication
|
|
|
|
|
* information produced by the security provider. This BLOB is called the authentication token and
|
|
|
|
|
* MUST be of size auth_length. The size MUST also be equal to the length from the first octet
|
|
|
|
|
* immediately after the sec_trailer structure all the way to the end of the fragment;
|
|
|
|
|
* the two values MUST be the same.
|
|
|
|
|
*
|
|
|
|
|
* A client or a server that (during composing of a PDU) has allocated more space for the
|
|
|
|
|
* authentication token than the security provider fills in SHOULD fill in the rest of
|
|
|
|
|
* the allocated space with zero octets. These zero octets are still considered to belong
|
|
|
|
|
* to the authentication token part of the PDU.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-16 01:25:22 +04:00
|
|
|
|
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length)
|
2012-11-15 04:51:45 +04:00
|
|
|
|
{
|
2012-11-15 08:06:56 +04:00
|
|
|
|
UINT32 alloc_hint = 0;
|
2012-11-16 01:25:22 +04:00
|
|
|
|
rpcconn_hdr_t* header;
|
2014-05-21 19:32:14 +04:00
|
|
|
|
UINT32 frag_length;
|
|
|
|
|
UINT32 auth_length;
|
|
|
|
|
UINT32 auth_pad_length;
|
|
|
|
|
UINT32 sec_trailer_offset;
|
|
|
|
|
rpc_sec_trailer* sec_trailer;
|
2015-02-01 00:56:25 +03:00
|
|
|
|
|
2012-11-15 04:51:45 +04:00
|
|
|
|
*offset = RPC_COMMON_FIELDS_LENGTH;
|
2012-11-16 01:25:22 +04:00
|
|
|
|
header = ((rpcconn_hdr_t*) buffer);
|
2012-11-15 04:51:45 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
switch (header->common.ptype)
|
2012-11-15 04:51:45 +04:00
|
|
|
|
{
|
2014-05-21 19:32:14 +04:00
|
|
|
|
case PTYPE_RESPONSE:
|
|
|
|
|
*offset += 8;
|
|
|
|
|
rpc_offset_align(offset, 8);
|
|
|
|
|
alloc_hint = header->response.alloc_hint;
|
|
|
|
|
break;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
case PTYPE_REQUEST:
|
|
|
|
|
*offset += 4;
|
|
|
|
|
rpc_offset_align(offset, 8);
|
|
|
|
|
alloc_hint = header->request.alloc_hint;
|
|
|
|
|
break;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
case PTYPE_RTS:
|
|
|
|
|
*offset += 4;
|
|
|
|
|
break;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
default:
|
2015-02-03 22:44:31 +03:00
|
|
|
|
WLog_ERR(TAG, "Unknown PTYPE: 0x%04X", header->common.ptype);
|
2014-05-21 19:32:14 +04:00
|
|
|
|
return FALSE;
|
2012-11-15 04:51:45 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!length)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (header->common.ptype == PTYPE_REQUEST)
|
2012-11-15 04:51:45 +04:00
|
|
|
|
{
|
2014-05-21 19:32:14 +04:00
|
|
|
|
UINT32 sec_trailer_offset;
|
|
|
|
|
sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8;
|
|
|
|
|
*length = sec_trailer_offset - *offset;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2012-11-15 12:08:30 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
frag_length = header->common.frag_length;
|
|
|
|
|
auth_length = header->common.auth_length;
|
|
|
|
|
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;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2012-12-08 02:41:12 +04:00
|
|
|
|
#if 0
|
2015-02-03 22:44:31 +03:00
|
|
|
|
WLog_DBG(TAG, "sec_trailer: type: %d level: %d pad_length: %d reserved: %d context_id: %d",
|
|
|
|
|
sec_trailer->auth_type, sec_trailer->auth_level,
|
|
|
|
|
sec_trailer->auth_pad_length, sec_trailer->auth_reserved,
|
|
|
|
|
sec_trailer->auth_context_id);
|
2012-12-08 02:41:12 +04:00
|
|
|
|
#endif
|
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
/**
|
|
|
|
|
* According to [MS-RPCE], auth_pad_length is the number of padding
|
|
|
|
|
* octets used to 4-byte align the security trailer, but in practice
|
|
|
|
|
* we get values up to 15, which indicates 16-byte alignment.
|
|
|
|
|
*/
|
2012-12-08 02:41:12 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
|
|
|
|
|
{
|
2015-02-01 00:56:25 +03:00
|
|
|
|
WLog_ERR(TAG, "invalid auth_length: actual: %d, expected: %d", auth_length,
|
2014-09-12 16:36:29 +04:00
|
|
|
|
(frag_length - (sec_trailer_offset + 8)));
|
2012-11-15 04:51:45 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
*length = frag_length - auth_length - 24 - 8 - auth_pad_length;
|
2012-11-15 04:51:45 +04:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_out_channel_read(RpcOutChannel* outChannel, BYTE* data, int length)
|
2012-11-17 12:45:15 +04:00
|
|
|
|
{
|
|
|
|
|
int status;
|
2014-12-15 17:42:04 +03:00
|
|
|
|
|
2015-02-11 22:27:29 +03:00
|
|
|
|
status = BIO_read(outChannel->tls->bio, data, length);
|
2014-06-02 05:37:20 +04:00
|
|
|
|
|
2014-08-19 20:26:39 +04:00
|
|
|
|
if (status > 0)
|
|
|
|
|
{
|
2014-05-21 19:32:14 +04:00
|
|
|
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(data, status);
|
|
|
|
|
#endif
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2012-11-17 12:45:15 +04:00
|
|
|
|
|
2015-02-11 22:27:29 +03:00
|
|
|
|
if (BIO_should_retry(outChannel->tls->bio))
|
2014-05-21 19:32:14 +04:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return -1;
|
2012-11-17 12:45:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_in_channel_write(RpcInChannel* inChannel, const BYTE* data, int length)
|
2012-11-17 12:45:15 +04:00
|
|
|
|
{
|
|
|
|
|
int status;
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
status = tls_write_all(inChannel->tls, data, length);
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2012-11-17 12:45:15 +04:00
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_out_channel_write(RpcOutChannel* outChannel, const BYTE* data, int length)
|
2012-11-17 12:45:15 +04:00
|
|
|
|
{
|
|
|
|
|
int status;
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
status = tls_write_all(outChannel->tls, data, length);
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2012-11-17 12:45:15 +04:00
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
|
2015-02-04 00:33:45 +03:00
|
|
|
|
{
|
|
|
|
|
int status = 1;
|
|
|
|
|
const char* str = "CLIENT_IN_CHANNEL_STATE_UNKNOWN";
|
|
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_INITIAL:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_INITIAL";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_CONNECTED:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_CONNECTED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_SECURITY:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_SECURITY";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_OPENED:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_OPENED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_IN_CHANNEL_STATE_FINAL:
|
|
|
|
|
str = "CLIENT_IN_CHANNEL_STATE_FINAL";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inChannel->State = state;
|
|
|
|
|
WLog_DBG(TAG, "%s", str);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_in_channel_rpch_init(rdpRpc* rpc, RpcInChannel* inChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
2015-02-12 20:03:15 +03:00
|
|
|
|
HttpContext* http;
|
|
|
|
|
|
2015-02-11 23:26:22 +03:00
|
|
|
|
inChannel->ntlm = ntlm_new();
|
|
|
|
|
|
|
|
|
|
if (!inChannel->ntlm)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
inChannel->http = http_context_new();
|
|
|
|
|
|
|
|
|
|
if (!inChannel->http)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2015-02-12 20:03:15 +03:00
|
|
|
|
http = inChannel->http;
|
|
|
|
|
|
|
|
|
|
http_context_set_method(http, "RPC_IN_DATA");
|
|
|
|
|
|
|
|
|
|
http_context_set_uri(http, "/rpc/rpcproxy.dll?localhost:3388");
|
|
|
|
|
http_context_set_accept(http, "application/rpc");
|
|
|
|
|
http_context_set_cache_control(http, "no-cache");
|
|
|
|
|
http_context_set_connection(http, "Keep-Alive");
|
|
|
|
|
http_context_set_user_agent(http, "MSRPC");
|
|
|
|
|
http_context_set_host(http, rpc->settings->GatewayHostname);
|
|
|
|
|
|
|
|
|
|
http_context_set_pragma(http, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729");
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_in_channel_init(rdpRpc* rpc, RpcInChannel* inChannel)
|
2015-02-12 20:03:15 +03:00
|
|
|
|
{
|
|
|
|
|
rts_generate_cookie((BYTE*) &inChannel->Cookie);
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
inChannel->rpc = rpc;
|
2015-02-12 20:03:15 +03:00
|
|
|
|
inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
|
|
|
|
|
inChannel->BytesSent = 0;
|
|
|
|
|
inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
|
|
|
|
|
inChannel->PingOriginator.ConnectionTimeout = 30;
|
|
|
|
|
inChannel->PingOriginator.KeepAliveInterval = 0;
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
if (rpc_in_channel_rpch_init(rpc, inChannel) < 0)
|
2015-02-12 20:03:15 +03:00
|
|
|
|
return -1;
|
2015-02-11 23:26:22 +03:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
void rpc_in_channel_rpch_uninit(RpcInChannel* inChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
if (inChannel->ntlm)
|
|
|
|
|
{
|
|
|
|
|
ntlm_free(inChannel->ntlm);
|
|
|
|
|
inChannel->ntlm = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inChannel->http)
|
|
|
|
|
{
|
|
|
|
|
http_context_free(inChannel->http);
|
|
|
|
|
inChannel->http = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
RpcInChannel* rpc_in_channel_new(rdpRpc* rpc)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
RpcInChannel* inChannel = NULL;
|
|
|
|
|
|
|
|
|
|
inChannel = (RpcInChannel*) calloc(1, sizeof(RpcInChannel));
|
|
|
|
|
|
|
|
|
|
if (inChannel)
|
|
|
|
|
{
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_in_channel_init(rpc, inChannel);
|
2015-02-11 23:26:22 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return inChannel;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
void rpc_in_channel_free(RpcInChannel* inChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
if (!inChannel)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_in_channel_rpch_uninit(inChannel);
|
2015-02-11 23:26:22 +03:00
|
|
|
|
|
2015-02-13 00:22:25 +03:00
|
|
|
|
if (inChannel->tls)
|
|
|
|
|
{
|
|
|
|
|
tls_free(inChannel->tls);
|
|
|
|
|
inChannel->tls = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-11 23:26:22 +03:00
|
|
|
|
free(inChannel);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
|
2015-02-04 00:33:45 +03:00
|
|
|
|
{
|
|
|
|
|
int status = 1;
|
|
|
|
|
const char* str = "CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
|
|
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_INITIAL:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_INITIAL";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_CONNECTED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_SECURITY:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_SECURITY";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_OPENED:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_OPENED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
|
|
|
|
|
break;
|
|
|
|
|
|
2015-03-17 23:54:45 +03:00
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_RECYCLED";
|
|
|
|
|
break;
|
|
|
|
|
|
2015-02-04 00:33:45 +03:00
|
|
|
|
case CLIENT_OUT_CHANNEL_STATE_FINAL:
|
|
|
|
|
str = "CLIENT_OUT_CHANNEL_STATE_FINAL";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outChannel->State = state;
|
|
|
|
|
WLog_DBG(TAG, "%s", str);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_out_channel_rpch_init(rdpRpc* rpc, RpcOutChannel* outChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
2015-02-12 20:03:15 +03:00
|
|
|
|
HttpContext* http;
|
|
|
|
|
|
2015-02-11 23:26:22 +03:00
|
|
|
|
outChannel->ntlm = ntlm_new();
|
|
|
|
|
|
|
|
|
|
if (!outChannel->ntlm)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
outChannel->http = http_context_new();
|
|
|
|
|
|
|
|
|
|
if (!outChannel->http)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2015-02-12 20:03:15 +03:00
|
|
|
|
http = outChannel->http;
|
|
|
|
|
|
|
|
|
|
http_context_set_method(http, "RPC_OUT_DATA");
|
|
|
|
|
|
|
|
|
|
http_context_set_uri(http, "/rpc/rpcproxy.dll?localhost:3388");
|
|
|
|
|
http_context_set_accept(http, "application/rpc");
|
|
|
|
|
http_context_set_cache_control(http, "no-cache");
|
|
|
|
|
http_context_set_connection(http, "Keep-Alive");
|
|
|
|
|
http_context_set_user_agent(http, "MSRPC");
|
|
|
|
|
http_context_set_host(http, rpc->settings->GatewayHostname);
|
|
|
|
|
|
|
|
|
|
http_context_set_pragma(http,
|
|
|
|
|
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, "
|
|
|
|
|
"SessionId=fbd9c34f-397d-471d-a109-1b08cc554624");
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_out_channel_init(rdpRpc* rpc, RpcOutChannel* outChannel)
|
2015-02-12 20:03:15 +03:00
|
|
|
|
{
|
|
|
|
|
rts_generate_cookie((BYTE*) &outChannel->Cookie);
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
outChannel->rpc = rpc;
|
2015-02-12 20:03:15 +03:00
|
|
|
|
outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
|
|
|
|
|
outChannel->BytesReceived = 0;
|
|
|
|
|
outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
|
|
|
|
|
outChannel->ReceiveWindow = rpc->ReceiveWindow;
|
|
|
|
|
outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
|
|
|
|
|
outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
if (rpc_out_channel_rpch_init(rpc, outChannel) < 0)
|
2015-02-12 20:03:15 +03:00
|
|
|
|
return -1;
|
2015-02-11 23:26:22 +03:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
void rpc_out_channel_rpch_uninit(RpcOutChannel* outChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
if (outChannel->ntlm)
|
|
|
|
|
{
|
|
|
|
|
ntlm_free(outChannel->ntlm);
|
|
|
|
|
outChannel->ntlm = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outChannel->http)
|
|
|
|
|
{
|
|
|
|
|
http_context_free(outChannel->http);
|
|
|
|
|
outChannel->http = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
RpcOutChannel* outChannel = NULL;
|
|
|
|
|
|
|
|
|
|
outChannel = (RpcOutChannel*) calloc(1, sizeof(RpcOutChannel));
|
|
|
|
|
|
|
|
|
|
if (outChannel)
|
|
|
|
|
{
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_out_channel_init(rpc, outChannel);
|
2015-02-11 23:26:22 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return outChannel;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
void rpc_out_channel_free(RpcOutChannel* outChannel)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
{
|
|
|
|
|
if (!outChannel)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_out_channel_rpch_uninit(outChannel);
|
2015-02-11 23:26:22 +03:00
|
|
|
|
|
2015-02-13 00:22:25 +03:00
|
|
|
|
if (outChannel->tls)
|
|
|
|
|
{
|
|
|
|
|
tls_free(outChannel->tls);
|
|
|
|
|
outChannel->tls = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-11 23:26:22 +03:00
|
|
|
|
free(outChannel);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
int rpc_virtual_connection_transition_to_state(rdpRpc* rpc,
|
2015-02-03 02:50:26 +03:00
|
|
|
|
RpcVirtualConnection* connection, VIRTUAL_CONNECTION_STATE state)
|
|
|
|
|
{
|
|
|
|
|
int status = 1;
|
|
|
|
|
const char* str = "VIRTUAL_CONNECTION_STATE_UNKNOWN";
|
|
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_INITIAL:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_INITIAL";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_WAIT_A3W";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_WAIT_C2:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_WAIT_C2";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_OPENED:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_OPENED";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VIRTUAL_CONNECTION_STATE_FINAL:
|
|
|
|
|
str = "VIRTUAL_CONNECTION_STATE_FINAL";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connection->State = state;
|
|
|
|
|
WLog_DBG(TAG, "%s", str);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
RpcVirtualConnection* rpc_virtual_connection_new(rdpRpc* rpc)
|
2012-04-21 21:28:20 +04:00
|
|
|
|
{
|
2015-02-03 22:44:31 +03:00
|
|
|
|
RpcVirtualConnection* connection;
|
|
|
|
|
|
|
|
|
|
connection = (RpcVirtualConnection*) calloc(1, sizeof(RpcVirtualConnection));
|
2012-04-21 21:28:20 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
if (!connection)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2015-02-12 21:14:43 +03:00
|
|
|
|
rts_generate_cookie((BYTE*) &(connection->Cookie));
|
|
|
|
|
rts_generate_cookie((BYTE*) &(connection->AssociationGroupId));
|
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
connection->DefaultInChannel = rpc_in_channel_new(rpc);
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
if (!connection->DefaultInChannel)
|
|
|
|
|
goto out_free;
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
connection->DefaultOutChannel = rpc_out_channel_new(rpc);
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
if (!connection->DefaultOutChannel)
|
|
|
|
|
goto out_default_in;
|
2012-04-21 21:28:20 +04:00
|
|
|
|
|
2012-11-16 20:25:10 +04:00
|
|
|
|
return connection;
|
2014-04-10 23:07:53 +04:00
|
|
|
|
out_default_in:
|
|
|
|
|
free(connection->DefaultInChannel);
|
|
|
|
|
out_free:
|
|
|
|
|
free(connection);
|
|
|
|
|
return NULL;
|
2012-04-21 21:28:20 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
void rpc_virtual_connection_free(RpcVirtualConnection* connection)
|
2012-04-21 21:28:20 +04:00
|
|
|
|
{
|
2015-02-12 21:14:43 +03:00
|
|
|
|
if (!connection)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
return;
|
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_in_channel_free(connection->DefaultInChannel);
|
|
|
|
|
rpc_in_channel_free(connection->NonDefaultInChannel);
|
2015-02-11 23:26:22 +03:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rpc_out_channel_free(connection->DefaultOutChannel);
|
|
|
|
|
rpc_out_channel_free(connection->NonDefaultOutChannel);
|
2015-02-12 21:14:43 +03:00
|
|
|
|
|
|
|
|
|
free(connection);
|
2012-04-21 21:28:20 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:40:26 +03:00
|
|
|
|
int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
|
|
|
|
|
{
|
2015-02-14 18:14:13 +03:00
|
|
|
|
int sockfd;
|
2015-02-12 22:40:26 +03:00
|
|
|
|
rdpTls* tls;
|
|
|
|
|
int tlsStatus;
|
2015-02-14 18:14:13 +03:00
|
|
|
|
BIO* socketBio;
|
|
|
|
|
BIO* bufferedBio;
|
2015-02-12 22:40:26 +03:00
|
|
|
|
rdpRpc* rpc = channel->rpc;
|
|
|
|
|
rdpContext* context = rpc->context;
|
|
|
|
|
rdpSettings* settings = context->settings;
|
|
|
|
|
|
2015-07-03 12:49:40 +03:00
|
|
|
|
sockfd = freerdp_tcp_connect(context, settings, settings->GatewayHostname,
|
|
|
|
|
settings->GatewayPort, timeout);
|
2015-02-12 22:40:26 +03:00
|
|
|
|
|
2015-02-14 18:14:13 +03:00
|
|
|
|
if (sockfd < 1)
|
2015-02-12 22:40:26 +03:00
|
|
|
|
return -1;
|
|
|
|
|
|
2015-02-14 18:14:13 +03:00
|
|
|
|
socketBio = BIO_new(BIO_s_simple_socket());
|
|
|
|
|
|
|
|
|
|
if (!socketBio)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
|
|
|
|
|
|
|
|
|
|
bufferedBio = BIO_new(BIO_s_buffered_socket());
|
|
|
|
|
|
|
|
|
|
if (!bufferedBio)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
bufferedBio = BIO_push(bufferedBio, socketBio);
|
|
|
|
|
|
|
|
|
|
if (!BIO_set_nonblock(bufferedBio, TRUE))
|
2015-02-12 22:40:26 +03:00
|
|
|
|
return -1;
|
|
|
|
|
|
2015-02-14 18:14:13 +03:00
|
|
|
|
channel->bio = bufferedBio;
|
|
|
|
|
|
2015-02-12 22:40:26 +03:00
|
|
|
|
tls = channel->tls = tls_new(settings);
|
|
|
|
|
|
|
|
|
|
if (!tls)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
tls->hostname = settings->GatewayHostname;
|
|
|
|
|
tls->port = settings->GatewayPort;
|
|
|
|
|
tls->isGatewayTransport = TRUE;
|
|
|
|
|
|
2015-02-14 18:14:13 +03:00
|
|
|
|
tlsStatus = tls_connect(tls, bufferedBio);
|
2015-02-12 22:40:26 +03:00
|
|
|
|
|
|
|
|
|
if (tlsStatus < 1)
|
|
|
|
|
{
|
|
|
|
|
if (tlsStatus < 0)
|
|
|
|
|
{
|
|
|
|
|
if (!freerdp_get_last_error(context))
|
|
|
|
|
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!freerdp_get_last_error(context))
|
|
|
|
|
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rpc_in_channel_connect(RpcInChannel* inChannel, int timeout)
|
|
|
|
|
{
|
|
|
|
|
rdpRpc* rpc = inChannel->rpc;
|
|
|
|
|
|
|
|
|
|
/* Connect IN Channel */
|
|
|
|
|
|
|
|
|
|
if (rpc_channel_tls_connect((RpcChannel*) inChannel, timeout) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
|
|
|
|
|
|
|
|
|
|
if (rpc_ncacn_http_ntlm_init(rpc, (RpcChannel*) inChannel) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* Send IN Channel Request */
|
|
|
|
|
|
|
|
|
|
if (rpc_ncacn_http_send_in_channel_request(rpc, inChannel) < 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rpc_out_channel_connect(RpcOutChannel* outChannel, int timeout)
|
|
|
|
|
{
|
|
|
|
|
rdpRpc* rpc = outChannel->rpc;
|
|
|
|
|
|
|
|
|
|
/* Connect OUT Channel */
|
|
|
|
|
|
|
|
|
|
if (rpc_channel_tls_connect((RpcChannel*) outChannel, timeout) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
|
|
|
|
|
|
|
|
|
|
if (rpc_ncacn_http_ntlm_init(rpc, (RpcChannel*) outChannel) < 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Send OUT Channel Request */
|
|
|
|
|
|
|
|
|
|
if (rpc_ncacn_http_send_out_channel_request(rpc, outChannel, FALSE) < 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-19 21:41:00 +03:00
|
|
|
|
int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout)
|
|
|
|
|
{
|
|
|
|
|
rdpRpc* rpc = outChannel->rpc;
|
|
|
|
|
|
|
|
|
|
/* Connect OUT Channel */
|
|
|
|
|
|
2015-02-19 23:06:57 +03:00
|
|
|
|
if (rpc_channel_tls_connect((RpcChannel*) outChannel, timeout) < 0)
|
2015-02-19 21:41:00 +03:00
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
|
|
|
|
|
|
2015-02-19 23:06:57 +03:00
|
|
|
|
if (rpc_ncacn_http_ntlm_init(rpc, (RpcChannel*) outChannel) < 0)
|
2015-02-19 21:41:00 +03:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Send OUT Channel Request */
|
|
|
|
|
|
|
|
|
|
if (rpc_ncacn_http_send_out_channel_request(rpc, outChannel, TRUE) < 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:40:26 +03:00
|
|
|
|
BOOL rpc_connect(rdpRpc* rpc, int timeout)
|
|
|
|
|
{
|
|
|
|
|
RpcInChannel* inChannel;
|
|
|
|
|
RpcOutChannel* outChannel;
|
|
|
|
|
RpcVirtualConnection* connection;
|
|
|
|
|
|
|
|
|
|
rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
|
|
|
|
|
|
|
|
|
|
if (!rpc->VirtualConnection)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
connection = rpc->VirtualConnection;
|
|
|
|
|
inChannel = connection->DefaultInChannel;
|
|
|
|
|
outChannel = connection->DefaultOutChannel;
|
|
|
|
|
|
|
|
|
|
rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
|
|
|
|
|
|
|
|
|
|
if (rpc_in_channel_connect(inChannel, timeout) < 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (rpc_out_channel_connect(outChannel, timeout) < 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-24 00:33:18 +04:00
|
|
|
|
rdpRpc* rpc_new(rdpTransport* transport)
|
|
|
|
|
{
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rdpRpc* rpc = (rdpRpc*) calloc(1, sizeof(rdpRpc));
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
if (!rpc)
|
|
|
|
|
return NULL;
|
2012-04-24 00:33:18 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->State = RPC_CLIENT_STATE_INITIAL;
|
2014-12-15 17:42:04 +03:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->transport = transport;
|
|
|
|
|
rpc->settings = transport->settings;
|
2014-12-15 17:42:04 +03:00
|
|
|
|
rpc->context = transport->context;
|
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->SendSeqNum = 0;
|
2014-12-11 19:25:34 +03:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->ntlm = ntlm_new();
|
2014-08-19 20:26:39 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
if (!rpc->ntlm)
|
|
|
|
|
goto out_free;
|
2012-04-24 00:33:18 +04:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->PipeCallId = 0;
|
|
|
|
|
rpc->StubCallId = 0;
|
|
|
|
|
rpc->StubFragCount = 0;
|
|
|
|
|
rpc->rpc_vers = 5;
|
|
|
|
|
rpc->rpc_vers_minor = 0;
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
/* little-endian data representation */
|
|
|
|
|
rpc->packed_drep[0] = 0x10;
|
|
|
|
|
rpc->packed_drep[1] = 0x00;
|
|
|
|
|
rpc->packed_drep[2] = 0x00;
|
|
|
|
|
rpc->packed_drep[3] = 0x00;
|
|
|
|
|
rpc->max_xmit_frag = 0x0FF8;
|
|
|
|
|
rpc->max_recv_frag = 0x0FF8;
|
2015-02-11 22:27:29 +03:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->ReceiveWindow = 0x00010000;
|
|
|
|
|
rpc->ChannelLifetime = 0x40000000;
|
|
|
|
|
rpc->KeepAliveInterval = 300000;
|
|
|
|
|
rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
|
|
|
|
|
rpc->CurrentKeepAliveTime = 0;
|
2014-12-11 19:25:34 +03:00
|
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
|
rpc->CallId = 2;
|
2012-11-28 22:38:01 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (rpc_client_new(rpc) < 0)
|
2015-02-11 23:26:22 +03:00
|
|
|
|
goto out_free_rpc_client;
|
2012-11-29 05:30:03 +04:00
|
|
|
|
|
2012-04-18 09:53:12 +04:00
|
|
|
|
return rpc;
|
2015-02-11 23:26:22 +03:00
|
|
|
|
out_free_rpc_client:
|
2014-05-21 19:32:14 +04:00
|
|
|
|
rpc_client_free(rpc);
|
2014-04-10 23:07:53 +04:00
|
|
|
|
out_free:
|
|
|
|
|
free(rpc);
|
|
|
|
|
return NULL;
|
2012-03-27 07:20:25 +04:00
|
|
|
|
}
|
2012-04-24 00:33:18 +04:00
|
|
|
|
|
|
|
|
|
void rpc_free(rdpRpc* rpc)
|
|
|
|
|
{
|
2014-12-11 19:25:34 +03:00
|
|
|
|
if (rpc)
|
2012-04-24 00:33:18 +04:00
|
|
|
|
{
|
2014-12-15 17:42:04 +03:00
|
|
|
|
rpc_client_free(rpc);
|
2012-12-13 05:02:56 +04:00
|
|
|
|
|
2014-12-11 19:25:34 +03:00
|
|
|
|
if (rpc->ntlm)
|
2012-12-13 05:02:56 +04:00
|
|
|
|
{
|
|
|
|
|
ntlm_client_uninit(rpc->ntlm);
|
|
|
|
|
ntlm_free(rpc->ntlm);
|
2014-12-11 19:25:34 +03:00
|
|
|
|
rpc->ntlm = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 22:40:26 +03:00
|
|
|
|
if (rpc->VirtualConnection)
|
|
|
|
|
{
|
|
|
|
|
rpc_virtual_connection_free(rpc->VirtualConnection);
|
|
|
|
|
rpc->VirtualConnection = NULL;
|
|
|
|
|
}
|
2014-12-11 19:25:34 +03:00
|
|
|
|
|
2012-10-09 07:21:26 +04:00
|
|
|
|
free(rpc);
|
2012-04-24 00:33:18 +04:00
|
|
|
|
}
|
|
|
|
|
}
|