2012-11-28 09:32:12 +04:00
|
|
|
|
/**
|
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
|
* RPC Secure Context Binding
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
|
#include <freerdp/log.h>
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2012-11-29 07:03:18 +04:00
|
|
|
|
#include "rpc_client.h"
|
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
#include "rpc_bind.h"
|
|
|
|
|
|
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-28 09:32:12 +04:00
|
|
|
|
/**
|
|
|
|
|
* Connection-Oriented RPC Protocol Client Details:
|
|
|
|
|
* http://msdn.microsoft.com/en-us/library/cc243724/
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Syntax UUIDs */
|
|
|
|
|
|
|
|
|
|
const p_uuid_t TSGU_UUID =
|
|
|
|
|
{
|
|
|
|
|
0x44E265DD, /* time_low */
|
|
|
|
|
0x7DAF, /* time_mid */
|
|
|
|
|
0x42CD, /* time_hi_and_version */
|
|
|
|
|
0x85, /* clock_seq_hi_and_reserved */
|
|
|
|
|
0x60, /* clock_seq_low */
|
|
|
|
|
{ 0x3C, 0xDB, 0x6E, 0x7A, 0x27, 0x29 } /* node[6] */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const p_uuid_t NDR_UUID =
|
|
|
|
|
{
|
|
|
|
|
0x8A885D04, /* time_low */
|
|
|
|
|
0x1CEB, /* time_mid */
|
|
|
|
|
0x11C9, /* time_hi_and_version */
|
|
|
|
|
0x9F, /* clock_seq_hi_and_reserved */
|
|
|
|
|
0xE8, /* clock_seq_low */
|
|
|
|
|
{ 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60 } /* node[6] */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const p_uuid_t BTFN_UUID =
|
|
|
|
|
{
|
|
|
|
|
0x6CB71C2C, /* time_low */
|
|
|
|
|
0x9812, /* time_mid */
|
|
|
|
|
0x4540, /* time_hi_and_version */
|
|
|
|
|
0x03, /* clock_seq_hi_and_reserved */
|
|
|
|
|
0x00, /* clock_seq_low */
|
|
|
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* node[6] */
|
|
|
|
|
};
|
|
|
|
|
|
2015-02-02 02:50:21 +03:00
|
|
|
|
/**
|
|
|
|
|
* Secure Connection-Oriented RPC Packet Sequence
|
|
|
|
|
*
|
|
|
|
|
* Client Server
|
|
|
|
|
* | |
|
|
|
|
|
* |-------------------SECURE_BIND-------------------->|
|
|
|
|
|
* | |
|
|
|
|
|
* |<----------------SECURE_BIND_ACK-------------------|
|
|
|
|
|
* | |
|
|
|
|
|
* |--------------------RPC_AUTH_3-------------------->|
|
|
|
|
|
* | |
|
|
|
|
|
* | |
|
|
|
|
|
* |------------------REQUEST_PDU_#1------------------>|
|
|
|
|
|
* |------------------REQUEST_PDU_#2------------------>|
|
|
|
|
|
* | |
|
|
|
|
|
* | ... |
|
|
|
|
|
* | |
|
|
|
|
|
* |<-----------------RESPONSE_PDU_#1------------------|
|
|
|
|
|
* |<-----------------RESPONSE_PDU_#2------------------|
|
|
|
|
|
* | |
|
|
|
|
|
* | ... |
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
/**
|
|
|
|
|
* SECURE_BIND: RPC bind PDU with sec_trailer and auth_token. Auth_token is generated by calling
|
|
|
|
|
* the implementation equivalent of the abstract GSS_Init_sec_context call. Upon receiving that, the
|
|
|
|
|
* server calls the implementation equivalent of the abstract GSS_Accept_sec_context call, which
|
|
|
|
|
* returns an auth_token and continue status in this example. Assume the following:
|
|
|
|
|
*
|
|
|
|
|
* 1) The client chooses the auth_context_id field in the sec_trailer sent with this PDU to be 1.
|
|
|
|
|
*
|
|
|
|
|
* 2) The client uses the RPC_C_AUTHN_LEVEL_PKT_PRIVACY authentication level and the
|
|
|
|
|
* Authentication Service (AS) NTLM.
|
|
|
|
|
*
|
|
|
|
|
* 3) The client sets the PFC_SUPPORT_HEADER_SIGN flag in the PDU header.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int rpc_send_bind_pdu(rdpRpc* rpc)
|
|
|
|
|
{
|
2015-02-02 04:47:43 +03:00
|
|
|
|
int status;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
BYTE* buffer;
|
|
|
|
|
UINT32 offset;
|
|
|
|
|
UINT32 length;
|
2012-12-13 07:03:40 +04:00
|
|
|
|
RpcClientCall* clientCall;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
p_cont_elem_t* p_cont_elem;
|
|
|
|
|
rpcconn_bind_hdr_t* bind_pdu;
|
2013-12-07 07:15:45 +04:00
|
|
|
|
BOOL promptPassword = FALSE;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
rdpSettings* settings = rpc->settings;
|
2013-12-07 07:15:45 +04:00
|
|
|
|
freerdp* instance = (freerdp*) settings->instance;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
RpcVirtualConnection* connection = rpc->VirtualConnection;
|
|
|
|
|
RpcInChannel* inChannel = connection->DefaultInChannel;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
|
WLog_DBG(TAG, "Sending Bind PDU");
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-02 19:50:56 +03:00
|
|
|
|
ntlm_free(rpc->ntlm);
|
2012-12-13 07:34:41 +04:00
|
|
|
|
rpc->ntlm = ntlm_new();
|
2014-12-11 19:25:34 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!rpc->ntlm)
|
|
|
|
|
return -1;
|
2012-12-13 16:37:41 +04:00
|
|
|
|
|
2013-12-07 07:15:45 +04:00
|
|
|
|
if ((!settings->GatewayPassword) || (!settings->GatewayUsername)
|
|
|
|
|
|| (!strlen(settings->GatewayPassword)) || (!strlen(settings->GatewayUsername)))
|
|
|
|
|
{
|
|
|
|
|
promptPassword = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (promptPassword)
|
|
|
|
|
{
|
|
|
|
|
if (instance->GatewayAuthenticate)
|
|
|
|
|
{
|
|
|
|
|
BOOL proceed = instance->GatewayAuthenticate(instance,
|
|
|
|
|
&settings->GatewayUsername, &settings->GatewayPassword, &settings->GatewayDomain);
|
|
|
|
|
|
|
|
|
|
if (!proceed)
|
2013-12-13 19:11:36 +04:00
|
|
|
|
{
|
2014-03-21 21:45:43 +04:00
|
|
|
|
freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
|
2013-12-07 07:15:45 +04:00
|
|
|
|
return 0;
|
2013-12-13 19:11:36 +04:00
|
|
|
|
}
|
2013-12-07 07:15:45 +04:00
|
|
|
|
|
|
|
|
|
if (settings->GatewayUseSameCredentials)
|
|
|
|
|
{
|
|
|
|
|
settings->Username = _strdup(settings->GatewayUsername);
|
|
|
|
|
settings->Domain = _strdup(settings->GatewayDomain);
|
|
|
|
|
settings->Password = _strdup(settings->GatewayPassword);
|
2014-05-21 19:32:14 +04:00
|
|
|
|
|
|
|
|
|
if (!settings->Username || !settings->Domain || settings->Password)
|
|
|
|
|
return -1;
|
2013-12-07 07:15:45 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-02 19:50:56 +03:00
|
|
|
|
if (!ntlm_client_init(rpc->ntlm, FALSE, settings->GatewayUsername, settings->GatewayDomain, settings->GatewayPassword, NULL))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (!ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (!ntlm_authenticate(rpc->ntlm))
|
2014-05-21 19:32:14 +04:00
|
|
|
|
return -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
bind_pdu = (rpcconn_bind_hdr_t*) calloc(1, sizeof(rpcconn_bind_hdr_t));
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!bind_pdu)
|
|
|
|
|
return -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) bind_pdu);
|
|
|
|
|
|
2014-02-11 07:12:13 +04:00
|
|
|
|
bind_pdu->auth_length = (UINT16) rpc->ntlm->outputBuffer[0].cbBuffer;
|
2013-01-09 09:20:08 +04:00
|
|
|
|
bind_pdu->auth_verifier.auth_value = rpc->ntlm->outputBuffer[0].pvBuffer;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
bind_pdu->ptype = PTYPE_BIND;
|
|
|
|
|
bind_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
|
|
|
|
|
bind_pdu->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;
|
|
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
|
bind_pdu->p_context_elem.p_cont_elem = calloc(bind_pdu->p_context_elem.n_context_elem, sizeof(p_cont_elem_t));
|
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!bind_pdu->p_context_elem.p_cont_elem)
|
|
|
|
|
return -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
|
|
|
|
|
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
|
|
|
|
|
|
|
|
|
|
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
|
|
|
|
if (!p_cont_elem->transfer_syntaxes)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
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->p_cont_id = 1;
|
|
|
|
|
p_cont_elem->n_transfer_syn = 1;
|
|
|
|
|
p_cont_elem->reserved = 0;
|
|
|
|
|
CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
|
|
|
|
|
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
|
|
|
|
|
|
|
|
|
|
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
|
|
|
|
if (!p_cont_elem->transfer_syntaxes)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
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->auth_length);
|
|
|
|
|
|
|
|
|
|
bind_pdu->frag_length = offset;
|
|
|
|
|
|
|
|
|
|
buffer = (BYTE*) malloc(bind_pdu->frag_length);
|
2015-02-12 22:08:38 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!buffer)
|
|
|
|
|
return -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
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->auth_length);
|
|
|
|
|
offset += (8 + bind_pdu->auth_length);
|
|
|
|
|
|
|
|
|
|
length = bind_pdu->frag_length;
|
|
|
|
|
|
2012-12-13 07:03:40 +04:00
|
|
|
|
clientCall = rpc_client_call_new(bind_pdu->call_id, 0);
|
2015-02-01 23:58:32 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (!clientCall)
|
2014-11-17 02:58:43 +03:00
|
|
|
|
{
|
|
|
|
|
free(buffer);
|
2014-05-21 19:32:14 +04:00
|
|
|
|
return -1;
|
2014-11-17 02:58:43 +03:00
|
|
|
|
}
|
2015-02-03 22:44:31 +03:00
|
|
|
|
|
2014-05-21 19:32:14 +04:00
|
|
|
|
if (ArrayList_Add(rpc->client->ClientCallList, clientCall) < 0)
|
2014-11-17 02:58:43 +03:00
|
|
|
|
{
|
|
|
|
|
free(buffer);
|
2014-05-21 19:32:14 +04:00
|
|
|
|
return -1;
|
2014-11-17 02:58:43 +03:00
|
|
|
|
}
|
2012-12-13 07:03:40 +04:00
|
|
|
|
|
2015-02-12 22:08:38 +03:00
|
|
|
|
status = rpc_in_channel_send_pdu(inChannel, buffer, length);
|
2012-12-13 07:03:40 +04:00
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
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);
|
|
|
|
|
|
2015-02-03 22:44:31 +03:00
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
|
|
return (status > 0) ? 1 : -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Maximum Transmit/Receive Fragment Size Negotiation
|
|
|
|
|
*
|
|
|
|
|
* The client determines, and then sends in the bind PDU, its desired maximum size for transmitting fragments,
|
|
|
|
|
* and its desired maximum receive fragment size. Similarly, the server determines its desired maximum sizes
|
|
|
|
|
* for transmitting and receiving fragments. Transmit and receive sizes may be different to help preserve buffering.
|
|
|
|
|
* When the server receives the client’s values, it sets its operational transmit size to the minimum of the client’s
|
|
|
|
|
* receive size (from the bind PDU) and its own desired transmit size. Then it sets its actual receive size to the
|
|
|
|
|
* minimum of the client’s transmit size (from the bind) and its own desired receive size. The server then returns its
|
|
|
|
|
* operational values in the bind_ack PDU. The client then sets its operational values from the received bind_ack PDU.
|
|
|
|
|
* The received transmit size becomes the client’s receive size, and the received receive size becomes the client’s
|
|
|
|
|
* transmit size. Either party may use receive buffers larger than negotiated — although this will not provide any
|
|
|
|
|
* advantage — but may not transmit larger fragments than negotiated.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* SECURE_BIND_ACK: RPC bind_ack PDU with sec_trailer and auth_token. The PFC_SUPPORT_HEADER_SIGN
|
|
|
|
|
* flag in the PDU header is also set in this example. Auth_token is generated by the server in the
|
|
|
|
|
* previous step. Upon receiving that PDU, the client calls the implementation equivalent of the
|
|
|
|
|
* abstract GSS_Init_sec_context call, which returns an auth_token and continue status in this example.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-29 10:33:19 +04:00
|
|
|
|
int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
|
2012-11-28 09:32:12 +04:00
|
|
|
|
{
|
|
|
|
|
BYTE* auth_data;
|
|
|
|
|
rpcconn_hdr_t* header;
|
|
|
|
|
|
2012-11-29 10:33:19 +04:00
|
|
|
|
header = (rpcconn_hdr_t*) buffer;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
|
WLog_DBG(TAG, "Receiving BindAck PDU");
|
|
|
|
|
|
2012-11-29 06:25:01 +04:00
|
|
|
|
rpc->max_recv_frag = header->bind_ack.max_xmit_frag;
|
|
|
|
|
rpc->max_xmit_frag = header->bind_ack.max_recv_frag;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2013-01-09 09:20:08 +04:00
|
|
|
|
rpc->ntlm->inputBuffer[0].cbBuffer = header->common.auth_length;
|
|
|
|
|
rpc->ntlm->inputBuffer[0].pvBuffer = malloc(header->common.auth_length);
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-01 23:58:32 +03:00
|
|
|
|
if (!rpc->ntlm->inputBuffer[0].pvBuffer)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2012-11-29 10:33:19 +04:00
|
|
|
|
auth_data = buffer + (header->common.frag_length - header->common.auth_length);
|
2013-01-09 09:20:08 +04:00
|
|
|
|
CopyMemory(rpc->ntlm->inputBuffer[0].pvBuffer, auth_data, header->common.auth_length);
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2012-11-29 06:25:01 +04:00
|
|
|
|
ntlm_authenticate(rpc->ntlm);
|
|
|
|
|
|
2012-11-29 10:33:19 +04:00
|
|
|
|
return (int) length;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* RPC_AUTH_3: The client knows that this is an NTLM that uses three legs. It sends an rpc_auth_3
|
|
|
|
|
* PDU with the auth_token obtained in the previous step. Upon receiving this PDU, the server calls
|
|
|
|
|
* the implementation equivalent of the abstract GSS_Accept_sec_context call, which returns success
|
|
|
|
|
* status in this example.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
|
|
|
|
|
{
|
2015-05-18 12:28:00 +03:00
|
|
|
|
int status = -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
BYTE* buffer;
|
|
|
|
|
UINT32 offset;
|
2015-02-02 04:47:43 +03:00
|
|
|
|
UINT32 length;
|
2012-12-13 07:03:40 +04:00
|
|
|
|
RpcClientCall* clientCall;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
rpcconn_rpc_auth_3_hdr_t* auth_3_pdu;
|
2015-02-12 22:08:38 +03:00
|
|
|
|
RpcVirtualConnection* connection = rpc->VirtualConnection;
|
|
|
|
|
RpcInChannel* inChannel = connection->DefaultInChannel;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-03 02:50:26 +03:00
|
|
|
|
WLog_DBG(TAG, "Sending RpcAuth3 PDU");
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-01-13 21:50:46 +03:00
|
|
|
|
auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*) calloc(1, sizeof(rpcconn_rpc_auth_3_hdr_t));
|
|
|
|
|
|
|
|
|
|
if (!auth_3_pdu)
|
|
|
|
|
return -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) auth_3_pdu);
|
|
|
|
|
|
2014-02-11 07:12:13 +04:00
|
|
|
|
auth_3_pdu->auth_length = (UINT16) rpc->ntlm->outputBuffer[0].cbBuffer;
|
2013-01-09 09:20:08 +04:00
|
|
|
|
auth_3_pdu->auth_verifier.auth_value = rpc->ntlm->outputBuffer[0].pvBuffer;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
auth_3_pdu->ptype = PTYPE_RPC_AUTH_3;
|
|
|
|
|
auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
|
|
|
|
|
auth_3_pdu->call_id = 2;
|
|
|
|
|
|
|
|
|
|
auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag;
|
|
|
|
|
auth_3_pdu->max_recv_frag = rpc->max_recv_frag;
|
|
|
|
|
|
2014-05-20 19:15:26 +04:00
|
|
|
|
offset = 20;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
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;
|
2014-05-20 19:15:26 +04:00
|
|
|
|
offset += (8 + auth_3_pdu->auth_length);
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2014-05-20 19:15:26 +04:00
|
|
|
|
auth_3_pdu->frag_length = offset;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
|
|
|
|
buffer = (BYTE*) malloc(auth_3_pdu->frag_length);
|
|
|
|
|
|
2015-01-13 21:50:46 +03:00
|
|
|
|
if (!buffer)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2014-05-20 19:15:26 +04:00
|
|
|
|
CopyMemory(buffer, auth_3_pdu, 20);
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2014-05-20 19:15:26 +04:00
|
|
|
|
offset = 20;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
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->auth_length);
|
|
|
|
|
offset += (8 + auth_3_pdu->auth_length);
|
|
|
|
|
|
2015-02-02 04:47:43 +03:00
|
|
|
|
length = auth_3_pdu->frag_length;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2012-12-13 07:03:40 +04:00
|
|
|
|
clientCall = rpc_client_call_new(auth_3_pdu->call_id, 0);
|
2015-05-18 12:28:00 +03:00
|
|
|
|
if (ArrayList_Add(rpc->client->ClientCallList, clientCall) >= 0)
|
|
|
|
|
{
|
|
|
|
|
status = rpc_in_channel_send_pdu(inChannel, buffer, length);
|
|
|
|
|
}
|
2012-12-13 07:03:40 +04:00
|
|
|
|
|
2012-11-28 09:32:12 +04:00
|
|
|
|
free(auth_3_pdu);
|
2015-02-03 22:44:31 +03:00
|
|
|
|
free(buffer);
|
2012-11-28 09:32:12 +04:00
|
|
|
|
|
2015-02-03 22:44:31 +03:00
|
|
|
|
return (status > 0) ? 1 : -1;
|
2012-11-28 09:32:12 +04:00
|
|
|
|
}
|