libfreerdp-core: protocol security negotiation partially working

This commit is contained in:
Marc-André Moreau 2011-07-03 12:42:35 -04:00
parent 3a9e3e51aa
commit ccaa0d33ed
19 changed files with 541 additions and 172 deletions

View File

@ -55,3 +55,5 @@ add_subdirectory(libfreerdp-kbd)
add_subdirectory(libfreerdp-gdi)
add_subdirectory(libfreerdp-core)
add_subdirectory(freerdp-ui)

View File

@ -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
View 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)

View 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

Binary file not shown.

60
freerdp-ui/test/freerdp.c Normal file
View 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;
}

View 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
};

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);
stream_seek(transport->recv_buffer, bytes);
return r;
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;
}

View File

@ -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);

View File

@ -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;
}