libfreerdp-core: protocol security negotiation partially working
This commit is contained in:
parent
3a9e3e51aa
commit
ccaa0d33ed
@ -55,3 +55,5 @@ add_subdirectory(libfreerdp-kbd)
|
||||
add_subdirectory(libfreerdp-gdi)
|
||||
|
||||
add_subdirectory(libfreerdp-core)
|
||||
|
||||
add_subdirectory(freerdp-ui)
|
||||
|
@ -28,7 +28,8 @@
|
||||
#include "transport.h"
|
||||
#include "test_transport.h"
|
||||
|
||||
static const char test_server[] = "192.168.0.1";
|
||||
static const char test_server[] = "192.168.1.200";
|
||||
|
||||
static const uint8 test_x224_req[] =
|
||||
{
|
||||
"\x03\x00\x00\x2C\x27\xE0\x00\x00\x00\x00\x00\x43\x6F\x6F\x6B\x69"
|
||||
@ -58,7 +59,7 @@ int add_transport_suite(void)
|
||||
static int test_finished = 0;
|
||||
|
||||
static int
|
||||
packet_received(STREAM * stream, void * callback_data)
|
||||
packet_received(rdpTransport * transport, STREAM * stream)
|
||||
{
|
||||
uint16 len;
|
||||
|
||||
@ -76,10 +77,9 @@ void test_transport(void)
|
||||
|
||||
transport = transport_new();
|
||||
transport->recv_callback = packet_received;
|
||||
transport->recv_callback_data = NULL;
|
||||
|
||||
r = transport_connect(transport, test_server, 3389);
|
||||
CU_ASSERT(r == 0);
|
||||
CU_ASSERT(r == True);
|
||||
|
||||
stream = stream_new(sizeof(test_x224_req));
|
||||
stream_write_buffer(stream, test_x224_req, sizeof(test_x224_req));
|
||||
@ -93,7 +93,7 @@ void test_transport(void)
|
||||
}
|
||||
|
||||
r = transport_disconnect(transport);
|
||||
CU_ASSERT(r == 0);
|
||||
CU_ASSERT(r == True);
|
||||
|
||||
transport_free(transport);
|
||||
}
|
||||
|
21
freerdp-ui/CMakeLists.txt
Normal file
21
freerdp-ui/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP User Interfaces
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
# User Interfaces
|
||||
add_subdirectory(test)
|
30
freerdp-ui/test/CMakeLists.txt
Normal file
30
freerdp-ui/test/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP Test UI cmake build script
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
include_directories(.)
|
||||
include_directories(../../include)
|
||||
include_directories(../../libfreerdp-core)
|
||||
|
||||
add_executable(freerdp-test
|
||||
freerdp.c)
|
||||
|
||||
target_link_libraries(freerdp-test freerdp-core)
|
||||
target_link_libraries(freerdp-test freerdp-gdi)
|
||||
target_link_libraries(freerdp-test freerdp-asn1)
|
||||
target_link_libraries(freerdp-test freerdp-utils)
|
BIN
freerdp-ui/test/freerdp-test
Executable file
BIN
freerdp-ui/test/freerdp-test
Executable file
Binary file not shown.
60
freerdp-ui/test/freerdp.c
Normal file
60
freerdp-ui/test/freerdp.c
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Test UI
|
||||
*
|
||||
* Copyright 2010 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tpkt.h"
|
||||
#include "nego.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
rdpNego * nego;
|
||||
rdpTransport * transport;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char* username;
|
||||
char* hostname;
|
||||
transport = transport_new();
|
||||
nego = nego_new(transport);
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("Usage: freerdp-test <hostname> <username>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hostname = (char*) xmalloc(strlen(argv[1]));
|
||||
memcpy(hostname, argv[1], strlen(argv[1]));
|
||||
|
||||
username = (char*) xmalloc(strlen(argv[2]));
|
||||
memcpy(username, argv[2], strlen(argv[2]));
|
||||
|
||||
printf("hostname: %s username: %s\n", hostname, username);
|
||||
|
||||
nego_init(nego);
|
||||
nego_set_target(nego, hostname, 3389);
|
||||
nego_set_protocols(nego, 1, 0, 0);
|
||||
nego_set_cookie(nego, username);
|
||||
nego_connect(nego);
|
||||
|
||||
return 0;
|
||||
}
|
40
include/freerdp/constants.h
Normal file
40
include/freerdp/constants.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* RDP Constants
|
||||
*
|
||||
* Copyright 2011 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Protocol Security Negotiation Protocols
|
||||
*/
|
||||
enum RDP_NEG_PROTOCOLS
|
||||
{
|
||||
PROTOCOL_RDP = 0x00000000,
|
||||
PROTOCOL_TLS = 0x00000001,
|
||||
PROTOCOL_NLA = 0x00000002
|
||||
};
|
||||
|
||||
/**
|
||||
* Protocol Security Negotiation Failure Codes
|
||||
*/
|
||||
enum RDP_NEG_FAILURE_FAILURECODES
|
||||
{
|
||||
SSL_REQUIRED_BY_SERVER = 0x00000001,
|
||||
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002,
|
||||
SSL_CERT_NOT_ON_SERVER = 0x00000003,
|
||||
INCONSISTENT_FLAGS = 0x00000004,
|
||||
HYBRID_REQUIRED_BY_SERVER = 0x00000005
|
||||
};
|
@ -23,8 +23,9 @@
|
||||
#include <stddef.h>
|
||||
|
||||
void* xmalloc(size_t size);
|
||||
void* xrealloc(void * oldmem, size_t size);
|
||||
void xfree(void * mem);
|
||||
char* xstrdup(const char * s);
|
||||
void* xzalloc(size_t size);
|
||||
void* xrealloc(void * ptr, size_t size);
|
||||
void xfree(void * ptr);
|
||||
char* xstrdup(const char * str);
|
||||
|
||||
#endif /* __MEMORY_UTILS_H */
|
||||
|
@ -45,6 +45,8 @@ stream_extend(STREAM * stream);
|
||||
#define stream_get_pos(_s) (_s->ptr - _s->buffer)
|
||||
#define stream_set_pos(_s,_m) _s->ptr = _s->buffer + (_m)
|
||||
#define stream_seek(_s,_offset) _s->ptr += (_offset)
|
||||
#define stream_get_mark(_s,_mark) _mark = _s->ptr
|
||||
#define stream_set_mark(_s,_mark) _s->ptr = _mark
|
||||
#define stream_get_head(_s) _s->buffer
|
||||
#define stream_get_tail(_s) _s->ptr
|
||||
|
||||
|
@ -24,8 +24,8 @@ add_definitions(-DL_ENDIAN=1)
|
||||
add_definitions(-DEXT_PATH="/usr/lib/freerdp/extensions")
|
||||
|
||||
set(LIBFREERDP_CORE_SRCS
|
||||
# nego.c
|
||||
# nego.h
|
||||
nego.c
|
||||
nego.h
|
||||
# credssp.c
|
||||
# credssp.h
|
||||
# ntlmssp.c
|
||||
|
@ -17,9 +17,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "stream.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
#include "tpkt.h"
|
||||
|
||||
#include "nego.h"
|
||||
|
||||
/**
|
||||
@ -28,7 +33,7 @@
|
||||
* @return
|
||||
*/
|
||||
|
||||
int nego_connect(NEGO *nego)
|
||||
int nego_connect(rdpNego *nego)
|
||||
{
|
||||
if (nego->state == NEGO_STATE_INITIAL)
|
||||
{
|
||||
@ -42,15 +47,21 @@ int nego_connect(NEGO *nego)
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
}
|
||||
|
||||
DEBUG_NEGO("Negotiating protocol security");
|
||||
|
||||
while (nego->state != NEGO_STATE_FINAL)
|
||||
{
|
||||
nego_send(nego);
|
||||
|
||||
DEBUG_NEGO("state: %s", NEGO_STATE_STRINGS[nego->state]);
|
||||
|
||||
if (nego->state == NEGO_STATE_FAIL)
|
||||
{
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -62,11 +73,11 @@ int nego_connect(NEGO *nego)
|
||||
* @return
|
||||
*/
|
||||
|
||||
int nego_tcp_connect(NEGO *nego)
|
||||
int nego_tcp_connect(rdpNego *nego)
|
||||
{
|
||||
if (nego->tcp_connected == 0)
|
||||
{
|
||||
if (tcp_connect(nego->net->tcp, nego->hostname, nego->port) == False)
|
||||
if (transport_connect(nego->transport, nego->hostname, nego->port) == False)
|
||||
{
|
||||
nego->tcp_connected = 0;
|
||||
return 0;
|
||||
@ -87,10 +98,10 @@ int nego_tcp_connect(NEGO *nego)
|
||||
* @return
|
||||
*/
|
||||
|
||||
int nego_tcp_disconnect(NEGO *nego)
|
||||
int nego_tcp_disconnect(rdpNego *nego)
|
||||
{
|
||||
if (nego->tcp_connected)
|
||||
tcp_disconnect(nego->net->tcp);
|
||||
transport_disconnect(nego->transport);
|
||||
|
||||
nego->tcp_connected = 0;
|
||||
return 1;
|
||||
@ -101,14 +112,17 @@ int nego_tcp_disconnect(NEGO *nego)
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_attempt_nla(NEGO *nego)
|
||||
void nego_attempt_nla(rdpNego *nego)
|
||||
{
|
||||
uint8 code;
|
||||
nego->requested_protocols = PROTOCOL_NLA | PROTOCOL_TLS;
|
||||
|
||||
DEBUG_NEGO("Attempting NLA security");
|
||||
|
||||
nego_tcp_connect(nego);
|
||||
x224_send_connection_request(nego->net->iso);
|
||||
tpkt_recv(nego->net->iso, &code, NULL);
|
||||
nego_send_negotiation_request(nego);
|
||||
|
||||
transport_check_fds(nego->transport);
|
||||
|
||||
if (nego->state != NEGO_STATE_FINAL)
|
||||
{
|
||||
@ -128,14 +142,17 @@ void nego_attempt_nla(NEGO *nego)
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_attempt_tls(NEGO *nego)
|
||||
void nego_attempt_tls(rdpNego *nego)
|
||||
{
|
||||
uint8 code;
|
||||
nego->requested_protocols = PROTOCOL_TLS;
|
||||
|
||||
DEBUG_NEGO("Attempting TLS security");
|
||||
|
||||
nego_tcp_connect(nego);
|
||||
x224_send_connection_request(nego->net->iso);
|
||||
tpkt_recv(nego->net->iso, &code, NULL);
|
||||
nego_send_negotiation_request(nego);
|
||||
|
||||
transport_check_fds(nego->transport);
|
||||
|
||||
if (nego->state != NEGO_STATE_FINAL)
|
||||
{
|
||||
@ -153,18 +170,17 @@ void nego_attempt_tls(NEGO *nego)
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_attempt_rdp(NEGO *nego)
|
||||
void nego_attempt_rdp(rdpNego *nego)
|
||||
{
|
||||
uint8 code;
|
||||
nego->requested_protocols = PROTOCOL_RDP;
|
||||
|
||||
nego_tcp_connect(nego);
|
||||
x224_send_connection_request(nego->net->iso);
|
||||
DEBUG_NEGO("Attempting RDP security");
|
||||
|
||||
if (tpkt_recv(nego->net->iso, &code, NULL) == NULL)
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
else
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
nego_tcp_connect(nego);
|
||||
nego_send_negotiation_request(nego);
|
||||
|
||||
transport_check_fds(nego->transport);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,10 +189,10 @@ void nego_attempt_rdp(NEGO *nego)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void nego_recv(NEGO *nego, STREAM s)
|
||||
void nego_recv(rdpNego *nego, STREAM* s)
|
||||
{
|
||||
uint8 type;
|
||||
in_uint8(s, type); /* Type */
|
||||
stream_read_uint8(s, type); /* Type */
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -194,7 +210,7 @@ void nego_recv(NEGO *nego, STREAM s)
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_send(NEGO *nego)
|
||||
void nego_send(rdpNego *nego)
|
||||
{
|
||||
if (nego->state == NEGO_STATE_NLA)
|
||||
nego_attempt_nla(nego);
|
||||
@ -204,21 +220,58 @@ void nego_send(NEGO *nego)
|
||||
nego_attempt_rdp(nego);
|
||||
}
|
||||
|
||||
void nego_send_negotiation_request(rdpNego *nego)
|
||||
{
|
||||
STREAM* s;
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
|
||||
s = stream_new(64);
|
||||
length = TPKT_HEADER_LENGTH + TPDU_CONNECTION_REQUEST_LENGTH;
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek(s, length);
|
||||
|
||||
if (nego->cookie)
|
||||
{
|
||||
int cookie_length = strlen(nego->cookie);
|
||||
stream_write_buffer(s, "Cookie: mstshash=", 17);
|
||||
stream_write_buffer(s, nego->cookie, cookie_length);
|
||||
stream_write_uint8(s, 0x0D); /* CR */
|
||||
stream_write_uint8(s, 0x0A); /* LF */
|
||||
length += cookie_length + 19;
|
||||
stream_get_mark(s, em);
|
||||
}
|
||||
else if (nego->routing_token)
|
||||
{
|
||||
int routing_token_length = strlen(nego->routing_token);
|
||||
stream_write_buffer(s, nego->routing_token, routing_token_length);
|
||||
length += routing_token_length;
|
||||
stream_get_mark(s, em);
|
||||
}
|
||||
|
||||
stream_set_mark(s, bm);
|
||||
tpkt_write_header(s, length);
|
||||
tpdu_write_connection_request(s, length - 5);
|
||||
stream_set_mark(s, em);
|
||||
|
||||
transport_send(nego->transport, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Negotiation Response from Connection Confirm message.
|
||||
* @param nego
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void nego_process_negotiation_response(NEGO *nego, STREAM s)
|
||||
void nego_process_negotiation_response(rdpNego *nego, STREAM* s)
|
||||
{
|
||||
uint8 flags;
|
||||
uint16 length;
|
||||
uint32 selectedProtocol;
|
||||
|
||||
in_uint8(s, flags);
|
||||
in_uint16_le(s, length);
|
||||
in_uint32_le(s, selectedProtocol);
|
||||
stream_read_uint8(s, flags);
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint32(s, selectedProtocol);
|
||||
|
||||
if (selectedProtocol == PROTOCOL_NLA)
|
||||
nego->selected_protocol = PROTOCOL_NLA;
|
||||
@ -236,68 +289,68 @@ void nego_process_negotiation_response(NEGO *nego, STREAM s)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void nego_process_negotiation_failure(NEGO *nego, STREAM s)
|
||||
void nego_process_negotiation_failure(rdpNego *nego, STREAM* s)
|
||||
{
|
||||
uint8 flags;
|
||||
uint16 length;
|
||||
uint32 failureCode;
|
||||
|
||||
in_uint8(s, flags);
|
||||
in_uint16_le(s, length);
|
||||
in_uint32_le(s, failureCode);
|
||||
stream_read_uint8(s, flags);
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint32(s, failureCode);
|
||||
|
||||
switch (failureCode)
|
||||
{
|
||||
case SSL_REQUIRED_BY_SERVER:
|
||||
//printf("Error: SSL_REQUIRED_BY_SERVER\n");
|
||||
DEBUG_NEGO("Error: SSL_REQUIRED_BY_SERVER");
|
||||
break;
|
||||
case SSL_NOT_ALLOWED_BY_SERVER:
|
||||
//printf("Error: SSL_NOT_ALLOWED_BY_SERVER\n");
|
||||
DEBUG_NEGO("Error: SSL_NOT_ALLOWED_BY_SERVER");
|
||||
break;
|
||||
case SSL_CERT_NOT_ON_SERVER:
|
||||
//printf("Error: SSL_CERT_NOT_ON_SERVER\n");
|
||||
DEBUG_NEGO("Error: SSL_CERT_NOT_ON_SERVER");
|
||||
break;
|
||||
case INCONSISTENT_FLAGS:
|
||||
//printf("Error: INCONSISTENT_FLAGS\n");
|
||||
DEBUG_NEGO("Error: INCONSISTENT_FLAGS");
|
||||
break;
|
||||
case HYBRID_REQUIRED_BY_SERVER:
|
||||
//printf("Error: HYBRID_REQUIRED_BY_SERVER\n");
|
||||
DEBUG_NEGO("Error: HYBRID_REQUIRED_BY_SERVER");
|
||||
break;
|
||||
default:
|
||||
printf("Error: Unknown protocol security error %d\n", failureCode);
|
||||
DEBUG_NEGO("Error: Unknown protocol security error %d", failureCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NEGO state machine instance.
|
||||
* @param iso
|
||||
* @return
|
||||
*/
|
||||
|
||||
NEGO* nego_new(struct rdp_network * net)
|
||||
{
|
||||
NEGO *nego = (NEGO*) xmalloc(sizeof(NEGO));
|
||||
|
||||
if (nego != NULL)
|
||||
{
|
||||
memset(nego, '\0', sizeof(NEGO));
|
||||
nego->net = net;
|
||||
nego_init(nego);
|
||||
}
|
||||
|
||||
return nego;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize NEGO state machine.
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_init(NEGO *nego)
|
||||
void nego_init(rdpNego *nego)
|
||||
{
|
||||
nego->state = NEGO_STATE_INITIAL;
|
||||
nego->requested_protocols = PROTOCOL_RDP;
|
||||
nego->transport->recv_callback = tpkt_recv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NEGO state machine instance.
|
||||
* @param transport
|
||||
* @return
|
||||
*/
|
||||
|
||||
rdpNego* nego_new(struct rdp_transport * transport)
|
||||
{
|
||||
rdpNego *nego = (rdpNego*) xzalloc(sizeof(rdpNego));
|
||||
|
||||
if (nego != NULL)
|
||||
{
|
||||
nego->transport = transport;
|
||||
nego_init(nego);
|
||||
}
|
||||
|
||||
return nego;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,7 +358,57 @@ void nego_init(NEGO *nego)
|
||||
* @param nego
|
||||
*/
|
||||
|
||||
void nego_free(NEGO *nego)
|
||||
void nego_free(rdpNego *nego)
|
||||
{
|
||||
xfree(nego);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set target hostname and port.
|
||||
* @param nego
|
||||
* @param hostname
|
||||
* @param port
|
||||
*/
|
||||
|
||||
void nego_set_target(rdpNego *nego, char* hostname, int port)
|
||||
{
|
||||
nego->hostname = hostname;
|
||||
nego->port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set enabled security protocols.
|
||||
* @param nego
|
||||
* @param rdp
|
||||
* @param tls
|
||||
* @param nla
|
||||
*/
|
||||
|
||||
void nego_set_protocols(rdpNego *nego, int rdp, int tls, int nla)
|
||||
{
|
||||
nego->enabled_protocols[PROTOCOL_RDP] = rdp;
|
||||
nego->enabled_protocols[PROTOCOL_TLS] = tls;
|
||||
nego->enabled_protocols[PROTOCOL_NLA] = nla;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set routing token.
|
||||
* @param nego
|
||||
* @param routing_token
|
||||
*/
|
||||
|
||||
void nego_set_routing_token(rdpNego *nego, char* routing_token)
|
||||
{
|
||||
nego->routing_token = routing_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cookie.
|
||||
* @param nego
|
||||
* @param cookie
|
||||
*/
|
||||
|
||||
void nego_set_cookie(rdpNego *nego, char* cookie)
|
||||
{
|
||||
nego->cookie = cookie;
|
||||
}
|
||||
|
@ -20,8 +20,10 @@
|
||||
#ifndef __NEGO_H
|
||||
#define __NEGO_H
|
||||
|
||||
#include "stream.h"
|
||||
#include "network.h"
|
||||
#include "transport.h"
|
||||
#include <freerdp/types/base.h>
|
||||
#include <freerdp/utils/debug.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
enum _NEGO_STATE
|
||||
{
|
||||
@ -34,33 +36,68 @@ enum _NEGO_STATE
|
||||
};
|
||||
typedef enum _NEGO_STATE NEGO_STATE;
|
||||
|
||||
struct _NEGO
|
||||
char NEGO_STATE_STRINGS[6][25] =
|
||||
{
|
||||
"NEGO_STATE_INITIAL",
|
||||
"NEGO_STATE_NLA",
|
||||
"NEGO_STATE_TLS",
|
||||
"NEGO_STATE_RDP",
|
||||
"NEGO_STATE_FAIL",
|
||||
"NEGO_STATE_FINAL"
|
||||
};
|
||||
|
||||
/* RDP Negotiation Messages */
|
||||
enum RDP_NEG_MSG
|
||||
{
|
||||
/* X224_TPDU_CONNECTION_REQUEST */
|
||||
TYPE_RDP_NEG_REQ = 0x1,
|
||||
/* X224_TPDU_CONNECTION_CONFIRM */
|
||||
TYPE_RDP_NEG_RSP = 0x2,
|
||||
TYPE_RDP_NEG_FAILURE = 0x3
|
||||
};
|
||||
|
||||
struct rdp_nego
|
||||
{
|
||||
int port;
|
||||
char *hostname;
|
||||
char* hostname;
|
||||
char *cookie;
|
||||
char* routing_token;
|
||||
NEGO_STATE state;
|
||||
int tcp_connected;
|
||||
struct rdp_network * net;
|
||||
uint32 selected_protocol;
|
||||
uint32 requested_protocols;
|
||||
uint8 enabled_protocols[3];
|
||||
struct rdp_transport * transport;
|
||||
};
|
||||
typedef struct _NEGO NEGO;
|
||||
typedef struct rdp_nego rdpNego;
|
||||
|
||||
int nego_connect(NEGO *nego);
|
||||
int nego_connect(rdpNego *nego);
|
||||
|
||||
void nego_attempt_nla(NEGO *nego);
|
||||
void nego_attempt_tls(NEGO *nego);
|
||||
void nego_attempt_rdp(NEGO *nego);
|
||||
void nego_attempt_nla(rdpNego *nego);
|
||||
void nego_attempt_tls(rdpNego *nego);
|
||||
void nego_attempt_rdp(rdpNego *nego);
|
||||
|
||||
void nego_send(NEGO *nego);
|
||||
void nego_recv(NEGO *nego, STREAM s);
|
||||
void nego_send(rdpNego *nego);
|
||||
void nego_recv(rdpNego *nego, STREAM* s);
|
||||
|
||||
void nego_process_negotiation_response(NEGO *nego, STREAM s);
|
||||
void nego_process_negotiation_failure(NEGO *nego, STREAM s);
|
||||
void nego_send_negotiation_request(rdpNego *nego);
|
||||
void nego_process_negotiation_response(rdpNego *nego, STREAM* s);
|
||||
void nego_process_negotiation_failure(rdpNego *nego, STREAM* s);
|
||||
|
||||
NEGO* nego_new(struct rdp_network * net);
|
||||
void nego_init(NEGO *nego);
|
||||
void nego_free(NEGO *nego);
|
||||
rdpNego* nego_new(struct rdp_transport * transport);
|
||||
void nego_free(rdpNego *nego);
|
||||
void nego_init(rdpNego *nego);
|
||||
void nego_set_target(rdpNego *nego, char* hostname, int port);
|
||||
void nego_set_protocols(rdpNego *nego, int rdp, int tls, int nla);
|
||||
void nego_set_routing_token(rdpNego *nego, char* routing_token);
|
||||
void nego_set_cookie(rdpNego *nego, char* cookie);
|
||||
|
||||
#define WITH_DEBUG_NEGO 1
|
||||
|
||||
#ifdef WITH_DEBUG_NEGO
|
||||
#define DEBUG_NEGO(fmt, ...) DEBUG_CLASS(NEGO, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_NEGO(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* __NEGO_H */
|
||||
|
@ -81,7 +81,7 @@ tpdu_read_header(STREAM* s, uint16 length)
|
||||
void
|
||||
tpdu_write_header(STREAM* s, uint16 length, uint8 code)
|
||||
{
|
||||
stream_write_uint8(s, length - 5); /* LI */
|
||||
stream_write_uint8(s, length); /* LI */
|
||||
stream_write_uint8(s, code); /* code */
|
||||
|
||||
if (code == X224_TPDU_DATA)
|
||||
@ -99,18 +99,17 @@ tpdu_write_header(STREAM* s, uint16 length, uint8 code)
|
||||
void
|
||||
tpdu_write_connection_request(STREAM* s, uint16 length)
|
||||
{
|
||||
tpdu_write_header(s, length - 5, X224_TPDU_CONNECTION_REQUEST);
|
||||
/* TODO: RDP_NEG_DATA */
|
||||
tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
|
||||
}
|
||||
|
||||
void
|
||||
tpdu_write_disconnect_request(STREAM* s, uint16 length)
|
||||
{
|
||||
tpdu_write_header(s, length - 5, X224_TPDU_DISCONNECT_REQUEST);
|
||||
tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
|
||||
}
|
||||
|
||||
void
|
||||
tpdu_write_data(STREAM* s, uint16 length)
|
||||
{
|
||||
tpdu_write_header(s, length - 5, X224_TPDU_DATA);
|
||||
tpdu_write_header(s, length, X224_TPDU_DATA);
|
||||
}
|
||||
|
@ -31,6 +31,10 @@ enum X224_TPDU_TYPE
|
||||
X224_TPDU_ERROR = 0x70
|
||||
};
|
||||
|
||||
#define TPDU_CONNECTION_REQUEST_LENGTH 7
|
||||
#define TPDU_CONNECTION_CONFIRM_LENGTH 7
|
||||
#define TPDU_DISCONNECT_REQUEST_LENGTH 7
|
||||
|
||||
uint8
|
||||
tpdu_read_header(STREAM* s, uint16 length);
|
||||
void
|
||||
|
@ -79,6 +79,16 @@ void
|
||||
tpkt_write_header(STREAM* s, int length)
|
||||
{
|
||||
stream_write_uint8(s, 3); /* version */
|
||||
stream_write_uint8(s, 8); /* reserved */
|
||||
stream_write_uint8(s, 0); /* reserved */
|
||||
stream_write_uint16_be(s, length); /* length */
|
||||
}
|
||||
|
||||
int
|
||||
tpkt_recv(rdpTransport * transport, STREAM* s)
|
||||
{
|
||||
uint16 length;
|
||||
|
||||
length = tpkt_read_header(s);
|
||||
|
||||
freerdp_hexdump(s->buffer, length);
|
||||
}
|
||||
|
@ -20,11 +20,21 @@
|
||||
#ifndef __TPKT_H
|
||||
#define __TPKT_H
|
||||
|
||||
#include "tpdu.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
#define TPKT_HEADER_LENGTH 4
|
||||
|
||||
uint16
|
||||
tpkt_read_header(STREAM* s);
|
||||
void
|
||||
tpkt_write_header(STREAM* s, int length);
|
||||
|
||||
void
|
||||
tpkt_send_connection_request(rdpTransport * transport);
|
||||
int
|
||||
tpkt_recv(rdpTransport * transport, STREAM* s);
|
||||
|
||||
#endif /* __TPKT_H */
|
||||
|
@ -61,34 +61,35 @@ transport_free(rdpTransport * transport)
|
||||
xfree(transport);
|
||||
}
|
||||
|
||||
static int
|
||||
static FRDP_BOOL
|
||||
transport_connect_sockfd(rdpTransport * transport, const char * server, int port)
|
||||
{
|
||||
int status;
|
||||
int sockfd = -1;
|
||||
char servname[10];
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo * res, * ai;
|
||||
int r;
|
||||
char servname[10];
|
||||
int sockfd = -1;
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
snprintf(servname, sizeof(servname), "%d", port);
|
||||
r = getaddrinfo(server, servname, &hints, &res);
|
||||
if (r != 0)
|
||||
status = getaddrinfo(server, servname, &hints, &res);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(r));
|
||||
return -1;
|
||||
printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
for (ai = res; ai; ai = ai->ai_next)
|
||||
{
|
||||
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
|
||||
if (sockfd < 0)
|
||||
continue;
|
||||
|
||||
r = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
|
||||
if (r == 0)
|
||||
if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 0)
|
||||
{
|
||||
printf("connected to %s:%s\n", server, servname);
|
||||
break;
|
||||
@ -101,44 +102,42 @@ transport_connect_sockfd(rdpTransport * transport, const char * server, int port
|
||||
if (sockfd == -1)
|
||||
{
|
||||
printf("unable to connect to %s:%s\n", server, servname);
|
||||
return -1;
|
||||
return False;
|
||||
}
|
||||
|
||||
transport->sockfd = sockfd;
|
||||
|
||||
return 0;
|
||||
return True;
|
||||
}
|
||||
|
||||
static int
|
||||
static FRDP_BOOL
|
||||
transport_configure_sockfd(rdpTransport * transport)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(transport->sockfd, F_GETFL);
|
||||
|
||||
if (flags == -1)
|
||||
{
|
||||
printf("transport_configure_sockfd: fcntl failed.\n");
|
||||
return -1;
|
||||
return False;
|
||||
}
|
||||
|
||||
fcntl(transport->sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
return 0;
|
||||
return True;
|
||||
}
|
||||
|
||||
int
|
||||
FRDP_BOOL
|
||||
transport_connect(rdpTransport * transport, const char * server, int port)
|
||||
{
|
||||
int r;
|
||||
if (transport_connect_sockfd(transport, server, port) != True)
|
||||
return False;
|
||||
|
||||
r = transport_connect_sockfd(transport, server, port);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (transport_configure_sockfd(transport) != True)
|
||||
return False;
|
||||
|
||||
r = transport_configure_sockfd(transport);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return True;
|
||||
}
|
||||
|
||||
int
|
||||
@ -149,7 +148,8 @@ transport_disconnect(rdpTransport * transport)
|
||||
close(transport->sockfd);
|
||||
transport->sockfd = -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
int
|
||||
@ -174,28 +174,33 @@ transport_send_tls(rdpTransport * transport, STREAM * stream)
|
||||
static int
|
||||
transport_send_tcp(rdpTransport * transport, STREAM * stream)
|
||||
{
|
||||
int bytes;
|
||||
uint8 * head;
|
||||
uint8 * tail;
|
||||
int r;
|
||||
|
||||
head = stream_get_head(stream);
|
||||
tail = stream_get_tail(stream);
|
||||
|
||||
while (head < tail)
|
||||
{
|
||||
r = send(transport->sockfd, head, tail - head, MSG_NOSIGNAL);
|
||||
if (r < 0)
|
||||
bytes = send(transport->sockfd, head, tail - head, MSG_NOSIGNAL);
|
||||
|
||||
if (bytes < 0)
|
||||
{
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
if (transport_delay(transport) != 0)
|
||||
return -1;
|
||||
|
||||
continue;
|
||||
}
|
||||
printf("transport_send_tcp: send (%d)\n", errno);
|
||||
|
||||
perror("send");
|
||||
return -1;
|
||||
}
|
||||
head += r;
|
||||
head += bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -217,69 +222,77 @@ transport_recv_tls(rdpTransport * transport)
|
||||
static int
|
||||
transport_recv_tcp(rdpTransport * transport)
|
||||
{
|
||||
int r;
|
||||
int bytes;
|
||||
|
||||
stream_check_capacity(transport->recv_buffer, BUFFER_SIZE);
|
||||
|
||||
r = recv(transport->sockfd, transport->recv_buffer->ptr, BUFFER_SIZE, 0);
|
||||
if (r == -1)
|
||||
bytes = recv(transport->sockfd, transport->recv_buffer->ptr, BUFFER_SIZE, 0);
|
||||
|
||||
if (bytes == -1)
|
||||
{
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return 0;
|
||||
printf("transport_recv_tcp: recv failed (%d).\n", errno);
|
||||
|
||||
perror("recv");
|
||||
return -1;
|
||||
}
|
||||
stream_seek(transport->recv_buffer, r);
|
||||
|
||||
return r;
|
||||
stream_seek(transport->recv_buffer, bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int
|
||||
transport_check_fds(rdpTransport * transport)
|
||||
{
|
||||
int r;
|
||||
int pos;
|
||||
uint16 len;
|
||||
int bytes;
|
||||
uint16 length;
|
||||
STREAM * received;
|
||||
|
||||
if (transport->tls)
|
||||
r = transport_recv_tls(transport);
|
||||
bytes = transport_recv_tls(transport);
|
||||
else
|
||||
r = transport_recv_tcp(transport);
|
||||
bytes = transport_recv_tcp(transport);
|
||||
|
||||
if (r <= 0)
|
||||
return r;
|
||||
if (bytes <= 0)
|
||||
return bytes;
|
||||
|
||||
pos = stream_get_pos(transport->recv_buffer);
|
||||
|
||||
/* Ensure the TPKT header is available. */
|
||||
if (pos <= 4)
|
||||
return 0;
|
||||
|
||||
stream_set_pos(transport->recv_buffer, 0);
|
||||
len = tpkt_read_header(transport->recv_buffer);
|
||||
if (len == 0)
|
||||
length = tpkt_read_header(transport->recv_buffer);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
printf("transport_check_fds: protocol error, not a TPKT header.\n");
|
||||
return -1;
|
||||
}
|
||||
if (pos < len)
|
||||
|
||||
if (pos < length)
|
||||
return 0; /* Packet is not yet completely received. */
|
||||
|
||||
/* A complete packet has been received. In case there are trailing data
|
||||
/*
|
||||
* A complete packet has been received. In case there are trailing data
|
||||
* for the next packet, we copy it to the new receive buffer.
|
||||
*/
|
||||
received = transport->recv_buffer;
|
||||
transport->recv_buffer = stream_new(BUFFER_SIZE);
|
||||
if (pos > len)
|
||||
|
||||
if (pos > length)
|
||||
{
|
||||
stream_set_pos(received, len);
|
||||
stream_check_capacity(transport->recv_buffer, pos - len);
|
||||
stream_copy(transport->recv_buffer, received, pos - len);
|
||||
stream_set_pos(received, length);
|
||||
stream_check_capacity(transport->recv_buffer, pos - length);
|
||||
stream_copy(transport->recv_buffer, received, pos - length);
|
||||
}
|
||||
|
||||
stream_set_pos(received, 0);
|
||||
r = transport->recv_callback(received, transport->recv_callback_data);
|
||||
bytes = transport->recv_callback(transport, received);
|
||||
stream_free(received);
|
||||
|
||||
return r;
|
||||
return bytes;
|
||||
}
|
||||
|
@ -20,9 +20,12 @@
|
||||
#ifndef __TRANSPORT_H
|
||||
#define __TRANSPORT_H
|
||||
|
||||
#include <time.h>
|
||||
#include <freerdp/types/base.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
typedef int (* PacketReceivedCallback) (STREAM * stream, void * callback_data);
|
||||
typedef struct rdp_transport rdpTransport;
|
||||
typedef int (* PacketReceivedCallback) (rdpTransport * transport, STREAM * stream);
|
||||
|
||||
struct rdp_transport
|
||||
{
|
||||
@ -30,19 +33,16 @@ struct rdp_transport
|
||||
struct crypto_tls * tls;
|
||||
struct timespec ts;
|
||||
STREAM * recv_buffer;
|
||||
|
||||
PacketReceivedCallback recv_callback;
|
||||
void * recv_callback_data;
|
||||
};
|
||||
typedef struct rdp_transport rdpTransport;
|
||||
|
||||
rdpTransport *
|
||||
transport_new(void);
|
||||
void
|
||||
transport_free(rdpTransport * transport);
|
||||
int
|
||||
FRDP_BOOL
|
||||
transport_connect(rdpTransport * transport, const char * server, int port);
|
||||
int
|
||||
FRDP_BOOL
|
||||
transport_disconnect(rdpTransport * transport);
|
||||
int
|
||||
transport_start_tls(rdpTransport * transport);
|
||||
|
@ -23,64 +23,101 @@
|
||||
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
/**
|
||||
* Allocate memory.
|
||||
* @param size
|
||||
*/
|
||||
|
||||
void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void * mem;
|
||||
|
||||
if (size < 1)
|
||||
{
|
||||
size = 1;
|
||||
}
|
||||
|
||||
mem = malloc(size);
|
||||
|
||||
if (mem == NULL)
|
||||
{
|
||||
perror("xmalloc");
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory initialized to zero.
|
||||
* @param size
|
||||
*/
|
||||
|
||||
void *
|
||||
xrealloc(void * oldmem, size_t size)
|
||||
xzalloc(size_t size)
|
||||
{
|
||||
void * mem;
|
||||
|
||||
if (size < 1)
|
||||
{
|
||||
size = 1;
|
||||
}
|
||||
mem = realloc(oldmem, size);
|
||||
|
||||
mem = calloc(1, size);
|
||||
|
||||
if (mem == NULL)
|
||||
{
|
||||
perror("xrealloc");
|
||||
}
|
||||
perror("xzalloc");
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void
|
||||
xfree(void * mem)
|
||||
/**
|
||||
* Reallocate memory.
|
||||
* @param ptr
|
||||
* @param size
|
||||
*/
|
||||
|
||||
void *
|
||||
xrealloc(void * ptr, size_t size)
|
||||
{
|
||||
if (mem != NULL)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
void * mem;
|
||||
|
||||
if (size < 1)
|
||||
size = 1;
|
||||
|
||||
mem = realloc(ptr, size);
|
||||
|
||||
if (mem == NULL)
|
||||
perror("xrealloc");
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free memory.
|
||||
* @param mem
|
||||
*/
|
||||
|
||||
void
|
||||
xfree(void * ptr)
|
||||
{
|
||||
if (ptr != NULL)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a string in memory.
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
|
||||
char *
|
||||
xstrdup(const char * s)
|
||||
xstrdup(const char * str)
|
||||
{
|
||||
char * mem;
|
||||
|
||||
#ifdef _WIN32
|
||||
mem = _strdup(s);
|
||||
mem = _strdup(str);
|
||||
#else
|
||||
mem = strdup(s);
|
||||
mem = strdup(str);
|
||||
#endif
|
||||
|
||||
if (mem == NULL)
|
||||
{
|
||||
perror("strdup");
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user