diff --git a/constants.h b/constants.h index 9801591..f262bd1 100644 --- a/constants.h +++ b/constants.h @@ -121,12 +121,26 @@ enum RDP_DATA_PDU_TYPE RDP_DATA_PDU_SYNCHRONISE = 31, RDP_DATA_PDU_BELL = 34, RDP_DATA_PDU_CLIENT_WINDOW_STATUS = 35, - RDP_DATA_PDU_LOGON = 38, + RDP_DATA_PDU_LOGON = 38, /* PDUTYPE2_SAVE_SESSION_INFO */ RDP_DATA_PDU_FONT2 = 39, RDP_DATA_PDU_KEYBOARD_INDICATORS = 41, RDP_DATA_PDU_DISCONNECT = 47 }; +enum RDP_SAVE_SESSION_PDU_TYPE +{ + INFOTYPE_LOGON = 0, + INFOTYPE_LOGON_LONG = 1, + INFOTYPE_LOGON_PLAINNOTIFY = 2, + INFOTYPE_LOGON_EXTENDED_INF = 3 +}; + +enum RDP_LOGON_INFO_EXTENDED_TYPE +{ + LOGON_EX_AUTORECONNECTCOOKIE = 1, + LOGON_EX_LOGONERRORS = 2 +}; + enum RDP_CONTROL_PDU_TYPE { RDP_CTL_REQUEST_CONTROL = 1, diff --git a/rdesktop.c b/rdesktop.c index f7c3e90..64f4bb3 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -103,6 +103,10 @@ char *g_redirect_username; char g_redirect_cookie[128]; uint32 g_redirect_flags = 0; +uint32 g_reconnect_logonid = 0; +char g_reconnect_random[16]; +uint8 g_client_random[SEC_RANDOM_SIZE]; + #ifdef WITH_RDPSND RD_BOOL g_rdpsnd = False; #endif diff --git a/rdp.c b/rdp.c index f5a2742..3d880dd 100644 --- a/rdp.c +++ b/rdp.c @@ -67,6 +67,10 @@ extern char g_redirect_cookie[128]; extern uint32 g_redirect_flags; /* END Session Directory support */ +extern uint32 g_reconnect_logonid; +extern char g_reconnect_random[16]; +extern uint8 g_client_random[SEC_RANDOM_SIZE]; + #if WITH_DEBUG static uint32 g_packetno; #endif @@ -331,6 +335,7 @@ rdp_send_logon_info(uint32 flags, char *domain, char *user, STREAM s; time_t t = time(NULL); time_t tzone; + uint8 security_verifier[16]; if (!g_use_rdp5 || 1 == g_server_rdp_version) { @@ -456,9 +461,16 @@ rdp_send_logon_info(uint32 flags, char *domain, char *user, /* Rest of TS_EXTENDED_INFO_PACKET */ out_uint32_le(s, 0xfffffffe); /* clientSessionId, consider changing to 0 */ out_uint32_le(s, g_rdp5_performanceflags); - out_uint16(s, 0); - + /* Client Auto-Reconnect */ + out_uint16_le(s, 28); /* cbAutoReconnectLen */ + /* ARC_CS_PRIVATE_PACKET */ + out_uint32_le(s, 28); /* cbLen */ + out_uint32_le(s, 1); /* Version */ + out_uint32_le(s, g_reconnect_logonid); /* LogonId */ + ssl_hmac_md5(g_reconnect_random, sizeof(g_reconnect_random), + g_client_random, SEC_RANDOM_SIZE, security_verifier); + out_uint8a(s, security_verifier, sizeof(security_verifier)); } s_mark_end(s); sec_send(s, sec_flags); @@ -1306,6 +1318,50 @@ process_update_pdu(STREAM s) ui_end_update(); } + +/* Process a Save Session Info PDU */ +void +process_pdu_logon(STREAM s) +{ + uint32 infotype; + in_uint32_le(s, infotype); + if (infotype == INFOTYPE_LOGON_EXTENDED_INF) + { + uint32 fieldspresent; + + in_uint8s(s, 2); /* Length */ + in_uint32_le(s, fieldspresent); + if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE) + { + uint32 len; + uint32 version; + + /* TS_LOGON_INFO_FIELD */ + in_uint8s(s, 4); /* cbFieldData */ + + /* ARC_SC_PRIVATE_PACKET */ + in_uint32_le(s, len); + if (len != 28) + { + warning("Invalid length in Auto-Reconnect packet\n"); + return; + } + + in_uint32_le(s, version); + if (version != 1) + { + warning("Unsupported version of Auto-Reconnect packet\n"); + return; + } + + in_uint32_le(s, g_reconnect_logonid); + in_uint8a(s, g_reconnect_random, 16); + DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid)); + } + } +} + + /* Process a disconnect PDU */ void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason) @@ -1382,6 +1438,7 @@ process_data_pdu(STREAM s, uint32 * ext_disc_reason) case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ + process_pdu_logon(s); break; case RDP_DATA_PDU_DISCONNECT: diff --git a/secure.c b/secure.c index 48f8d7f..55ee69e 100644 --- a/secure.c +++ b/secure.c @@ -34,6 +34,7 @@ extern RD_BOOL g_console_session; extern int g_server_depth; extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; +extern uint8 g_client_random[SEC_RANDOM_SIZE]; static int g_rc4_key_len; static SSL_RC4 g_rc4_decrypt_key; @@ -667,7 +668,6 @@ static void sec_process_crypt_info(STREAM s) { uint8 *server_random = NULL; - uint8 client_random[SEC_RANDOM_SIZE]; uint8 modulus[SEC_MAX_MODULUS_SIZE]; uint8 exponent[SEC_EXPONENT_SIZE]; uint32 rc4_key_size; @@ -680,10 +680,10 @@ sec_process_crypt_info(STREAM s) return; } DEBUG(("Generating client random\n")); - generate_random(client_random); - sec_rsa_encrypt(g_sec_crypted_random, client_random, SEC_RANDOM_SIZE, + generate_random(g_client_random); + sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE, g_server_public_key_len, modulus, exponent); - sec_generate_keys(client_random, server_random, rc4_key_size); + sec_generate_keys(g_client_random, server_random, rc4_key_size); } diff --git a/ssl.c b/ssl.c index 0655680..fb1e729 100644 --- a/ssl.c +++ b/ssl.c @@ -223,3 +223,13 @@ ssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, */ return True; } + + +void +ssl_hmac_md5(const void *key, int key_len, const unsigned char *msg, int msg_len, unsigned char *md) +{ + HMAC_CTX ctx; + HMAC_CTX_init(&ctx); + HMAC(EVP_md5(), key, key_len, msg, msg_len, md, NULL); + HMAC_CTX_cleanup(&ctx); +} diff --git a/ssl.h b/ssl.h index 42150e9..92ed9f1 100644 --- a/ssl.h +++ b/ssl.h @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) #define D2I_X509_CONST const @@ -60,4 +61,7 @@ int ssl_rkey_get_exp_mod(SSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, RD_BOOL ssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, uint8 * signature, uint32 sig_len); +void ssl_hmac_md5(const void *key, int key_len, + const unsigned char *msg, int msg_len, unsigned char *md); + #endif