From ac128313a96e9fed1056066dca09f65ca3779ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 3 Sep 2011 16:36:27 -0400 Subject: [PATCH] libfreerdp-core: further improvements to server redirection code --- include/freerdp/utils/string.h | 39 ++++++++++ libfreerdp-core/connection.c | 27 +++++++ libfreerdp-core/connection.h | 1 + libfreerdp-core/rdp.c | 2 + libfreerdp-core/rdp.h | 2 + libfreerdp-core/redirection.c | 134 ++++++++++++++++++++++---------- libfreerdp-core/redirection.h | 21 +++++ libfreerdp-core/tcp.c | 3 - libfreerdp-core/tcp.h | 6 -- libfreerdp-core/tls.c | 4 - libfreerdp-core/tls.h | 6 -- libfreerdp-core/transport.c | 18 ++--- libfreerdp-utils/CMakeLists.txt | 1 + libfreerdp-utils/string.c | 39 ++++++++++ 14 files changed, 232 insertions(+), 71 deletions(-) create mode 100644 include/freerdp/utils/string.h create mode 100644 libfreerdp-utils/string.c diff --git a/include/freerdp/utils/string.h b/include/freerdp/utils/string.h new file mode 100644 index 000000000..636b93b04 --- /dev/null +++ b/include/freerdp/utils/string.h @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * String Utils + * + * 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. + */ + +#ifndef __STRING_UTILS_H +#define __STRING_UTILS_H + +#include +#include +#include +#include + +struct rdp_string +{ + char* ascii; + char* unicode; + uint32 length; +}; +typedef struct rdp_string rdpString; + +FREERDP_API void freerdp_string_read_length32(STREAM* s, rdpString* string, UNICONV* uniconv); +FREERDP_API void freerdp_string_free(rdpString* string); + +#endif /* __STRING_UTILS_H */ diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index 0d5be304b..c22a97e7f 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -104,6 +104,33 @@ boolean rdp_client_connect(rdpRdp* rdp) return True; } +boolean rdp_client_disconnect(rdpRdp* rdp) +{ + return transport_disconnect(rdp->transport); +} + +boolean rdp_client_redirect(rdpRdp* rdp) +{ + rdpSettings* settings = rdp->settings; + rdpRedirection* redirection = rdp->redirection; + + rdp_client_disconnect(rdp); + + rdp->transport->layer = TRANSPORT_LAYER_TCP; + settings->redirected_session_id = redirection->sessionID; + + if (redirection->flags & LB_TARGET_NET_ADDRESS) + settings->hostname = redirection->targetNetAddress.ascii; + + if (redirection->flags & LB_USERNAME) + settings->username = redirection->username.ascii; + + if (redirection->flags & LB_DOMAIN) + settings->domain = redirection->domain.ascii; + + return rdp_client_connect(rdp); +} + boolean rdp_client_connect_mcs_connect_response(rdpRdp* rdp, STREAM* s) { if (!mcs_recv_connect_response(rdp->mcs, s)) diff --git a/libfreerdp-core/connection.h b/libfreerdp-core/connection.h index c761da641..2d78e33ee 100644 --- a/libfreerdp-core/connection.h +++ b/libfreerdp-core/connection.h @@ -45,6 +45,7 @@ enum CONNECTION_STATE }; boolean rdp_client_connect(rdpRdp* rdp); +boolean rdp_client_redirect(rdpRdp* rdp); boolean rdp_client_connect_mcs_connect_response(rdpRdp* rdp, STREAM* s); boolean rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, STREAM* s); boolean rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, STREAM* s); diff --git a/libfreerdp-core/rdp.c b/libfreerdp-core/rdp.c index 064935923..1a049fa85 100644 --- a/libfreerdp-core/rdp.c +++ b/libfreerdp-core/rdp.c @@ -602,6 +602,7 @@ rdpRdp* rdp_new(freerdp* instance) rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); rdp->vchan = vchan_new(instance); + rdp->redirection = redirection_new(); } return rdp; @@ -625,6 +626,7 @@ void rdp_free(rdpRdp* rdp) nego_free(rdp->nego); mcs_free(rdp->mcs); vchan_free(rdp->vchan); + redirection_free(rdp->redirection); xfree(rdp); } } diff --git a/libfreerdp-core/rdp.h b/libfreerdp-core/rdp.h index fb50fea27..d1fcc7e36 100644 --- a/libfreerdp-core/rdp.h +++ b/libfreerdp-core/rdp.h @@ -34,6 +34,7 @@ typedef struct rdp_rdp rdpRdp; #include "security.h" #include "transport.h" #include "connection.h" +#include "redirection.h" #include "capabilities.h" #include "vchan.h" #include "mppc.h" @@ -122,6 +123,7 @@ struct rdp_rdp struct rdp_update* update; struct rdp_fastpath* fastpath; struct rdp_license* license; + struct rdp_redirection* redirection; struct rdp_settings* settings; struct rdp_transport* transport; struct rdp_vchan* vchan; diff --git a/libfreerdp-core/redirection.c b/libfreerdp-core/redirection.c index 2c8d63a99..91a1546f2 100644 --- a/libfreerdp-core/redirection.c +++ b/libfreerdp-core/redirection.c @@ -17,6 +17,8 @@ * limitations under the License. */ +#include "connection.h" + #include "redirection.h" void rdp_print_redirection_flags(uint32 flags) @@ -57,90 +59,98 @@ boolean rdp_recv_server_redirection_pdu(rdpRdp* rdp, STREAM* s) { uint16 flags; uint16 length; - uint32 sessionID; - uint32 redirFlags; - uint32 targetNetAddressLength; - uint32 loadBalanceInfoLength; - uint32 userNameLength; - uint32 domainLength; - uint32 passwordLength; - uint32 targetFQDNLength; - uint32 targetNetBiosNameLength; - uint32 tsvUrlLength; - uint32 targetNetAddressesLength; + rdpRedirection* redirection = rdp->redirection; stream_read_uint16(s, flags); /* flags (2 bytes) */ stream_read_uint16(s, length); /* length (2 bytes) */ - stream_read_uint32(s, sessionID); /* sessionID (4 bytes) */ - stream_read_uint32(s, redirFlags); /* redirFlags (4 bytes) */ + stream_read_uint32(s, redirection->sessionID); /* sessionID (4 bytes) */ + stream_read_uint32(s, redirection->flags); /* redirFlags (4 bytes) */ - DEBUG_REDIR("flags: 0x%04X, length:%d, sessionID:0x%08X", flags, length, sessionID); + DEBUG_REDIR("flags: 0x%04X, length:%d, sessionID:0x%08X", flags, length, redirection->sessionID); #ifdef WITH_DEBUG_REDIR - rdp_print_redirection_flags(redirFlags); + rdp_print_redirection_flags(redirection->flags); #endif - if (redirFlags & LB_TARGET_NET_ADDRESS) + if (redirection->flags & LB_TARGET_NET_ADDRESS) { - stream_read_uint32(s, targetNetAddressLength); /* targetNetAddressLength (4 bytes) */ - stream_seek(s, targetNetAddressLength); + freerdp_string_read_length32(s, &redirection->targetNetAddress, rdp->settings->uniconv); + DEBUG_REDIR("targetNetAddress: %s", redirection->targetNetAddress.ascii); } - if (redirFlags & LB_LOAD_BALANCE_INFO) + if (redirection->flags & LB_LOAD_BALANCE_INFO) { - stream_read_uint32(s, loadBalanceInfoLength); /* loadBalanceInfoLength (4 bytes) */ - stream_seek(s, loadBalanceInfoLength); + freerdp_string_read_length32(s, &redirection->loadBalanceInfo, rdp->settings->uniconv); + DEBUG_REDIR("loadBalanceInfo: %s", redirection->loadBalanceInfo.ascii); } - if (redirFlags & LB_USERNAME) + if (redirection->flags & LB_USERNAME) { - stream_read_uint32(s, userNameLength); /* userNameLength (4 bytes) */ - stream_seek(s, userNameLength); + freerdp_string_read_length32(s, &redirection->username, rdp->settings->uniconv); + DEBUG_REDIR("username: %s", redirection->username.ascii); } - if (redirFlags & LB_DOMAIN) + if (redirection->flags & LB_DOMAIN) { - stream_read_uint32(s, domainLength); /* domainLength (4 bytes) */ - stream_seek(s, domainLength); + freerdp_string_read_length32(s, &redirection->domain, rdp->settings->uniconv); + DEBUG_REDIR("domain: %s", redirection->domain.ascii); } - if (redirFlags & LB_PASSWORD) + if (redirection->flags & LB_PASSWORD) { - stream_read_uint32(s, passwordLength); /* passwordLength (4 bytes) */ - stream_seek(s, passwordLength); + freerdp_string_read_length32(s, &redirection->password, rdp->settings->uniconv); + DEBUG_REDIR("password: %s", redirection->password.ascii); } - if (redirFlags & LB_TARGET_FQDN) + if (redirection->flags & LB_TARGET_FQDN) { - stream_read_uint32(s, targetFQDNLength); /* targetFQDNLength (4 bytes) */ - stream_seek(s, targetFQDNLength); + freerdp_string_read_length32(s, &redirection->targetFQDN, rdp->settings->uniconv); + DEBUG_REDIR("targetFQDN: %s", redirection->targetFQDN.ascii); } - if (redirFlags & LB_TARGET_NETBIOS_NAME) + if (redirection->flags & LB_TARGET_NETBIOS_NAME) { - stream_read_uint32(s, targetNetBiosNameLength); /* targetNetBiosNameLength (4 bytes) */ - stream_seek(s, targetNetBiosNameLength); + freerdp_string_read_length32(s, &redirection->targetNetBiosName, rdp->settings->uniconv); + DEBUG_REDIR("targetNetBiosName: %s", redirection->targetNetBiosName.ascii); } - if (redirFlags & LB_CLIENT_TSV_URL) + if (redirection->flags & LB_CLIENT_TSV_URL) { - stream_read_uint32(s, tsvUrlLength); /* tsvUrlLength (4 bytes) */ - stream_seek(s, tsvUrlLength); + freerdp_string_read_length32(s, &redirection->tsvUrl, rdp->settings->uniconv); + DEBUG_REDIR("tsvUrl: %s", redirection->tsvUrl.ascii); } - if (redirFlags & LB_TARGET_NET_ADDRESSES) + if (redirection->flags & LB_TARGET_NET_ADDRESSES) { - stream_read_uint32(s, targetNetAddressesLength); /* targetNetAddressesLength (4 bytes) */ - stream_seek(s, targetNetAddressesLength); + uint32 count; + uint32 targetNetAddressesLength; + + stream_read_uint32(s, targetNetAddressesLength); + + stream_read_uint32(s, redirection->targetNetAddressesCount); + count = redirection->targetNetAddressesCount; + + redirection->targetNetAddresses = (rdpString*) xzalloc(count * sizeof(rdpString)); + + while (count > 0) + { + freerdp_string_read_length32(s, redirection->targetNetAddresses, rdp->settings->uniconv); + DEBUG_REDIR("targetNetAddresses: %s", redirection->targetNetAddresses->ascii); + redirection->targetNetAddresses++; + count--; + } } stream_seek(s, 8); /* pad (8 bytes) */ + rdp_client_redirect(rdp); + return True; } boolean rdp_recv_redirection_packet(rdpRdp* rdp, STREAM* s) { + rdp_recv_server_redirection_pdu(rdp, s); return True; } @@ -152,3 +162,43 @@ boolean rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, STREAM* s) return True; } +rdpRedirection* redirection_new() +{ + rdpRedirection* redirection; + + redirection = (rdpRedirection*) xzalloc(sizeof(rdpRedirection)); + + if (redirection != NULL) + { + freerdp_string_free(&redirection->tsvUrl); + freerdp_string_free(&redirection->username); + freerdp_string_free(&redirection->domain); + freerdp_string_free(&redirection->password); + freerdp_string_free(&redirection->targetFQDN); + freerdp_string_free(&redirection->loadBalanceInfo); + freerdp_string_free(&redirection->targetNetBiosName); + freerdp_string_free(&redirection->targetNetAddress); + + if (redirection->targetNetAddresses != NULL) + { + int i; + + for (i = 0; i < redirection->targetNetAddressesCount; i++) + freerdp_string_free(&redirection->targetNetAddresses[i]); + + xfree(redirection->targetNetAddresses); + } + } + + return redirection; +} + +void redirection_free(rdpRedirection* redirection) +{ + if (redirection != NULL) + { + xfree(redirection); + } +} + + diff --git a/libfreerdp-core/redirection.h b/libfreerdp-core/redirection.h index afccbbc7d..60c83b90f 100644 --- a/libfreerdp-core/redirection.h +++ b/libfreerdp-core/redirection.h @@ -25,6 +25,7 @@ #include #include #include +#include /* Redirection Flags */ #define LB_TARGET_NET_ADDRESS 0x00000001 @@ -41,9 +42,29 @@ #define LB_CLIENT_TSV_URL 0x00001000 #define LB_SERVER_TSV_CAPABLE 0x00002000 +struct rdp_redirection +{ + uint32 flags; + uint32 sessionID; + rdpString tsvUrl; + rdpString username; + rdpString domain; + rdpString password; + rdpString targetFQDN; + rdpString loadBalanceInfo; + rdpString targetNetBiosName; + rdpString targetNetAddress; + uint32 targetNetAddressesCount; + rdpString* targetNetAddresses; +}; +typedef struct rdp_redirection rdpRedirection; + boolean rdp_recv_redirection_packet(rdpRdp* rdp, STREAM* s); boolean rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, STREAM* s); +rdpRedirection* redirection_new(); +void redirection_free(rdpRedirection* redirection); + #ifdef WITH_DEBUG_REDIR #define DEBUG_REDIR(fmt, ...) DEBUG_CLASS(REDIR, fmt, ## __VA_ARGS__) #else diff --git a/libfreerdp-core/tcp.c b/libfreerdp-core/tcp.c index 88c849358..e55de84e8 100644 --- a/libfreerdp-core/tcp.c +++ b/libfreerdp-core/tcp.c @@ -231,9 +231,6 @@ rdpTcp* tcp_new(rdpSettings* settings) { tcp->sockfd = -1; tcp->settings = settings; - tcp->connect = tcp_connect; - tcp->disconnect = tcp_disconnect; - tcp->set_blocking_mode = tcp_set_blocking_mode; } return tcp; diff --git a/libfreerdp-core/tcp.h b/libfreerdp-core/tcp.h index b9277ff12..907145dbf 100644 --- a/libfreerdp-core/tcp.h +++ b/libfreerdp-core/tcp.h @@ -36,9 +36,6 @@ #endif typedef struct rdp_tcp rdpTcp; -typedef boolean (*TcpConnect) (rdpTcp* tcp, const char* hostname, uint16 port); -typedef boolean (*TcpDisconnect) (rdpTcp* tcp); -typedef boolean (*TcpSetBlockingMode) (rdpTcp* tcp, boolean blocking); struct rdp_tcp { @@ -46,9 +43,6 @@ struct rdp_tcp char ip_address[32]; uint8 mac_address[6]; struct rdp_settings* settings; - TcpConnect connect; - TcpDisconnect disconnect; - TcpSetBlockingMode set_blocking_mode; #ifdef _WIN32 WSAEVENT wsa_event; #endif diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index aa01c40d0..271fab86a 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -235,10 +235,6 @@ rdpTls* tls_new() if (tls != NULL) { - tls->connect = tls_connect; - tls->accept = tls_accept; - tls->disconnect = tls_disconnect; - SSL_load_error_strings(); SSL_library_init(); } diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h index 52b301c40..a4d42d591 100644 --- a/libfreerdp-core/tls.h +++ b/libfreerdp-core/tls.h @@ -29,18 +29,12 @@ #include typedef struct rdp_tls rdpTls; -typedef boolean (*TlsConnect) (rdpTls* tls); -typedef boolean (*TlsAccept) (rdpTls* tls, const char* cert_file, const char* privatekey_file); -typedef boolean (*TlsDisconnect) (rdpTls* tls); struct rdp_tls { SSL* ssl; int sockfd; SSL_CTX* ctx; - TlsConnect connect; - TlsAccept accept; - TlsDisconnect disconnect; }; boolean tls_connect(rdpTls* tls); diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c index bbb62b30a..df007281b 100644 --- a/libfreerdp-core/transport.c +++ b/libfreerdp-core/transport.c @@ -60,7 +60,7 @@ STREAM* transport_send_stream_init(rdpTransport* transport, int size) boolean transport_connect(rdpTransport* transport, const char* hostname, uint16 port) { - return transport->tcp->connect(transport->tcp, hostname, port); + return tcp_connect(transport->tcp, hostname, port); } void transport_attach(rdpTransport* transport, int sockfd) @@ -70,9 +70,10 @@ void transport_attach(rdpTransport* transport, int sockfd) boolean transport_disconnect(rdpTransport* transport) { - if (transport->tls) - IFCALL(transport->tls->disconnect, transport->tls); - return transport->tcp->disconnect(transport->tcp); + if (transport->layer == TRANSPORT_LAYER_TLS) + return tls_disconnect(transport->tls); + else + return tcp_disconnect(transport->tcp); } boolean transport_connect_rdp(rdpTransport* transport) @@ -355,15 +356,10 @@ int transport_check_fds(rdpTransport* transport) return 0; } -void transport_init(rdpTransport* transport) -{ - transport->layer = TRANSPORT_LAYER_TCP; -} - boolean transport_set_blocking_mode(rdpTransport* transport, boolean blocking) { transport->blocking = blocking; - return transport->tcp->set_blocking_mode(transport->tcp, blocking); + return tcp_set_blocking_mode(transport->tcp, blocking); } rdpTransport* transport_new(rdpSettings* settings) @@ -389,6 +385,8 @@ rdpTransport* transport_new(rdpSettings* settings) transport->send_stream = stream_new(BUFFER_SIZE); transport->blocking = True; + + transport->layer = TRANSPORT_LAYER_TCP; } return transport; diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index 946d5cb82..b93b14cf4 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -40,6 +40,7 @@ set(FREERDP_UTILS_SRCS sleep.c stopwatch.c stream.c + string.c svc_plugin.c thread.c unicode.c diff --git a/libfreerdp-utils/string.c b/libfreerdp-utils/string.c new file mode 100644 index 000000000..c3b2a3ab3 --- /dev/null +++ b/libfreerdp-utils/string.c @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * String Utils + * + * 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 + +#include + +void freerdp_string_read_length32(STREAM* s, rdpString* string, UNICONV* uniconv) +{ + stream_read_uint32(s, string->length); + string->unicode = (char*) xmalloc(string->length); + stream_read(s, string->unicode, string->length); + string->ascii = freerdp_uniconv_in(uniconv, (uint8*) string->unicode, string->length); +} + +void freerdp_string_free(rdpString* string) +{ + if (string->unicode != NULL) + xfree(string->unicode); + + if (string->ascii != NULL) + xfree(string->ascii); +}