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:
Peter Åstrand 2005-08-08 19:15:57 +00:00
parent 2daead38a7
commit 75ea7d9148
9 changed files with 356 additions and 28 deletions

View File

@ -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
};

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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);

View File

@ -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
View File

@ -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)

View File

@ -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
View File

@ -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;
}