diff --git a/CMakeLists.txt b/CMakeLists.txt index e506e3245..a9f8d1e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,3 +55,5 @@ add_subdirectory(libfreerdp-kbd) add_subdirectory(libfreerdp-gdi) add_subdirectory(libfreerdp-core) + +add_subdirectory(freerdp-ui) diff --git a/cunit/test_transport.c b/cunit/test_transport.c index 1d3ec9ed4..914fe89d0 100644 --- a/cunit/test_transport.c +++ b/cunit/test_transport.c @@ -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); } diff --git a/freerdp-ui/CMakeLists.txt b/freerdp-ui/CMakeLists.txt new file mode 100644 index 000000000..e2fd4ca31 --- /dev/null +++ b/freerdp-ui/CMakeLists.txt @@ -0,0 +1,21 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP User Interfaces +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# 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) diff --git a/freerdp-ui/test/CMakeLists.txt b/freerdp-ui/test/CMakeLists.txt new file mode 100644 index 000000000..ad2275498 --- /dev/null +++ b/freerdp-ui/test/CMakeLists.txt @@ -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 +# Copyright 2011 Marc-Andre Moreau +# +# 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) diff --git a/freerdp-ui/test/freerdp-test b/freerdp-ui/test/freerdp-test new file mode 100755 index 000000000..0e3c7518e Binary files /dev/null and b/freerdp-ui/test/freerdp-test differ diff --git a/freerdp-ui/test/freerdp.c b/freerdp-ui/test/freerdp.c new file mode 100644 index 000000000..714866b7e --- /dev/null +++ b/freerdp-ui/test/freerdp.c @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Test UI + * + * Copyright 2010 Marc-Andre Moreau + * + * 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 +#include + +#include "tpkt.h" +#include "nego.h" +#include "transport.h" + +#include + +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 \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; +} diff --git a/include/freerdp/constants.h b/include/freerdp/constants.h new file mode 100644 index 000000000..233fc3f26 --- /dev/null +++ b/include/freerdp/constants.h @@ -0,0 +1,40 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * RDP Constants + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 +}; diff --git a/include/freerdp/utils/memory.h b/include/freerdp/utils/memory.h index 520906284..cb5cc9ddc 100644 --- a/include/freerdp/utils/memory.h +++ b/include/freerdp/utils/memory.h @@ -23,8 +23,9 @@ #include 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 */ diff --git a/include/freerdp/utils/stream.h b/include/freerdp/utils/stream.h index 3c8376661..e8f06c842 100644 --- a/include/freerdp/utils/stream.h +++ b/include/freerdp/utils/stream.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 diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index 9f25c5df3..13ea4913b 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -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 diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c index 77b7401c8..bf85a8627 100644 --- a/libfreerdp-core/nego.c +++ b/libfreerdp-core/nego.c @@ -17,9 +17,14 @@ * limitations under the License. */ -#include "stream.h" +#include +#include + +#include #include +#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; +} diff --git a/libfreerdp-core/nego.h b/libfreerdp-core/nego.h index 64367c8c8..23224d4cd 100644 --- a/libfreerdp-core/nego.h +++ b/libfreerdp-core/nego.h @@ -20,8 +20,10 @@ #ifndef __NEGO_H #define __NEGO_H -#include "stream.h" -#include "network.h" +#include "transport.h" +#include +#include +#include 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 */ diff --git a/libfreerdp-core/tpdu.c b/libfreerdp-core/tpdu.c index ea0d26694..282eaa637 100644 --- a/libfreerdp-core/tpdu.c +++ b/libfreerdp-core/tpdu.c @@ -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); } diff --git a/libfreerdp-core/tpdu.h b/libfreerdp-core/tpdu.h index 253cc28b3..8acefb6be 100644 --- a/libfreerdp-core/tpdu.h +++ b/libfreerdp-core/tpdu.h @@ -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 diff --git a/libfreerdp-core/tpkt.c b/libfreerdp-core/tpkt.c index 0bc5814ff..9ff407161 100644 --- a/libfreerdp-core/tpkt.c +++ b/libfreerdp-core/tpkt.c @@ -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); +} diff --git a/libfreerdp-core/tpkt.h b/libfreerdp-core/tpkt.h index 5d744449c..1f1645746 100644 --- a/libfreerdp-core/tpkt.h +++ b/libfreerdp-core/tpkt.h @@ -20,11 +20,21 @@ #ifndef __TPKT_H #define __TPKT_H +#include "tpdu.h" +#include "transport.h" + #include +#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 */ diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c index 62d9900ad..eb200f3b5 100644 --- a/libfreerdp-core/transport.c +++ b/libfreerdp-core/transport.c @@ -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; } diff --git a/libfreerdp-core/transport.h b/libfreerdp-core/transport.h index 316f6d912..85c5a3395 100644 --- a/libfreerdp-core/transport.h +++ b/libfreerdp-core/transport.h @@ -20,9 +20,12 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H +#include +#include #include -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); diff --git a/libfreerdp-utils/memory.c b/libfreerdp-utils/memory.c index c8fd2bda0..148c316cd 100644 --- a/libfreerdp-utils/memory.c +++ b/libfreerdp-utils/memory.c @@ -23,64 +23,101 @@ #include +/** + * 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; }