summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libxrdp/libxrdp.h43
-rw-r--r--libxrdp/libxrdpinc.h2
-rw-r--r--libxrdp/xrdp_channel.c239
-rw-r--r--libxrdp/xrdp_mcs.c102
-rw-r--r--libxrdp/xrdp_rdp.c11
-rw-r--r--libxrdp/xrdp_sec.c232
6 files changed, 548 insertions, 81 deletions
diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h
index dd87096e..eadb9c0e 100644
--- a/libxrdp/libxrdp.h
+++ b/libxrdp/libxrdp.h
@@ -48,6 +48,15 @@ struct xrdp_iso
struct xrdp_tcp* tcp_layer;
};
+/* used in mcs */
+struct mcs_channel_item
+{
+ char name[16];
+ int flags;
+ int chanid;
+ struct stream* in_s;
+};
+
/* mcs */
struct xrdp_mcs
{
@@ -57,6 +66,7 @@ struct xrdp_mcs
int chanid;
struct stream* client_mcs_data;
struct stream* server_mcs_data;
+ struct list* channel_list;
};
/* sec */
@@ -64,6 +74,7 @@ struct xrdp_sec
{
struct xrdp_rdp* rdp_layer; /* owner */
struct xrdp_mcs* mcs_layer;
+ struct xrdp_channel* chan_layer;
char server_random[32];
char client_random[64];
char client_crypt_random[72];
@@ -85,6 +96,14 @@ struct xrdp_sec
char pub_mod[64];
char pub_sig[64];
char pri_exp[64];
+ int channel_code;
+};
+
+/* channel */
+struct xrdp_channel
+{
+ struct xrdp_sec* sec_layer;
+ struct xrdp_mcs* mcs_layer;
};
/* rdp */
@@ -223,7 +242,7 @@ xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s);
int APP_CC
xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan);
int APP_CC
-xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s);
+xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s, int chan);
int APP_CC
xrdp_mcs_incoming(struct xrdp_mcs* self);
int APP_CC
@@ -231,7 +250,8 @@ xrdp_mcs_disconnect(struct xrdp_mcs* self);
/* xrdp_sec.c */
struct xrdp_sec* APP_CC
-xrdp_sec_create(struct xrdp_rdp* owner, int sck, int crypt_level);
+xrdp_sec_create(struct xrdp_rdp* owner, int sck, int crypt_level,
+ int channel_code);
void APP_CC
xrdp_sec_delete(struct xrdp_sec* self);
int APP_CC
@@ -239,7 +259,11 @@ xrdp_sec_init(struct xrdp_sec* self, struct stream* s);
int APP_CC
xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan);
int APP_CC
-xrdp_sec_send(struct xrdp_sec* self, struct stream* s);
+xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int chan);
+int APP_CC
+xrdp_sec_process_mcs_data(struct xrdp_sec* self);
+int APP_CC
+xrdp_sec_out_mcs_data(struct xrdp_sec* self);
int APP_CC
xrdp_sec_incoming(struct xrdp_sec* self);
int APP_CC
@@ -356,4 +380,17 @@ xrdp_bitmap_compress(char* in_data, int width, int height,
int start_line, struct stream* temp,
int e);
+/* xrdp_channel.c */
+struct xrdp_channel* APP_CC
+xrdp_channel_create(struct xrdp_sec* owner, struct xrdp_mcs* mcs_layer);
+void APP_CC
+xrdp_channel_delete(struct xrdp_channel* self);
+int APP_CC
+xrdp_channel_init(struct xrdp_channel* self, struct stream* s);
+int APP_CC
+xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id);
+int APP_CC
+xrdp_channel_process(struct xrdp_channel* self, struct stream* s,
+ int chanid);
+
#endif
diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h
index 74ebfda3..a7e8927d 100644
--- a/libxrdp/libxrdpinc.h
+++ b/libxrdp/libxrdpinc.h
@@ -57,6 +57,8 @@ struct xrdp_client_info
int rdp_compression;
int rdp_autologin;
int crypt_level; /* 1, 2, 3 = low, medium, high */
+ int channel_code; /* 0 = no channels 1 = channels */
+ int sound_code; /* 1 = leave sound at server */
};
struct xrdp_brush
diff --git a/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c
new file mode 100644
index 00000000..f5ddfef3
--- /dev/null
+++ b/libxrdp/xrdp_channel.c
@@ -0,0 +1,239 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2006
+
+ channel layer
+
+*/
+
+#include "libxrdp.h"
+
+/* todo, move these to constants.h */
+//#define CHANNEL_CHUNK_LENGTH 1600 /* todo, why is this so small? */
+#define CHANNEL_CHUNK_LENGTH 8192
+#define CHANNEL_FLAG_FIRST 0x01
+#define CHANNEL_FLAG_LAST 0x02
+#define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
+
+/*****************************************************************************/
+/* returns pointer or nil on error */
+static struct mcs_channel_item* APP_CC
+xrdp_channel_get_item(struct xrdp_channel* self, int channel_id)
+{
+ struct mcs_channel_item* channel;
+
+ channel = (struct mcs_channel_item*)
+ list_get_item(self->mcs_layer->channel_list, channel_id);
+ return channel;
+}
+
+/*****************************************************************************/
+struct xrdp_channel* APP_CC
+xrdp_channel_create(struct xrdp_sec* owner, struct xrdp_mcs* mcs_layer)
+{
+ struct xrdp_channel* self;
+
+ self = (struct xrdp_channel*)g_malloc(sizeof(struct xrdp_channel), 1);
+ self->sec_layer = owner;
+ self->mcs_layer = mcs_layer;
+ return self;
+}
+
+/*****************************************************************************/
+/* returns error */
+void APP_CC
+xrdp_channel_delete(struct xrdp_channel* self)
+{
+ if (self == 0)
+ {
+ return;
+ }
+ g_free(self);
+}
+
+/*****************************************************************************/
+/* returns error */
+int APP_CC
+xrdp_channel_init(struct xrdp_channel* self, struct stream* s)
+{
+ if (xrdp_sec_init(self->sec_layer, s) != 0)
+ {
+ return 1;
+ }
+ s_push_layer(s, channel_hdr, 8);
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* This sends data out to the secure layer, breaking up the data to
+ CHANNEL_CHUNK_LENGTH as needed. This can end up sending many packets. */
+int APP_CC
+xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id)
+{
+ int length;
+ int flags;
+ int thislength;
+ int remaining;
+ char* data;
+ struct mcs_channel_item* channel;
+
+ channel = xrdp_channel_get_item(self, channel_id);
+ if (channel == 0)
+ {
+ return 1;
+ }
+ s_pop_layer(s, channel_hdr);
+ length = (int)((s->end - s->p) - 8);
+ thislength = MIN(length, CHANNEL_CHUNK_LENGTH);
+ remaining = length - thislength;
+ flags = (remaining == 0) ?
+ CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
+ if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
+ {
+ flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
+ }
+ out_uint32_le(s, length);
+ out_uint32_le(s, flags);
+ s->end = s->p + thislength;
+ data = s->end;
+ if (xrdp_sec_send(self->sec_layer, s, channel->chanid) != 0)
+ {
+ return 1;
+ }
+ while (remaining > 0)
+ {
+ thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH);
+ remaining -= thislength;
+ flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0;
+ if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
+ {
+ flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
+ }
+ if (xrdp_sec_init(self->sec_layer, s) != 0)
+ {
+ return 1;
+ }
+ out_uint32_le(s, length);
+ out_uint32_le(s, flags);
+ /* this is copying a later part of the stream up to the front */
+ out_uint8a(s, data, thislength);
+ s_mark_end(s);
+ if (xrdp_sec_send(self->sec_layer, s, channel->chanid) != 0)
+ {
+ return 1;
+ }
+ data += thislength;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* this will inform the callback, whatever it is that some channel data is
+ ready. the default for this is a call to xrdp_wm.c. */
+static int APP_CC
+xrdp_channel_call_callback(struct xrdp_channel* self, struct stream* s,
+ int channel_id)
+{
+ struct xrdp_session* session;
+ int rv;
+ int size;
+
+ rv = 0;
+ session = self->sec_layer->rdp_layer->session;
+ if (session != 0)
+ {
+ if (session->callback != 0)
+ {
+ size = (int)(s->end - s->p);
+ /* in xrdp_wm.c */
+ rv = session->callback(session->id, 0x5555, channel_id, size,
+ (long)s->p, 0);
+ }
+ else
+ {
+ g_writeln("in xrdp_channel_process1, session->callback is nil");
+ }
+ }
+ else
+ {
+ g_writeln("in xrdp_channel_process1, session is nil");
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* This is called from the secure layer to process an incomming non global
+ channel packet. It copies the channel data to a special stream contained
+ in the channel struct(the one in xrdp_mcs->channel_list) untill the
+ whole data message is ready.
+ 'chanid' passed in here is the mcs channel id so it MCS_GLOBAL_CHANNEL
+ plus something. */
+int APP_CC
+xrdp_channel_process(struct xrdp_channel* self, struct stream* s,
+ int chanid)
+{
+ int length;
+ int flags;
+ int thislength;
+ int rv;
+ int channel_id;
+ struct stream* in_s;
+ struct mcs_channel_item* channel;
+
+ /* this assumes that the channels are in order of chanid(mcs channel id)
+ but they should be, see xrdp_sec_process_mcs_data_channels
+ the first channel should be MCS_GLOBAL_CHANNEL + 1, second
+ one should be MCS_GLOBAL_CHANNEL + 2, and so on */
+ channel_id = (chanid - MCS_GLOBAL_CHANNEL) - 1;
+ channel = xrdp_channel_get_item(self, channel_id);
+ if (channel == 0)
+ {
+ g_writeln("xrdp_channel_process, channel not found");
+ return 1;
+ }
+ rv = 0;
+ in_uint32_le(s, length);
+ in_uint32_le(s, flags);
+ if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST))
+ {
+ rv = xrdp_channel_call_callback(self, s, channel_id);
+ }
+ else
+ {
+ if (channel->in_s == 0)
+ {
+ make_stream(channel->in_s);
+ }
+ in_s = channel->in_s;
+ if (flags & CHANNEL_FLAG_FIRST)
+ {
+ init_stream(in_s, length);
+ }
+ thislength = MIN(s->end - s->p, (in_s->data + in_s->size) - in_s->p);
+ out_uint8a(in_s, s->p, thislength);
+ if (flags & CHANNEL_FLAG_LAST)
+ {
+ in_s->end = in_s->p;
+ in_s->p = in_s->data;
+ rv = xrdp_channel_call_callback(self, in_s, channel_id);
+ }
+ }
+ return rv;
+}
diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c
index 0c589a02..ca6660bf 100644
--- a/libxrdp/xrdp_mcs.c
+++ b/libxrdp/xrdp_mcs.c
@@ -37,6 +37,7 @@ xrdp_mcs_create(struct xrdp_sec* owner, int sck,
self->client_mcs_data = client_mcs_data;
self->server_mcs_data = server_mcs_data;
self->iso_layer = xrdp_iso_create(self, sck);
+ self->channel_list = list_create();
return self;
}
@@ -44,10 +45,27 @@ xrdp_mcs_create(struct xrdp_sec* owner, int sck,
void APP_CC
xrdp_mcs_delete(struct xrdp_mcs* self)
{
+ struct mcs_channel_item* channel_item;
+ int index;
+ int count;
+
if (self == 0)
{
return;
}
+ /* here we have to free the channel items and anything in them */
+ count = self->channel_list->count;
+ for (index = count - 1; index >= 0; index--)
+ {
+ channel_item = (struct mcs_channel_item*)
+ list_get_item(self->channel_list, index);
+ if (channel_item != 0)
+ {
+ free_stream(channel_item->in_s);
+ g_free(channel_item);
+ }
+ }
+ list_delete(self->channel_list);
xrdp_iso_delete(self->iso_layer);
g_free(self);
}
@@ -55,7 +73,7 @@ xrdp_mcs_delete(struct xrdp_mcs* self)
/*****************************************************************************/
/* returns error */
static int APP_CC
-xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int chanid)
+xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int userid, int chanid)
{
struct stream* s;
@@ -68,7 +86,7 @@ xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int chanid)
}
out_uint8(s, (MCS_CJCF << 2) | 2);
out_uint8(s, 0);
- out_uint16_be(s, self->userid);
+ out_uint16_be(s, userid);
out_uint16_be(s, chanid);
out_uint16_be(s, chanid);
s_mark_end(s);
@@ -89,6 +107,8 @@ xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan)
int appid;
int opcode;
int len;
+ int userid;
+ int chanid;
DEBUG((" in xrdp_mcs_recv"));
while (1)
@@ -105,9 +125,12 @@ xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan)
DEBUG((" out xrdp_mcs_recv appid != MCS_DPUM"));
return 1;
}
+ /* this is channels getting added from the client */
if (appid == MCS_CJRQ)
{
- xrdp_mcs_send_cjcf(self, self->userid + MCS_USERCHANNEL_BASE);
+ in_uint16_be(s, userid);
+ in_uint16_be(s, chanid);
+ xrdp_mcs_send_cjcf(self, userid, chanid);
continue;
}
break;
@@ -499,12 +522,12 @@ xrdp_mcs_send_connect_response(struct xrdp_mcs* self)
init_stream(s, 8192);
data_len = self->server_mcs_data->end - self->server_mcs_data->data;
xrdp_iso_init(self->iso_layer, s);
- xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, 313);
+ xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, data_len + 38);
xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1);
out_uint8(s, 0);
xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1);
out_uint8(s, 0);
- xrdp_mcs_out_domain_params(self, s, 2, 2, 0, 0xffff);
+ xrdp_mcs_out_domain_params(self, s, 22, 3, 0, 0xfff8);
xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len);
/* mcs data */
out_uint8a(s, self->server_mcs_data->data, data_len);
@@ -532,6 +555,16 @@ xrdp_mcs_incoming(struct xrdp_mcs* self)
{
return 1;
}
+ /* in xrdp_sec.c */
+ if (xrdp_sec_process_mcs_data(self->sec_layer) != 0)
+ {
+ return 1;
+ }
+ /* in xrdp_sec.c */
+ if (xrdp_sec_out_mcs_data(self->sec_layer) != 0)
+ {
+ return 1;
+ }
if (xrdp_mcs_send_connect_response(self) != 0)
{
return 1;
@@ -552,7 +585,8 @@ xrdp_mcs_incoming(struct xrdp_mcs* self)
{
return 1;
}
- if (xrdp_mcs_send_cjcf(self, self->userid + MCS_USERCHANNEL_BASE) != 0)
+ if (xrdp_mcs_send_cjcf(self, self->userid,
+ self->userid + MCS_USERCHANNEL_BASE) != 0)
{
return 1;
}
@@ -560,7 +594,7 @@ xrdp_mcs_incoming(struct xrdp_mcs* self)
{
return 1;
}
- if (xrdp_mcs_send_cjcf(self, MCS_GLOBAL_CHANNEL) != 0)
+ if (xrdp_mcs_send_cjcf(self, self->userid, MCS_GLOBAL_CHANNEL) != 0)
{
return 1;
}
@@ -580,24 +614,74 @@ xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s)
/*****************************************************************************/
/* returns error */
+/* Inform the callback that an mcs packet has been sent. This is needed so
+ the module can send any high priority mcs packets like audio. */
+static int APP_CC
+xrdp_mcs_call_callback(struct xrdp_mcs* self)
+{
+ int rv;
+ struct xrdp_session* session;
+
+ rv = 0;
+ /* if there is a callback, call it here */
+ session = self->sec_layer->rdp_layer->session;
+ if (session != 0)
+ {
+ if (session->callback != 0)
+ {
+ /* in xrdp_wm.c */
+ rv = session->callback(session->id, 0x5556, 0, 0, 0, 0);
+ }
+ else
+ {
+ g_writeln("in xrdp_mcs_send, session->callback is nil");
+ }
+ }
+ else
+ {
+ g_writeln("in xrdp_mcs_send, session is nil");
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
int APP_CC
-xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s)
+xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s, int chan)
{
int len;
+ //static int max_len = 0;
DEBUG((" in xrdp_mcs_send"));
s_pop_layer(s, mcs_hdr);
len = (s->end - s->p) - 8;
+ if (len > 8192 * 2)
+ {
+ g_writeln("error in xrdp_mcs_send, size too bog, its %d", len);
+ }
+ //if (len > max_len)
+ //{
+ // max_len = len;
+ // g_printf("mcs max length is %d\r\n", max_len);
+ //}
+ //g_printf("mcs length %d max length is %d\r\n", len, max_len);
+ //g_printf("mcs length %d\r\n", len);
len = len | 0x8000;
out_uint8(s, MCS_SDIN << 2);
out_uint16_be(s, self->userid);
- out_uint16_be(s, MCS_GLOBAL_CHANNEL);
+ out_uint16_be(s, chan);
out_uint8(s, 0x70);
out_uint16_be(s, len);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
return 1;
}
+ /* todo, do we need to call this for every mcs packet,
+ maybe every 5 or so */
+ if (chan == MCS_GLOBAL_CHANNEL)
+ {
+ xrdp_mcs_call_callback(self);
+ }
DEBUG((" out xrdp_mcs_send"));
return 0;
}
diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c
index 45a29d1b..2fa61eb4 100644
--- a/libxrdp/xrdp_rdp.c
+++ b/libxrdp/xrdp_rdp.c
@@ -122,7 +122,8 @@ xrdp_rdp_create(struct xrdp_session* session, int sck)
/* read ini settings */
xrdp_rdp_read_config(&self->client_info);
/* create sec layer */
- self->sec_layer = xrdp_sec_create(self, sck, self->client_info.crypt_level);
+ self->sec_layer = xrdp_sec_create(self, sck, self->client_info.crypt_level,
+ self->client_info.channel_code);
/* default 8 bit v1 color bitmap cache entries and size */
self->client_info.cache1_entries = 600;
self->client_info.cache1_size = 256;
@@ -198,6 +199,10 @@ xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code)
}
if (chan != MCS_GLOBAL_CHANNEL && chan > 0)
{
+ if (chan > MCS_GLOBAL_CHANNEL)
+ {
+ xrdp_channel_process(self->sec_layer->chan_layer, s, chan);
+ }
s->next_packet = 0;
*code = 0;
DEBUG(("out xrdp_rdp_recv"));
@@ -237,7 +242,7 @@ xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type)
out_uint16_le(s, len);
out_uint16_le(s, 0x10 | pdu_type);
out_uint16_le(s, self->mcs_channel);
- if (xrdp_sec_send(self->sec_layer, s) != 0)
+ if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
DEBUG(("out xrdp_rdp_send error"));
return 1;
@@ -266,7 +271,7 @@ xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s,
out_uint8(s, data_pdu_type);
out_uint8(s, 0);
out_uint16_le(s, 0);
- if (xrdp_sec_send(self->sec_layer, s) != 0)
+ if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
DEBUG(("out xrdp_rdp_send_data error"));
return 1;
diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c
index c80cb844..ea165c62 100644
--- a/libxrdp/xrdp_sec.c
+++ b/libxrdp/xrdp_sec.c
@@ -139,7 +139,7 @@ hex_to_bin(char* in, char* out)
}
/*****************************************************************************/
-static void
+static void APP_CC
hex_str_to_bin(char* in, char* out, int out_len)
{
int in_index;
@@ -169,7 +169,8 @@ hex_str_to_bin(char* in, char* out, int out_len)
/*****************************************************************************/
struct xrdp_sec* APP_CC
-xrdp_sec_create(struct xrdp_rdp* owner, int sck, int crypt_level)
+xrdp_sec_create(struct xrdp_rdp* owner, int sck, int crypt_level,
+ int channel_code)
{
struct xrdp_sec* self;
struct list* items;
@@ -198,6 +199,7 @@ xrdp_sec_create(struct xrdp_rdp* owner, int sck, int crypt_level)
self->crypt_level = 3;
break;
}
+ self->channel_code = channel_code;
self->decrypt_rc4_info = ssl_rc4_info_create();
self->encrypt_rc4_info = ssl_rc4_info_create();
g_random(self->server_random, 32);
@@ -398,6 +400,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec* self, struct stream* s)
{ /* must be or error */
return 1;
}
+ if (flags & RDP_LOGON_LEAVE_AUDIO)
+ {
+ self->rdp_layer->client_info.sound_code = 1;
+ }
if (flags & RDP_LOGON_AUTO)
{
self->rdp_layer->client_info.rdp_autologin = 1;
@@ -451,7 +457,7 @@ xrdp_sec_send_lic_initial(struct xrdp_sec* self)
}
out_uint8a(s, g_lic1, 322);
s_mark_end(s);
- if (xrdp_mcs_send(self->mcs_layer, s) != 0)
+ if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
free_stream(s);
return 1;
@@ -476,7 +482,7 @@ xrdp_sec_send_lic_response(struct xrdp_sec* self)
}
out_uint8a(s, g_lic2, 20);
s_mark_end(s);
- if (xrdp_mcs_send(self->mcs_layer, s) != 0)
+ if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
free_stream(s);
return 1;
@@ -682,7 +688,7 @@ xrdp_sec_sign(struct xrdp_sec* self, char* out, int out_len,
/*****************************************************************************/
/* returns error */
int APP_CC
-xrdp_sec_send(struct xrdp_sec* self, struct stream* s)
+xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int chan)
{
int datalen;
@@ -699,7 +705,7 @@ xrdp_sec_send(struct xrdp_sec* self, struct stream* s)
{
out_uint32_le(s, 0);
}
- if (xrdp_mcs_send(self->mcs_layer, s) != 0)
+ if (xrdp_mcs_send(self->mcs_layer, s, chan) != 0)
{
return 1;
}
@@ -708,73 +714,168 @@ xrdp_sec_send(struct xrdp_sec* self, struct stream* s)
}
/*****************************************************************************/
+/* this adds the mcs channels in the list of channels to be used when
+ creating the server mcs data */
+static int APP_CC
+xrdp_sec_process_mcs_data_channels(struct xrdp_sec* self, struct stream* s)
+{
+ int num_channels;
+ int index;
+ struct mcs_channel_item* channel_item;
+
+ /* this is an option set in xrdp.ini */
+ if (self->channel_code != 1) /* are channels on? */
+ {
+ return 0;
+ }
+ in_uint32_le(s, num_channels);
+ for (index = 0; index < num_channels; index++)
+ {
+ channel_item = (struct mcs_channel_item*)
+ g_malloc(sizeof(struct mcs_channel_item), 1);
+ in_uint8a(s, channel_item->name, 8);
+ in_uint32_be(s, channel_item->flags);
+ channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
+ list_add_item(self->mcs_layer->channel_list, (long)channel_item);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* process client mcs data, we need some things in here to create the server
+ mcs data */
+int APP_CC
+xrdp_sec_process_mcs_data(struct xrdp_sec* self)
+{
+ struct stream* s;
+ char* hold_p;
+ int tag;
+ int size;
+
+ s = &self->client_mcs_data;
+ /* set p to beginning */
+ s->p = s->data;
+ /* skip header */
+ in_uint8s(s, 23);
+ while (s_check_rem(s, 4))
+ {
+ hold_p = s->p;
+ in_uint16_le(s, tag);
+ in_uint16_le(s, size);
+ if (size < 4 || !s_check_rem(s, size - 4))
+ {
+ g_writeln("error in xrdp_sec_process_mcs_data tag %d size %d",
+ tag, size);
+ break;
+ }
+ switch (tag)
+ {
+ case SEC_TAG_CLI_INFO:
+ break;
+ case SEC_TAG_CLI_CRYPT:
+ break;
+ case SEC_TAG_CLI_CHANNELS:
+ xrdp_sec_process_mcs_data_channels(self, s);
+ break;
+ case SEC_TAG_CLI_4:
+ break;
+ default:
+ g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d",
+ tag, size);
+ break;
+ }
+ s->p = hold_p + size;
+ }
+ /* set p to beginning */
+ s->p = s->data;
+ return 0;
+}
+
+/*****************************************************************************/
/* prepare server mcs data to send in mcs layer */
-static void APP_CC
+int APP_CC
xrdp_sec_out_mcs_data(struct xrdp_sec* self)
{
- struct stream* p;
-
- p = &self->server_mcs_data;
- init_stream(p, 512);
- out_uint16_be(p, 5);
- out_uint16_be(p, 0x14);
- out_uint8(p, 0x7c);
- out_uint16_be(p, 1);
- out_uint8(p, 0x2a);
- out_uint8(p, 0x14);
- out_uint8(p, 0x76);
- out_uint8(p, 0x0a);
- out_uint8(p, 1);
- out_uint8(p, 1);
- out_uint8(p, 0);
- out_uint16_le(p, 0xc001);
- out_uint8(p, 0);
- out_uint8(p, 0x4d); /* M */
- out_uint8(p, 0x63); /* c */
- out_uint8(p, 0x44); /* D */
- out_uint8(p, 0x6e); /* n */
- out_uint16_be(p, 0x80fc);
- out_uint16_le(p, SEC_TAG_SRV_INFO);
- out_uint16_le(p, 8); /* len */
- out_uint8(p, 4); /* 4 = rdp5 1 = rdp4 */
- out_uint8(p, 0);
- out_uint8(p, 8);
- out_uint8(p, 0);
- out_uint16_le(p, SEC_TAG_SRV_CHANNELS);
- out_uint16_le(p, 8); /* len */
- out_uint8(p, 0xeb);
- out_uint8(p, 3);
- out_uint8(p, 0);
- out_uint8(p, 0);
- out_uint16_le(p, SEC_TAG_SRV_CRYPT);
- out_uint16_le(p, 0x00ec); /* len is 236 */
- out_uint32_le(p, self->rc4_key_size); /* key len 1 = 40 bit 2 = 128 bit */
- out_uint32_le(p, self->crypt_level); /* crypt level 1 = low 2 = medium */
+ struct stream* s;
+ int num_channels_even;
+ int num_channels;
+ int index;
+ int channel;
+
+ num_channels = self->mcs_layer->channel_list->count;
+ num_channels_even = num_channels + (num_channels & 1);
+ s = &self->server_mcs_data;
+ init_stream(s, 512);
+ out_uint16_be(s, 5);
+ out_uint16_be(s, 0x14);
+ out_uint8(s, 0x7c);
+ out_uint16_be(s, 1);
+ out_uint8(s, 0x2a);
+ out_uint8(s, 0x14);
+ out_uint8(s, 0x76);
+ out_uint8(s, 0x0a);
+ out_uint8(s, 1);
+ out_uint8(s, 1);
+ out_uint8(s, 0);
+ out_uint16_le(s, 0xc001);
+ out_uint8(s, 0);
+ out_uint8(s, 0x4d); /* M */
+ out_uint8(s, 0x63); /* c */
+ out_uint8(s, 0x44); /* D */
+ out_uint8(s, 0x6e); /* n */
+ out_uint16_be(s, 0x80fc + (num_channels_even * 2));
+ out_uint16_le(s, SEC_TAG_SRV_INFO);
+ out_uint16_le(s, 8); /* len */
+ out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */
+ out_uint8(s, 0);
+ out_uint8(s, 8);
+ out_uint8(s, 0);
+ out_uint16_le(s, SEC_TAG_SRV_CHANNELS);
+ out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */
+ out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */
+ out_uint16_le(s, num_channels); /* number of other channels */
+ for (index = 0; index < num_channels_even; index++)
+ {
+ if (index < num_channels)
+ {
+ channel = MCS_GLOBAL_CHANNEL + (index + 1);
+ out_uint16_le(s, channel);
+ }
+ else
+ {
+ out_uint16_le(s, 0);
+ }
+ }
+ out_uint16_le(s, SEC_TAG_SRV_CRYPT);
+ out_uint16_le(s, 0x00ec); /* len is 236 */
+ out_uint32_le(s, self->rc4_key_size); /* key len 1 = 40 bit 2 = 128 bit */
+ out_uint32_le(s, self->crypt_level); /* crypt level 1 = low 2 = medium */
/* 3 = high */
- out_uint32_le(p, 32); /* 32 bytes random len */
- out_uint32_le(p, 0xb8); /* 184 bytes rsa info(certificate) len */
- out_uint8a(p, self->server_random, 32);
+ out_uint32_le(s, 32); /* 32 bytes random len */
+ out_uint32_le(s, 0xb8); /* 184 bytes rsa info(certificate) len */
+ out_uint8a(s, self->server_random, 32);
/* here to end is certificate */
/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */
/* TermService\Parameters\Certificate */
- out_uint32_le(p, 1);
- out_uint32_le(p, 1);
- out_uint32_le(p, 1);
- out_uint16_le(p, SEC_TAG_PUBKEY);
- out_uint16_le(p, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */
- out_uint32_le(p, SEC_RSA_MAGIC);
- out_uint32_le(p, 0x48); /* 72 bytes modulus len */
- out_uint32_be(p, 0x00020000);
- out_uint32_be(p, 0x3f000000);
- out_uint8a(p, self->pub_exp, 4); /* pub exp */
- out_uint8a(p, self->pub_mod, 64); /* pub mod */
- out_uint8s(p, 8); /* pad */
- out_uint16_le(p, SEC_TAG_KEYSIG);
- out_uint16_le(p, 72); /* len */
- out_uint8a(p, self->pub_sig, 64); /* pub sig */
- out_uint8s(p, 8); /* pad */
+ out_uint32_le(s, 1);
+ out_uint32_le(s, 1);
+ out_uint32_le(s, 1);
+ out_uint16_le(s, SEC_TAG_PUBKEY);
+ out_uint16_le(s, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */
+ out_uint32_le(s, SEC_RSA_MAGIC);
+ out_uint32_le(s, 0x48); /* 72 bytes modulus len */
+ out_uint32_be(s, 0x00020000);
+ out_uint32_be(s, 0x3f000000);
+ out_uint8a(s, self->pub_exp, 4); /* pub exp */
+ out_uint8a(s, self->pub_mod, 64); /* pub mod */
+ out_uint8s(s, 8); /* pad */
+ out_uint16_le(s, SEC_TAG_KEYSIG);
+ out_uint16_le(s, 72); /* len */
+ out_uint8a(s, self->pub_sig, 64); /* pub sig */
+ out_uint8s(s, 8); /* pad */
/* end certificate */
- s_mark_end(p);
+ s_mark_end(s);
+ return 0;
}
/*****************************************************************************/
@@ -818,7 +919,6 @@ int APP_CC
xrdp_sec_incoming(struct xrdp_sec* self)
{
DEBUG(("in xrdp_sec_incoming"));
- xrdp_sec_out_mcs_data(self);
if (xrdp_mcs_incoming(self->mcs_layer) != 0)
{
return 1;