Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/neutrinolabs/NeutrinoRDP.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Sorg <jay.sorg@gmail.com>2014-07-10 03:28:41 +0400
committerJay Sorg <jay.sorg@gmail.com>2014-07-10 03:28:41 +0400
commit26f612a5331749f8ed04be68ba777a58480fd6c0 (patch)
tree6bd2f16d950160fdd88756f3a0fe8f20edfdc816
parent4f51e7d9d91e43ae6cbe8780a291b8373fe2e124 (diff)
parent1fb5636af2c910b6b03455fc37d4bd5d4d20a582 (diff)
Merge branch 'tsg1'
-rw-r--r--include/freerdp/settings.h8
-rw-r--r--include/freerdp/types.h10
-rw-r--r--include/freerdp/utils/unicode.h2
-rw-r--r--libfreerdp-core/CMakeLists.txt4
-rw-r--r--libfreerdp-core/connection.c25
-rw-r--r--libfreerdp-core/credssp.c25
-rw-r--r--libfreerdp-core/credssp.h5
-rw-r--r--libfreerdp-core/crypto.c32
-rw-r--r--libfreerdp-core/crypto.h3
-rw-r--r--libfreerdp-core/fastpath.c44
-rw-r--r--libfreerdp-core/license.c2
-rw-r--r--libfreerdp-core/mcs.c30
-rw-r--r--libfreerdp-core/nego.c44
-rw-r--r--libfreerdp-core/ntlmssp.c23
-rw-r--r--libfreerdp-core/orders.c44
-rw-r--r--libfreerdp-core/peer.c319
-rw-r--r--libfreerdp-core/per.c19
-rw-r--r--libfreerdp-core/rdp.c119
-rw-r--r--libfreerdp-core/redirection.c1
-rw-r--r--libfreerdp-core/rpch.c1654
-rw-r--r--libfreerdp-core/rpch.h630
-rw-r--r--libfreerdp-core/tcp.c19
-rw-r--r--libfreerdp-core/tls.c109
-rw-r--r--libfreerdp-core/tls.h5
-rw-r--r--libfreerdp-core/transport.c530
-rw-r--r--libfreerdp-core/transport.h11
-rw-r--r--libfreerdp-core/tsg.c309
-rw-r--r--libfreerdp-core/tsg.h59
-rw-r--r--libfreerdp-utils/args.c69
-rw-r--r--libfreerdp-utils/memory.c13
-rw-r--r--libfreerdp-utils/unicode.c4
31 files changed, 3645 insertions, 526 deletions
diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h
index 19b048a..cf4ea44 100644
--- a/include/freerdp/settings.h
+++ b/include/freerdp/settings.h
@@ -443,6 +443,14 @@ struct rdp_settings
struct rdp_ext_set extensions[16];
int skip_bs;
+
+ /* TSG */
+ tbool tsg;
+ char* tsg_username;
+ char* tsg_password;
+ char* tsg_domain;
+ char* tsg_server;
+
};
typedef struct rdp_settings rdpSettings;
diff --git a/include/freerdp/types.h b/include/freerdp/types.h
index 0708920..eea090b 100644
--- a/include/freerdp/types.h
+++ b/include/freerdp/types.h
@@ -152,6 +152,16 @@ typedef int boolean;
#include <freerdp/settings.h>
+typedef struct _uuid
+{
+ uint32 time_low;
+ uint16 time_mid;
+ uint16 time_hi_and_version;
+ uint8 clock_seq_hi_and_reserved;
+ uint8 clock_seq_low;
+ uint8 node[6];
+} uuid;
+
struct _RDP_PLUGIN_DATA
{
uint16 size;
diff --git a/include/freerdp/utils/unicode.h b/include/freerdp/utils/unicode.h
index 7268a8e..0dabc93 100644
--- a/include/freerdp/utils/unicode.h
+++ b/include/freerdp/utils/unicode.h
@@ -48,7 +48,7 @@ typedef struct _UNICONV UNICONV;
FREERDP_API UNICONV* freerdp_uniconv_new();
FREERDP_API void freerdp_uniconv_free(UNICONV *uniconv);
FREERDP_API char* freerdp_uniconv_in(UNICONV *uniconv, unsigned char* pin, size_t in_len);
-FREERDP_API char* freerdp_uniconv_out(UNICONV *uniconv, char *str, size_t *pout_len);
+FREERDP_API char* freerdp_uniconv_out(UNICONV *uniconv, const char *str, size_t *pout_len);
FREERDP_API void freerdp_uniconv_uppercase(UNICONV *uniconv, char *wstr, int length);
#endif /* __UNICODE_UTILS_H */
diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt
index b5b7b64..c144d3f 100644
--- a/libfreerdp-core/CMakeLists.txt
+++ b/libfreerdp-core/CMakeLists.txt
@@ -94,6 +94,10 @@ set(LIBFREERDP_CORE_SRCS
mppc.c
pointer.c
pointer.h
+ tsg.c
+ tsg.h
+ rpch.c
+ rpch.h
)
add_library(freerdp-core ${LIBFREERDP_CORE_SRCS})
diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c
index 55c2ca0..51b8a16 100644
--- a/libfreerdp-core/connection.c
+++ b/libfreerdp-core/connection.c
@@ -23,6 +23,12 @@
#include "connection.h"
+#define LLOG_LEVEL 11
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
/**
* Connection Sequence
* client server
@@ -88,29 +94,48 @@ tbool rdp_client_connect(rdpRdp* rdp)
status = false;
if (selectedProtocol & PROTOCOL_NLA)
+ {
status = transport_connect_nla(rdp->transport);
+ }
else if (selectedProtocol & PROTOCOL_TLS)
+ {
status = transport_connect_tls(rdp->transport);
+ }
else if (selectedProtocol == PROTOCOL_RDP) /* 0 */
+ {
status = transport_connect_rdp(rdp->transport);
+ }
if (status == false)
+ {
return false;
+ }
rdp_set_blocking_mode(rdp, false);
rdp->state = CONNECTION_STATE_NEGO;
rdp->finalize_sc_pdus = 0;
+ LLOGLN(10, ("rdp_client_connect: calling mcs_send_connect_initial"));
+
+ //freerdp_usleep(1000 * 1000 * 10);
+
if (mcs_send_connect_initial(rdp->mcs) == false)
{
printf("Error: unable to send MCS Connect Initial\n");
return false;
}
+ //freerdp_usleep(1000 * 1000 * 10);
+
while (rdp->state != CONNECTION_STATE_ACTIVE)
{
+ /* TODO: don't use sleep here */
+ freerdp_usleep(1000 * 100);
if (rdp_check_fds(rdp) < 0)
+ {
+ LLOGLN(0, ("rdp_client_connect: error rdp_check_fds failed"));
return false;
+ }
}
return true;
diff --git a/libfreerdp-core/credssp.c b/libfreerdp-core/credssp.c
index a1aee21..ad45549 100644
--- a/libfreerdp-core/credssp.c
+++ b/libfreerdp-core/credssp.c
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -76,7 +76,7 @@ int credssp_ntlmssp_init(rdpCredssp* credssp)
{
freerdp* instance;
NTLMSSP* ntlmssp = credssp->ntlmssp;
- rdpSettings* settings = credssp->transport->settings;
+ rdpSettings* settings = credssp->settings;
instance = (freerdp*) settings->instance;
if ((settings->password == NULL) || (settings->username == NULL))
@@ -128,7 +128,7 @@ int credssp_get_public_key(rdpCredssp* credssp)
int status;
CryptoCert cert;
- cert = tls_get_certificate(credssp->transport->tls);
+ cert = tls_get_certificate(credssp->tls);
if (cert == NULL)
{
@@ -136,8 +136,8 @@ int credssp_get_public_key(rdpCredssp* credssp)
return 0;
}
- if (!tls_verify_certificate(credssp->transport->tls, cert, credssp->transport->settings->hostname))
- tls_disconnect(credssp->transport->tls);
+ if (!tls_verify_certificate(credssp->tls, cert, credssp->settings->hostname))
+ tls_disconnect(credssp->tls);
status = crypto_cert_get_public_key(cert, &credssp->public_key);
crypto_cert_free(cert);
@@ -530,7 +530,7 @@ void credssp_send(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rd
ber_write_octet_string(s, pubKeyAuth->data, length);
}
- transport_write(credssp->transport, s);
+ tls_write(credssp->tls, s->data, stream_get_length(s));
stream_free(s);
}
@@ -550,8 +550,8 @@ int credssp_recv(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rdp
int status;
uint32 version;
- s = transport_recv_stream_init(credssp->transport, 2048);
- status = transport_read(credssp->transport, s);
+ s = stream_new(2048);
+ status = tls_read(credssp->tls, s->data, stream_get_left(s));
if (status < 0)
return -1;
@@ -635,20 +635,19 @@ void credssp_current_time(uint8* timestamp)
* @return new CredSSP state machine.
*/
-rdpCredssp* credssp_new(rdpTransport* transport)
+rdpCredssp* credssp_new(freerdp* instance, struct rdp_tls* tls, rdpSettings* settings)
{
rdpCredssp* self;
self = (rdpCredssp*) xzalloc(sizeof(rdpCredssp));
-
if (self != NULL)
{
- self->transport = transport;
+ self->instance = instance;
+ self->settings = settings;
+ self->tls = tls;
self->send_seq_num = 0;
self->ntlmssp = ntlmssp_new();
- self->settings = transport->settings;
}
-
return self;
}
diff --git a/libfreerdp-core/credssp.h b/libfreerdp-core/credssp.h
index 3277425..a1bf456 100644
--- a/libfreerdp-core/credssp.h
+++ b/libfreerdp-core/credssp.h
@@ -36,6 +36,8 @@ typedef struct rdp_credssp rdpCredssp;
struct rdp_credssp
{
+ freerdp* instance;
+ struct rdp_tls* tls;
rdpBlob negoToken;
rdpBlob pubKeyAuth;
rdpBlob authInfo;
@@ -45,7 +47,6 @@ struct rdp_credssp
rdpSettings* settings;
CryptoRc4 rc4_seal_state;
struct _NTLMSSP *ntlmssp;
- struct rdp_transport* transport;
};
int credssp_authenticate(rdpCredssp* credssp);
@@ -61,7 +62,7 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp);
void credssp_current_time(uint8* timestamp);
void credssp_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext);
-rdpCredssp* credssp_new(rdpTransport* transport);
+rdpCredssp* credssp_new(freerdp* instance, struct rdp_tls* tls, rdpSettings* settings);
void credssp_free(rdpCredssp* credssp);
#endif /* __CREDSSP_H */
diff --git a/libfreerdp-core/crypto.c b/libfreerdp-core/crypto.c
index 217b9f7..f6fa50a 100644
--- a/libfreerdp-core/crypto.c
+++ b/libfreerdp-core/crypto.c
@@ -560,3 +560,35 @@ void crypto_cert_print_info(X509* xcert)
xfree(issuer);
xfree(fp);
}
+
+void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_length)
+{
+ BIO *bmem, *b64;
+ BUF_MEM *bptr;
+
+ b64 = BIO_new(BIO_f_base64());
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ bmem = BIO_new(BIO_s_mem());
+ b64 = BIO_push(b64, bmem);
+ BIO_write(b64, data, length);
+ BIO_flush(b64);
+ BIO_get_mem_ptr(b64, &bptr);
+ *res_length = bptr->length - 1;
+ *enc_data = xmalloc(*res_length);
+ memcpy(*enc_data, bptr->data, *res_length);
+ BIO_free_all(b64);
+}
+
+void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length)
+{
+ BIO *b64, *bmem;
+
+ *dec_data = xmalloc(length);
+ memset(*dec_data, 0, length);
+ b64 = BIO_new(BIO_f_base64());
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ bmem = BIO_new_mem_buf(enc_data, length);
+ bmem = BIO_push(b64, bmem);
+ *res_length = BIO_read(bmem, *dec_data, length);
+ BIO_free_all(bmem);
+}
diff --git a/libfreerdp-core/crypto.h b/libfreerdp-core/crypto.h
index 384fdbb..4552c68 100644
--- a/libfreerdp-core/crypto.h
+++ b/libfreerdp-core/crypto.h
@@ -141,4 +141,7 @@ void crypto_rsa_private_decrypt(const uint8* input, int length, uint32 key_lengt
void crypto_reverse(uint8* data, int length);
void crypto_nonce(uint8* nonce, int size);
+void crypto_base64_encode(uint8* data, int length, uint8** enc_data, int* res_length);
+void crypto_base64_decode(uint8* enc_data, int length, uint8** dec_data, int* res_length);
+
#endif /* __CRYPTO_H */
diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c
index 1d28117..0fd740e 100644
--- a/libfreerdp-core/fastpath.c
+++ b/libfreerdp-core/fastpath.c
@@ -30,6 +30,12 @@
#include "fastpath.h"
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
/**
* Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises
* server output packets from the first byte with the goal of improving
@@ -77,7 +83,10 @@ uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s)
fastpath->numberEvents = (header & 0x3C) >> 2;
}
- per_read_length(s, &length);
+ if (!per_read_length(s, &length))
+ {
+ LLOGLN(10, ("fastpath_read_header: error"));
+ }
return length;
}
@@ -104,20 +113,31 @@ INLINE void fastpath_write_update_header(STREAM* s, uint8 updateCode, uint8 frag
uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s)
{
+ uint8 byte;
uint8 header;
uint16 length;
+ LLOGLN(10, ("fastpath_read_header_rdp:"));
stream_read_uint8(s, header);
-
if (fastpath != NULL)
{
fastpath->encryptionFlags = (header & 0xC0) >> 6;
fastpath->numberEvents = (header & 0x3C) >> 2;
}
-
- per_read_length(s, &length);
-
- return length - stream_get_length(s);
+ stream_read_uint8(s, byte);
+ if (byte & 0x80)
+ {
+ length = byte & 0x7F;
+ stream_read_uint8(s, byte);
+ length = (length << 8) | byte;
+ length -= 3;
+ }
+ else
+ {
+ length = byte;
+ length -= 2;
+ }
+ return length;
}
static void fastpath_recv_orders(rdpFastPath* fastpath, STREAM* s)
@@ -125,10 +145,12 @@ static void fastpath_recv_orders(rdpFastPath* fastpath, STREAM* s)
rdpUpdate* update = fastpath->rdp->update;
uint16 numberOrders;
+ LLOGLN(10, ("fastpath_recv_orders:"));
stream_read_uint16(s, numberOrders); /* numberOrders (2 bytes) */
while (numberOrders > 0)
{
+ LLOGLN(10, ("fastpath_recv_orders: loop"));
update_recv_order(update, s);
numberOrders--;
}
@@ -167,6 +189,7 @@ static void fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uint32
rdpContext* context = fastpath->rdp->update->context;
rdpPointerUpdate* pointer = update->pointer;
+ LLOGLN(10, ("fastpath_recv_update: %d", updateCode));
switch (updateCode)
{
case FASTPATH_UPDATETYPE_ORDERS:
@@ -238,6 +261,7 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s)
uint32 roff;
uint32 rlen;
+ LLOGLN(10, ("fastpath_recv_update_data:"));
rdp = fastpath->rdp;
fastpath_read_update_header(s, &updateCode, &fragmentation, &compression);
@@ -301,17 +325,17 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s)
tbool fastpath_recv_updates(rdpFastPath* fastpath, STREAM* s)
{
- rdpUpdate* update = fastpath->rdp->update;
+ rdpUpdate* update;
+ LLOGLN(10, ("fastpath_recv_updates:"));
+ update = fastpath->rdp->update;
update->BeginPaint(update->context);
-
while (stream_get_left(s) >= 3)
{
+ LLOGLN(10, ("fastpath_recv_updates: loop"));
fastpath_recv_update_data(fastpath, s);
}
-
update->EndPaint(update->context);
-
return true;
}
diff --git a/libfreerdp-core/license.c b/libfreerdp-core/license.c
index 2609968..c019f85 100644
--- a/libfreerdp-core/license.c
+++ b/libfreerdp-core/license.c
@@ -293,7 +293,7 @@ void license_generate_hwid(rdpLicense* license)
uint8* mac_address;
memset(license->hwid, 0, HWID_LENGTH);
- mac_address = license->rdp->transport->tcp->mac_address;
+ mac_address = license->rdp->transport->tcp_in->mac_address;
md5 = crypto_md5_init();
crypto_md5_update(md5, mac_address, 6);
diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c
index 7837d6d..4681deb 100644
--- a/libfreerdp-core/mcs.c
+++ b/libfreerdp-core/mcs.c
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -182,23 +182,31 @@ static const char* const mcs_result_enumerated[] =
* @return
*/
+static tbool mcs_read_domain_mcspdu_header_check(STREAM* s, enum DomainMCSPDU* domainMCSPDU, uint16* length)
+{
+ enum DomainMCSPDU MCSPDU;
+
+ MCSPDU = *domainMCSPDU;
+ if (!mcs_read_domain_mcspdu_header(s, domainMCSPDU, length))
+ return false;
+ if (*domainMCSPDU != MCSPDU)
+ return false;
+ return true;
+}
+
+/* do not return false on MCSPDU */
tbool mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU, uint16* length)
{
uint8 choice;
- enum DomainMCSPDU MCSPDU;
*length = tpkt_read_header(s);
if (tpdu_read_data(s) == 0)
return false;
- MCSPDU = *domainMCSPDU;
per_read_choice(s, &choice);
*domainMCSPDU = (choice >> 2);
- if (*domainMCSPDU != MCSPDU)
- return false;
-
return true;
}
@@ -562,7 +570,7 @@ tbool mcs_recv_erect_domain_request(rdpMcs* mcs, STREAM* s)
enum DomainMCSPDU MCSPDU;
MCSPDU = DomainMCSPDU_ErectDomainRequest;
- if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
+ if (!mcs_read_domain_mcspdu_header_check(s, &MCSPDU, &length))
return false;
return true;
@@ -604,7 +612,7 @@ tbool mcs_recv_attach_user_request(rdpMcs* mcs, STREAM* s)
enum DomainMCSPDU MCSPDU;
MCSPDU = DomainMCSPDU_AttachUserRequest;
- if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
+ if (!mcs_read_domain_mcspdu_header_check(s, &MCSPDU, &length))
return false;
return true;
@@ -643,7 +651,7 @@ tbool mcs_recv_attach_user_confirm(rdpMcs* mcs, STREAM* s)
enum DomainMCSPDU MCSPDU;
MCSPDU = DomainMCSPDU_AttachUserConfirm;
- if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
+ if (!mcs_read_domain_mcspdu_header_check(s, &MCSPDU, &length))
return false;
per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */
@@ -690,7 +698,7 @@ tbool mcs_recv_channel_join_request(rdpMcs* mcs, STREAM* s, uint16* channel_id)
uint16 user_id;
MCSPDU = DomainMCSPDU_ChannelJoinRequest;
- if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
+ if (!mcs_read_domain_mcspdu_header_check(s, &MCSPDU, &length))
return false;
if (!per_read_integer16(s, &user_id, MCS_BASE_CHANNEL_ID))
@@ -742,7 +750,7 @@ tbool mcs_recv_channel_join_confirm(rdpMcs* mcs, STREAM* s, uint16* channel_id)
enum DomainMCSPDU MCSPDU;
MCSPDU = DomainMCSPDU_ChannelJoinConfirm;
- if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
+ if (!mcs_read_domain_mcspdu_header_check(s, &MCSPDU, &length))
return false;
per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */
diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c
index ab8beed..86effe0 100644
--- a/libfreerdp-core/nego.c
+++ b/libfreerdp-core/nego.c
@@ -27,6 +27,12 @@
#include "nego.h"
+#define LLOG_LEVEL 11
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
static const char* const NEGO_STATE_STRINGS[] =
{
"NEGO_STATE_INITIAL",
@@ -55,13 +61,24 @@ tbool nego_connect(rdpNego* nego)
if (nego->state == NEGO_STATE_INITIAL)
{
if (nego->enabled_protocols[PROTOCOL_NLA] > 0)
+ {
+ LLOGLN(10, ("nego_connect: PROTOCOL_NLA"));
nego->state = NEGO_STATE_NLA;
+ }
else if (nego->enabled_protocols[PROTOCOL_TLS] > 0)
+ {
+ LLOGLN(10, ("nego_connect: PROTOCOL_TLS"));
nego->state = NEGO_STATE_TLS;
+ }
else if (nego->enabled_protocols[PROTOCOL_RDP] > 0)
+ {
+ LLOGLN(10, ("nego_connect: PROTOCOL_RDP"));
nego->state = NEGO_STATE_RDP;
+ }
else
+ {
nego->state = NEGO_STATE_FAIL;
+ }
}
do
@@ -86,7 +103,7 @@ tbool nego_connect(rdpNego* nego)
nego->transport->settings->selected_protocol = nego->selected_protocol;
nego->transport->settings->negotiationFlags = nego->flags;
- if(nego->selected_protocol == PROTOCOL_RDP)
+ if (nego->selected_protocol == PROTOCOL_RDP)
{
nego->transport->settings->encryption = true;
nego->transport->settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
@@ -225,27 +242,28 @@ void nego_attempt_tls(rdpNego* nego)
void nego_attempt_rdp(rdpNego* nego)
{
+ LLOGLN(10, ("nego_attempt_rdp:"));
nego->requested_protocols = PROTOCOL_RDP;
-
DEBUG_NEGO("Attempting RDP security");
-
if (!nego_tcp_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
}
-
+ LLOGLN(10, ("nego_attempt_rdp: nego_tcp_connect ok"));
if (!nego_send_negotiation_request(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
}
-
+ LLOGLN(10, ("nego_attempt_rdp: nego_send_negotiation_request ok"));
if (!nego_recv_response(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
}
+ //freerdp_usleep(1000 * 1000 * 360);
+ LLOGLN(10, ("nego_attempt_rdp: out"));
}
/**
@@ -255,10 +273,18 @@ void nego_attempt_rdp(rdpNego* nego)
tbool nego_recv_response(rdpNego* nego)
{
+ tbool rv;
STREAM* s = transport_recv_stream_init(nego->transport, 1024);
+
+ LLOGLN(10, ("nego_recv_response:"));
if (transport_read(nego->transport, s) < 0)
+ {
+ LLOGLN(0, ("nego_recv_response: transport_read failed"));
return false;
- return nego_recv(nego->transport, s, nego->transport->recv_extra);
+ }
+ rv = nego_recv(nego->transport, s, nego->transport->recv_extra);
+ LLOGLN(10, ("nego_recv_response: out"));
+ return rv;
}
/**
@@ -275,8 +301,13 @@ tbool nego_recv(rdpTransport* transport, STREAM* s, void* extra)
uint8 type;
rdpNego* nego = (rdpNego*) extra;
+ LLOGLN(10, ("nego_recv:"));
+
if (tpkt_read_header(s) == 0)
+ {
+ LLOGLN(0, ("nego_recv: tpkt_read_header failed"));
return false;
+ }
li = tpdu_read_connection_confirm(s);
@@ -366,6 +397,7 @@ tbool nego_read_request(rdpNego* nego, STREAM* s)
void nego_send(rdpNego* nego)
{
+ LLOGLN(10, ("nego_send:"));
if (nego->state == NEGO_STATE_NLA)
nego_attempt_nla(nego);
else if (nego->state == NEGO_STATE_TLS)
diff --git a/libfreerdp-core/ntlmssp.c b/libfreerdp-core/ntlmssp.c
index e285836..0069cb4 100644
--- a/libfreerdp-core/ntlmssp.c
+++ b/libfreerdp-core/ntlmssp.c
@@ -941,7 +941,7 @@ void ntlmssp_input_av_pairs(NTLMSSP* ntlmssp, STREAM* s)
void ntlmssp_output_av_pairs(NTLMSSP* ntlmssp, STREAM* s)
{
AV_PAIRS* av_pairs = ntlmssp->av_pairs;
-
+
if (av_pairs->NbDomainName.length > 0)
{
stream_write_uint16(s, MsvAvNbDomainName); /* AvId */
@@ -1107,7 +1107,7 @@ void ntlmssp_print_av_pairs(NTLMSSP* ntlmssp)
void ntlmssp_free_av_pairs(NTLMSSP* ntlmssp)
{
AV_PAIRS *av_pairs = ntlmssp->av_pairs;
-
+
if (av_pairs != NULL)
{
if (av_pairs->NbComputerName.value != NULL)
@@ -1156,7 +1156,7 @@ void ntlmssp_compute_message_integrity_check(NTLMSSP* ntlmssp)
{
HMAC_CTX hmac_ctx;
- /*
+ /*
* Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE,
* CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey
*/
@@ -1193,11 +1193,14 @@ void ntlmssp_encrypt_message(NTLMSSP* ntlmssp, rdpBlob* msg, rdpBlob* encrypted_
HMAC_Update(&hmac_ctx, msg->data, msg->length);
HMAC_Final(&hmac_ctx, digest, NULL);
- /* Allocate space for encrypted message */
- freerdp_blob_alloc(encrypted_msg, msg->length);
+ if (encrypted_msg != NULL)
+ {
+ /* Allocate space for encrypted message */
+ freerdp_blob_alloc(encrypted_msg, msg->length);
- /* Encrypt message using with RC4 */
- crypto_rc4(ntlmssp->send_rc4_seal, msg->length, msg->data, encrypted_msg->data);
+ /* Encrypt message using with RC4 */
+ crypto_rc4(ntlmssp->send_rc4_seal, msg->length, msg->data, encrypted_msg->data);
+ }
/* RC4-encrypt first 8 bytes of digest */
crypto_rc4(ntlmssp->send_rc4_seal, 8, digest, checksum);
@@ -1661,7 +1664,7 @@ void ntlmssp_send_authenticate_message(NTLMSSP* ntlmssp, STREAM* s)
#ifdef WITH_DEBUG_NLA
ntlmssp_print_negotiate_flags(negotiateFlags);
#endif
-
+
if (negotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{
/* Only present if NTLMSSP_NEGOTIATE_VERSION is set */
@@ -1758,7 +1761,7 @@ void ntlmssp_send_authenticate_message(NTLMSSP* ntlmssp, STREAM* s)
{
/* Message Integrity Check */
ntlmssp_compute_message_integrity_check(ntlmssp);
-
+
s->p = mic_offset;
stream_write(s, ntlmssp->message_integrity_check, 16);
s->p = s->data + length;
@@ -1790,12 +1793,10 @@ int ntlmssp_send(NTLMSSP* ntlmssp, STREAM* s)
{
if (ntlmssp->state == NTLMSSP_STATE_INITIAL)
ntlmssp->state = NTLMSSP_STATE_NEGOTIATE;
-
if (ntlmssp->state == NTLMSSP_STATE_NEGOTIATE)
ntlmssp_send_negotiate_message(ntlmssp, s);
else if (ntlmssp->state == NTLMSSP_STATE_AUTHENTICATE)
ntlmssp_send_authenticate_message(ntlmssp, s);
-
return (ntlmssp->state == NTLMSSP_STATE_FINAL) ? 0 : 1;
}
diff --git a/libfreerdp-core/orders.c b/libfreerdp-core/orders.c
index 78c8e10..424307f 100644
--- a/libfreerdp-core/orders.c
+++ b/libfreerdp-core/orders.c
@@ -24,6 +24,12 @@
#include "orders.h"
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
#ifdef WITH_DEBUG_ORDERS
static const char* const PRIMARY_DRAWING_ORDER_STRINGS[] =
@@ -1689,6 +1695,8 @@ void update_recv_primary_order(rdpUpdate* update, STREAM* s, uint8 flags)
rdpContext* context = update->context;
rdpPrimaryUpdate* primary = update->primary;
+ LLOGLN(10, ("update_recv_primary_order:"));
+
orderInfo = &(primary->order_info);
if (flags & ORDER_TYPE_CHANGE)
@@ -1717,116 +1725,139 @@ void update_recv_primary_order(rdpUpdate* update, STREAM* s, uint8 flags)
switch (orderInfo->orderType)
{
case ORDER_TYPE_DSTBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_DSTBLT"));
update_read_dstblt_order(s, orderInfo, &(primary->dstblt));
IFCALL(primary->DstBlt, context, &primary->dstblt);
break;
case ORDER_TYPE_PATBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_PATBLT"));
update_read_patblt_order(s, orderInfo, &(primary->patblt));
IFCALL(primary->PatBlt, context, &primary->patblt);
break;
case ORDER_TYPE_SCRBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_SCRBLT"));
update_read_scrblt_order(s, orderInfo, &(primary->scrblt));
IFCALL(primary->ScrBlt, context, &primary->scrblt);
break;
case ORDER_TYPE_OPAQUE_RECT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_OPAQUE_RECT"));
update_read_opaque_rect_order(s, orderInfo, &(primary->opaque_rect));
IFCALL(primary->OpaqueRect, context, &primary->opaque_rect);
break;
case ORDER_TYPE_DRAW_NINE_GRID:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_DRAW_NINE_GRID"));
update_read_draw_nine_grid_order(s, orderInfo, &(primary->draw_nine_grid));
IFCALL(primary->DrawNineGrid, context, &primary->draw_nine_grid);
break;
case ORDER_TYPE_MULTI_DSTBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MULTI_DSTBLT"));
update_read_multi_dstblt_order(s, orderInfo, &(primary->multi_dstblt));
IFCALL(primary->MultiDstBlt, context, &primary->multi_dstblt);
break;
case ORDER_TYPE_MULTI_PATBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MULTI_PATBLT"));
update_read_multi_patblt_order(s, orderInfo, &(primary->multi_patblt));
IFCALL(primary->MultiPatBlt, context, &primary->multi_patblt);
break;
case ORDER_TYPE_MULTI_SCRBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MULTI_SCRBLT"));
update_read_multi_scrblt_order(s, orderInfo, &(primary->multi_scrblt));
IFCALL(primary->MultiScrBlt, context, &primary->multi_scrblt);
break;
case ORDER_TYPE_MULTI_OPAQUE_RECT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MULTI_OPAQUE_RECT"));
update_read_multi_opaque_rect_order(s, orderInfo, &(primary->multi_opaque_rect));
IFCALL(primary->MultiOpaqueRect, context, &primary->multi_opaque_rect);
break;
case ORDER_TYPE_MULTI_DRAW_NINE_GRID:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MULTI_DRAW_NINE_GRID"));
update_read_multi_draw_nine_grid_order(s, orderInfo, &(primary->multi_draw_nine_grid));
IFCALL(primary->MultiDrawNineGrid, context, &primary->multi_draw_nine_grid);
break;
case ORDER_TYPE_LINE_TO:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_LINE_TO"));
update_read_line_to_order(s, orderInfo, &(primary->line_to));
IFCALL(primary->LineTo, context, &primary->line_to);
break;
case ORDER_TYPE_POLYLINE:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_POLYLINE"));
update_read_polyline_order(s, orderInfo, &(primary->polyline));
IFCALL(primary->Polyline, context, &primary->polyline);
break;
case ORDER_TYPE_MEMBLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MEMBLT"));
update_read_memblt_order(s, orderInfo, &(primary->memblt));
IFCALL(primary->MemBlt, context, &primary->memblt);
break;
case ORDER_TYPE_MEM3BLT:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_MEM3BLT"));
update_read_mem3blt_order(s, orderInfo, &(primary->mem3blt));
IFCALL(primary->Mem3Blt, context, &primary->mem3blt);
break;
case ORDER_TYPE_SAVE_BITMAP:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_SAVE_BITMAP"));
update_read_save_bitmap_order(s, orderInfo, &(primary->save_bitmap));
IFCALL(primary->SaveBitmap, context, &primary->save_bitmap);
break;
case ORDER_TYPE_GLYPH_INDEX:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_GLYPH_INDEX"));
update_read_glyph_index_order(s, orderInfo, &(primary->glyph_index));
IFCALL(primary->GlyphIndex, context, &primary->glyph_index);
break;
case ORDER_TYPE_FAST_INDEX:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_FAST_INDEX"));
update_read_fast_index_order(s, orderInfo, &(primary->fast_index));
IFCALL(primary->FastIndex, context, &primary->fast_index);
break;
case ORDER_TYPE_FAST_GLYPH:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_FAST_GLYPH"));
update_read_fast_glyph_order(s, orderInfo, &(primary->fast_glyph));
IFCALL(primary->FastGlyph, context, &primary->fast_glyph);
break;
case ORDER_TYPE_POLYGON_SC:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_POLYGON_SC"));
update_read_polygon_sc_order(s, orderInfo, &(primary->polygon_sc));
IFCALL(primary->PolygonSC, context, &primary->polygon_sc);
break;
case ORDER_TYPE_POLYGON_CB:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_POLYGON_CB"));
update_read_polygon_cb_order(s, orderInfo, &(primary->polygon_cb));
IFCALL(primary->PolygonCB, context, &primary->polygon_cb);
break;
case ORDER_TYPE_ELLIPSE_SC:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_ELLIPSE_SC"));
update_read_ellipse_sc_order(s, orderInfo, &(primary->ellipse_sc));
IFCALL(primary->EllipseSC, context, &primary->ellipse_sc);
break;
case ORDER_TYPE_ELLIPSE_CB:
+ LLOGLN(10, ("update_recv_primary_order: ORDER_TYPE_ELLIPSE_CB"));
update_read_ellipse_cb_order(s, orderInfo, &(primary->ellipse_cb));
IFCALL(primary->EllipseCB, context, &primary->ellipse_cb);
break;
default:
+ LLOGLN(10, ("update_recv_primary_order: unknown order %d", orderInfo->orderType));
break;
}
@@ -1845,6 +1876,8 @@ void update_recv_secondary_order(rdpUpdate* update, STREAM* s, uint8 flags)
rdpContext* context = update->context;
rdpSecondaryUpdate* secondary = update->secondary;
+ LLOGLN(10, ("update_recv_secondary_order:"));
+
stream_read_uint16(s, orderLength); /* orderLength (2 bytes) */
stream_read_uint16(s, extraFlags); /* extraFlags (2 bytes) */
stream_read_uint8(s, orderType); /* orderType (1 byte) */
@@ -1921,6 +1954,7 @@ void update_recv_altsec_order(rdpUpdate* update, STREAM* s, uint8 flags)
rdpContext* context = update->context;
rdpAltSecUpdate* altsec = update->altsec;
+ LLOGLN(10, ("update_recv_altsec_order:"));
orderType = flags >>= 2; /* orderType is in higher 6 bits of flags field */
#ifdef WITH_DEBUG_ORDERS
@@ -2008,12 +2042,22 @@ void update_recv_order(rdpUpdate* update, STREAM* s)
{
uint8 controlFlags;
+ LLOGLN(10, ("update_recv_order:"));
stream_read_uint8(s, controlFlags); /* controlFlags (1 byte) */
if (!(controlFlags & ORDER_STANDARD))
+ {
+ LLOGLN(10, ("update_recv_order: calling update_recv_altsec_order"));
update_recv_altsec_order(update, s, controlFlags);
+ }
else if (controlFlags & ORDER_SECONDARY)
+ {
+ LLOGLN(10, ("update_recv_order: calling update_recv_secondary_order"));
update_recv_secondary_order(update, s, controlFlags);
+ }
else
+ {
+ LLOGLN(10, ("update_recv_order: calling update_recv_primary_order"));
update_recv_primary_order(update, s, controlFlags);
+ }
}
diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c
index 2f96acb..334cb12 100644
--- a/libfreerdp-core/peer.c
+++ b/libfreerdp-core/peer.c
@@ -19,337 +19,20 @@
#include "peer.h"
-static tbool freerdp_peer_initialize(freerdp_peer* client)
-{
- client->context->rdp->settings->server_mode = true;
- client->context->rdp->state = CONNECTION_STATE_INITIAL;
- if (client->context->rdp->settings->rdp_key_file != NULL) {
- client->context->rdp->settings->server_key =
- key_new(client->context->rdp->settings->rdp_key_file);
- }
-
- return true;
-}
-
-static tbool freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
-{
- rfds[*rcount] = (void*)(long)(client->context->rdp->transport->tcp->sockfd);
- (*rcount)++;
-
- return true;
-}
-
-static tbool freerdp_peer_check_fds(freerdp_peer* client)
-{
- rdpRdp* rdp;
- int status;
-
- rdp = client->context->rdp;
-
- status = rdp_check_fds(rdp);
- if (status < 0)
- return false;
-
- return true;
-}
-
-static tbool peer_recv_data_pdu(freerdp_peer* client, STREAM* s)
-{
- uint8 type;
- uint16 length;
- uint32 share_id;
- uint8 compressed_type;
- uint16 compressed_len;
-
-
- if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len))
- return false;
-
- switch (type)
- {
- case DATA_PDU_TYPE_SYNCHRONIZE:
- if (!rdp_recv_client_synchronize_pdu(client->context->rdp, s))
- return false;
- break;
-
- case DATA_PDU_TYPE_CONTROL:
- if (!rdp_server_accept_client_control_pdu(client->context->rdp, s))
- return false;
- break;
-
- case DATA_PDU_TYPE_INPUT:
- if (!input_recv(client->context->rdp->input, s))
- return false;
- break;
-
- case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST:
- /* TODO: notify server bitmap cache data */
- break;
-
- case DATA_PDU_TYPE_FONT_LIST:
- if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s))
- return false;
- if (client->PostConnect)
- {
- if (!client->PostConnect(client))
- return false;
- /**
- * PostConnect should only be called once and should not be called
- * after a reactivation sequence.
- */
- client->PostConnect = NULL;
- }
- if (client->Activate)
- {
- /* Activate will be called everytime after the client is activated/reactivated. */
- if (!client->Activate(client))
- return false;
- }
- break;
-
- case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
- mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs);
- return false;
-
- default:
- printf("Data PDU type %d\n", type);
- break;
- }
-
- return true;
-}
-
-static tbool peer_recv_tpkt_pdu(freerdp_peer* client, STREAM* s)
-{
- rdpRdp *rdp;
- uint16 length;
- uint16 pduType;
- uint16 pduLength;
- uint16 pduSource;
- uint16 channelId;
- uint16 securityFlags;
-
- rdp = client->context->rdp;
-
- if (!rdp_read_header(rdp, s, &length, &channelId))
- {
- printf("Incorrect RDP header.\n");
- return false;
- }
-
- if (rdp->settings->encryption)
- {
- rdp_read_security_header(s, &securityFlags);
- if (securityFlags & SEC_ENCRYPT)
- {
- if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
- {
- printf("rdp_decrypt failed\n");
- return false;
- }
- }
- }
-
- if (channelId != MCS_GLOBAL_CHANNEL_ID)
- {
- freerdp_channel_peer_process(client, s, channelId);
- }
- else
- {
- if (!rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource))
- return false;
-
- client->settings->pdu_source = pduSource;
-
- switch (pduType)
- {
- case PDU_TYPE_DATA:
- if (!peer_recv_data_pdu(client, s))
- return false;
- break;
-
- default:
- printf("Client sent pduType %d\n", pduType);
- return false;
- }
- }
-
- return true;
-}
-
-static tbool peer_recv_fastpath_pdu(freerdp_peer* client, STREAM* s)
-{
- uint16 length;
- rdpRdp* rdp;
- rdpFastPath* fastpath;
-
- rdp = client->context->rdp;
- fastpath = rdp->fastpath;
- length = fastpath_read_header_rdp(fastpath, s);
-
- if (length == 0 || length > stream_get_left(s))
- {
- printf("incorrect FastPath PDU header length %d\n", length);
- return false;
- }
-
- if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
- {
- rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0);
- }
-
- return fastpath_recv_inputs(fastpath, s);
-}
-
-static tbool peer_recv_pdu(freerdp_peer* client, STREAM* s)
-{
- if (tpkt_verify_header(s))
- return peer_recv_tpkt_pdu(client, s);
- else
- return peer_recv_fastpath_pdu(client, s);
-}
-
-static tbool peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
-{
- freerdp_peer* client = (freerdp_peer*) extra;
-
- switch (client->context->rdp->state)
- {
- case CONNECTION_STATE_INITIAL:
- if (!rdp_server_accept_nego(client->context->rdp, s))
- return false;
- break;
-
- case CONNECTION_STATE_NEGO:
- if (!rdp_server_accept_mcs_connect_initial(client->context->rdp, s))
- return false;
- break;
-
- case CONNECTION_STATE_MCS_CONNECT:
- if (!rdp_server_accept_mcs_erect_domain_request(client->context->rdp, s))
- return false;
- break;
-
- case CONNECTION_STATE_MCS_ERECT_DOMAIN:
- if (!rdp_server_accept_mcs_attach_user_request(client->context->rdp, s))
- return false;
- break;
-
- case CONNECTION_STATE_MCS_ATTACH_USER:
- if (!rdp_server_accept_mcs_channel_join_request(client->context->rdp, s))
- return false;
- break;
-
- case CONNECTION_STATE_MCS_CHANNEL_JOIN:
- if (client->context->rdp->settings->encryption) {
- if (!rdp_server_accept_client_keys(client->context->rdp, s))
- return false;
- break;
- }
- client->context->rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
- /* FALLTHROUGH */
-
- case CONNECTION_STATE_ESTABLISH_KEYS:
- if (!rdp_server_accept_client_info(client->context->rdp, s))
- return false;
- IFCALL(client->Capabilities, client);
- if (!rdp_send_demand_active(client->context->rdp))
- return false;
- break;
-
- case CONNECTION_STATE_LICENSE:
- if (!rdp_server_accept_confirm_active(client->context->rdp, s))
- {
- /**
- * During reactivation sequence the client might sent some input or channel data
- * before receiving the Deactivate All PDU. We need to process them as usual.
- */
- stream_set_pos(s, 0);
- return peer_recv_pdu(client, s);
- }
- break;
-
- case CONNECTION_STATE_ACTIVE:
- if (!peer_recv_pdu(client, s))
- return false;
- break;
-
- default:
- printf("Invalid state %d\n", client->context->rdp->state);
- return false;
- }
-
- return true;
-}
-
-static void freerdp_peer_disconnect(freerdp_peer* client)
-{
- transport_disconnect(client->context->rdp->transport);
-}
-
-static int freerdp_peer_send_channel_data(freerdp_peer* client, int channelId, uint8* data, int size)
-{
- return rdp_send_channel_data(client->context->rdp, channelId, data, size);
-}
-
void freerdp_peer_context_new(freerdp_peer* client)
{
- rdpRdp* rdp;
-
- rdp = rdp_new(NULL);
- client->input = rdp->input;
- client->update = rdp->update;
- client->settings = rdp->settings;
-
- client->context = (rdpContext*) xzalloc(client->context_size);
- client->context->rdp = rdp;
- client->context->peer = client;
-
- client->update->context = client->context;
- client->input->context = client->context;
-
- update_register_server_callbacks(client->update);
-
- transport_attach(rdp->transport, client->sockfd);
-
- rdp->transport->recv_callback = peer_recv_callback;
- rdp->transport->recv_extra = client;
- transport_set_blocking_mode(rdp->transport, false);
-
- IFCALL(client->ContextNew, client, client->context);
}
void freerdp_peer_context_free(freerdp_peer* client)
{
- IFCALL(client->ContextFree, client, client->context);
}
freerdp_peer* freerdp_peer_new(int sockfd)
{
- freerdp_peer* client;
-
- client = xnew(freerdp_peer);
-
- if (client != NULL)
- {
- client->sockfd = sockfd;
- client->context_size = sizeof(rdpContext);
- client->Initialize = freerdp_peer_initialize;
- client->GetFileDescriptor = freerdp_peer_get_fds;
- client->CheckFileDescriptor = freerdp_peer_check_fds;
- client->Disconnect = freerdp_peer_disconnect;
- client->SendChannelData = freerdp_peer_send_channel_data;
- }
-
- return client;
+ return 0;
}
void freerdp_peer_free(freerdp_peer* client)
{
- if (client)
- {
- rdp_free(client->context->rdp);
- xfree(client);
- }
}
diff --git a/libfreerdp-core/per.c b/libfreerdp-core/per.c
index 4365cb2..f85514c 100644
--- a/libfreerdp-core/per.c
+++ b/libfreerdp-core/per.c
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -30,10 +30,18 @@ tbool per_read_length(STREAM* s, uint16* length)
{
uint8 byte;
+ if (stream_get_left(s) < 1)
+ {
+ return false;
+ }
stream_read_uint8(s, byte);
if (byte & 0x80)
{
+ if (stream_get_left(s) < 1)
+ {
+ return false;
+ }
byte &= ~(0x80);
*length = (byte << 8);
stream_read_uint8(s, byte);
@@ -250,12 +258,11 @@ void per_write_integer16(STREAM* s, uint16 integer, uint16 min)
tbool per_read_enumerated(STREAM* s, uint8* enumerated, uint8 count)
{
- stream_read_uint8(s, *enumerated);
-
- /* check that enumerated value falls within expected range */
- if (*enumerated + 1 > count)
+ if (stream_get_left(s) < 1)
+ {
return false;
-
+ }
+ stream_read_uint8(s, *enumerated);
return true;
}
diff --git a/libfreerdp-core/rdp.c b/libfreerdp-core/rdp.c
index 621abf3..0b0480e 100644
--- a/libfreerdp-core/rdp.c
+++ b/libfreerdp-core/rdp.c
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -23,6 +23,12 @@
#include "per.h"
#include "redirection.h"
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
static const char* const DATA_PDU_TYPE_STRINGS[] =
{
"", "", /* 0x00 - 0x01 */
@@ -219,34 +225,50 @@ STREAM* rdp_data_pdu_init(rdpRdp* rdp)
tbool rdp_read_header(rdpRdp* rdp, STREAM* s, uint16* length, uint16* channel_id)
{
+ uint8 reason;
uint16 initiator;
enum DomainMCSPDU MCSPDU;
MCSPDU = (rdp->settings->server_mode) ? DomainMCSPDU_SendDataRequest : DomainMCSPDU_SendDataIndication;
- mcs_read_domain_mcspdu_header(s, &MCSPDU, length);
-
+ if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, length))
+ {
+ LLOGLN(0, ("rdp_read_header: mcs_read_domain_mcspdu_header failed"));
+ return false;
+ }
if (*length - 8 > stream_get_left(s))
+ {
+ LLOGLN(0, ("rdp_read_header: parse error"));
return false;
-
+ }
if (MCSPDU == DomainMCSPDU_DisconnectProviderUltimatum)
{
- uint8 reason;
-
- (void) per_read_enumerated(s, &reason, 0);
-
+ if (!per_read_enumerated(s, &reason, 0))
+ {
+ LLOGLN(0, ("rdp_read_header: per_read_enumerated failed"));
+ return false;
+ }
rdp->disconnect = true;
-
+ *channel_id = MCS_GLOBAL_CHANNEL_ID;
return true;
}
-
+ if (stream_get_left(s) < 5)
+ {
+ LLOGLN(0, ("rdp_read_header: parse error"));
+ return false;
+ }
per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
per_read_integer16(s, channel_id, 0); /* channelId */
stream_seek(s, 1); /* dataPriority + Segmentation (0x70) */
- per_read_length(s, length); /* userData (OCTET_STRING) */
-
+ if (!per_read_length(s, length)) /* userData (OCTET_STRING) */
+ {
+ LLOGLN(0, ("rdp_read_header: per_read_length failed"));
+ return false;
+ }
if (*length > stream_get_left(s))
+ {
return false;
-
+ LLOGLN(0, ("rdp_read_header: parse error"));
+ }
return true;
}
@@ -484,14 +506,16 @@ tbool rdp_recv_data_pdu(rdpRdp* rdp, STREAM* s)
}
else
{
- printf("decompress_rdp() failed\n");
+ LLOGLN(0, ("decompress_rdp() failed"));
return false;
}
}
#ifdef WITH_DEBUG_RDP
if (type != DATA_PDU_TYPE_UPDATE)
- printf("recv %s Data PDU (0x%02X), length:%d\n", DATA_PDU_TYPE_STRINGS[type], type, length);
+ {
+ LLOGLN(0, ("recv %s Data PDU (0x%02X), length:%d", DATA_PDU_TYPE_STRINGS[type], type, length));
+ }
#endif
switch (type)
@@ -595,6 +619,7 @@ tbool rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, STREAM* s)
uint16 length;
uint16 channelId;
+ LLOGLN(0, ("rdp_recv_out_of_sequence_pdu:"));
rdp_read_share_control_header(s, &length, &type, &channelId);
if (type == PDU_TYPE_DATA)
@@ -623,6 +648,7 @@ tbool rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags)
{
uint8 cmac[8], wmac[8];
+ LLOGLN(10, ("rdp_decrypt:"));
if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
{
uint16 len;
@@ -634,19 +660,19 @@ tbool rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags)
stream_read_uint8(s, pad);
sig = s->p;
- stream_seek(s, 8); /* signature */
+ stream_seek(s, 8); /* signature */
length -= 12;
if (!security_fips_decrypt(s->p, length, rdp))
{
- printf("FATAL: cannot decrypt\n");
+ LLOGLN(0, ("FATAL: cannot decrypt"));
return false; /* TODO */
}
if (!security_fips_check_signature(s->p, length - pad, sig, rdp))
{
- printf("FATAL: invalid packet signature\n");
+ LLOGLN(0, ("FATAL: invalid packet signature FIPS"));
return false; /* TODO */
}
@@ -659,12 +685,16 @@ tbool rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags)
length -= sizeof(wmac);
security_decrypt(s->p, length, rdp);
if (securityFlags & SEC_SECURE_CHECKSUM)
+ {
security_salted_mac_signature(rdp, s->p, length, false, cmac);
+ }
else
+ {
security_mac_signature(rdp, s->p, length, cmac);
+ }
if (memcmp(wmac, cmac, sizeof(wmac)) != 0)
{
- printf("WARNING: invalid packet signature\n");
+ LLOGLN(0, ("WARNING: invalid packet signature non-FIPS"));
/*
* Because Standard RDP Security is totally broken,
* and cannot protect against MITM, don't treat signature
@@ -674,6 +704,10 @@ tbool rdp_decrypt(rdpRdp* rdp, STREAM* s, int length, uint16 securityFlags)
*/
//return false;
}
+ else
+ {
+ LLOGLN(10, ("rdp_decrypt: signature ok"));
+ }
return true;
}
@@ -693,25 +727,34 @@ static tbool rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
uint16 securityFlags;
uint8* nextp;
+ LLOGLN(10, ("rdp_recv_tpkt_pdu:"));
if (!rdp_read_header(rdp, s, &length, &channelId))
{
- printf("Incorrect RDP header.\n");
+ LLOGLN(0, ("Incorrect RDP header."));
+ return false;
+ }
+ LLOGLN(10, ("rdp_recv_tpkt_pdu: length %d", length));
+ if (rdp->disconnect)
+ {
+ LLOGLN(0, ("rdp_recv_tpkt_pdu: disconnect"));
return false;
}
if (rdp->settings->encryption)
{
rdp_read_security_header(s, &securityFlags);
- if (securityFlags & (SEC_ENCRYPT|SEC_REDIRECTION_PKT))
+ LLOGLN(10, ("rdp_recv_tpkt_pdu: securityFlags 0x%8.8x", securityFlags));
+ if (securityFlags & (SEC_ENCRYPT | SEC_REDIRECTION_PKT))
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
- printf("rdp_decrypt failed\n");
+ LLOGLN(0, ("rdp_decrypt failed"));
return false;
}
}
if (securityFlags & SEC_REDIRECTION_PKT)
{
+ LLOGLN(0, ("rdp_recv_tpkt_pdu: got SEC_REDIRECTION_PKT securityFlags 0x%8.8x", securityFlags));
/*
* [MS-RDPBCGR] 2.2.13.2.1
* - no share control header, nor the 2 byte pad
@@ -741,7 +784,7 @@ static tbool rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
case PDU_TYPE_DATA:
if (!rdp_recv_data_pdu(rdp, s))
{
- printf("rdp_recv_data_pdu failed\n");
+ LLOGLN(0, ("rdp_recv_data_pdu failed"));
return false;
}
break;
@@ -756,7 +799,7 @@ static tbool rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
break;
default:
- printf("incorrect PDU type: 0x%04X\n", pduType);
+ LLOGLN(0, ("incorrect PDU type: 0x%04X", pduType));
break;
}
stream_set_mark(s, nextp);
@@ -769,20 +812,27 @@ static tbool rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
static tbool rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
{
uint16 length;
+ uint16 securityFlags;
rdpFastPath* fastpath;
+ LLOGLN(10, ("rdp_recv_fastpath_pdu:"));
+ LHEXDUMP(10, (s->p, 4));
fastpath = rdp->fastpath;
length = fastpath_read_header_rdp(fastpath, s);
+ LLOGLN(10, ("rdp_recv_fastpath_pdu: length %d", length));
if (length == 0 || length > stream_get_left(s))
{
- printf("incorrect FastPath PDU header length %d\n", length);
+ LLOGLN(0, ("rdp_recv_fastpath_pdu: incorrect FastPath PDU header length %d", length));
return false;
}
if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED)
{
- rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0);
+ securityFlags = fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM ? SEC_SECURE_CHECKSUM : 0;
+ rdp_decrypt(rdp, s, length, securityFlags);
+ LLOGLN(10, ("rdp_recv_fastpath_pdu: decrypted data length %d", length));
+ LHEXDUMP(10, (s->p, length));
}
return fastpath_recv_updates(rdp->fastpath, s);
@@ -790,10 +840,17 @@ static tbool rdp_recv_fastpath_pdu(rdpRdp* rdp, STREAM* s)
static tbool rdp_recv_pdu(rdpRdp* rdp, STREAM* s)
{
+ LLOGLN(10, ("rdp_recv_pdu:"));
if (tpkt_verify_header(s))
+ {
+ LLOGLN(10, ("rdp_recv_pdu: tpkt"));
return rdp_recv_tpkt_pdu(rdp, s);
+ }
else
+ {
+ LLOGLN(10, ("rdp_recv_pdu: fast path"));
return rdp_recv_fastpath_pdu(rdp, s);
+ }
}
/**
@@ -815,6 +872,7 @@ static tbool rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
{
rdpRdp* rdp = (rdpRdp*) extra;
+ LLOGLN(10, ("rdp_recv_callback: state %d", rdp->state));
switch (rdp->state)
{
case CONNECTION_STATE_NEGO:
@@ -840,7 +898,7 @@ static tbool rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
case CONNECTION_STATE_CAPABILITY:
if (!rdp_client_connect_demand_active(rdp, s))
{
- printf("rdp_client_connect_demand_active failed\n");
+ LLOGLN(0, ("rdp_client_connect_demand_active failed"));
return false;
}
break;
@@ -858,7 +916,7 @@ static tbool rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
break;
default:
- printf("Invalid state %d\n", rdp->state);
+ LLOGLN(0, ("Invalid state %d", rdp->state));
return false;
}
@@ -911,7 +969,7 @@ int rdp_send_suppress_output(rdpRdp* rdp, int code, int x, int y, int w, int h)
case 0: /* shut the server up */
break;
case 1: /* receive data again */
- printf("x %d y %d w %d h %d\n", x, y, w, h);
+ LLOGLN(0, ("x %d y %d w %d h %d", x, y, w, h));
stream_write_uint16(s, x);
stream_write_uint16(s, y);
stream_write_uint16(s, w);
@@ -923,7 +981,7 @@ int rdp_send_suppress_output(rdpRdp* rdp, int code, int x, int y, int w, int h)
}
/**
- * Set non-blocking mode information.
+ * Set non- mode information.
* @param rdp RDP module
* @param blocking blocking mode
*/
@@ -936,6 +994,7 @@ void rdp_set_blocking_mode(rdpRdp* rdp, tbool blocking)
int rdp_check_fds(rdpRdp* rdp)
{
+ LLOGLN(10, ("rdp_check_fds:"));
return transport_check_fds(rdp->transport);
}
diff --git a/libfreerdp-core/redirection.c b/libfreerdp-core/redirection.c
index aac3429..4a81b4e 100644
--- a/libfreerdp-core/redirection.c
+++ b/libfreerdp-core/redirection.c
@@ -169,6 +169,7 @@ tbool rdp_recv_redirection_packet(rdpRdp* rdp, STREAM* s)
tbool rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, STREAM* s)
{
+ printf("rdp_recv_enhanced_security_redirection_packet:\n");
stream_seek_uint16(s); /* pad2Octets (2 bytes) */
rdp_recv_server_redirection_pdu(rdp, s);
stream_seek_uint8(s); /* pad2Octets (1 byte) */
diff --git a/libfreerdp-core/rpch.c b/libfreerdp-core/rpch.c
new file mode 100644
index 0000000..6c060e2
--- /dev/null
+++ b/libfreerdp-core/rpch.c
@@ -0,0 +1,1654 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * RDP Security
+ *
+ * Copyright 2012 Fujitsu Technology Solutions GmbH -
+ * Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
+ * Copyright 2014 Jay Sorg <jay.sorg@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.
+ *
+ * http://msdn.microsoft.com/en-us/library/cc243950.aspx
+ *
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/rand.h>
+
+#include "rpch.h"
+
+#define HTTP_STREAM_SIZE 0xFFFF
+
+//#define WITH_DEBUG_RPCH 1
+
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+
+rdpRpch* rpch_new(rdpSettings* settings)
+{
+ rdpRpch* rpch;
+ rpch = (rdpRpch*) xzalloc(sizeof(rdpRpch));
+
+ rpch->http_in = (rdpRpchHTTP*) xzalloc(sizeof(rdpRpchHTTP));
+ rpch->http_out = (rdpRpchHTTP*) xzalloc(sizeof(rdpRpchHTTP));
+
+ rpch->http_in->ntht = ntlmssp_new();
+ rpch->http_out->ntht = ntlmssp_new();
+ rpch->http_in->state = RPCH_HTTP_DISCONNECTED;
+ rpch->http_out->state = RPCH_HTTP_DISCONNECTED;
+
+ rpch->read_buffer = NULL;
+ rpch->write_buffer = NULL;
+ rpch->read_buffer_len = 0;
+ rpch->write_buffer_len = 0;
+
+ rpch->BytesReceived = 0;
+ rpch->AwailableWindow = 0;
+ rpch->BytesSent = 0;
+ rpch->RecAwailableWindow = 0;
+
+ rpch->settings = settings;
+
+ rpch->ntlmssp = ntlmssp_new();
+
+ rpch->call_id = 0;
+ return rpch;
+}
+
+tbool rpch_attach(rdpRpch* rpch, rdpTcp* tcp_in, rdpTcp* tcp_out, rdpTls* tls_in, rdpTls* tls_out)
+{
+ rpch->tcp_in = tcp_in;
+ rpch->tcp_out = tcp_out;
+ rpch->tls_in = tls_in;
+ rpch->tls_out = tls_out;
+
+ return true;
+}
+
+int force_read(rdpTls* tls, uint8* data, int bytes)
+{
+ int total_read;
+ int read;
+
+ LLOGLN(10, ("force_read:"));
+ total_read = 0;
+ while (total_read < bytes)
+ {
+ LLOGLN(10, ("force_read: reading %d bytes", bytes - total_read));
+ read = tls_read(tls, data + total_read, bytes - total_read);
+ if (read < 0)
+ {
+ /* disconnect or other error */
+ return -1;
+ }
+ if (read == 0)
+ {
+ LLOGLN(0, ("force_read: read == 0, sleeping and reading again"));
+ tcp_can_recv(tls->sockfd, 100);
+ continue;
+ }
+ total_read += read;
+ }
+ return total_read;
+}
+
+STREAM * read_http(rdpTls* tls, int* acontent_length, tbool read_content)
+{
+ uint8 buf[1024];
+ tbool done;
+ int bytes;
+ int offset;
+ int processed;
+ int content_length;
+ STREAM* s;
+ char mark[4];
+ char cc;
+ char* find_text;
+
+ mark[0] = 0;
+ mark[1] = 0;
+ mark[2] = 0;
+ mark[3] = 0;
+ s = stream_new(64 * 1024);
+ bytes = 0;
+ offset = 0;
+ processed = 0;
+ done = false;
+ while (!done)
+ {
+ if (bytes < 1)
+ {
+ offset = 0;
+ LLOGLN(0, ("read_http: reading 1024"));
+ bytes = tls_read(tls, buf, 1024);
+ if (bytes < 0)
+ {
+ LLOGLN(0, ("read_http: tls_read failed"));
+ stream_free(s);
+ return NULL;
+ }
+ if (bytes == 0)
+ {
+ tcp_can_recv(tls->sockfd, 100);
+ continue;
+ }
+ }
+ cc = buf[offset];
+ processed++;
+ offset++;
+ bytes--;
+ mark[0] = mark[1];
+ mark[1] = mark[2];
+ mark[2] = mark[3];
+ mark[3] = cc;
+ stream_write_uint8(s, cc);
+ if ((mark[2] == '\n') && (mark[3] == '\n'))
+ {
+ done = true;
+ continue;
+ }
+ if ((mark[0] == '\r') && (mark[1] == '\n') &&
+ (mark[2] == '\r') && (mark[3] == '\n'))
+ {
+ done = true;
+ continue;
+ }
+ }
+
+ LLOGLN(0, ("read_http: bytes %d offset %d", bytes, offset));
+ tls_return(tls, buf + offset, bytes);
+
+ find_text = strstr((char*)(s->data), "Content-Length:");
+ if (find_text == NULL)
+ {
+ LLOGLN(0, ("read_http: can not fine 'Content-Length:' in http"));
+ stream_free(s);
+ return NULL;
+ }
+ offset = 15;
+ while (find_text[offset] == ' ')
+ {
+ offset++;
+ }
+ content_length = atoi(find_text + offset);
+ if (acontent_length != NULL)
+ {
+ *acontent_length = content_length;
+ }
+ if (content_length > 0 && read_content)
+ {
+ while (content_length > 0)
+ {
+ bytes = tls_read(tls, s->p, content_length);
+ if (bytes < 0)
+ {
+ LLOGLN(0, ("read_http: tls_read failed"));
+ stream_free(s);
+ return NULL;
+ }
+ if (bytes == 0)
+ {
+ tcp_can_recv(tls->sockfd, 100);
+ continue;
+ }
+ s->p += bytes;
+ content_length -= bytes;
+ }
+ }
+
+ return s;
+}
+
+tbool rpch_out_connect_http(rdpRpch* rpch)
+{
+ rdpTls* tls_out = rpch->tls_out;
+ rdpSettings* settings = rpch->settings;
+ rdpRpchHTTP* http_out = rpch->http_out;
+ NTLMSSP* http_out_ntlmssp = http_out->ntht;
+
+ STREAM* ntlmssp_stream;
+ STREAM* http_stream;
+
+ int decoded_ntht_length;
+ int encoded_ntht_length = 0;
+ int bytes;
+
+ char* ntlm_text;
+
+ LLOGLN(10, ("rpch_out_connect_http:"));
+
+ uint8* decoded_ntht_data;
+ uint8* encoded_ntht_data = NULL;
+
+ ntlmssp_stream = stream_new(0xFFFF);
+ http_stream = stream_new(0xFFFF);
+
+ ntlmssp_set_username(http_out_ntlmssp, settings->tsg_username);
+ ntlmssp_set_password(http_out_ntlmssp, settings->tsg_password);
+ ntlmssp_set_domain(http_out_ntlmssp, settings->tsg_domain);
+ ntlmssp_set_workstation(http_out_ntlmssp, "WORKSTATION"); /* TODO insert proper w.name */
+
+ LLOGLN(10, ("rpch_out_connect_http: tsg_username %s tsg_password %s tsg_domain %s",
+ settings->tsg_username, settings->tsg_password, settings->tsg_domain));
+
+ ntlmssp_send(http_out_ntlmssp, ntlmssp_stream);
+
+ decoded_ntht_length = (int) (ntlmssp_stream->p - ntlmssp_stream->data);
+ decoded_ntht_data = (uint8*) xmalloc(decoded_ntht_length);
+
+ ntlmssp_stream->p = ntlmssp_stream->data;
+ stream_read(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ crypto_base64_encode(decoded_ntht_data, decoded_ntht_length, &encoded_ntht_data, &encoded_ntht_length);
+
+ stream_write(http_stream, "RPC_OUT_DATA /rpc/rpcproxy.dll?localhost:3388 HTTP/1.1\n", 55);
+ stream_write(http_stream, "Accept: application/rpc\n", 24);
+ stream_write(http_stream, "Cache-Control: no-cache\n", 24);
+ stream_write(http_stream, "Connection: Keep-Alive\n", 23);
+ stream_write(http_stream, "Content-Length: 0\n", 18);
+ stream_write(http_stream, "User-Agent: MSRPC\n", 18);
+ stream_write(http_stream, "Host: ", 6);
+ stream_write(http_stream, settings->tsg_server, strlen(settings->tsg_server));
+ stream_write(http_stream, "\n", 1);
+ stream_write(http_stream, "Pragma: ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, SessionId=33ad20ac-7469-4f63-946d-113eac21a23c\n", 110);
+ stream_write(http_stream, "Authorization: NTLM ", 20);
+ stream_write(http_stream, encoded_ntht_data, encoded_ntht_length);
+ stream_write(http_stream, "\n\n", 2);
+
+ LLOGLN(10, ("rpch_out_connect_http: sending\n%s", http_stream->data));
+
+ DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
+
+ bytes = (int) (http_stream->p - http_stream->data);
+ tls_write(tls_out, http_stream->data, bytes);
+ stream_clear(http_stream);
+ http_stream->p = http_stream->data;
+
+ xfree(decoded_ntht_data);
+
+ encoded_ntht_length = -1;
+ xfree(encoded_ntht_data);
+ encoded_ntht_data = NULL;
+ http_out->contentLength = 0;
+
+ LLOGLN(10, ("rpch_out_connect_http: 1"));
+
+ stream_free(http_stream);
+ http_stream = read_http(tls_out, NULL, true);
+
+ if (http_stream == NULL)
+ {
+ LLOGLN(0, ("rpch_out_connect_http: error http_stream is nil"));
+ return false;
+ }
+
+ ntlm_text = strstr((char*)(http_stream->data), "NTLM ");
+ if (ntlm_text != NULL)
+ {
+ encoded_ntht_data = (uint8*)(ntlm_text + 5);
+ encoded_ntht_length = 0;
+ while (encoded_ntht_data[encoded_ntht_length] != '\r' &&
+ encoded_ntht_data[encoded_ntht_length] != '\n')
+ {
+ encoded_ntht_length++;
+ }
+ }
+
+ LLOGLN(0, ("rpch_out_connect_http: encoded_ntht_length %d encoded_ntht_data %s",
+ encoded_ntht_length, encoded_ntht_data));
+
+ if (encoded_ntht_length < 1) /* No NTLM data was found */
+ {
+ LLOGLN(0, ("rpch_out_connect_http: error encoded_ntht_length < 1"));
+ return false;
+ }
+
+ http_stream->p = http_stream->data;
+
+ crypto_base64_decode(encoded_ntht_data, encoded_ntht_length,
+ &decoded_ntht_data, &decoded_ntht_length);
+
+ stream_write(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ xfree(decoded_ntht_data);
+
+ ntlmssp_recv(http_out_ntlmssp, ntlmssp_stream);
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ ntlmssp_send(http_out_ntlmssp, ntlmssp_stream);
+
+ decoded_ntht_length = (int) (ntlmssp_stream->p - ntlmssp_stream->data);
+ decoded_ntht_data = (uint8*) xmalloc(decoded_ntht_length);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+ stream_read(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ crypto_base64_encode(decoded_ntht_data, decoded_ntht_length,
+ &encoded_ntht_data, &encoded_ntht_length);
+
+ stream_write(http_stream, "RPC_OUT_DATA /rpc/rpcproxy.dll?localhost:3388 HTTP/1.1\n", 55);
+ stream_write(http_stream, "Accept: application/rpc\n", 24);
+ stream_write(http_stream, "Cache-Control: no-cache\n", 24);
+ stream_write(http_stream, "Connection: Keep-Alive\n", 23);
+ stream_write(http_stream, "Content-Length: 76\n", 19);
+ stream_write(http_stream, "User-Agent: MSRPC\n", 18);
+ stream_write(http_stream, "Host: ", 6);
+ stream_write(http_stream, settings->tsg_server, strlen(settings->tsg_server));
+ stream_write(http_stream, "\n", 1);
+ stream_write(http_stream, "Pragma: ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, SessionId=33ad20ac-7469-4f63-946d-113eac21a23c\n", 110);
+ stream_write(http_stream, "Authorization: NTLM ", 20);
+ stream_write(http_stream, encoded_ntht_data, encoded_ntht_length);
+ stream_write(http_stream, "\n\n", 2);
+
+ http_out->contentLength = 76;
+ http_out->remContentLength = 76;
+
+ DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
+
+ tls_write(tls_out, http_stream->data, http_stream->p - http_stream->data);
+
+ stream_clear(http_stream);
+ http_stream->p = http_stream->data;
+
+ xfree(decoded_ntht_data);
+ xfree(encoded_ntht_data);
+ /* At this point OUT connection is ready to send CONN/A1 and start with recieving data */
+
+ http_out->state = RPCH_HTTP_SENDING;
+
+ LLOGLN(10, ("rpch_out_connect_http: out"));
+
+ return true;
+}
+
+tbool rpch_in_connect_http(rdpRpch* rpch)
+{
+ rdpTls* tls_in = rpch->tls_in;
+ rdpSettings* settings = rpch->settings;
+ rdpRpchHTTP* http_in = rpch->http_in;
+ NTLMSSP* http_in_ntlmssp = http_in->ntht;
+
+ STREAM* ntlmssp_stream;
+ STREAM* http_stream;
+
+ int decoded_ntht_length;
+ int encoded_ntht_length = 0;
+ int bytes;
+
+ uint8* decoded_ntht_data;
+ uint8* encoded_ntht_data = NULL;
+
+ char* ntlm_text;
+
+ LLOGLN(10, ("rpch_in_connect_http:"));
+
+ ntlmssp_stream = stream_new(0xFFFF);
+ http_stream = stream_new(0xFFFF);
+
+ ntlmssp_set_username(http_in_ntlmssp, settings->tsg_username);
+ ntlmssp_set_password(http_in_ntlmssp, settings->tsg_password);
+ ntlmssp_set_domain(http_in_ntlmssp, settings->tsg_domain);
+ ntlmssp_set_workstation(http_in_ntlmssp, "WORKSTATION"); /* TODO insert proper w.name */
+
+ LLOGLN(10, ("rpch_in_connect_http: tsg_username %s tsg_password %s tsg_domain %s",
+ settings->tsg_username, settings->tsg_password, settings->tsg_domain));
+
+ ntlmssp_send(http_in_ntlmssp, ntlmssp_stream);
+
+ decoded_ntht_length = (int) (ntlmssp_stream->p - ntlmssp_stream->data);
+ decoded_ntht_data = (uint8*) xmalloc(decoded_ntht_length);
+
+ ntlmssp_stream->p = ntlmssp_stream->data;
+ stream_read(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ crypto_base64_encode(decoded_ntht_data, decoded_ntht_length, &encoded_ntht_data, &encoded_ntht_length);
+
+ stream_write(http_stream, "RPC_IN_DATA /rpc/rpcproxy.dll?localhost:3388 HTTP/1.1\n", 54);
+ stream_write(http_stream, "Accept: application/rpc\n", 24);
+ stream_write(http_stream, "Cache-Control: no-cache\n", 24);
+ stream_write(http_stream, "Connection: Keep-Alive\n", 23);
+ stream_write(http_stream, "Content-Length: 0\n", 18);
+ stream_write(http_stream, "User-Agent: MSRPC\n", 18);
+ stream_write(http_stream, "Host: ", 6);
+ stream_write(http_stream, settings->tsg_server, strlen(settings->tsg_server));
+ stream_write(http_stream, "\n", 1);
+ stream_write(http_stream, "Pragma: ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, SessionId=33ad20ac-7469-4f63-946d-113eac21a23c\n", 110);
+ stream_write(http_stream, "Authorization: NTLM ", 20);
+ stream_write(http_stream, encoded_ntht_data, encoded_ntht_length);
+ stream_write(http_stream, "\n\n", 2);
+
+ LLOGLN(10, ("rpch_in_connect_http: sending\n%s", http_stream->data));
+
+ DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
+
+ bytes = (int) (http_stream->p - http_stream->data);
+ tls_write(tls_in, http_stream->data, bytes);
+ stream_clear(http_stream);
+ http_stream->p = http_stream->data;
+
+ xfree(decoded_ntht_data);
+
+ encoded_ntht_length = -1;
+ xfree(encoded_ntht_data);
+ encoded_ntht_data = NULL;
+ http_in->contentLength = 0;
+
+ LLOGLN(10, ("rpch_in_connect_http: 1"));
+
+ stream_free(http_stream);
+ http_stream = read_http(tls_in, NULL, true);
+
+ if (http_stream == NULL)
+ {
+ LLOGLN(0, ("rpch_in_connect_http: error http_stream is nil"));
+ return false;
+ }
+
+ ntlm_text = strstr((char*)(http_stream->data), "NTLM ");
+ if (ntlm_text != NULL)
+ {
+ encoded_ntht_data = (uint8*)(ntlm_text + 5);
+ encoded_ntht_length = 0;
+ while (encoded_ntht_data[encoded_ntht_length] != '\r' &&
+ encoded_ntht_data[encoded_ntht_length] != '\n')
+ {
+ encoded_ntht_length++;
+ }
+ }
+
+ LLOGLN(0, ("rpch_in_connect_http: encoded_ntht_length %d encoded_ntht_data %s",
+ encoded_ntht_length, encoded_ntht_data));
+
+
+ if (encoded_ntht_length < 1) /* No NTLM data was found */
+ {
+ LLOGLN(0, ("rpch_in_connect_http: error encoded_ntht_length < 1"));
+ return false;
+ }
+
+ http_stream->p = http_stream->data;
+
+ crypto_base64_decode(encoded_ntht_data, encoded_ntht_length,
+ &decoded_ntht_data, &decoded_ntht_length);
+
+ stream_write(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ xfree(decoded_ntht_data);
+
+ ntlmssp_recv(http_in_ntlmssp, ntlmssp_stream);
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ ntlmssp_send(http_in_ntlmssp, ntlmssp_stream);
+
+ decoded_ntht_length = (int) (ntlmssp_stream->p - ntlmssp_stream->data);
+ decoded_ntht_data = (uint8*) xmalloc(decoded_ntht_length);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+ stream_read(ntlmssp_stream, decoded_ntht_data, decoded_ntht_length);
+
+ stream_clear(ntlmssp_stream);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ crypto_base64_encode(decoded_ntht_data, decoded_ntht_length, &encoded_ntht_data, &encoded_ntht_length);
+
+ stream_write(http_stream, "RPC_IN_DATA /rpc/rpcproxy.dll?localhost:3388 HTTP/1.1\n", 54);
+ stream_write(http_stream, "Accept: application/rpc\n", 24);
+ stream_write(http_stream, "Cache-Control: no-cache\n", 24);
+ stream_write(http_stream, "Connection: Keep-Alive\n", 23);
+ stream_write(http_stream, "Content-Length: 1073741824\n", 27);
+ stream_write(http_stream, "User-Agent: MSRPC\n", 18);
+ stream_write(http_stream, "Host: ", 6);
+ stream_write(http_stream, settings->tsg_server, strlen(settings->tsg_server));
+ stream_write(http_stream, "\n", 1);
+ stream_write(http_stream, "Pragma: ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, SessionId=33ad20ac-7469-4f63-946d-113eac21a23c\n", 110);
+ stream_write(http_stream, "Authorization: NTLM ", 20);
+ stream_write(http_stream, encoded_ntht_data, encoded_ntht_length);
+ stream_write(http_stream, "\n\n", 2);
+
+ http_in->contentLength = 1073741824;
+ http_in->remContentLength = 1073741824;
+
+ DEBUG_RPCH("\nSend:\n%s\n", http_stream->data);
+
+ tls_write(tls_in, http_stream->data, http_stream->p - http_stream->data);
+
+ stream_clear(http_stream);
+ http_stream->p = http_stream->data;
+
+ xfree(decoded_ntht_data);
+ xfree(encoded_ntht_data);
+ /* At this point IN connection is ready to send CONN/B1 and start with sending data */
+
+ http_in->state = RPCH_HTTP_SENDING;
+
+ LLOGLN(10, ("rpch_in_connect_http: out"));
+
+ return true;
+}
+
+int rpch_out_write(rdpRpch* rpch, uint8* data, int length)
+{
+ rdpRpchHTTP* http_out = rpch->http_out;
+ rdpTls* tls_out = rpch->tls_out;
+ int status = -1;
+ int sent = 0;
+
+ LLOGLN(10, ("rpch_out_write: in length %d", length));
+
+ if (http_out->remContentLength < length)
+ {
+ LLOGLN(0, ("rpch_out_write: RPCH Error: HTTP frame is over."));
+ return -1;/* TODO ChannelRecycling */
+ }
+
+#ifdef WITH_DEBUG_RPCH
+ printf("rpch_out_write(): length: %d\n", length);
+ freerdp_hexdump(data, length);
+ printf("\n");
+#endif
+ while (sent < length)
+ {
+ status = tls_write(tls_out, data + sent, length - sent);
+
+ if (status <= 0)
+ {
+ LLOGLN(0, ("rpch_out_write: error"));
+ return status; /* TODO no idea how to handle errors */
+ }
+
+ sent += status;
+ }
+
+ http_out->remContentLength -= sent;
+
+ LLOGLN(10, ("rpch_out_write: out sent %d", sent));
+
+ return sent;
+}
+
+int rpch_in_write(rdpRpch* rpch, uint8* data, int length)
+{
+ rdpRpchHTTP* http_in = rpch->http_in;
+ rdpTls* tls_in = rpch->tls_in;
+ int status = -1;
+ int sent = 0;
+
+ LLOGLN(10, ("rpch_in_write:"));
+
+ if (http_in->remContentLength < length)
+ {
+ printf("RPCH Error: HTTP frame is over.\n");
+ return -1;/* TODO ChannelRecycling */
+ }
+#ifdef WITH_DEBUG_RPCH
+ printf("\nrpch_in_send(): length: %d, remaining content length: %d\n", length, http_in->remContentLength);
+ freerdp_hexdump(data, length);
+ printf("\n");
+#endif
+ while (sent < length)
+ {
+ status = tls_write(tls_in, data+sent, length-sent);
+
+ if (status <= 0)
+ return status;/* TODO no idea how to handle errors */
+
+ sent += status;
+ }
+
+ rpch->BytesSent += sent;
+ http_in->remContentLength -= sent;
+
+ return sent;
+}
+
+uint8* rpch_create_cookie()
+{
+ uint8 *ret = xmalloc(16);
+ RAND_pseudo_bytes(ret, 16);
+ return ret;
+}
+
+tbool rpch_out_send_CONN_A1(rdpRpch* rpch)
+{
+ STREAM* pdu = stream_new(76);
+
+ uint8 rpc_vers = 0x05;
+ uint8 rpc_vers_minor = 0x00;
+ uint8 ptype = PTYPE_RTS;
+ uint8 pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
+ uint32 packet_drep = 0x00000010;
+ uint16 frag_length = 76;
+ uint16 auth_length = 0;
+ uint32 call_id = 0x00000000;
+ uint16 flags = 0x0000;
+ uint16 num_commands = 0x0004;
+
+ /* Version */
+ uint32 vCommandType = 0x00000006;
+ uint32 Version = 0x00000001;
+
+ /* VirtualConnectionCookie */
+ uint32 vccCommandType = 0x00000003;
+
+ LLOGLN(10, ("rpch_out_send_CONN_A1:"));
+
+ rpch->virtualConnectionCookie = rpch_create_cookie(); /* 16 bytes */
+
+ LLOGLN(10, ("rpch_out_send_CONN_A1: 1"));
+
+ /* OUTChannelCookie */
+ uint32 occCommandType = 0x00000003;
+ rpch->OUTChannelCookie = rpch_create_cookie(); /* 16 bytes */
+
+ LLOGLN(10, ("rpch_out_send_CONN_A1: 2"));
+
+ /* ReceiveWindowSize */
+ uint32 rwsCommandType = 0x00000000;
+ uint32 reseiveWindowSize = 0x00010000;
+ rpch->AwailableWindow = reseiveWindowSize;
+
+ stream_write_uint8(pdu, rpc_vers);
+ stream_write_uint8(pdu, rpc_vers_minor);
+ stream_write_uint8(pdu, ptype);
+ stream_write_uint8(pdu, pfc_flags);
+ stream_write_uint32(pdu, packet_drep);
+ stream_write_uint16(pdu, frag_length);
+ stream_write_uint16(pdu, auth_length);
+ stream_write_uint32(pdu, call_id);
+ stream_write_uint16(pdu, flags);
+ stream_write_uint16(pdu, num_commands);
+ stream_write_uint32(pdu, vCommandType);
+ stream_write_uint32(pdu, Version);
+ stream_write_uint32(pdu, vccCommandType);
+ stream_write(pdu, rpch->virtualConnectionCookie, 16);
+ stream_write_uint32(pdu, occCommandType);
+ stream_write(pdu, rpch->OUTChannelCookie, 16);
+ stream_write_uint32(pdu, rwsCommandType);
+ stream_write_uint32(pdu, reseiveWindowSize);
+
+ if (!rpch_out_write(rpch, pdu->data, pdu->p - pdu->data))
+ {
+ LLOGLN(0, ("rpch_out_send_CONN_A1: rpch_out_write failed"));
+ stream_free(pdu);
+ return false;
+ }
+
+ stream_free(pdu);
+
+ LLOGLN(10, ("rpch_out_send_CONN_A1: out"));
+ return true;
+}
+
+tbool rpch_in_send_CONN_B1(rdpRpch* rpch)
+{
+ STREAM* pdu = stream_new(104);
+
+ uint8 rpc_vers = 0x05;
+ uint8 rpc_vers_minor = 0x00;
+ uint8 ptype = PTYPE_RTS;
+ uint8 pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
+ uint32 packet_drep = 0x00000010;
+ uint16 frag_length = 104;
+ uint16 auth_length = 0;
+ uint32 call_id = 0x00000000;
+ uint16 flags = 0x0000;
+ uint16 num_commands = 0x0006;
+
+ /* Version */
+ uint32 vCommandType = 0x00000006;
+ uint32 Version = 0x00000001;
+
+ /* VirtualConnectionCookie */
+ uint32 vccCommandType = 0x00000003;
+
+ /* INChannelCookie */
+ uint32 iccCommandType = 0x00000003;
+ rpch->INChannelCookie = rpch_create_cookie(); /* 16bytes */
+
+ /* ChannelLifetime */
+ uint32 clCommandType = 0x00000004;
+ uint32 ChannelLifetime = 0x40000000;
+
+ /* ClientKeepalive */
+ uint32 ckCommandType = 0x00000005;
+ uint32 ClientKeepalive = 0x000493e0;
+
+ /* AssociationGroupId */
+ uint32 agidCommandType = 0x0000000c;
+ uint8* AssociationGroupId = rpch_create_cookie(); /* 16bytes */
+
+ LLOGLN(10, ("rpch_in_send_CONN_B1:"));
+
+ stream_write_uint8(pdu, rpc_vers);
+ stream_write_uint8(pdu, rpc_vers_minor);
+ stream_write_uint8(pdu, ptype);
+ stream_write_uint8(pdu, pfc_flags);
+ stream_write_uint32(pdu, packet_drep);
+ stream_write_uint16(pdu, frag_length);
+ stream_write_uint16(pdu, auth_length);
+ stream_write_uint32(pdu, call_id);
+ stream_write_uint16(pdu, flags);
+ stream_write_uint16(pdu, num_commands);
+ stream_write_uint32(pdu, vCommandType);
+ stream_write_uint32(pdu, Version);
+ stream_write_uint32(pdu, vccCommandType);
+ stream_write(pdu, rpch->virtualConnectionCookie, 16);
+ stream_write_uint32(pdu, iccCommandType);
+ stream_write(pdu, rpch->INChannelCookie, 16);
+ stream_write_uint32(pdu, clCommandType);
+ stream_write_uint32(pdu, ChannelLifetime);
+ stream_write_uint32(pdu, ckCommandType);
+ stream_write_uint32(pdu, ClientKeepalive);
+ stream_write_uint32(pdu, agidCommandType);
+ stream_write(pdu, AssociationGroupId, 16);
+
+ rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+
+ stream_free(pdu);
+ LLOGLN(10, ("rpch_in_send_CONN_B1: out"));
+
+ return true;
+}
+
+tbool rpch_in_send_keep_alive(rdpRpch* rpch)
+{
+ STREAM* pdu = stream_new(28);
+
+ uint8 rpc_vers = 0x05;
+ uint8 rpc_vers_minor = 0x00;
+ uint8 ptype = PTYPE_RTS;
+ uint8 pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
+ uint32 packet_drep = 0x00000010;
+ uint16 frag_length = 28;
+ uint16 auth_length = 0;
+ uint32 call_id = 0x00000000;
+ uint16 flags = 0x0002;
+ uint16 num_commands = 0x0001;
+
+ /* ClientKeepalive */
+ uint32 ckCommandType = 0x00000005;
+ uint32 ClientKeepalive = 0x00007530;
+
+ LLOGLN(10, ("rpch_in_send_keep_alive:"));
+ stream_write_uint8(pdu, rpc_vers);
+ stream_write_uint8(pdu, rpc_vers_minor);
+ stream_write_uint8(pdu, ptype);
+ stream_write_uint8(pdu, pfc_flags);
+ stream_write_uint32(pdu, packet_drep);
+ stream_write_uint16(pdu, frag_length);
+ stream_write_uint16(pdu, auth_length);
+ stream_write_uint32(pdu, call_id);
+ stream_write_uint16(pdu, flags);
+ stream_write_uint16(pdu, num_commands);
+ stream_write_uint32(pdu, ckCommandType);
+ stream_write_uint32(pdu, ClientKeepalive);
+
+ rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+
+ stream_free(pdu);
+
+ return true;
+}
+
+tbool rpch_in_send_bind(rdpRpch* rpch)
+{
+ STREAM* ntlm_stream = stream_new(0xFFFF);
+ STREAM* pdu;
+ int bytes;
+ rpcconn_bind_hdr_t* bind_pdu;
+
+ LLOGLN(10, ("rpch_in_send_bind:"));
+
+ rpch->ntlmssp = ntlmssp_new();
+ rpch->ntlmssp->ntlm_v2 = true;
+ ntlmssp_set_username(rpch->ntlmssp, rpch->settings->tsg_username);
+ ntlmssp_set_password(rpch->ntlmssp, rpch->settings->tsg_password);
+ ntlmssp_set_domain(rpch->ntlmssp, rpch->settings->tsg_domain);
+ ntlmssp_set_workstation(rpch->ntlmssp, "WORKSTATION"); /* TODO insert proper w.name */
+
+ ntlmssp_send(rpch->ntlmssp, ntlm_stream);
+
+ bind_pdu = (rpcconn_bind_hdr_t*) xmalloc(sizeof(rpcconn_bind_hdr_t));
+ bind_pdu->rpc_vers = 5;
+ bind_pdu->rpc_vers_minor = 0;
+ bind_pdu->PTYPE = PTYPE_BIND;
+ bind_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_PENDING_CANCEL | PFC_CONC_MPX;
+ bind_pdu->packed_drep[0] = 0x10;
+ bind_pdu->packed_drep[1] = 0x00;
+ bind_pdu->packed_drep[2] = 0x00;
+ bind_pdu->packed_drep[3] = 0x00;
+ bytes = (int) (ntlm_stream->p - ntlm_stream->data);
+ bind_pdu->frag_length = 124 + bytes;
+ bind_pdu->auth_length = bytes;
+ bind_pdu->call_id = 2;
+ bind_pdu->max_xmit_frag = 0x0FF8;
+ bind_pdu->max_recv_frag = 0x0FF8;
+ bind_pdu->assoc_group_id = 0;
+ bind_pdu->p_context_elem.n_context_elem = 2;
+ bind_pdu->p_context_elem.reserved = 0;
+ bind_pdu->p_context_elem.reserved2 = 0;
+ bind_pdu->p_context_elem.p_cont_elem = (p_cont_elem_t*) xmalloc(sizeof(p_cont_elem_t) * bind_pdu->p_context_elem.n_context_elem);
+ bind_pdu->p_context_elem.p_cont_elem[0].p_cont_id = 0;
+ bind_pdu->p_context_elem.p_cont_elem[0].n_transfer_syn = 1;
+ bind_pdu->p_context_elem.p_cont_elem[0].reserved = 0;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.time_low = 0x44e265dd;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.time_mid = 0x7daf;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.time_hi_and_version = 0x42cd;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.clock_seq_hi_and_reserved = 0x85;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.clock_seq_low = 0x60;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[0] = 0x3c;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[1] = 0xdb;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[2] = 0x6e;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[3] = 0x7a;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[4] = 0x27;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid.node[5] = 0x29;
+ bind_pdu->p_context_elem.p_cont_elem[0].abstract_syntax.if_version = 0x00030001;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes = xmalloc(sizeof(p_syntax_id_t));
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.time_low = 0x8a885d04;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.time_mid = 0x1ceb;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.time_hi_and_version = 0x11c9;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.clock_seq_hi_and_reserved = 0x9f;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.clock_seq_low = 0xe8;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[0] = 0x08;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[1] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[2] = 0x2b;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[3] = 0x10;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[4] = 0x48;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_uuid.node[5] = 0x60;
+ bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes[0].if_version = 0x00000002;
+ bind_pdu->p_context_elem.p_cont_elem[1].p_cont_id = 1;
+ bind_pdu->p_context_elem.p_cont_elem[1].n_transfer_syn = 1;
+ bind_pdu->p_context_elem.p_cont_elem[1].reserved = 0;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.time_low = 0x44e265dd;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.time_mid = 0x7daf;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.time_hi_and_version = 0x42cd;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.clock_seq_hi_and_reserved = 0x85;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.clock_seq_low = 0x60;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[0] = 0x3c;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[1] = 0xdb;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[2] = 0x6e;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[3] = 0x7a;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[4] = 0x27;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_uuid.node[5] = 0x29;
+ bind_pdu->p_context_elem.p_cont_elem[1].abstract_syntax.if_version = 0x00030001;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes = xmalloc(sizeof(p_syntax_id_t));
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.time_low = 0x6cb71c2c;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.time_mid = 0x9812;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.time_hi_and_version = 0x4540;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.clock_seq_hi_and_reserved = 0x03;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.clock_seq_low = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[0] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[1] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[2] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[3] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[4] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_uuid.node[5] = 0x00;
+ bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes[0].if_version = 0x00000001;
+ bind_pdu->auth_verifier.auth_pad = NULL; /* align(4); size_is(auth_pad_length) p*/
+ bind_pdu->auth_verifier.auth_type = 0x0a; /* :01 which authent service */
+ bind_pdu->auth_verifier.auth_level = 0x05; /* :01 which level within service */
+ bind_pdu->auth_verifier.auth_pad_length = 0x00; /* :01 */
+ bind_pdu->auth_verifier.auth_reserved = 0x00; /* :01 reserved, m.b.z. */
+ bind_pdu->auth_verifier.auth_context_id = 0x00000000; /* :04 */
+ bind_pdu->auth_verifier.auth_value = xmalloc(bind_pdu->auth_length); /* credentials; size_is(auth_length) p*/;
+ memcpy(bind_pdu->auth_verifier.auth_value, ntlm_stream->data, bind_pdu->auth_length);
+
+ stream_free(ntlm_stream);
+
+ pdu = stream_new(bind_pdu->frag_length);
+
+ stream_write(pdu, bind_pdu, 24);
+ stream_write(pdu, &bind_pdu->p_context_elem, 4);
+ stream_write(pdu, bind_pdu->p_context_elem.p_cont_elem, 24);
+ stream_write(pdu, bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes, 20);
+ stream_write(pdu, bind_pdu->p_context_elem.p_cont_elem + 1, 24);
+ stream_write(pdu, bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes, 20);
+ if (bind_pdu->auth_verifier.auth_pad_length > 0)
+ {
+ stream_write(pdu, bind_pdu->auth_verifier.auth_pad, bind_pdu->auth_verifier.auth_pad_length);
+ }
+ stream_write(pdu, &bind_pdu->auth_verifier.auth_type, 8); /* assumed that uint8 pointer is 32bit long (4 bytes) */
+ stream_write(pdu, bind_pdu->auth_verifier.auth_value, bind_pdu->auth_length);
+
+ rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+ /* TODO there are some alocatad memory */
+ xfree(bind_pdu);
+ return true;
+}
+
+tbool rpch_in_send_rpc_auth_3(rdpRpch* rpch)
+{
+ STREAM* ntlm_stream = stream_new(0xFFFF);
+ STREAM* pdu;
+ int bytes;
+ rpcconn_rpc_auth_3_hdr_t* rpc_auth_3_pdu;
+
+ LLOGLN(10, ("rpch_in_send_rpc_auth_3:"));
+ ntlmssp_send(rpch->ntlmssp, ntlm_stream);
+
+ rpc_auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*) xmalloc(sizeof(rpcconn_rpc_auth_3_hdr_t));
+ rpc_auth_3_pdu->rpc_vers = 5;
+ rpc_auth_3_pdu->rpc_vers_minor = 0;
+ rpc_auth_3_pdu->PTYPE = PTYPE_RPC_AUTH_3;
+ rpc_auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
+ rpc_auth_3_pdu->packed_drep[0] = 0x10;
+ rpc_auth_3_pdu->packed_drep[1] = 0x00;
+ rpc_auth_3_pdu->packed_drep[2] = 0x00;
+ rpc_auth_3_pdu->packed_drep[3] = 0x00;
+ bytes = (int) (ntlm_stream->p - ntlm_stream->data);
+ rpc_auth_3_pdu->frag_length = 28 + bytes;
+ rpc_auth_3_pdu->auth_length = bytes;
+ rpc_auth_3_pdu->call_id = 2;
+ rpc_auth_3_pdu->max_xmit_frag = 0x0FF8;
+ rpc_auth_3_pdu->max_recv_frag = 0x0FF8;
+ rpc_auth_3_pdu->auth_verifier.auth_pad = NULL; /* align(4); size_is(auth_pad_length) p */
+ rpc_auth_3_pdu->auth_verifier.auth_type = 0x0a; /* :01 which authent service */
+ rpc_auth_3_pdu->auth_verifier.auth_level = 0x05; /* :01 which level within service */
+ rpc_auth_3_pdu->auth_verifier.auth_pad_length = 0x00; /* :01 */
+ rpc_auth_3_pdu->auth_verifier.auth_reserved = 0x00; /* :01 reserved, m.b.z. */
+ rpc_auth_3_pdu->auth_verifier.auth_context_id = 0x00000000; /* :04 */
+ rpc_auth_3_pdu->auth_verifier.auth_value = xmalloc(rpc_auth_3_pdu->auth_length); /* credentials; size_is(auth_length) p */;
+ memcpy(rpc_auth_3_pdu->auth_verifier.auth_value, ntlm_stream->data, rpc_auth_3_pdu->auth_length);
+
+ stream_free(ntlm_stream);
+
+ pdu = stream_new(rpc_auth_3_pdu->frag_length);
+
+ stream_write(pdu, rpc_auth_3_pdu, 20);
+ if (rpc_auth_3_pdu->auth_verifier.auth_pad_length > 0)
+ {
+ stream_write(pdu, rpc_auth_3_pdu->auth_verifier.auth_pad, rpc_auth_3_pdu->auth_verifier.auth_pad_length);
+ }
+ stream_write(pdu, &rpc_auth_3_pdu->auth_verifier.auth_type, 8);
+ stream_write(pdu, rpc_auth_3_pdu->auth_verifier.auth_value, rpc_auth_3_pdu->auth_length);
+
+ rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+ xfree(rpc_auth_3_pdu);
+ return true;
+}
+
+/*
+rpch_proceed_RTS: CommandType 0x00000001
+0000 01 00 00 00 46 80 00 00 00 00 01 00 3c c1 c2 bf ....F.......<...
+0010 04 78 ad b2 d7 73 e1 49 e2 94 99 73 .x...s.I...s
+*
+* 0x08046
+* 0x100a6
+* 0x180c6
+*/
+static tbool rpch_in_send_flow_control(rdpRpch* rpch)
+{
+ int bytes;
+ STREAM* s;
+ uint8* fl_p; /* frag_length */
+ uint8* holdp;
+
+ LLOGLN(10, ("rpch_in_send_flow_control: BytesReceived 0x%8.8x", rpch->BytesReceived));
+ s = stream_new(1024);
+ rpch->AwailableWindow = 0x00010000;
+ stream_write_uint8(s, 0x05); /* rpc_vers */
+ stream_write_uint8(s, 0x00); /* rpc_vers_minor */
+ stream_write_uint8(s, PTYPE_RTS); /* ptype */
+ stream_write_uint8(s, PFC_FIRST_FRAG | PFC_LAST_FRAG); /* pfc_flags */
+ stream_write_uint32(s, 0x00000010); /* packet_drep */
+ fl_p = s->p;
+ stream_write_uint16(s, 0); /* frag_length, set later */
+ stream_write_uint16(s, 0); /* auth_length */
+ stream_write_uint32(s, 0x00000000); /* call_id */
+ stream_write_uint16(s, 0x0002); /* flags */
+ stream_write_uint16(s, 0x0002); /* num_commands */
+ /* command 1 Destination */
+ stream_write_uint32(s, 0x0000000d); /* ckCommandType */
+ stream_write_uint32(s, 0x00000003); /* FDOutProxy */
+ /* command 2 ClientKeepalive */
+ stream_write_uint32(s, 0x00000001); /* ckCommandType */
+ stream_write_uint32(s, rpch->BytesReceived);
+ stream_write_uint32(s, 0x00010000);
+ stream_write(s, rpch->OUTChannelCookie, 16);
+ bytes = (int) (s->p - s->data);
+ holdp = s->p;
+ s->p = fl_p;
+ stream_write_uint16(s, bytes);
+ s->p = holdp;
+ rpch_in_write(rpch, s->data, bytes);
+ stream_free(s);
+ return true;
+}
+
+tbool rpch_in_send_ping(rdpRpch* rpch)
+{
+ STREAM* pdu = stream_new(20);
+
+ uint8 rpc_vers = 0x05;
+ uint8 rpc_vers_minor = 0x00;
+ uint8 ptype = PTYPE_RTS;
+ uint8 pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
+ uint32 packet_drep = 0x00000010;
+ uint16 frag_length = 56;
+ uint16 auth_length = 0;
+ uint32 call_id = 0x00000000;
+ uint16 flags = 0x0001;
+ uint16 num_commands = 0x0000;
+
+ stream_write_uint8(pdu, rpc_vers);
+ stream_write_uint8(pdu, rpc_vers_minor);
+ stream_write_uint8(pdu, ptype);
+ stream_write_uint8(pdu, pfc_flags);
+ stream_write_uint32(pdu, packet_drep);
+ stream_write_uint16(pdu, frag_length);
+ stream_write_uint16(pdu, auth_length);
+ stream_write_uint32(pdu, call_id);
+ stream_write_uint16(pdu, flags);
+ stream_write_uint16(pdu, num_commands);
+
+ rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+
+ stream_free(pdu);
+
+ return true;
+}
+
+int rpch_out_read_http_header(rdpRpch* rpch)
+{
+ int status;
+ int content_length;
+ rdpTls* tls_out = rpch->tls_out;
+ rdpRpchHTTP* http_out = rpch->http_out;
+ STREAM* http_stream;
+
+ http_stream = read_http(tls_out, &content_length, false);
+ if (http_stream == NULL)
+ {
+ LLOGLN(0, ("rpch_out_read_http_header: read_http failed"));
+ return -1;
+ }
+
+ status = 0;
+ http_out->contentLength = content_length;
+ http_out->remContentLength = http_out->contentLength;
+
+ DEBUG_RPCH("\nRecv HTTP header:\n%s", stream_get_head(http_stream));
+
+ stream_free(http_stream);
+
+ return status;
+}
+
+int rpch_proceed_RTS(rdpRpch* rpch, uint8* pdu, int length)
+{
+ uint16 flags = *(uint16*)(pdu + 16);
+ uint16 num_commands = *(uint16*)(pdu + 18);
+ uint8* iterator = pdu + 20;
+ uint32 CommandType;
+ int i;
+
+ LLOGLN(10, ("rpch_proceed_RTS:"));
+
+ if (flags & RTS_FLAG_PING)
+ {
+ LLOGLN(0, ("rpch_proceed_RTS: calling rpch_in_send_keep_alive"));
+ rpch_in_send_keep_alive(rpch);
+ return 0;
+ }
+
+ for (i = 0; i < num_commands; i++)
+ {
+ CommandType = *(uint32*) iterator;
+ LLOGLN(10, ("rpch_proceed_RTS: CommandType 0x%8.8x", CommandType));
+ switch (CommandType)
+ {
+ case 0x00000000: /* ReceiveWindowSize */
+ iterator += 8;
+ break;
+ case 0x00000001: /* FlowControlAck */
+ //freerdp_hexdump(iterator, 28);
+ iterator += 28;
+ break;
+ case 0x00000002: /* ConnectionTimeout */
+ iterator += 8;
+ break;
+ case 0x00000003: /* Cookie */
+ iterator += 20;
+ break;
+ case 0x00000004: /* ChannelLifetime */
+ iterator += 8;
+ break;
+ case 0x00000005: /* ClientKeepalive */
+ iterator += 8;
+ break;
+ case 0x00000006: /* Version */
+ iterator += 8;
+ break;
+ case 0x00000007: /* Empty */
+ iterator += 4;
+ break;
+ case 0x00000008: /* Padding */
+ iterator += 8 + *(uint32*)(iterator + 4);
+ break;
+ case 0x00000009: /* NegativeANCE */
+ iterator += 4;
+ break;
+ case 0x0000000a: /* ANCE */
+ iterator += 4;
+ break;
+ case 0x0000000b: /* ClientAddress */
+ iterator+= 4 + 4 + (12 * (*(uint32*)(iterator + 4))) + 12 ;
+ break;
+ case 0x0000000c: /* AssociationGroupId */
+ iterator += 20;
+ break;
+ case 0x0000000d: /* Destination */
+ //freerdp_hexdump(iterator, 8);
+ iterator += 8;
+ break;
+ case 0x0000000e: /* PingTrafficSentNotify */
+ iterator += 8;
+ break;
+ default:
+ LLOGLN(0, ("rpch_proceed_RTS: Error: Unknown RTS CommandType: 0x%x", CommandType));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int rpch_out_read(rdpRpch* rpch, uint8* data, int length)
+{
+ int status;
+ rdpTls* tls_out = rpch->tls_out;
+ rdpRpchHTTP* http_out = rpch->http_out;
+ uint8* pdu;
+ uint8 ptype;
+ uint16 frag_length;
+
+ LLOGLN(10, ("rpch_out_read:"));
+
+#if 0
+ if (rpch->AwailableWindow < 0x00008FFF) /* Just a simple workaround */
+ {
+ LLOGLN(10, ("rpch_out_read: calling rpch_in_send_flow_control"));
+ rpch_in_send_flow_control(rpch); /* send FlowControlAck every time AW reaches the half */
+ }
+
+ LLOGLN(10, ("rpch_out_read: 1"));
+ if (http_out->remContentLength <= 0xFFFF) /* TODO make ChannelRecycling */
+ {
+ LLOGLN(10, ("rpch_out_read: calling rpch_out_read_http_header"));
+ if (rpch_out_read_http_header(rpch) < 0)
+ {
+ LLOGLN(0, ("rpch_out_read: rpch_out_read_http_header failed"));
+ return -1;
+ }
+ }
+ LLOGLN(10, ("rpch_out_read: 2"));
+
+ if (http_out->contentLength != 0x40000000)
+ {
+ LLOGLN(0, ("rpch_out_read: 'Bad Request'"));
+ return -1;
+ }
+#endif
+
+ pdu = (uint8*) xmalloc(0xFFFF);
+
+#if 0
+ status = force_read(tls_out, pdu, 1);
+ if (status != 0)
+ {
+ LLOGLN(0, ("rpch_out_read: error"));
+ return -1;
+ }
+ if (pdu[0] == 'H')
+ {
+ if (rpch_out_read_http_header(rpch) < 0)
+ {
+ LLOGLN(0, ("rpch_out_read: rpch_out_read_http_header failed"));
+ return -1;
+> }
+ return 0;
+ }
+#endif
+
+ //status = tls_read(tls_out, pdu, 10);
+ status = force_read(tls_out, pdu, 10);
+ if (status <= 9) /* read first 10 bytes to get the frag_length value */
+ {
+ LLOGLN(0, ("rpch_out_read: tls_read failed, not enough"));
+ xfree(pdu);
+ return -1;
+ }
+
+ ptype = *(pdu + 2);
+ frag_length = *((uint16*)(pdu + 8));
+ LLOGLN(10, ("rpch_out_read: frag_length %d", frag_length));
+
+ //status = tls_read(tls_out, pdu + 10, frag_length - 10);
+ status = force_read(tls_out, pdu + 10, frag_length - 10);
+ if (status < 0)
+ {
+ xfree(pdu);
+ return status;
+ }
+
+ if (ptype == 0x14) /* RTS PDU */
+ {
+ LLOGLN(0, ("rpch_out_read: RTS PDU received..."));
+ LLOGLN(10, ("rpch_out_read: calling rpch_proceed_RTS"));
+ rpch_proceed_RTS(rpch, pdu, frag_length);
+ xfree(pdu);
+ return 0;
+ }
+ else
+ {
+ rpch->BytesReceived += frag_length; /* RTS PDUs are not subjects for FlowControl */
+ rpch->AwailableWindow -= frag_length;
+ }
+
+ http_out->remContentLength -= frag_length;
+
+ if (length < frag_length)
+ {
+ LLOGLN(10, ("rpch_out_read: length %d frag_length %d", length, frag_length));
+ printf("rcph_out_read(): Error! Given buffer is to small. Recieved data fits not in.\n");
+ xfree(pdu);
+ /* TODO add buffer for storing remaining data for the next read in
+ * case destination buffer is to small */
+ return -1;
+ }
+
+ memcpy(data, pdu, frag_length);
+
+#ifdef WITH_DEBUG_RPCH
+ printf("\nrpch_out_recv(): length: %d, remaining content length: %d\n", frag_length, http_out->remContentLength);
+ freerdp_hexdump(data, frag_length);
+ printf("\n");
+#endif
+
+ xfree(pdu);
+
+ return frag_length;
+}
+
+int rpch_out_recv_bind_ack(rdpRpch* rpch)
+{
+ int pdu_length = 0x8FFF; /*32KB buffer*/
+ uint8* pdu = xmalloc(pdu_length);
+ int status = rpch_out_read(rpch, pdu, pdu_length);
+ if (status > 0)
+ {
+ uint16 frag_length = *((uint16*)(pdu + 8));
+ uint16 auth_length = *((uint16*)(pdu + 10));
+
+ STREAM* ntlmssp_stream = stream_new(0xFFFF);
+ stream_write(ntlmssp_stream, (pdu+(frag_length-auth_length)), auth_length);
+ ntlmssp_stream->p = ntlmssp_stream->data;
+
+ ntlmssp_recv(rpch->ntlmssp, ntlmssp_stream);
+
+ stream_free(ntlmssp_stream);
+ }
+ xfree(pdu);
+ return status;
+}
+
+int rpch_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum)
+{
+ int status = -1;
+ rpcconn_request_hdr_t* request_pdu;
+ int i;
+ rdpBlob rdpMsg;
+ STREAM* pdu;
+ uint8 auth_pad_length = (16 - ((24 + length + 8 + 16) % 16)) & 15;
+
+ LLOGLN(10, ("rpch_write:"));
+ request_pdu = (rpcconn_request_hdr_t*) xmalloc(sizeof(rpcconn_request_hdr_t));
+ request_pdu->rpc_vers = 5;
+ request_pdu->rpc_vers_minor = 0;
+ request_pdu->PTYPE = PTYPE_REQUEST;
+ request_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
+ request_pdu->packed_drep[0] = 0x10;
+ request_pdu->packed_drep[1] = 0x00;
+ request_pdu->packed_drep[2] = 0x00;
+ request_pdu->packed_drep[3] = 0x00;
+ request_pdu->frag_length = 24 + length + auth_pad_length + 8 + 16;
+ request_pdu->auth_length = 16;
+ request_pdu->call_id = ++rpch->call_id;
+ LLOGLN(10, ("rpch_write: 1"));
+ if (opnum == 8)
+ {
+ LLOGLN(10, ("rpch_write: opnum is 8"));
+ /* opnum=8 means [MS-TSGU]TsProxySetupRecievePipe, save call_id for checking pipe responces */
+ rpch->pipe_call_id = rpch->call_id;
+ }
+ request_pdu->alloc_hint = length;
+ request_pdu->p_cont_id = 0x0000;
+ request_pdu->opnum = opnum;
+ request_pdu->stub_data = data;
+ request_pdu->auth_verifier.auth_type = 0x0a; /* :01 which authent service */
+ request_pdu->auth_verifier.auth_level = 0x05; /* :01 which level within service */
+ request_pdu->auth_verifier.auth_pad_length = auth_pad_length; /* :01 */
+ request_pdu->auth_verifier.auth_pad = xmalloc(auth_pad_length); /* align(4); size_is(auth_pad_length) p*/
+ LLOGLN(10, ("rpch_write: 2"));
+ for (i = 0; i < auth_pad_length; i++)
+ {
+ request_pdu->auth_verifier.auth_pad[i] = 0x00;
+ }
+ request_pdu->auth_verifier.auth_reserved = 0x00; /* :01 reserved, m.b.z. */
+ request_pdu->auth_verifier.auth_context_id = 0x00000000; /* :04 */
+ request_pdu->auth_verifier.auth_value = xmalloc(request_pdu->auth_length); /* credentials; size_is(auth_length) p*/;
+
+ pdu = stream_new(request_pdu->frag_length);
+
+ LLOGLN(10, ("rpch_write: 3"));
+ stream_write(pdu, request_pdu, 24);
+ stream_write(pdu, request_pdu->stub_data, request_pdu->alloc_hint);
+ if (request_pdu->auth_verifier.auth_pad_length > 0)
+ {
+ stream_write(pdu, request_pdu->auth_verifier.auth_pad, request_pdu->auth_verifier.auth_pad_length);
+ }
+ LLOGLN(10, ("rpch_write: 3.1"));
+ stream_write(pdu, &request_pdu->auth_verifier.auth_type, 8);
+
+ rdpMsg.data = pdu->data;
+ rdpMsg.length = (int) (pdu->p - pdu->data);
+ LLOGLN(10, ("rpch_write: 3.2"));
+ ntlmssp_encrypt_message(rpch->ntlmssp, &rdpMsg, NULL, request_pdu->auth_verifier.auth_value);
+ LLOGLN(10, ("rpch_write: 3.3"));
+
+ LLOGLN(10, ("rpch_write: 4"));
+ stream_write(pdu, request_pdu->auth_verifier.auth_value, request_pdu->auth_length);
+
+ status = rpch_in_write(rpch, pdu->data, pdu->p - pdu->data);
+
+ xfree(request_pdu->auth_verifier.auth_value);
+ xfree(request_pdu->auth_verifier.auth_pad);
+ xfree(request_pdu);
+
+ LLOGLN(10, ("rpch_write: 5"));
+
+ if (status < 0)
+ {
+ LLOGLN(0, ("rpch_write: rcph_in_write failed"));
+ return status;
+ }
+
+ LLOGLN(10, ("rpch_write: out"));
+
+ return length;
+}
+
+int rpch_read(rdpRpch* rpch, uint8* data, int length)
+{/*TODO*/
+ int rpch_length = 0xffff; // length + 0xFF;
+ int status;
+ int readed = 0;
+ int data_length;
+ uint8* rpch_data;
+ /*uint32 return_code;*/
+ uint16 frag_length;
+ uint16 auth_length;
+ uint8 auth_pad_length;
+ uint32 call_id = -1;
+
+ LLOGLN(10, ("rpch_read:"));
+ LLOGLN(10, ("rpch_read: read_buffer_len %d length %d", rpch->read_buffer_len, length));
+ if (rpch->read_buffer_len > 0)
+ {
+ if (rpch->read_buffer_len > length)
+ {
+ /* TODO fix read_buffer is too long problem */
+ printf("ERROR! RPCH Stores data in read_buffer fits not in data on rpch_read.\n");
+ return -1;
+ }
+ memcpy(data, rpch->read_buffer, rpch->read_buffer_len);
+ readed += rpch->read_buffer_len;
+ xfree(rpch->read_buffer);
+ rpch->read_buffer_len = 0;
+ }
+ if (readed >= length)
+ {
+ return readed;
+ }
+ rpch_data = (uint8*) xmalloc(rpch_length);
+ while (true)
+ {
+ status = rpch_out_read(rpch, rpch_data, rpch_length);
+ if (status == 0)
+ {
+ xfree(rpch_data);
+ return readed;
+ }
+ else if (status < 0)
+ {
+ LLOGLN(10, ("rpch_read: error rpch_out_read failed"));
+ xfree(rpch_data);
+ return status;
+ }
+
+ frag_length = *(uint16*)(rpch_data + 8);
+ auth_length = *(uint16*)(rpch_data + 10);
+ call_id = *(uint32*)(rpch_data + 12);
+ status = *(uint32*)(rpch_data + 16); /* alloc_hint */
+ auth_pad_length = *(rpch_data + frag_length - auth_length - 6); /* -6 = -8 + 2 (sec_trailer + 2) */
+ /* data_length must be calculated because alloc_hint carries size of more than one pdu */
+ data_length = frag_length - auth_length - 24 - 8 - auth_pad_length; /* 24 is header; 8 is sec_trailer */
+ if (status == 4)
+ {
+ LLOGLN(10, ("rpch_read: continue 1"));
+ continue;
+ }
+ if (readed + data_length > length) /* if readed data is greater then given buffer */
+ {
+ LLOGLN(10, ("rpch_read: saving extra data"));
+ rpch->read_buffer_len = readed + data_length - length;
+ rpch->read_buffer = (uint8*) xmalloc(rpch->read_buffer_len);
+ data_length -= rpch->read_buffer_len;
+ memcpy(rpch->read_buffer, rpch_data + 24 + data_length, rpch->read_buffer_len);
+ }
+ memcpy(data + readed, rpch_data + 24, data_length);
+ readed += data_length;
+ if (status > data_length && readed < length)
+ {
+ LLOGLN(10, ("rpch_read: continue 2"));
+ continue;
+ }
+ break;
+ }
+ xfree(rpch_data);
+ return readed;
+}
+
+tbool rpch_connect(rdpRpch* rpch)
+{
+ int pdu_length;
+ uint8* pdu;
+ int status;
+ rdpRpchHTTP* http_out = rpch->http_out;
+ rdpRpchHTTP* http_in = rpch->http_in;
+
+ LLOGLN(10, ("rpch_connect:"));
+
+ if (http_out->state == RPCH_HTTP_DISCONNECTED)
+ {
+ LLOGLN(10, ("rpch_connect: calling rpch_out_connect_http"));
+ if (!rpch_out_connect_http(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_connect_http failed"));
+ return false;
+ }
+ }
+
+ if (!rpch_out_send_CONN_A1(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_send_CONN_A1 fault"));
+ return false;
+ }
+
+ if (http_in->state == RPCH_HTTP_DISCONNECTED)
+ {
+ LLOGLN(10, ("rpch_connect: calling rpch_in_connect_http"));
+ if (!rpch_in_connect_http(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_in_connect_http failed"));
+ return -1;
+ }
+ }
+
+ if (!rpch_in_send_CONN_B1(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_in_send_CONN_B1 fault"));
+ return false;
+ }
+
+ LLOGLN(10, ("rpch_connect: 1"));
+
+ /* Out Channel Response (section 2.1.2.1.4 ) */
+ if (rpch_out_read_http_header(rpch) < 0)
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_read_http_header failed"));
+ return -1;
+ }
+
+ if (http_out->contentLength != 0x40000000)
+ {
+ LLOGLN(0, ("rpch_connect: 'Bad Request'"));
+ return -1;
+ }
+
+ pdu_length = 0xFFFF;
+ pdu = (uint8*) xmalloc(pdu_length);
+
+ LLOGLN(10, ("rpch_connect: 2"));
+
+ /* CONN/A3 RTS PDU (section 2.2.4.4 ) 28 bytes */
+ status = rpch_out_read(rpch, pdu, pdu_length);
+ if (status < 0)
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_read failed"));
+ return false;
+ }
+
+ /* CONN/C2 RTS PDU (section 2.2.4.9 ) 46 bytes */
+ status = rpch_out_read(rpch, pdu, pdu_length);
+ if (status < 0)
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_read failed"));
+ return false;
+ }
+
+ LLOGLN(10, ("rpch_connect: 3"));
+
+ /* [MS-RPCH] 3.2.1.5.3.1 Connection Establishment
+ at this point VirtualChannel is created */
+
+ if (!rpch_in_send_bind(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_send_bind fault"));
+ return false;
+ }
+ LLOGLN(10, ("rpch_connect: 4"));
+
+ if (!rpch_out_recv_bind_ack(rpch))
+ {
+ LLOGLN(0, ("rpch_connect: rpch_out_recv_bind_ack fault"));
+ return false;
+ }
+ LLOGLN(10, ("rpch_connect: 5"));
+
+ if (!rpch_in_send_rpc_auth_3(rpch))
+ {
+ printf("rpch_out_send_rpc_auth_3 fault!\n");
+ return false;
+ }
+ LLOGLN(10, ("rpch_connect: 6"));
+
+ xfree(pdu);
+ LLOGLN(10, ("rpch_connect: out"));
+ return true;
+}
+
+/* check if pdu can be skipped by upper layers eg it's a control pdu */
+tbool rpch_skip_pdu(rdpRpch* rpch, STREAM* s)
+{
+ uint8* phold;
+ int frag_length;
+ int auth_length;
+ int call_id;
+ int status;
+ int ptype;
+ int pfc_flags;
+
+ phold = s->p;
+ s->p += 2;
+ stream_read_uint8(s, ptype);
+ stream_read_uint8(s, pfc_flags);
+ s->p += 4;
+ stream_read_uint16(s, frag_length);
+ stream_read_uint16(s, auth_length);
+ stream_read_uint32(s, call_id);
+ stream_read_uint32(s, status);
+ LLOGLN(10, ("rpch_skip_pdu: ptype %d pfc_flags %d frag_length %d "
+ "auth_length %d call_id %d status %d", ptype, pfc_flags,
+ frag_length, auth_length, call_id, status));
+
+ if (ptype == 0x14)
+ {
+ LLOGLN(10, ("rpch_skip_pdu: calling rpch_proceed_RTS"));
+ rpch_proceed_RTS(rpch, s->data, frag_length);
+ return true;
+ }
+
+ rpch->BytesReceived += frag_length;
+ //rpch->total_for_flow += frag_length;
+ rpch->AwailableWindow -= frag_length;
+
+ if (call_id == 5 && status == 4)
+ {
+ LLOGLN(0, ("rpch_skip_pdu: yup, 4"));
+ }
+
+ //if (status == 0x04)
+ if (call_id != 5)
+ {
+ return true;
+ }
+
+ //if (rpch->total_for_flow > 16 * 1024)
+ //if (rpch->total_for_flow > 35535)
+ if (rpch->AwailableWindow < 0x00008FFF) /* Just a simple workaround */
+ {
+ LLOGLN(10, ("rpch_skip_pdu: calling rpch_in_send_flow_control"));
+ //rpch->BytesReceived = 0;
+ rpch_in_send_flow_control(rpch);
+ //rpch->total_for_flow = 0;
+ }
+
+ s->p = phold + 24;
+ return false;
+}
diff --git a/libfreerdp-core/rpch.h b/libfreerdp-core/rpch.h
new file mode 100644
index 0000000..5a12ad3
--- /dev/null
+++ b/libfreerdp-core/rpch.h
@@ -0,0 +1,630 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * RDP Security
+ *
+ * Copyright 2012 Fujitsu Technology Solutions GmbH - Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.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.
+ */
+
+#ifndef __RPCH_H_
+#define __RPCH_H_
+
+typedef struct rdp_rpch rdpRpch;
+typedef struct rdp_rpch_http rdpRpchHTTP;
+
+#include "tcp.h"
+#include "ntlmssp.h"
+#include "tls.h"
+#include "crypto.h"
+
+#include <time.h>
+#include <freerdp/types.h>
+#include <freerdp/settings.h>
+#include <freerdp/utils/wait_obj.h>
+#include <freerdp/utils/sleep.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/hexdump.h>
+
+#define PTYPE_REQUEST 0x00
+#define PTYPE_PING 0x01
+#define PTYPE_RESPONSE 0x02
+#define PTYPE_FAULT 0x03
+#define PTYPE_WORKING 0x04
+#define PTYPE_NOCALL 0x05
+#define PTYPE_REJECT 0x06
+#define PTYPE_ACK 0x07
+#define PTYPE_CL_CANCEL 0x08
+#define PTYPE_FACK 0x09
+#define PTYPE_CANCEL_ACK 0x0a
+#define PTYPE_BIND 0x0b
+#define PTYPE_BIND_ACK 0x0c
+#define PTYPE_BIND_NAK 0x0d
+#define PTYPE_ALTER_CONTEXT 0x0e
+#define PTYPE_ALTER_CONTEXT_RESP 0x0f
+#define PTYPE_RPC_AUTH_3 0x10
+#define PTYPE_SHUTDOWN 0x11
+#define PTYPE_CO_CANCEL 0x12
+#define PTYPE_ORPHANED 0x13
+#define PTYPE_RTS 0x14
+
+#define PFC_FIRST_FRAG 0x01 /* First fragment */
+#define PFC_LAST_FRAG 0x02 /* Last fragment */
+#define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
+#define PFC_RESERVED_1 0x08
+#define PFC_CONC_MPX 0x10 /* supports concurrent multiplexing
+ * of a single connection. */
+#define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
+ * if true, guaranteed call did not
+ * execute. */
+#define PFC_MAYBE 0x40 /* 'maybe' call semantics requested */
+#define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
+ * was specified in the handle, and
+ * is present in the optional object
+ * field. If false, the object field
+ * is omitted. */
+
+#define RTS_FLAG_NONE 0x0000 /* No special flags. */
+#define RTS_FLAG_PING 0x0001 /* Proves that the sender is still active; can also be used to flush the pipeline by the other party. */
+#define RTS_FLAG_OTHER_CMD 0x0002 /* Indicates that the PDU contains a command that cannot be defined by the other flags in this table. */
+#define RTS_FLAG_RECYCLE_CHANNEL 0x0004 /* Indicates that the PDU is associated with recycling a channel. */
+#define RTS_FLAG_IN_CHANNEL 0x0008 /* Indicates that the PDU is associated with IN channel communications. */
+#define RTS_FLAG_OUT_CHANNEL 0x0010 /* Indicates that the PDU is associated with OUT channel communications. */
+#define RTS_FLAG_EOF 0x0020 /* Indicates that this is the last PDU on an IN channel or OUT channel. Not all channels, however, use this to indicate the last PDU. */
+#define RTS_FLAG_ECHO 0x0040 /* Signifies that this PDU is an echo request or response. */
+
+typedef uint16 p_context_id_t;
+
+typedef struct
+{
+ uuid if_uuid;
+ uint32 if_version;
+} p_syntax_id_t;
+
+typedef struct
+{
+ p_context_id_t p_cont_id;
+ uint8 n_transfer_syn; /* number of items */
+ uint8 reserved; /* alignment pad, m.b.z. */
+ p_syntax_id_t abstract_syntax; /* transfer syntax list */
+ p_syntax_id_t* transfer_syntaxes; /* size_is(n_transfer_syn)*/
+} p_cont_elem_t;
+
+typedef struct
+{
+ uint8 n_context_elem; /* number of items */
+ uint8 reserved; /* alignment pad, m.b.z. */
+ uint16 reserved2; /* alignment pad, m.b.z. */
+ p_cont_elem_t* p_cont_elem; /*size_is(n_cont_elem) */
+} p_cont_list_t;
+
+typedef enum _p_cont_def_result_t
+{
+ acceptance,
+ user_rejection,
+ provider_rejection
+} p_cont_def_result_t;
+
+typedef enum
+{
+ reason_not_specified,
+ abstract_syntax_not_supported,
+ proposed_transfer_syntaxes_not_supported,
+ local_limit_exceeded
+} p_provider_reason_t;
+
+
+typedef struct
+{
+ p_cont_def_result_t result;
+ p_provider_reason_t reason; /* only relevant if result != acceptance */
+ p_syntax_id_t transfer_syntax; /* tr syntax selected 0 if result not accepted */
+} p_result_t;
+
+/* Same order and number of elements as in bind request */
+
+typedef struct
+{
+ uint8 n_results; /* count */
+ uint8 reserved; /* alignment pad, m.b.z. */
+ uint16 reserved2; /* alignment pad, m.b.z. */
+ p_result_t* p_results; /* size_is(n_results) */
+} p_result_list_t;
+
+typedef struct
+{
+ uint8 major;
+ uint8 minor;
+} version_t;
+
+typedef version_t p_rt_version_t;
+
+typedef struct
+{
+ uint8 n_protocols; /* count */
+ p_rt_version_t* p_protocols; /* size_is(n_protocols) */
+} p_rt_versions_supported_t;
+
+typedef struct
+{
+ uint16 length;
+ char* port_spec; /* port string spec; size_is(length) */
+} port_any_t;
+
+#define REASON_NOT_SPECIFIED 0
+#define TEMPORARY_CONGESTION 1
+#define LOCAL_LIMIT_EXCEEDED 2
+#define CALLED_PADDR_UNKNOWN 3 /* not used */
+#define PROTOCOL_VERSION_NOT_SUPPORTED 4
+#define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
+#define USER_DATA_NOT_READABLE 6 /* not used */
+#define NO_PSAP_AVAILABLE 7 /* not used */
+
+typedef uint16 rpcrt_reason_code_t;/* 0..65535 */
+
+typedef struct {
+ uint8 rpc_vers;
+ uint8 rpc_vers_minor;
+ uint8 reserved[2];/* must be zero */
+ uint8 packed_drep[4];
+ uint32 reject_status;
+ uint8 reserved2[4];
+} rpcrt_optional_data_t;
+
+typedef struct {
+ rpcrt_reason_code_t reason_code; /* 0..65535 */
+ rpcrt_optional_data_t rpc_info; /* may be RPC specific */
+} rpcconn_reject_optional_data_t;
+
+typedef struct {
+ rpcrt_reason_code_t reason_code; /* 0..65535 */
+ rpcrt_optional_data_t rpc_info; /* may be RPC-specific */
+} rpcconn_disc_optional_data_t;
+
+typedef struct{
+ /* restore 4 byte alignment */
+
+ uint8* auth_pad; /* align(4); size_is(auth_pad_length) */
+ uint8 auth_type; /* :01 which authent service */
+ uint8 auth_level; /* :01 which level within service */
+ uint8 auth_pad_length; /* :01 */
+ uint8 auth_reserved; /* :01 reserved, m.b.z. */
+ uint32 auth_context_id; /* :04 */
+ uint8* auth_value; /* credentials; size_is(auth_length) */
+} auth_verifier_co_t;
+
+/* Connection-oriented PDU Definitions */
+
+typedef struct _rpcconn_alter_context_hdr_t {
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor ; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 alter context PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label */
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ uint16 max_xmit_frag; /* ignored */
+ uint16 max_recv_frag; /* ignored */
+ uint32 assoc_group_id; /* ignored */
+
+ /* presentation context list */
+
+ p_cont_list_t p_context_elem; /* variable size */
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier;
+
+} rpcconn_alter_context_hdr_t;
+
+typedef struct _rpcconn_alter_context_response_hdr_t {
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 alter
+ context response PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ uint16 max_xmit_frag; /* ignored */
+ uint16 max_recv_frag; /* ignored */
+ uint32 assoc_group_id; /* ignored */
+ port_any_t sec_addr; /* ignored */
+
+ /* restore 4-octet alignment */
+
+ uint8* pad2; /* size_is(align(4)) */
+
+ /* presentation context result list, including hints */
+
+ p_result_list_t p_result_list; /* variable size */
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_alter_context_response_hdr_t;
+
+/* bind header */
+typedef struct _rpcconn_bind_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 bind PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ uint16 max_xmit_frag; /* 16:02 max transmit frag size, bytes */
+ uint16 max_recv_frag; /* 18:02 max receive frag size, bytes */
+ uint32 assoc_group_id; /* 20:04 incarnation of client-server
+ * assoc group */
+ /* presentation context list */
+
+ p_cont_list_t p_context_elem; /* variable size */
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier;
+} rpcconn_bind_hdr_t;
+
+typedef struct _rpcconn_bind_ack_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor ; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 bind ack PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ uint16 max_xmit_frag; /* 16:02 max transmit frag size */
+ uint16 max_recv_frag; /* 18:02 max receive frag size */
+ uint32 assoc_group_id; /* 20:04 returned assoc_group_id */
+ port_any_t sec_addr; /* 24:yy optional secondary address
+ * for process incarnation; local port
+ * part of address only */
+ /* restore 4-octet alignment */
+
+ uint8* pad2; /* size_is(align(4)) */
+
+ /* presentation context result list, including hints */
+
+ p_result_list_t p_result_list; /* variable size */
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_bind_ack_hdr_t;
+
+typedef struct _rpcconn_rpc_auth_3_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor ; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 bind ack PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ uint16 max_xmit_frag; /* 16:02 max transmit frag size */
+ uint16 max_recv_frag; /* 18:02 max receive frag size */
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_rpc_auth_3_hdr_t;
+
+typedef struct _rpcconn_bind_nak_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor ; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 bind nak PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /*p_reject_reason_t*/uint16 provider_reject_reason; /* 16:02 presentation (TODO search definition of p_reject_reason_t)
+ context reject */
+
+ p_rt_versions_supported_t versions; /* 18:yy array of protocol
+ * versions supported */
+} rpcconn_bind_nak_hdr_t;
+
+
+typedef struct _rpcconn_cancel_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 CO cancel PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /* optional authentication verifier
+ * following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+
+} rpcconn_cancel_hdr_t;
+
+typedef struct _rpcconn_fault_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 fault PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label */
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /* needed for request, response, fault */
+
+ uint32 alloc_hint; /* 16:04 allocation hint */
+ p_context_id_t p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+
+ uint8 cancel_count; /* 22:01 received cancel count */
+ uint8 reserved; /* 23:01 reserved, m.b.z. */
+
+ /* fault code */
+
+ uint32 status; /* 24:04 run-time fault code or zero */
+
+ /* always pad to next 8-octet boundary */
+
+ uint8 reserved2[4]; /* 28:04 reserved padding, m.b.z. */
+
+ /* stub data here, 8-octet aligned
+ .
+ .
+ . */
+ uint8* stub_data;
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_fault_hdr_t;
+
+
+typedef struct _rpcconn_orphaned_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 orphaned PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /* optional authentication verifier
+ * following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_orphaned_hdr_t;
+
+
+typedef struct _rpcconn_request_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 request PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label */
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /* needed on request, response, fault */
+
+ uint32 alloc_hint; /* 16:04 allocation hint */
+ p_context_id_t p_cont_id; /* 20:02 pres context, i.e. data rep */
+ uint16 opnum; /* 22:02 operation # within the interface */
+
+ /* optional field for request, only present if the PFC_OBJECT_UUID
+ * field is non-zero */
+
+ uuid object; /* 24:16 object UID */
+
+ /* stub data, 8-octet aligned
+ .
+ .
+ . */
+ uint8* stub_data;
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_request_hdr_t;
+
+typedef struct _rpcconn_response_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 response PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 length of auth_value */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+
+ /* needed for request, response, fault */
+
+ uint32 alloc_hint; /* 16:04 allocation hint */
+ p_context_id_t p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+
+ uint8 cancel_count; /* 22:01 cancel count */
+ uint8 reserved; /* 23:01 reserved, m.b.z. */
+
+ /* stub data here, 8-octet aligned */
+ uint8* stub_data;
+
+ /* optional authentication verifier */
+ /* following fields present iff auth_length != 0 */
+
+ auth_verifier_co_t auth_verifier; /* xx:yy */
+} rpcconn_response_hdr_t;
+
+typedef struct _rpcconn_shutdown_hdr_t
+{
+ /* start 8-octet aligned */
+
+ /* common fields */
+ uint8 rpc_vers; /* 00:01 RPC version */
+ uint8 rpc_vers_minor; /* 01:01 minor version */
+ uint8 PTYPE; /* 02:01 shutdown PDU */
+ uint8 pfc_flags; /* 03:01 flags */
+ uint8 packed_drep[4]; /* 04:04 NDR data rep format label*/
+ uint16 frag_length; /* 08:02 total length of fragment */
+ uint16 auth_length; /* 10:02 */
+ uint32 call_id; /* 12:04 call identifier */
+
+ /* end common fields */
+} rpcconn_shutdown_hdr_t;
+
+/* proprietary stuff from Dmitrij Jasnov */
+
+#define RPCH_HTTP_DISCONNECTED 0
+#define RPCH_HTTP_SENDING 1
+#define RPCH_HTTP_RECIEVING 2
+
+struct rdp_rpch_http
+{
+ int state;
+ int contentLength;
+ int remContentLength;
+ struct _NTLMSSP *ntht;
+};
+
+struct rdp_rpch
+{
+ struct rdp_settings* settings;
+ struct rdp_tcp* tcp_in;
+ struct rdp_tcp* tcp_out;
+ struct rdp_tls* tls_in;
+ struct rdp_tls* tls_out;
+ struct _NTLMSSP *ntlmssp;
+
+ struct rdp_rpch_http* http_in;
+ struct rdp_rpch_http* http_out;
+
+ uint8* write_buffer;
+ uint32 write_buffer_len;
+ uint8* read_buffer;
+ uint32 read_buffer_len;
+
+ uint32 BytesReceived;
+ uint32 AwailableWindow;
+ uint32 BytesSent;
+ uint32 RecAwailableWindow;
+ uint8* virtualConnectionCookie;
+ uint8* OUTChannelCookie;
+ uint8* INChannelCookie;
+ uint32 call_id;
+ uint32 pipe_call_id;
+ int total_for_flow;
+};
+
+rdpRpch* rpch_new(rdpSettings* settings);
+tbool rpch_attach(rdpRpch* rpch, rdpTcp* tcp_in, rdpTcp* tcp_out, struct rdp_tls* tls_in, struct rdp_tls* tls_out);
+tbool rpch_connect(rdpRpch* rpch);
+int rpch_write(rdpRpch* rpch, uint8* data, int length, uint16 opnum);
+int rpch_read(rdpRpch* rpch, uint8* data, int length);
+tbool rpch_skip_pdu(rdpRpch* rpch, STREAM* s);
+
+#ifdef WITH_DEBUG_RPCH
+#define DEBUG_RPCH(fmt, ...) DEBUG_CLASS(RPCH, fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_RPCH(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
+#endif
+
+#endif /* __RPCH_H_ */
diff --git a/libfreerdp-core/tcp.c b/libfreerdp-core/tcp.c
index abd93fa..32c3190 100644
--- a/libfreerdp-core/tcp.c
+++ b/libfreerdp-core/tcp.c
@@ -49,9 +49,16 @@
#include <freerdp/utils/print.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/memory.h>
+#include <freerdp/utils/hexdump.h>
#include "tcp.h"
+#define LLOG_LEVEL 11
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
void tcp_get_ip_address(rdpTcp * tcp)
{
uint8* ip;
@@ -207,6 +214,9 @@ int tcp_read(rdpTcp* tcp, uint8* data, int length)
status = recv(tcp->sockfd, data, length, 0);
+ LLOGLN(10, ("tcp_read: length %d status %d", length, status));
+ LHEXDUMP(10, (data, length));
+
if (status == 0)
{
/* Peer disconnected. */
@@ -231,6 +241,10 @@ int tcp_read(rdpTcp* tcp, uint8* data, int length)
#endif
return -1;
}
+ else
+ {
+ //freerdp_hexdump(data, status);
+ }
return status;
}
@@ -239,8 +253,13 @@ int tcp_write(rdpTcp* tcp, uint8* data, int length)
{
int status;
+ LLOGLN(10, ("tcp_write:"));
+
status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
+ LLOGLN(10, ("tcp_write: length %d status %d", length, status));
+ LHEXDUMP(10, (data, length));
+
if (status < 0)
{
#ifdef _WIN32
diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c
index 34baa2a..6e97392 100644
--- a/libfreerdp-core/tls.c
+++ b/libfreerdp-core/tls.c
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -22,10 +22,19 @@
#include "tls.h"
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
+
+static int g_total_read = 0;
+
tbool tls_connect(rdpTls* tls)
{
int connection_status;
+ LLOGLN(10, ("tls_connect:"));
tls->ctx = SSL_CTX_new(TLSv1_client_method());
if (tls->ctx == NULL)
@@ -126,53 +135,139 @@ tbool tls_disconnect(rdpTls* tls)
return true;
}
+/* try to read length bytes
+ * returns the number of bytes read or -1 on error
+ * returns zero on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
+ * returns zero if length < 1 */
int tls_read(rdpTls* tls, uint8* data, int length)
{
int status;
+ int left;
+
+ LLOGLN(10, ("tls_read: in length %d", length));
+
+ if (length < 1)
+ {
+ return 0;
+ }
+
+ if (tls->read_extra != NULL)
+ {
+ LLOGLN(10, ("tls_read: got left over, using first"));
+ left = stream_get_left(tls->read_extra);
+ if (length < left)
+ {
+ memcpy(data, tls->read_extra->p, length);
+ tls->read_extra->p += length;
+ LHEXDUMP(10, (data, length));
+ return length;
+ }
+ memcpy(data, tls->read_extra->p, left);
+ LLOGLN(10, ("tls_read: freeing read_extra"));
+ stream_free(tls->read_extra);
+ tls->read_extra = NULL;
+ status = tls_read(tls, data + left, length - left);
+ if (status < 0)
+ {
+ return -1;
+ }
+ LHEXDUMP(10, (data, left + status));
+ return left + status;
+ }
status = SSL_read(tls->ssl, data, length);
+ LLOGLN(10, ("tls_read: ssl %p SSL_read rv %d", tls->ssl, status));
+ if (status > 0)
+ {
+ g_total_read += status;
+ LLOGLN(10, ("tls_read: g_total_read %d", g_total_read));
+ LHEXDUMP(10, (data, status));
+ return status;
+ }
+
+ if (status == 0)
+ {
+ return -1; /* disconnected */
+ }
+
+ /* status must be < 0 */
switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_NONE:
break;
-
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
status = 0;
break;
-
default:
tls_print_error("SSL_read", tls->ssl, status);
status = -1;
break;
}
-
+ LLOGLN(10, ("tls_read: out status %d", status));
return status;
}
+int tls_return(rdpTls* tls, uint8* data, int length)
+{
+ int offset;
+ int org_size;
+
+ LLOGLN(10, ("tls_return: returning %d bytes", length));
+ if (length < 1)
+ {
+ return 0;
+ }
+ if (tls->read_extra == NULL)
+ {
+ tls->read_extra = stream_new(length);
+ memcpy(tls->read_extra->data, data, length);
+ return 0;
+ }
+ org_size = tls->read_extra->size;
+ offset = (int) (tls->read_extra->p - tls->read_extra->data);
+ tls->read_extra->size += length;
+ tls->read_extra->data = (uint8*) xrealloc(tls->read_extra->data, tls->read_extra->size);
+ tls->read_extra->p = tls->read_extra->data + offset;
+ memcpy(tls->read_extra->data + org_size, data, length);
+ return 0;
+}
+
int tls_write(rdpTls* tls, uint8* data, int length)
{
int status;
+ LLOGLN(10, ("tls_write: int length %d", length));
+
status = SSL_write(tls->ssl, data, length);
+ LLOGLN(10, ("tls_write: ssl %p SSL_write rv %d", tls->ssl, status));
+ if (status > 0)
+ {
+ LHEXDUMP(10, (data, status));
+ return status;
+ }
+
+ if (status == 0)
+ {
+ return -1; /* disconnected */
+ }
+
switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_NONE:
break;
-
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
status = 0;
break;
-
default:
tls_print_error("SSL_write", tls->ssl, status);
status = -1;
break;
}
-
+ LLOGLN(10, ("tls_write: out status %d", status));
return status;
}
diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h
index c3f2f59..8800a50 100644
--- a/libfreerdp-core/tls.h
+++ b/libfreerdp-core/tls.h
@@ -8,7 +8,7 @@
* 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
+ * 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,
@@ -38,6 +38,7 @@ struct rdp_tls
SSL_CTX* ctx;
rdpSettings* settings;
rdpCertificateStore* certificate_store;
+ STREAM* read_extra;
};
boolean tls_connect(rdpTls* tls);
@@ -47,6 +48,8 @@ boolean tls_disconnect(rdpTls* tls);
int tls_read(rdpTls* tls, uint8* data, int length);
int tls_write(rdpTls* tls, uint8* data, int length);
+int tls_return(rdpTls* tls, uint8* data, int length);
+
CryptoCert tls_get_certificate(rdpTls* tls);
boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname);
void tls_print_certificate_error(char* hostname, char* fingerprint);
diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c
index 620a088..a19a044 100644
--- a/libfreerdp-core/transport.c
+++ b/libfreerdp-core/transport.c
@@ -40,7 +40,13 @@
#include "credssp.h"
#include "transport.h"
-#define BUFFER_SIZE 16384
+#define BUFFER_SIZE (16384 * 2)
+
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+#define LHEXDUMP(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { freerdp_hexdump _args ; } } while (0)
STREAM* transport_recv_stream_init(rdpTransport* transport, int size)
{
@@ -58,21 +64,102 @@ STREAM* transport_send_stream_init(rdpTransport* transport, int size)
return s;
}
+boolean transport_tsg_connect(rdpTransport* transport, const char* hostname, uint16 port)
+{
+ rdpTsg* tsg = tsg_new(transport->settings);
+ tsg->transport = transport;
+ transport->tsg = tsg;
+
+ LLOGLN(10, ("transport_tsg_connect:"));
+ if (transport->tls_in == NULL)
+ {
+ LLOGLN(10, ("transport_tsg_connect: tls_in calling tls_new"));
+ transport->tls_in = tls_new(transport->settings);
+ }
+ transport->tls_in->sockfd = transport->tcp_in->sockfd;
+ if (transport->tls_out == NULL)
+ {
+ LLOGLN(10, ("transport_tsg_connect: tls_out calling tls_new"));
+ transport->tls_out = tls_new(transport->settings);
+ }
+ transport->tls_out->sockfd = transport->tcp_out->sockfd;
+ if (tls_connect(transport->tls_in) == false)
+ {
+ LLOGLN(0, ("transport_tsg_connect: tls_in tls_connect failed"));
+ return false;
+ }
+ LLOGLN(10, ("transport_tsg_connect: tls_in tls_connect ok"));
+ if (tls_connect(transport->tls_out) == false)
+ {
+ LLOGLN(0, ("transport_tsg_connect: tls_out tls_connect failed"));
+ return false;
+ }
+ LLOGLN(10, ("transport_tsg_connect: tls_out tls_connect ok"));
+ if (!tsg_connect(tsg, hostname, port))
+ {
+ LLOGLN(0, ("transport_tsg_connect: tsg_connect failed"));
+ return false;
+ }
+ LLOGLN(10, ("transport_tsg_connect: tsg_connect ok"));
+ LLOGLN(10, ("transport_tsg_connect: ok"));
+ return true;
+}
+
tbool transport_connect(rdpTransport* transport, const char* hostname, uint16 port)
{
- return tcp_connect(transport->tcp, hostname, port);
+ tbool ok;
+
+ LLOGLN(10, ("transport_connect:"));
+ if (transport->settings->tsg)
+ {
+ LLOGLN(10, ("transport_connect: settings->tsg set"));
+ transport->layer = TRANSPORT_LAYER_TSG;
+ transport->tcp_out = tcp_new(transport->settings);
+ ok = tcp_connect(transport->tcp_in, transport->settings->tsg_server, 443);
+ if (ok)
+ {
+ ok = tcp_connect(transport->tcp_out, transport->settings->tsg_server, 443);
+ if (ok)
+ {
+ ok = transport_tsg_connect(transport, hostname, port);
+ if (ok)
+ {
+ LLOGLN(0, ("transport_connect: gw connect ok"));
+ }
+ else
+ {
+ LLOGLN(0, ("transport_connect: gw transport_tsg_connect failed"));
+ }
+ }
+ else
+ {
+ LLOGLN(0, ("transport_connect: gw tcp_connect tcp_out failed"));
+ }
+ }
+ else
+ {
+ LLOGLN(0, ("transport_connect: gw tcp_connect tcp_in failed"));
+ }
+ return ok;
+ }
+ else
+ {
+ LLOGLN(10, ("transport_connect: settings->tsg not set"));
+ transport->tcp_out = transport->tcp_in;
+ return tcp_connect(transport->tcp_in, hostname, port);
+ }
}
void transport_attach(rdpTransport* transport, int sockfd)
{
- transport->tcp->sockfd = sockfd;
+ transport->tcp_in->sockfd = sockfd;
}
tbool transport_disconnect(rdpTransport* transport)
{
if (transport->layer == TRANSPORT_LAYER_TLS)
- tls_disconnect(transport->tls);
- return tcp_disconnect(transport->tcp);
+ tls_disconnect(transport->tls_in);
+ return tcp_disconnect(transport->tcp_in);
}
tbool transport_connect_rdp(rdpTransport* transport)
@@ -84,13 +171,13 @@ tbool transport_connect_rdp(rdpTransport* transport)
tbool transport_connect_tls(rdpTransport* transport)
{
- if (transport->tls == NULL)
- transport->tls = tls_new(transport->settings);
+ if (transport->tls_in == NULL)
+ transport->tls_in = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
- transport->tls->sockfd = transport->tcp->sockfd;
+ transport->tls_in->sockfd = transport->tcp_in->sockfd;
- if (tls_connect(transport->tls) == false)
+ if (tls_connect(transport->tls_in) == false)
return false;
return true;
@@ -98,13 +185,16 @@ tbool transport_connect_tls(rdpTransport* transport)
tbool transport_connect_nla(rdpTransport* transport)
{
- if (transport->tls == NULL)
- transport->tls = tls_new(transport->settings);
+ freerdp* instance;
+ rdpSettings* settings;
+
+ if (transport->tls_in == NULL)
+ transport->tls_in = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
- transport->tls->sockfd = transport->tcp->sockfd;
+ transport->tls_in->sockfd = transport->tcp_in->sockfd;
- if (tls_connect(transport->tls) == false)
+ if (tls_connect(transport->tls_in) == false)
return false;
/* Network Level Authentication */
@@ -112,8 +202,11 @@ tbool transport_connect_nla(rdpTransport* transport)
if (transport->settings->authentication == false)
return true;
+ settings = transport->settings;
+ instance = (freerdp*) settings->instance;
+
if (transport->credssp == NULL)
- transport->credssp = credssp_new(transport);
+ transport->credssp = credssp_new(instance, transport->tls_in, settings);
if (credssp_authenticate(transport->credssp) < 0)
{
@@ -138,13 +231,13 @@ tbool transport_accept_rdp(rdpTransport* transport)
tbool transport_accept_tls(rdpTransport* transport)
{
- if (transport->tls == NULL)
- transport->tls = tls_new(transport->settings);
+ if (transport->tls_in == NULL)
+ transport->tls_in = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
- transport->tls->sockfd = transport->tcp->sockfd;
+ transport->tls_in->sockfd = transport->tcp_in->sockfd;
- if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) == false)
+ if (tls_accept(transport->tls_in, transport->settings->cert_file, transport->settings->privatekey_file) == false)
return false;
return true;
@@ -152,13 +245,13 @@ tbool transport_accept_tls(rdpTransport* transport)
tbool transport_accept_nla(rdpTransport* transport)
{
- if (transport->tls == NULL)
- transport->tls = tls_new(transport->settings);
+ if (transport->tls_in == NULL)
+ transport->tls_in = tls_new(transport->settings);
transport->layer = TRANSPORT_LAYER_TLS;
- transport->tls->sockfd = transport->tcp->sockfd;
+ transport->tls_in->sockfd = transport->tcp_in->sockfd;
- if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) == false)
+ if (tls_accept(transport->tls_in, transport->settings->cert_file, transport->settings->privatekey_file) == false)
return false;
/* Network Level Authentication */
@@ -171,19 +264,32 @@ tbool transport_accept_nla(rdpTransport* transport)
return true;
}
+/* will not return until all data is read if transport->blocking is set */
+/* else returns 0 if call would block */
int transport_read_layer(rdpTransport* transport, uint8* data, int bytes)
{
int read = 0;
int status = -1;
+ LLOGLN(10, ("transport_read_layer:"));
while (read < bytes)
{
- if (transport->layer == TRANSPORT_LAYER_TLS)
- status = tls_read(transport->tls, data + read, bytes - read);
- else if (transport->layer == TRANSPORT_LAYER_TCP)
- status = tcp_read(transport->tcp, data + read, bytes - read);
- //else if (transport->layer == TRANSPORT_LAYER_TSG)
- // status = tsg_read(transport->tsg, data + read, bytes - read);
+ switch (transport->layer)
+ {
+ case TRANSPORT_LAYER_TSG:
+ case TRANSPORT_LAYER_TLS:
+ status = tls_read(transport->tls_out, data + read, bytes - read);
+ break;
+ case TRANSPORT_LAYER_TCP:
+ status = tcp_read(transport->tcp_out, data + read, bytes - read);
+ break;
+ //case TRANSPORT_LAYER_TSG:
+ //status = tsg_read(transport->tsg, data + read, bytes - read);
+ //break;
+ default:
+ LLOGLN(0, ("transport_read_layer: unknown layer %d", transport->layer));
+ break;
+ }
/* blocking means that we can't continue until this is read
it's not tcp blocking */
@@ -198,12 +304,19 @@ int transport_read_layer(rdpTransport* transport, uint8* data, int bytes)
if (status == 0)
{
- if (transport->layer == TRANSPORT_LAYER_TLS)
- tcp_can_recv(transport->tls->sockfd, 100);
- else if (transport->layer == TRANSPORT_LAYER_TCP)
- tcp_can_recv(transport->tcp->sockfd, 100);
- else
- freerdp_usleep(transport->usleep_interval);
+ switch (transport->layer)
+ {
+ case TRANSPORT_LAYER_TSG:
+ case TRANSPORT_LAYER_TLS:
+ tcp_can_recv(transport->tls_out->sockfd, 100);
+ break;
+ case TRANSPORT_LAYER_TCP:
+ tcp_can_recv(transport->tcp_out->sockfd, 100);
+ break;
+ default:
+ freerdp_usleep(transport->usleep_interval);
+ break;
+ }
}
}
@@ -216,70 +329,92 @@ int transport_read(rdpTransport* transport, STREAM* s)
int pdu_bytes;
int stream_bytes;
int transport_status;
+ int header_bytes;
+ tbool got_whole_pdu;
+ LLOGLN(10, ("transport_read: blocking %d", transport->blocking));
transport_status = 0;
/* first check if we have header */
stream_bytes = stream_get_length(s);
- if (stream_bytes < 4)
+ header_bytes = transport->layer == TRANSPORT_LAYER_TSG ? 10 : 4;
+
+ if (stream_bytes < header_bytes)
{
+ LLOGLN(10, ("transport_read: transport_read_layer 1st call"));
status = transport_read_layer(transport, s->data + stream_bytes,
- 4 - stream_bytes);
+ header_bytes - stream_bytes);
if (status < 0)
+ {
+ LLOGLN(0, ("transport_read: transport_read_layer failed"));
return status;
+ }
transport_status += status;
- if ((status + stream_bytes) < 4)
+ if ((status + stream_bytes) < header_bytes)
+ {
+ LLOGLN(10, ("transport_read: not enough for header"));
return transport_status;
+ }
stream_bytes += status;
}
pdu_bytes = 0;
- /* if header is present, read in exactly one PDU */
- if (s->data[0] == 0x03)
+
+ if (transport->layer == TRANSPORT_LAYER_TSG)
{
- /* TPKT header */
- pdu_bytes = (s->data[2] << 8) | s->data[3];
+ pdu_bytes = s->data[8];
+ pdu_bytes |= s->data[9] << 8;
}
- else if (s->data[0] == 0x30)
+ else
{
- /* TSRequest (NLA) */
- if (s->data[1] & 0x80)
+ /* if header is present, read in exactly one PDU */
+ if (s->data[0] == 0x03)
{
- if ((s->data[1] & ~(0x80)) == 1)
- {
- pdu_bytes = s->data[2];
- pdu_bytes += 3;
- }
- else if ((s->data[1] & ~(0x80)) == 2)
+ /* TPKT header */
+ pdu_bytes = (s->data[2] << 8) | s->data[3];
+ }
+ else if (s->data[0] == 0x30)
+ {
+ /* TSRequest (NLA) */
+ if (s->data[1] & 0x80)
{
- pdu_bytes = (s->data[2] << 8) | s->data[3];
- pdu_bytes += 4;
+ if ((s->data[1] & ~(0x80)) == 1)
+ {
+ pdu_bytes = s->data[2];
+ pdu_bytes += 3;
+ }
+ else if ((s->data[1] & ~(0x80)) == 2)
+ {
+ pdu_bytes = (s->data[2] << 8) | s->data[3];
+ pdu_bytes += 4;
+ }
+ else
+ {
+ printf("Error reading TSRequest!\n");
+ }
}
else
{
- printf("Error reading TSRequest!\n");
+ pdu_bytes = s->data[1];
+ pdu_bytes += 2;
}
}
else
{
- pdu_bytes = s->data[1];
- pdu_bytes += 2;
+ /* Fast-Path Header */
+ if (s->data[1] & 0x80)
+ pdu_bytes = ((s->data[1] & 0x7f) << 8) | s->data[2];
+ else
+ pdu_bytes = s->data[1];
}
}
- else
- {
- /* Fast-Path Header */
- if (s->data[1] & 0x80)
- pdu_bytes = ((s->data[1] & 0x7f) << 8) | s->data[2];
- else
- pdu_bytes = s->data[1];
- }
+ LLOGLN(10, ("transport_read: transport_read_layer 2nd call"));
status = transport_read_layer(transport, s->data + stream_bytes,
pdu_bytes - stream_bytes);
@@ -288,15 +423,37 @@ int transport_read(rdpTransport* transport, STREAM* s)
transport_status += status;
+ got_whole_pdu = stream_bytes + status >= pdu_bytes;
+
#ifdef WITH_DEBUG_TRANSPORT
/* dump when whole PDU is read */
- if (stream_bytes + status >= pdu_bytes)
+ if (got_whole_pdu)
{
printf("Local < Remote\n");
freerdp_hexdump(s->data, pdu_bytes);
}
#endif
+#if 1
+ if (transport->blocking)
+ {
+ if ((transport->layer == TRANSPORT_LAYER_TSG) && got_whole_pdu)
+ {
+ //uint8* jj = s->p; // why don't work
+ LLOGLN(10, ("transport_read: calling tsg_skip_pdu"));
+ s->p = s->data;
+ if (tsg_skip_pdu(transport->tsg, s))
+ {
+ LLOGLN(10, ("transport_read: skipping"));
+ s->p = s->data;
+ return transport_read(transport, s);
+ }
+ //s->p = jj;
+ }
+ }
+#endif
+
+ LLOGLN(10, ("transport_read: returning %d", transport_status));
return transport_status;
}
@@ -306,12 +463,12 @@ static int transport_read_nonblocking(rdpTransport* transport)
stream_check_size(transport->recv_buffer, 32 * 1024);
status = transport_read(transport, transport->recv_buffer);
-
if (status <= 0)
+ {
+ /* error or blocking */
return status;
-
+ }
stream_seek(transport->recv_buffer, status);
-
return status;
}
@@ -320,6 +477,8 @@ int transport_write(rdpTransport* transport, STREAM* s)
int status = -1;
int length;
+ LLOGLN(10, ("transport_write:"));
+
length = stream_get_length(s);
stream_set_pos(s, 0);
@@ -333,10 +492,21 @@ int transport_write(rdpTransport* transport, STREAM* s)
while (length > 0)
{
- if (transport->layer == TRANSPORT_LAYER_TLS)
- status = tls_write(transport->tls, stream_get_tail(s), length);
- else if (transport->layer == TRANSPORT_LAYER_TCP)
- status = tcp_write(transport->tcp, stream_get_tail(s), length);
+ switch (transport->layer)
+ {
+ case TRANSPORT_LAYER_TLS:
+ status = tls_write(transport->tls_in, stream_get_tail(s), length);
+ break;
+ case TRANSPORT_LAYER_TCP:
+ status = tcp_write(transport->tcp_in, stream_get_tail(s), length);
+ break;
+ case TRANSPORT_LAYER_TSG:
+ status = tsg_write(transport->tsg, stream_get_tail(s), length);
+ break;
+ default:
+ LLOGLN(0, ("transport_write: unknown transport->layer %d", transport->layer));
+ break;
+ }
if (status < 0)
break; /* error occurred */
@@ -345,7 +515,6 @@ int transport_write(rdpTransport* transport, STREAM* s)
{
/* blocking while sending */
freerdp_usleep(transport->usleep_interval);
-
}
length -= status;
@@ -363,56 +532,129 @@ int transport_write(rdpTransport* transport, STREAM* s)
void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount)
{
- rfds[*rcount] = (void*)(long)(transport->tcp->sockfd);
+ LLOGLN(10, ("transport_get_fds:"));
+ rfds[*rcount] = (void*)(long)(transport->tcp_out->sockfd);
(*rcount)++;
+ LLOGLN(10, (" fd1 %d", transport->tcp_out->sockfd));
+ if (transport->tcp_in == transport->tcp_out)
+ {
+ }
+ else
+ {
+ rfds[*rcount] = (void*)(long)(transport->tcp_in->sockfd);
+ (*rcount)++;
+ LLOGLN(10, (" fd1 %d", transport->tcp_in->sockfd));
+ }
+}
+
+int get_rdp_pdu_length(uint8* data)
+{
+ int pdu_bytes;
+
+ if (data[0] == 0x03)
+ {
+ /* TPKT header */
+ pdu_bytes = (data[2] << 8) | data[3];
+ }
+ else
+ {
+ /* Fast-Path Header */
+ if (data[1] & 0x80)
+ {
+ pdu_bytes = ((data[1] & 0x7f) << 8) | data[2];
+ }
+ else
+ {
+ pdu_bytes = data[1];
+ }
+ }
+ return pdu_bytes;
+}
+
+static int do_callback(rdpTransport* transport, STREAM* s)
+{
+ int rv;
+
+ rv = 0;
+ transport->level++;
+ if (transport->recv_callback(transport, s, transport->recv_extra) == false)
+ {
+ LLOGLN(0, ("transport_check_fds: transport->recv_callback failed"));
+ rv = -1;
+ }
+ transport->level--;
+ return rv;
}
int transport_check_fds(rdpTransport* transport)
{
int pos;
int status;
+ int rdp_pdu_length;
+ int extra_bytes;
uint16 length;
+ STREAM* proc_s;
+ STREAM* s;
+
+ int ptype;
+ int pfc_flags;
+ int frag_length;
+ int auth_length;
+ int call_id;
+ int alloc_hint;
+ int auth_pad_length;
+
+ LLOGLN(10, ("transport_check_fds:"));
+ /* test for nested calls */
if (transport->level != 0)
{
- printf("transport_check_fds: error, nested calls\n");
+ LLOGLN(0, ("transport_check_fds: error, nested calls"));
return -1;
}
status = transport_read_nonblocking(transport);
if (status < 0)
+ {
+ LLOGLN(0, ("transport_check_fds: transport_read_nonblocking failed"));
return status;
+ }
- if ((pos = stream_get_pos(transport->recv_buffer)) > 0)
+ pos = stream_get_pos(transport->recv_buffer);
+ if (pos > 0)
{
stream_set_pos(transport->recv_buffer, 0);
- if (tpkt_verify_header(transport->recv_buffer)) /* TPKT */
+ if (transport->layer == TRANSPORT_LAYER_TSG)
{
- /* Ensure the TPKT header is available. */
- if (pos <= 4)
+ if (pos <= 10)
{
stream_set_pos(transport->recv_buffer, pos);
return 0;
}
- length = tpkt_read_header(transport->recv_buffer);
+ stream_set_pos(transport->recv_buffer, 8);
+ stream_read_uint16(transport->recv_buffer, length);
+ stream_set_pos(transport->recv_buffer, 0);
+ LLOGLN(10, ("transport_check_fds: got header tsg packet length %d", length));
+ LLOGLN(10, ("transport_check_fds: dumping 1st 10 bytes of HTTP data"));
+ LHEXDUMP(10, (transport->recv_buffer->data, 10));
}
- else /* Fast Path */
+ else
{
- /* Ensure the Fast Path header is available. */
- if (pos <= 2)
+ /* Ensure header is available. */
+ if (pos <= 4)
{
stream_set_pos(transport->recv_buffer, pos);
return 0;
}
- /* Fastpath header can be two or three bytes long. */
- length = fastpath_header_length(transport->recv_buffer);
- if (pos < length)
+ if (tpkt_verify_header(transport->recv_buffer)) /* TPKT */
{
- stream_set_pos(transport->recv_buffer, pos);
- return 0;
+ length = tpkt_read_header(transport->recv_buffer);
+ }
+ else /* Fast Path */
+ {
+ length = fastpath_read_header(NULL, transport->recv_buffer);
}
- length = fastpath_read_header(NULL, transport->recv_buffer);
}
if (length == 0)
@@ -428,19 +670,95 @@ int transport_check_fds(rdpTransport* transport)
return 0; /* Packet is not yet completely received. */
}
- stream_set_pos(transport->recv_buffer, length);
- stream_seal(transport->recv_buffer);
- stream_set_pos(transport->recv_buffer, 0);
+ /* whole PDU is read in, for tsg, this is just the fragment */
+ LLOGLN(10, ("transport_check_fds: got whole transport pdu"));
- transport->level++;
- if (transport->recv_callback(transport, transport->recv_buffer, transport->recv_extra) == false)
- status = -1;
- transport->level--;
+ proc_s = NULL;
+ if (transport->layer == TRANSPORT_LAYER_TSG)
+ {
+
+ stream_set_pos(transport->recv_buffer, 0);
+ if (tsg_skip_pdu(transport->tsg, transport->recv_buffer))
+ {
+ LLOGLN(10, ("transport_check_fds: tsg_skip_pdu returned true"));
+ stream_set_pos(transport->recv_buffer, 0);
+ return 0;
+ }
+
+ stream_set_pos(transport->recv_buffer, 0);
+ stream_seek(transport->recv_buffer, 2);
+ stream_read_uint8(transport->recv_buffer, ptype);
+ stream_read_uint8(transport->recv_buffer, pfc_flags);
+ stream_seek(transport->recv_buffer, 4);
+ stream_read_uint16(transport->recv_buffer, frag_length);
+ stream_read_uint16(transport->recv_buffer, auth_length);
+ stream_read_uint32(transport->recv_buffer, call_id);
+ stream_read_uint32(transport->recv_buffer, alloc_hint);
+ auth_pad_length = transport->recv_buffer->data[frag_length - auth_length - 6];
+ length = frag_length - auth_length - 24 - 8 - auth_pad_length;
+
+ LLOGLN(10, ("transport_check_fds: ptype %d pfc_flags %d "
+ "frag_length %d auth_length %d call_id %d alloc_hint %d auth_pad_length %d length %d",
+ ptype, pfc_flags, frag_length, auth_length, call_id, alloc_hint, auth_pad_length, length));
+
+ s = transport->proc_buffer;
+ memcpy(s->p, transport->recv_buffer->data + 24, length);
+ stream_seek(s, length);
+
+ while (true) /* can be more than one RDP PDU in one TSG PDU */
+ {
+ pos = stream_get_pos(s);
+ if (pos > 3)
+ {
+ rdp_pdu_length = get_rdp_pdu_length(s->data);
+ LLOGLN(10, ("transport_check_fds: rdp_pdu_length %d pos %d", rdp_pdu_length, pos));
+ if (pos >= rdp_pdu_length)
+ {
+ LLOGLN(10, ("transport_check_fds: got whole rdp pdu"));
+ stream_set_pos(s, rdp_pdu_length);
+ stream_seal(s);
+ stream_set_pos(s, 0);
+ if (do_callback(transport, s) != 0)
+ {
+ LLOGLN(0, ("transport_check_fds: do_callback failed"));
+ return -1;
+ }
+ stream_set_pos(s, 0);
+ extra_bytes = pos - rdp_pdu_length;
+ LLOGLN(10, ("transport_check_fds: extra_bytes %d", extra_bytes));
+ LHEXDUMP(10, (s->data + rdp_pdu_length - extra_bytes, extra_bytes));
+ memmove(s->p, s->data + rdp_pdu_length, extra_bytes);
+ stream_seek(s, extra_bytes);
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ proc_s = transport->recv_buffer;
+ stream_set_pos(transport->recv_buffer, length);
+ stream_seal(transport->recv_buffer);
+ stream_set_pos(transport->recv_buffer, 0);
+ }
+
+ if (proc_s != NULL)
+ {
+ if (do_callback(transport, proc_s) != 0)
+ {
+ LLOGLN(0, ("transport_check_fds: do_callback failed"));
+ return -1;
+ }
+ }
stream_set_pos(transport->recv_buffer, 0);
if (status < 0)
+ {
+ LLOGLN(0, ("transport_check_fds: failed"));
return status;
+ }
}
return 0;
@@ -449,7 +767,9 @@ int transport_check_fds(rdpTransport* transport)
tbool transport_set_blocking_mode(rdpTransport* transport, tbool blocking)
{
transport->blocking = blocking;
- return tcp_set_blocking_mode(transport->tcp, blocking);
+ if (transport->settings->tsg)
+ tcp_set_blocking_mode(transport->tcp_in, blocking);
+ return tcp_set_blocking_mode(transport->tcp_out, blocking);
}
rdpTransport* transport_new(rdpSettings* settings)
@@ -460,7 +780,7 @@ rdpTransport* transport_new(rdpSettings* settings)
if (transport != NULL)
{
- transport->tcp = tcp_new(settings);
+ transport->tcp_in = tcp_new(settings);
transport->settings = settings;
/* a small 0.1ms delay when transport is blocking. */
@@ -469,6 +789,9 @@ rdpTransport* transport_new(rdpSettings* settings)
/* receive buffer for non-blocking read. */
transport->recv_buffer = stream_new(BUFFER_SIZE);
+ /* for tsg fragmenting */
+ transport->proc_buffer = stream_new(BUFFER_SIZE);
+
/* buffers for blocking read/write */
transport->recv_stream = stream_new(BUFFER_SIZE);
transport->send_stream = stream_new(BUFFER_SIZE);
@@ -488,9 +811,16 @@ void transport_free(rdpTransport* transport)
stream_free(transport->recv_buffer);
stream_free(transport->recv_stream);
stream_free(transport->send_stream);
- if (transport->tls)
- tls_free(transport->tls);
- tcp_free(transport->tcp);
+ stream_free(transport->proc_buffer);
+ if (transport->tls_in)
+ {
+ tls_free(transport->tls_in);
+ if (transport->layer == TRANSPORT_LAYER_TSG)
+ tls_free(transport->tls_out);
+ }
+ tcp_free(transport->tcp_in);
+ if (transport->layer == TRANSPORT_LAYER_TSG)
+ tcp_free(transport->tcp_out);
xfree(transport);
}
}
diff --git a/libfreerdp-core/transport.h b/libfreerdp-core/transport.h
index 1d02b32..8d45da6 100644
--- a/libfreerdp-core/transport.h
+++ b/libfreerdp-core/transport.h
@@ -24,6 +24,7 @@ typedef enum
{
TRANSPORT_LAYER_TCP,
TRANSPORT_LAYER_TLS,
+ TRANSPORT_LAYER_TSG,
TRANSPORT_LAYER_CLOSED
} TRANSPORT_LAYER;
@@ -32,6 +33,7 @@ typedef struct rdp_transport rdpTransport;
#include "tcp.h"
#include "tls.h"
#include "credssp.h"
+#include "tsg.h"
#include <time.h>
#include <freerdp/types.h>
@@ -46,16 +48,21 @@ struct rdp_transport
STREAM* recv_stream;
STREAM* send_stream;
TRANSPORT_LAYER layer;
- struct rdp_tcp* tcp;
- struct rdp_tls* tls;
+ struct rdp_tcp* tcp_in;
+ struct rdp_tcp* tcp_out;
+ struct rdp_tls* tls_in;
+ struct rdp_tls* tls_out;
struct rdp_settings* settings;
struct rdp_credssp* credssp;
+ struct rdp_tsg* tsg;
uint32 usleep_interval;
void* recv_extra;
STREAM* recv_buffer;
TransportRecv recv_callback;
boolean blocking;
int level;
+ STREAM* proc_buffer;
+ int tsg_frag_state;
};
STREAM* transport_recv_stream_init(rdpTransport* transport, int size);
diff --git a/libfreerdp-core/tsg.c b/libfreerdp-core/tsg.c
new file mode 100644
index 0000000..5053252
--- /dev/null
+++ b/libfreerdp-core/tsg.c
@@ -0,0 +1,309 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * Gateway
+ *
+ * Copyright 2012 Fujitsu Technology Solutions GmbH -
+ * Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
+ * Copyright 2014 Jay Sorg - jay.sorg@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 "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/sleep.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/hexdump.h>
+#include <freerdp/utils/unicode.h>
+
+#include "tsg.h"
+
+static uint8 g_p1[108] = {
+ 0x43, 0x56, 0x00, 0x00, 0x43, 0x56, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x52, 0x54, 0x43, 0x56,
+ 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0xDD, 0x65, 0xE2, 0x44,
+ 0xAF, 0x7D, 0xCD, 0x42, 0x85, 0x60, 0x3C, 0xDB,
+ 0x6E, 0x7A, 0x27, 0x29, 0x01, 0x00, 0x03, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00 };
+static uint8 g_p2[112] = {
+ 0x00, 0x00, 0x00, 0x00, 0x6A, 0x78, 0xE9, 0xAB,
+ 0x02, 0x90, 0x1C, 0x44, 0x8D, 0x99, 0x29, 0x30,
+ 0x53, 0x6C, 0x04, 0x33, 0x52, 0x51, 0x00, 0x00,
+ 0x52, 0x51, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x2D, 0x00,
+ 0x4E, 0x00, 0x48, 0x00, 0x35, 0x00, 0x37, 0x00,
+ 0x30, 0x00, 0x2E, 0x00, 0x43, 0x00, 0x53, 0x00,
+ 0x4F, 0x00, 0x44, 0x00, 0x2E, 0x00, 0x6C, 0x00,
+ 0x6F, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6C, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static uint8 g_p3[40] = {
+ 0x00, 0x00, 0x00, 0x00, 0x6A, 0x78, 0xE9, 0xAB,
+ 0x02, 0x90, 0x1C, 0x44, 0x8D, 0x99, 0x29, 0x30,
+ 0x53, 0x6C, 0x04, 0x33, 0x01, 0x00, 0x00, 0x00,
+ 0x52, 0x47, 0x00, 0x00, 0x52, 0x47, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00 };
+static uint8 g_p4[48] = {
+ 0x00, 0x00, 0x00, 0x00, 0x6A, 0x78, 0xE9, 0xAB,
+ 0x02, 0x90, 0x1C, 0x44, 0x8D, 0x99, 0x29, 0x30,
+ 0x53, 0x6C, 0x04, 0x33, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00 };
+static uint8 g_p5[20] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+//#define WITH_DEBUG_TSG 1
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
+
+static tbool tsg_get_tunnel_context(uint8* data, int data_bytes, uint8* tunnel_context)
+{
+ //uint8* ldata = data;
+ //uint8* lend = data + data_bytes;
+
+ LLOGLN(10, ("get_tunnel_context: data_bytes %d", data_bytes));
+ //while(ldata < lend)
+ //{
+ // ldata++;
+ //}
+ memcpy(tunnel_context, data + data_bytes - 60 + 36, 16);
+ return true;
+}
+
+tbool tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port)
+{
+ int status = -1;
+ rdpRpch* rpch = tsg->rpch;
+ rdpTransport* transport = tsg->transport;
+ uint32 length;
+ uint32 dest_addr_unic_len;
+ uint8* data;
+ uint8* dest_addr_unic;
+ UNICONV* tsg_uniconv;
+ STREAM* s_p4;
+
+ LLOGLN(10, ("tsg_connect:"));
+ if (!rpch_attach(rpch, transport->tcp_in, transport->tcp_out,
+ transport->tls_in, transport->tls_out))
+ {
+ LLOGLN(0, ("tsg_connect: rpch_attach failed"));
+ return false;
+ }
+ LLOGLN(10, ("tsg_connect: rpch_attach ok"));
+ if (!rpch_connect(rpch))
+ {
+ LLOGLN(0, ("tsg_connect: rpch_connect failed"));
+ return false;
+ }
+ LLOGLN(10, ("tsg_connect: rpch_connect ok"));
+
+ status = rpch_write(rpch, g_p1, 108, 1);
+ if (status <= 0)
+ {
+ LLOGLN(0, ("tsg_connect: rpch_write opnum=1 failed"));
+ return false;
+ }
+
+ LLOGLN(10, ("tsg_connect: 1"));
+
+ /* read certificate here */
+ length = 0x8FFF;
+ data = xmalloc(length);
+ status = rpch_read(rpch, data, length);
+ if (status <= 0)
+ {
+ printf("rpch_recv failed!\n");
+ return false;
+ }
+
+ if (!tsg_get_tunnel_context(data, status, tsg->tunnelContext))
+ {
+ printf("get_tunnel_context failed!\n");
+ return false;
+ }
+
+#ifdef WITH_DEBUG_TSG
+ printf("TSG tunnelContext:\n");
+ freerdp_hexdump(tsg->tunnelContext, 16);
+ printf("\n");
+#endif
+
+ memcpy(g_p2 + 4, tsg->tunnelContext, 16);
+
+ LLOGLN(10, ("tsg_connect: 2"));
+
+ status = rpch_write(rpch, g_p2, 112, 2);
+ if (status <= 0)
+ {
+ printf("rpch_write opnum=2 failed!\n");
+ return false;
+ }
+
+ LLOGLN(10, ("tsg_connect: 3"));
+
+ status = rpch_read(rpch, data, length);
+ if (status <= 0)
+ {
+ printf("rpch_recv failed!\n");
+ return false;
+ }
+
+ LLOGLN(10, ("tsg_connect: 4"));
+
+ memcpy(g_p3 + 4, tsg->tunnelContext, 16);
+ status = rpch_write(rpch, g_p3, 40, 3);
+ if (status <= 0)
+ {
+ printf("rpch_write opnum=3 failed!\n");
+ return false;
+ }
+ status = -1;
+
+ tsg_uniconv = freerdp_uniconv_new();
+ dest_addr_unic = (uint8*)freerdp_uniconv_out(tsg_uniconv, hostname, (size_t*)&dest_addr_unic_len);
+ freerdp_uniconv_free(tsg_uniconv);
+
+ memcpy(g_p4 + 4, tsg->tunnelContext, 16);
+ memcpy(g_p4 + 38, &port, 2);
+
+ s_p4 = stream_new(60 + dest_addr_unic_len + 2);
+ stream_write(s_p4, g_p4, 48);
+ stream_write_uint32(s_p4, (dest_addr_unic_len / 2) + 1); /* MaximumCount */
+ stream_write_uint32(s_p4, 0x00000000); /* Offset */
+ stream_write_uint32(s_p4, (dest_addr_unic_len / 2) + 1); /* ActualCount */
+ stream_write(s_p4, dest_addr_unic, dest_addr_unic_len);
+ stream_write_uint16(s_p4, 0x0000); /* unicode zero to terminate hostname string */
+
+ LLOGLN(10, ("tsg_connect: 5"));
+
+ status = rpch_write(rpch, s_p4->data, s_p4->size, 4);
+ if (status <= 0)
+ {
+ printf("rpch_write opnum=4 failed!\n");
+ return false;
+ }
+ xfree(dest_addr_unic);
+
+ LLOGLN(10, ("tsg_connect: 6"));
+
+ status = rpch_read(rpch, data, length);
+ if (status < 0)
+ {
+ printf("rpch_recv failed!\n");
+ return false;
+ }
+
+ memcpy(tsg->channelContext, data + 4, 16);
+
+#ifdef WITH_DEBUG_TSG
+ printf("TSG channelContext:\n");
+ freerdp_hexdump(tsg->channelContext, 16);
+ printf("\n");
+#endif
+
+ LLOGLN(10, ("tsg_connect: 7"));
+
+ memcpy(g_p5 + 4, tsg->channelContext, 16);
+ status = rpch_write(rpch, g_p5, 20, 8);
+ if (status <= 0)
+ {
+ printf("rpch_write opnum=8 failed!\n");
+ return false;
+ }
+
+ LLOGLN(10, ("tsg_connect: out"));
+
+ return true;
+}
+
+int tsg_write(rdpTsg* tsg, uint8* data, uint32 length)
+{
+ int status;
+ uint16 opnum = 9;
+ uint32 tsg_length;
+ uint32 totalDataBytes;
+ uint8 pp[8] = { 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ STREAM* s;
+ uint8* tsg_pkg;
+
+ LLOGLN(10, ("tsg_write: int length %d", length));
+ tsg_length = length + 16 + 4 + 12 + 8;
+ totalDataBytes = length + 4;
+ s = stream_new(12);
+ stream_write_uint32_be(s, totalDataBytes);
+ stream_write_uint32_be(s, 0x01);
+ stream_write_uint32_be(s, length);
+ tsg_pkg = (uint8*) xmalloc(tsg_length);
+ memset(tsg_pkg, 0, 4);
+ memcpy(tsg_pkg + 4, tsg->channelContext, 16);
+ memcpy(tsg_pkg + 20, s->data, 12);
+ memcpy(tsg_pkg + 32, data, length);
+ memcpy(tsg_pkg + 32 + length, pp, 8);
+ status = rpch_write(tsg->rpch, tsg_pkg, tsg_length, opnum);
+ xfree(tsg_pkg);
+ stream_free(s);
+ if (status <= 0)
+ {
+ printf("rpch_write failed!\n");
+ return -1;
+ }
+ LLOGLN(10, ("tsg_write: out length %d", length));
+ return length;
+}
+
+int tsg_read(rdpTsg* tsg, uint8* data, uint32 length)
+{
+ int status;
+
+ LLOGLN(10, ("tsg_read:"));
+ status = rpch_read(tsg->rpch, data, length);
+ return status;
+}
+
+tbool tsg_skip_pdu(rdpTsg* tsg, STREAM* s)
+{
+ return rpch_skip_pdu(tsg->rpch, s);
+}
+
+rdpTsg* tsg_new(rdpSettings* settings)
+{
+ rdpTsg* tsg;
+
+ tsg = (rdpTsg*) xzalloc(sizeof(rdpTsg));
+ tsg->settings = settings;
+ tsg->rpch = rpch_new(settings);
+ return tsg;
+}
+
+void tsg_free(rdpTsg* tsg)
+{
+ xfree(tsg);
+}
diff --git a/libfreerdp-core/tsg.h b/libfreerdp-core/tsg.h
new file mode 100644
index 0000000..795df66
--- /dev/null
+++ b/libfreerdp-core/tsg.h
@@ -0,0 +1,59 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * RDP Security
+ *
+ * Copyright 2012 Fujitsu Technology Solutions GmbH -
+ * Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.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.
+ */
+
+#ifndef __TSG_H_
+#define __TSG_H_
+
+typedef struct rdp_tsg rdpTsg;
+
+#include "transport.h"
+#include "rpch.h"
+
+#include <time.h>
+#include <freerdp/types.h>
+#include <freerdp/settings.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/wait_obj.h>
+#include <freerdp/utils/debug.h>
+
+struct rdp_tsg
+{
+ struct rdp_settings* settings;
+ struct rdp_transport* transport;
+ struct rdp_rpch* rpch;
+
+ uint8 tunnelContext[16];
+ uint8 channelContext[16];
+};
+
+tbool tsg_connect(rdpTsg* tsg, const char* hostname, uint16 port);
+int tsg_write(rdpTsg* tsg, uint8* data, uint32 length);
+int tsg_read(rdpTsg* tsg, uint8* data, uint32 length);
+tbool tsg_skip_pdu(rdpTsg* tsg, STREAM* s);
+rdpTsg* tsg_new(rdpSettings* settings);
+void tsg_free(rdpTsg* tsg);
+
+#ifdef WITH_DEBUG_TSG
+#define DEBUG_TSG(fmt, ...) DEBUG_CLASS(TSG, fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_TSG(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
+#endif
+
+#endif /* __TSG_H_ */
diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c
index fc1a1e3..7064bf5 100644
--- a/libfreerdp-utils/args.c
+++ b/libfreerdp-utils/args.c
@@ -2,7 +2,7 @@
* FreeRDP: A Remote Desktop Protocol client.
* Arguments Parsing
*
- * Copyright 2009-2013 Jay Sorg <jay.sorg@gmail.com>
+ * Copyright 2009-2014 Jay Sorg <jay.sorg@gmail.com>
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -117,6 +117,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
" --no-rdp: disable Standard RDP encryption\n"
" --no-tls: disable TLS encryption\n"
" --no-nla: disable network level authentication\n"
+ " --tsg <TSG Username>:<Password>:<Domain>:<TSG Adress>: Connect through TSG\n"
" --ntlm: force NTLM authentication protocol version (1 or 2)\n"
" --ignore-certificate: ignore verification of logon certificate\n"
" --sec: force protocol security (rdp, tls or nla)\n"
@@ -574,6 +575,72 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
{
settings->nla_security = false;
}
+ else if (strcmp("--tsg", argv[index]) == 0)
+ {
+ char* ptr1;
+ char* ptr2;
+ settings->tsg = true;
+ index++;
+ if (index == argc)
+ {
+ printf("missing TSG params\n");
+ return -1;
+ }
+ /* username */
+ ptr1 = argv[index];
+ ptr2 = strstr(ptr1, ":");
+ if (ptr2 == NULL)
+ {
+ printf("missing TSG params\n");
+ return -1;
+ }
+ settings->tsg_username = strndup(ptr1, ptr2 - ptr1);
+ /* password */
+ ptr1 = ptr2 + 1;
+ ptr2 = strstr(ptr1, ":");
+ if (ptr2 == NULL)
+ {
+ printf("missing TSG params\n");
+ return -1;
+ }
+ settings->tsg_password = strndup(ptr1, ptr2 - ptr1);
+ /* domain */
+ ptr1 = ptr2 + 1;
+ ptr2 = strstr(ptr1, ":");
+ if (ptr2 == NULL)
+ {
+ printf("missing TSG params\n");
+ return -1;
+ }
+ settings->tsg_domain = strndup(ptr1, ptr2 - ptr1);
+ /* gateway name */
+ ptr1 = ptr2 + 1;
+ settings->tsg_server = strdup(ptr1);
+#if 0
+ settings->tsg_username = xstrdup(argv[index]);
+ index++;
+ if (index == argc)
+ {
+ printf("missing TSG password\n");
+ return -1;
+ }
+ settings->tsg_password = xstrdup(argv[index]);
+ index++;
+ if (index == argc)
+ {
+ printf("missing TSG domain\n");
+ return -1;
+ }
+ settings->tsg_domain = xstrdup(argv[index]);
+ index++;
+ if (index == argc)
+ {
+ printf("missing TSG server\n");
+ return -1;
+ }
+ settings->tsg_server = xstrdup(argv[index]);
+#endif
+ }
else if (strcmp("--sec", argv[index]) == 0)
{
index++;
diff --git a/libfreerdp-utils/memory.c b/libfreerdp-utils/memory.c
index dbba5e3..72a8dae 100644
--- a/libfreerdp-utils/memory.c
+++ b/libfreerdp-utils/memory.c
@@ -2,7 +2,7 @@
* FreeRDP: A Remote Desktop Protocol Client
* Memory Utils
*
- * Copyright 2009-2013 Jay Sorg
+ * Copyright 2009-2014 Jay Sorg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,16 +35,21 @@ void* xmalloc(size_t size)
void* mem;
if (size < 1)
+ {
+ printf("xmalloc: adjusting xmalloc bytes\n");
size = 1;
-
+ }
+ if (size > 16 * 1024 * 1024)
+ {
+ printf("xmalloc: bad size\n");
+ return NULL;
+ }
mem = malloc(size);
-
if (mem == NULL)
{
perror("xmalloc");
printf("xmalloc: failed to allocate memory of size: %d\n", (int) size);
}
-
return mem;
}
diff --git a/libfreerdp-utils/unicode.c b/libfreerdp-utils/unicode.c
index 6524a35..ae26767 100644
--- a/libfreerdp-utils/unicode.c
+++ b/libfreerdp-utils/unicode.c
@@ -98,11 +98,11 @@ char* freerdp_uniconv_in(UNICONV* uniconv, unsigned char* pin, size_t in_len)
/* Convert str from DEFAULT_CODEPAGE to WINDOWS_CODEPAGE and return buffer like xstrdup.
* Buffer is 0-terminated but that is not included in the returned length. */
-char* freerdp_uniconv_out(UNICONV *uniconv, char *str, size_t *pout_len)
+char* freerdp_uniconv_out(UNICONV *uniconv, const char *str, size_t *pout_len)
{
size_t ibl;
size_t obl;
- char* pin;
+ const char* pin;
char* pout;
char* pout0;