Applied patch #1247780 (slightly modified) from Brian Chapeau: Session Directory support.
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@976 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
2daead38a7
commit
75ea7d9148
@ -69,6 +69,7 @@ enum MCS_PDU_TYPE
|
||||
#define SEC_ENCRYPT 0x0008
|
||||
#define SEC_LOGON_INFO 0x0040
|
||||
#define SEC_LICENCE_NEG 0x0080
|
||||
#define SEC_REDIRECT_ENCRYPT 0x0C00
|
||||
|
||||
#define SEC_TAG_SRV_INFO 0x0c01
|
||||
#define SEC_TAG_SRV_CRYPT 0x0c02
|
||||
@ -106,6 +107,7 @@ enum RDP_PDU_TYPE
|
||||
{
|
||||
RDP_PDU_DEMAND_ACTIVE = 1,
|
||||
RDP_PDU_CONFIRM_ACTIVE = 3,
|
||||
RDP_PDU_REDIRECT = 4, /* MS Server 2003 Session Redirect */
|
||||
RDP_PDU_DEACTIVATE = 6,
|
||||
RDP_PDU_DATA = 7
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
rdesktop (1.4.1)
|
||||
* Session Directory support (patch from Brian Chapeau <lheria@users.sourceforge.net>)
|
||||
* persistent bitmap cache optimisations
|
||||
* support for more RDP-orders (ellipse, polygon)
|
||||
* libao sound-driver (for Mac OSX and others)
|
||||
|
31
iso.c
31
iso.c
@ -191,6 +191,30 @@ iso_connect(char *server, char *username)
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Establish a reconnection up to the ISO layer */
|
||||
BOOL
|
||||
iso_reconnect(char *server)
|
||||
{
|
||||
uint8 code = 0;
|
||||
|
||||
if (!tcp_connect(server))
|
||||
return False;
|
||||
|
||||
iso_send_msg(ISO_PDU_CR);
|
||||
|
||||
if (iso_recv_msg(&code, NULL) == NULL)
|
||||
return False;
|
||||
|
||||
if (code != ISO_PDU_CC)
|
||||
{
|
||||
error("expected CC, got 0x%x\n", code);
|
||||
tcp_disconnect();
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Disconnect from the ISO layer */
|
||||
void
|
||||
iso_disconnect(void)
|
||||
@ -198,3 +222,10 @@ iso_disconnect(void)
|
||||
iso_send_msg(ISO_PDU_DR);
|
||||
tcp_disconnect();
|
||||
}
|
||||
|
||||
/* reset the state to support reconnecting */
|
||||
void
|
||||
iso_reset_state(void)
|
||||
{
|
||||
tcp_reset_state();
|
||||
}
|
||||
|
49
mcs.c
49
mcs.c
@ -412,9 +412,58 @@ mcs_connect(char *server, STREAM mcs_data, char *username)
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Establish a connection up to the MCS layer */
|
||||
BOOL
|
||||
mcs_reconnect(char *server, STREAM mcs_data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!iso_reconnect(server))
|
||||
return False;
|
||||
|
||||
mcs_send_connect_initial(mcs_data);
|
||||
if (!mcs_recv_connect_response(mcs_data))
|
||||
goto error;
|
||||
|
||||
mcs_send_edrq();
|
||||
|
||||
mcs_send_aurq();
|
||||
if (!mcs_recv_aucf(&g_mcs_userid))
|
||||
goto error;
|
||||
|
||||
mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE);
|
||||
|
||||
if (!mcs_recv_cjcf())
|
||||
goto error;
|
||||
|
||||
mcs_send_cjrq(MCS_GLOBAL_CHANNEL);
|
||||
if (!mcs_recv_cjcf())
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < g_num_channels; i++)
|
||||
{
|
||||
mcs_send_cjrq(g_channels[i].mcs_id);
|
||||
if (!mcs_recv_cjcf())
|
||||
goto error;
|
||||
}
|
||||
return True;
|
||||
|
||||
error:
|
||||
iso_disconnect();
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Disconnect from the MCS layer */
|
||||
void
|
||||
mcs_disconnect(void)
|
||||
{
|
||||
iso_disconnect();
|
||||
}
|
||||
|
||||
/* reset the state of the mcs layer */
|
||||
void
|
||||
mcs_reset_state(void)
|
||||
{
|
||||
g_mcs_userid = 0;
|
||||
iso_reset_state();
|
||||
}
|
||||
|
10
proto.h
10
proto.h
@ -46,7 +46,9 @@ STREAM iso_init(int length);
|
||||
void iso_send(STREAM s);
|
||||
STREAM iso_recv(uint8 * rdpver);
|
||||
BOOL iso_connect(char *server, char *username);
|
||||
BOOL iso_reconnect(char *server);
|
||||
void iso_disconnect(void);
|
||||
void iso_reset_state(void);
|
||||
/* licence.c */
|
||||
void licence_process(STREAM s);
|
||||
/* mcs.c */
|
||||
@ -55,7 +57,9 @@ void mcs_send_to_channel(STREAM s, uint16 channel);
|
||||
void mcs_send(STREAM s);
|
||||
STREAM mcs_recv(uint16 * channel, uint8 * rdpver);
|
||||
BOOL mcs_connect(char *server, STREAM mcs_data, char *username);
|
||||
BOOL mcs_reconnect(char *server, STREAM mcs_data);
|
||||
void mcs_disconnect(void);
|
||||
void mcs_reset_state(void);
|
||||
/* orders.c */
|
||||
void process_orders(STREAM s, uint16 num_orders);
|
||||
void reset_order_state(void);
|
||||
@ -114,6 +118,9 @@ void rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason);
|
||||
BOOL rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason);
|
||||
BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command,
|
||||
char *directory);
|
||||
BOOL rdp_reconnect(char *server, uint32 flags, char *domain, char *password, char *command,
|
||||
char *directory, char *cookie);
|
||||
void rdp_reset_state(void);
|
||||
void rdp_disconnect(void);
|
||||
/* rdpdr.c */
|
||||
int get_device_index(NTHANDLE handle);
|
||||
@ -148,7 +155,9 @@ void sec_send(STREAM s, uint32 flags);
|
||||
void sec_process_mcs_data(STREAM s);
|
||||
STREAM sec_recv(uint8 * rdpver);
|
||||
BOOL sec_connect(char *server, char *username);
|
||||
BOOL sec_reconnect(char *server);
|
||||
void sec_disconnect(void);
|
||||
void sec_reset_state(void);
|
||||
/* serial.c */
|
||||
int serial_enum_devices(uint32 * id, char *optarg);
|
||||
BOOL serial_get_event(NTHANDLE handle, uint32 * result);
|
||||
@ -160,6 +169,7 @@ STREAM tcp_recv(STREAM s, uint32 length);
|
||||
BOOL tcp_connect(char *server);
|
||||
void tcp_disconnect(void);
|
||||
char *tcp_get_address(void);
|
||||
void tcp_reset_state(void);
|
||||
/* xclip.c */
|
||||
void ui_clip_format_announce(uint8 * data, uint32 length);
|
||||
void ui_clip_handle_data(uint8 * data, uint32 length);
|
||||
|
83
rdesktop.c
83
rdesktop.c
@ -92,6 +92,14 @@ BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
|
||||
uint32 g_embed_wnd;
|
||||
uint32 g_rdp5_performanceflags =
|
||||
RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
|
||||
/* Session Directory redirection */
|
||||
BOOL g_redirect = False;
|
||||
char g_redirect_server[64];
|
||||
char g_redirect_domain[16];
|
||||
char g_redirect_password[64];
|
||||
char g_redirect_username[64];
|
||||
char g_redirect_cookie[128];
|
||||
uint32 g_redirect_flags = 0;
|
||||
|
||||
#ifdef WITH_RDPSND
|
||||
BOOL g_rdpsnd = False;
|
||||
@ -275,6 +283,12 @@ print_disconnect_reason(uint16 reason)
|
||||
fprintf(stderr, "disconnect: %s.\n", text);
|
||||
}
|
||||
|
||||
static void
|
||||
rdesktop_reset_state(void)
|
||||
{
|
||||
rdp_reset_state();
|
||||
}
|
||||
|
||||
static BOOL
|
||||
read_password(char *password, int size)
|
||||
{
|
||||
@ -376,6 +390,8 @@ main(int argc, char *argv[])
|
||||
int c;
|
||||
char *locale = NULL;
|
||||
int username_option = 0;
|
||||
int run_count = 0; /* Session Directory support */
|
||||
BOOL continue_connect = True; /* Session Directory support */
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* Set locale according to environment */
|
||||
@ -790,26 +806,59 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
rdpdr_init();
|
||||
|
||||
if (!rdp_connect(server, flags, domain, password, shell, directory))
|
||||
return 1;
|
||||
|
||||
/* By setting encryption to False here, we have an encrypted login
|
||||
packet but unencrypted transfer of other packets */
|
||||
if (!packet_encryption)
|
||||
g_encryption = False;
|
||||
|
||||
|
||||
DEBUG(("Connection successful.\n"));
|
||||
memset(password, 0, sizeof(password));
|
||||
|
||||
if (ui_create_window())
|
||||
while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
|
||||
{
|
||||
rdp_main_loop(&deactivated, &ext_disc_reason);
|
||||
ui_destroy_window();
|
||||
if (run_count == 0)
|
||||
{
|
||||
if (!rdp_connect(server, flags, domain, password, shell, directory))
|
||||
return 1;
|
||||
}
|
||||
else if (!rdp_reconnect
|
||||
(server, flags, domain, password, shell, directory, g_redirect_cookie))
|
||||
return 1;
|
||||
|
||||
/* By setting encryption to False here, we have an encrypted login
|
||||
packet but unencrypted transfer of other packets */
|
||||
if (!packet_encryption)
|
||||
g_encryption = False;
|
||||
|
||||
|
||||
DEBUG(("Connection successful.\n"));
|
||||
memset(password, 0, sizeof(password));
|
||||
|
||||
if (run_count == 0)
|
||||
if (!ui_create_window())
|
||||
continue_connect = False;
|
||||
|
||||
if (continue_connect)
|
||||
rdp_main_loop(&deactivated, &ext_disc_reason);
|
||||
|
||||
DEBUG(("Disconnecting...\n"));
|
||||
rdp_disconnect();
|
||||
|
||||
if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
|
||||
{
|
||||
/* reset state of major globals */
|
||||
rdesktop_reset_state();
|
||||
|
||||
STRNCPY(domain, g_redirect_domain, sizeof(domain));
|
||||
STRNCPY(g_username, g_redirect_username, sizeof(g_username));
|
||||
STRNCPY(password, g_redirect_password, sizeof(password));
|
||||
STRNCPY(server, g_redirect_server, sizeof(server));
|
||||
flags |= RDP_LOGON_AUTO;
|
||||
|
||||
g_redirect = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue_connect = False;
|
||||
ui_destroy_window();
|
||||
break;
|
||||
}
|
||||
|
||||
run_count++;
|
||||
}
|
||||
|
||||
DEBUG(("Disconnecting...\n"));
|
||||
rdp_disconnect();
|
||||
cache_save_state();
|
||||
ui_deinit();
|
||||
|
||||
|
88
rdp.c
88
rdp.c
@ -55,6 +55,16 @@ uint32 g_rdp_shareid;
|
||||
|
||||
extern RDPCOMP g_mppc_dict;
|
||||
|
||||
/* Session Directory support */
|
||||
extern BOOL g_redirect;
|
||||
extern char g_redirect_server[64];
|
||||
extern char g_redirect_domain[16];
|
||||
extern char g_redirect_password[64];
|
||||
extern char g_redirect_username[64];
|
||||
extern char g_redirect_cookie[128];
|
||||
extern uint32 g_redirect_flags;
|
||||
/* END Session Directory support */
|
||||
|
||||
#if WITH_DEBUG
|
||||
static uint32 g_packetno;
|
||||
#endif
|
||||
@ -71,7 +81,7 @@ rdp_recv(uint8 * type)
|
||||
uint16 length, pdu_type;
|
||||
uint8 rdpver;
|
||||
|
||||
if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end))
|
||||
if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
|
||||
{
|
||||
rdp_s = sec_recv(&rdpver);
|
||||
if (rdp_s == NULL)
|
||||
@ -260,6 +270,10 @@ rdp_in_unistr(STREAM s, char *string, int uni_len)
|
||||
g_iconv_works = False;
|
||||
return rdp_in_unistr(s, string, uni_len);
|
||||
}
|
||||
|
||||
/* we must update the location of the current STREAM for future reads of s->p */
|
||||
s->p += uni_len;
|
||||
|
||||
return pout - string;
|
||||
}
|
||||
else
|
||||
@ -1284,6 +1298,54 @@ process_data_pdu(STREAM s, uint32 * ext_disc_reason)
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Process redirect PDU from Session Directory */
|
||||
static BOOL
|
||||
process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ )
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
/* these 2 bytes are unknown, seem to be zeros */
|
||||
in_uint8s(s, 2);
|
||||
|
||||
/* read connection flags */
|
||||
in_uint32_le(s, g_redirect_flags);
|
||||
|
||||
/* read length of ip string */
|
||||
in_uint32_le(s, len);
|
||||
|
||||
/* read ip string */
|
||||
rdp_in_unistr(s, g_redirect_server, len);
|
||||
|
||||
/* read length of cookie string */
|
||||
in_uint32_le(s, len);
|
||||
|
||||
/* read cookie string (plain ASCII) */
|
||||
in_uint8a(s, g_redirect_cookie, len);
|
||||
g_redirect_cookie[len] = 0;
|
||||
|
||||
/* read length of username string */
|
||||
in_uint32_le(s, len);
|
||||
|
||||
/* read username string */
|
||||
rdp_in_unistr(s, g_redirect_username, len);
|
||||
|
||||
/* read length of domain string */
|
||||
in_uint32_le(s, len);
|
||||
|
||||
/* read domain string */
|
||||
rdp_in_unistr(s, g_redirect_domain, len);
|
||||
|
||||
/* read length of password string */
|
||||
in_uint32_le(s, len);
|
||||
|
||||
/* read password string */
|
||||
rdp_in_unistr(s, g_redirect_password, len);
|
||||
|
||||
g_redirect = True;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Process incoming packets */
|
||||
/* nevers gets out of here till app is done */
|
||||
void
|
||||
@ -1317,6 +1379,9 @@ rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason)
|
||||
DEBUG(("RDP_PDU_DEACTIVATE\n"));
|
||||
*deactivated = True;
|
||||
break;
|
||||
case RDP_PDU_REDIRECT:
|
||||
return process_redirect_pdu(s);
|
||||
break;
|
||||
case RDP_PDU_DATA:
|
||||
disc = process_data_pdu(s, ext_disc_reason);
|
||||
break;
|
||||
@ -1344,6 +1409,27 @@ rdp_connect(char *server, uint32 flags, char *domain, char *password,
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Establish a reconnection up to the RDP layer */
|
||||
BOOL
|
||||
rdp_reconnect(char *server, uint32 flags, char *domain, char *password,
|
||||
char *command, char *directory, char *cookie)
|
||||
{
|
||||
if (!sec_reconnect(server))
|
||||
return False;
|
||||
|
||||
rdp_send_logon_info(flags, domain, g_username, password, command, directory);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Called during redirection to reset the state to support redirection */
|
||||
void
|
||||
rdp_reset_state(void)
|
||||
{
|
||||
g_next_packet = NULL; /* reset the packet information */
|
||||
g_rdp_shareid = 0;
|
||||
sec_reset_state();
|
||||
}
|
||||
|
||||
/* Disconnect from the RDP layer */
|
||||
void
|
||||
rdp_disconnect(void)
|
||||
|
86
secure.c
86
secure.c
@ -56,6 +56,10 @@ static uint8 sec_crypted_random[SEC_MODULUS_SIZE];
|
||||
|
||||
uint16 g_server_rdp_version = 0;
|
||||
|
||||
/* These values must be available to reset state - Session Directory */
|
||||
static int sec_encrypt_use_count = 0;
|
||||
static int sec_decrypt_use_count = 0;
|
||||
|
||||
/*
|
||||
* I believe this is based on SSLv3 with the following differences:
|
||||
* MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields
|
||||
@ -251,34 +255,30 @@ sec_update(uint8 * key, uint8 * update_key)
|
||||
static void
|
||||
sec_encrypt(uint8 * data, int length)
|
||||
{
|
||||
static int use_count;
|
||||
|
||||
if (use_count == 4096)
|
||||
if (sec_encrypt_use_count == 4096)
|
||||
{
|
||||
sec_update(sec_encrypt_key, sec_encrypt_update_key);
|
||||
RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
|
||||
use_count = 0;
|
||||
sec_encrypt_use_count = 0;
|
||||
}
|
||||
|
||||
RC4(&rc4_encrypt_key, length, data, data);
|
||||
use_count++;
|
||||
sec_encrypt_use_count++;
|
||||
}
|
||||
|
||||
/* Decrypt data using RC4 */
|
||||
void
|
||||
sec_decrypt(uint8 * data, int length)
|
||||
{
|
||||
static int use_count;
|
||||
|
||||
if (use_count == 4096)
|
||||
if (sec_decrypt_use_count == 4096)
|
||||
{
|
||||
sec_update(sec_decrypt_key, sec_decrypt_update_key);
|
||||
RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
|
||||
use_count = 0;
|
||||
sec_decrypt_use_count = 0;
|
||||
}
|
||||
|
||||
RC4(&rc4_decrypt_key, length, data, data);
|
||||
use_count++;
|
||||
sec_decrypt_use_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -853,6 +853,41 @@ sec_recv(uint8 * rdpver)
|
||||
licence_process(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sec_flags & 0x0400) /* SEC_REDIRECT_ENCRYPT */
|
||||
{
|
||||
uint8 swapbyte;
|
||||
|
||||
in_uint8s(s, 8); /* signature */
|
||||
sec_decrypt(s->p, s->end - s->p);
|
||||
|
||||
/* Check for a redirect packet, starts with 00 04 */
|
||||
if (s->p[0] == 0 && s->p[1] == 4)
|
||||
{
|
||||
/* for some reason the PDU and the length seem to be swapped.
|
||||
This isn't good, but we're going to do a byte for byte
|
||||
swap. So the first foure value appear as: 00 04 XX YY,
|
||||
where XX YY is the little endian length. We're going to
|
||||
use 04 00 as the PDU type, so after our swap this will look
|
||||
like: XX YY 04 00 */
|
||||
swapbyte = s->p[0];
|
||||
s->p[0] = s->p[2];
|
||||
s->p[2] = swapbyte;
|
||||
|
||||
swapbyte = s->p[1];
|
||||
s->p[1] = s->p[3];
|
||||
s->p[3] = swapbyte;
|
||||
|
||||
swapbyte = s->p[2];
|
||||
s->p[2] = s->p[3];
|
||||
s->p[3] = swapbyte;
|
||||
}
|
||||
#ifdef WITH_DEBUG
|
||||
/* warning! this debug statement will show passwords in the clear! */
|
||||
hexdump(s->p, s->end - s->p);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (channel != MCS_GLOBAL_CHANNEL)
|
||||
@ -889,9 +924,40 @@ sec_connect(char *server, char *username)
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Establish a secure connection */
|
||||
BOOL
|
||||
sec_reconnect(char *server)
|
||||
{
|
||||
struct stream mcs_data;
|
||||
|
||||
/* We exchange some RDP data during the MCS-Connect */
|
||||
mcs_data.size = 512;
|
||||
mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size);
|
||||
sec_out_mcs_data(&mcs_data);
|
||||
|
||||
if (!mcs_reconnect(server, &mcs_data))
|
||||
return False;
|
||||
|
||||
/* sec_process_mcs_data(&mcs_data); */
|
||||
if (g_encryption)
|
||||
sec_establish_key();
|
||||
xfree(mcs_data.data);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Disconnect a connection */
|
||||
void
|
||||
sec_disconnect(void)
|
||||
{
|
||||
mcs_disconnect();
|
||||
}
|
||||
|
||||
/* reset the state of the sec layer */
|
||||
void
|
||||
sec_reset_state(void)
|
||||
{
|
||||
g_server_rdp_version = 0;
|
||||
sec_encrypt_use_count = 0;
|
||||
sec_decrypt_use_count = 0;
|
||||
mcs_reset_state();
|
||||
}
|
||||
|
34
tcp.c
34
tcp.c
@ -242,3 +242,37 @@ tcp_get_address()
|
||||
strcpy(ipaddr, "127.0.0.1");
|
||||
return ipaddr;
|
||||
}
|
||||
|
||||
/* reset the state of the tcp layer */
|
||||
/* Support for Session Directory */
|
||||
void
|
||||
tcp_reset_state(void)
|
||||
{
|
||||
sock = -1; /* reset socket */
|
||||
|
||||
/* Clear the incoming stream */
|
||||
if (in.data != NULL)
|
||||
xfree(in.data);
|
||||
in.p = NULL;
|
||||
in.end = NULL;
|
||||
in.data = NULL;
|
||||
in.size = 0;
|
||||
in.iso_hdr = NULL;
|
||||
in.mcs_hdr = NULL;
|
||||
in.sec_hdr = NULL;
|
||||
in.rdp_hdr = NULL;
|
||||
in.channel_hdr = NULL;
|
||||
|
||||
/* Clear the outgoing stream */
|
||||
if (out.data != NULL)
|
||||
xfree(out.data);
|
||||
out.p = NULL;
|
||||
out.end = NULL;
|
||||
out.data = NULL;
|
||||
out.size = 0;
|
||||
out.iso_hdr = NULL;
|
||||
out.mcs_hdr = NULL;
|
||||
out.sec_hdr = NULL;
|
||||
out.rdp_hdr = NULL;
|
||||
out.channel_hdr = NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user