summaryrefslogtreecommitdiffstats
path: root/libxrdp
diff options
context:
space:
mode:
authorjsorg71 <jay.sorg@gmail.com>2018-10-11 22:09:20 -0700
committerGitHub <noreply@github.com>2018-10-11 22:09:20 -0700
commitae1514c1679e87edfdeba5ca3eb2b3659ef44b1a (patch)
tree9f07228ba6be179dd5c0a46e070ca86c16214ab4 /libxrdp
parent6049cf8dad919ded363c0dd5ac53a56e4c82b5ad (diff)
downloadxrdp-proprietary-ae1514c1679e87edfdeba5ca3eb2b3659ef44b1a.tar.gz
xrdp-proprietary-ae1514c1679e87edfdeba5ca3eb2b3659ef44b1a.zip
dynamic virtual channel improvements
remove not used chansrv <-> xrdp messages move static channel disable control into libxrdp remove some blocking read, write chansrv calls add drdynvc calls to libxrdp add drdynvc calls to chansrv channel cleanup
Diffstat (limited to 'libxrdp')
-rw-r--r--libxrdp/libxrdp.c87
-rw-r--r--libxrdp/libxrdp.h34
-rw-r--r--libxrdp/libxrdpinc.h24
-rw-r--r--libxrdp/xrdp_channel.c649
-rw-r--r--libxrdp/xrdp_rdp.c1
-rw-r--r--libxrdp/xrdp_sec.c45
6 files changed, 811 insertions, 29 deletions
diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c
index 99da37f8..2720fab2 100644
--- a/libxrdp/libxrdp.c
+++ b/libxrdp/libxrdp.c
@@ -1264,6 +1264,93 @@ libxrdp_send_to_channel(struct xrdp_session *session, int channel_id,
}
/*****************************************************************************/
+int
+libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
+ int is_disabled)
+{
+ struct xrdp_rdp *rdp;
+ struct xrdp_mcs *mcs;
+ struct mcs_channel_item *channel_item;
+
+ rdp = (struct xrdp_rdp *) (session->rdp);
+ mcs = rdp->sec_layer->mcs_layer;
+ if (mcs->channel_list == NULL)
+ {
+ return 1;
+ }
+ channel_item = (struct mcs_channel_item *)
+ list_get_item(mcs->channel_list, channel_id);
+ if (channel_item == NULL)
+ {
+ return 1;
+ }
+ channel_item->disabled = is_disabled;
+ return 1;
+}
+
+/*****************************************************************************/
+int
+libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
+ int flags, struct xrdp_drdynvc_procs *procs,
+ int *chan_id)
+{
+ struct xrdp_rdp *rdp;
+ struct xrdp_sec *sec;
+ struct xrdp_channel *chan;
+
+ rdp = (struct xrdp_rdp *) (session->rdp);
+ sec = rdp->sec_layer;
+ chan = sec->chan_layer;
+ return xrdp_channel_drdynvc_open(chan, name, flags, procs, chan_id);
+}
+
+/*****************************************************************************/
+int
+libxrdp_drdynvc_close(struct xrdp_session *session, int chan_id)
+{
+ struct xrdp_rdp *rdp;
+ struct xrdp_sec *sec;
+ struct xrdp_channel *chan;
+
+ rdp = (struct xrdp_rdp *) (session->rdp);
+ sec = rdp->sec_layer;
+ chan = sec->chan_layer;
+ return xrdp_channel_drdynvc_close(chan, chan_id);
+}
+
+/*****************************************************************************/
+int
+libxrdp_drdynvc_data_first(struct xrdp_session *session, int chan_id,
+ const char *data, int data_bytes,
+ int total_data_bytes)
+{
+ struct xrdp_rdp *rdp;
+ struct xrdp_sec *sec;
+ struct xrdp_channel *chan;
+
+ rdp = (struct xrdp_rdp *) (session->rdp);
+ sec = rdp->sec_layer;
+ chan = sec->chan_layer;
+ return xrdp_channel_drdynvc_data_first(chan, chan_id, data, data_bytes,
+ total_data_bytes);
+}
+
+/*****************************************************************************/
+int
+libxrdp_drdynvc_data(struct xrdp_session *session, int chan_id,
+ const char *data, int data_bytes)
+{
+ struct xrdp_rdp *rdp;
+ struct xrdp_sec *sec;
+ struct xrdp_channel *chan;
+
+ rdp = (struct xrdp_rdp *) (session->rdp);
+ sec = rdp->sec_layer;
+ chan = sec->chan_layer;
+ return xrdp_channel_drdynvc_data(chan, chan_id, data, data_bytes);
+}
+
+/*****************************************************************************/
int EXPORT_CC
libxrdp_orders_send_brush(struct xrdp_session *session,
int width, int height, int bpp, int type,
diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h
index 0ac5f635..98c8f030 100644
--- a/libxrdp/libxrdp.h
+++ b/libxrdp/libxrdp.h
@@ -51,6 +51,8 @@ struct mcs_channel_item
char name[16];
int flags;
int chanid;
+ int disabled;
+ int pad0;
};
/* mcs */
@@ -128,11 +130,27 @@ struct xrdp_sec
int is_security_header_present; /* boolean */
};
+struct xrdp_drdynvc
+{
+ int chan_id;
+ int status; /* see XRDP_DRDYNVC_STATUS_* */
+ int flags;
+ int pad0;
+ int (*open_response)(intptr_t id, int chan_id, int creation_status);
+ int (*close_response)(intptr_t id, int chan_id);
+ int (*data_first)(intptr_t id, int chan_id, char *data, int bytes, int total_bytes);
+ int (*data)(intptr_t id, int chan_id, char *data, int bytes);
+};
+
/* channel */
struct xrdp_channel
{
struct xrdp_sec *sec_layer;
struct xrdp_mcs *mcs_layer;
+ int drdynvc_channel_id;
+ int drdynvc_state;
+ struct stream *s;
+ struct xrdp_drdynvc drdynvcs[256];
};
/* rdp */
@@ -285,7 +303,6 @@ struct xrdp_mppc_enc
tui16 *hash_table;
};
-
int
compress_rdp(struct xrdp_mppc_enc *enc, tui8 *srcData, int len);
struct xrdp_mppc_enc *
@@ -553,6 +570,21 @@ xrdp_channel_send(struct xrdp_channel *self, struct stream *s, int channel_id,
int
xrdp_channel_process(struct xrdp_channel *self, struct stream *s,
int chanid);
+int
+xrdp_channel_drdynvc_start(struct xrdp_channel *self);
+int
+xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
+ int flags, struct xrdp_drdynvc_procs *procs,
+ int *chan_id);
+int
+xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id);
+int
+xrdp_channel_drdynvc_data_first(struct xrdp_channel *self, int chan_id,
+ const char *data, int data_bytes,
+ int total_data_bytes);
+int
+xrdp_channel_drdynvc_data(struct xrdp_channel *self, int chan_id,
+ const char *data, int data_bytes);
/* xrdp_fastpath.c */
struct xrdp_fastpath *
diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h
index 38bd4b34..c236bec9 100644
--- a/libxrdp/libxrdpinc.h
+++ b/libxrdp/libxrdpinc.h
@@ -76,6 +76,14 @@ struct xrdp_session
struct source_info si;
};
+struct xrdp_drdynvc_procs
+{
+ int (*open_response)(intptr_t id, int chan_id, int creation_status);
+ int (*close_response)(intptr_t id, int chan_id);
+ int (*data_first)(intptr_t id, int chan_id, char *data, int bytes, int total_bytes);
+ int (*data)(intptr_t id, int chan_id, char *data, int bytes);
+};
+
struct xrdp_session *
libxrdp_init(tbus id, struct trans *trans);
int
@@ -195,6 +203,22 @@ libxrdp_send_to_channel(struct xrdp_session *session, int channel_id,
char *data, int data_len,
int total_data_len, int flags);
int
+libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
+ int is_disabled);
+int
+libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
+ int flags, struct xrdp_drdynvc_procs *procs,
+ int *chan_id);
+int
+libxrdp_drdynvc_close(struct xrdp_session *session, int chan_id);
+int
+libxrdp_drdynvc_data_first(struct xrdp_session *session, int chan_id,
+ const char *data, int data_bytes,
+ int total_data_bytes);
+int
+libxrdp_drdynvc_data(struct xrdp_session *session, int chan_id,
+ const char *data, int data_bytes);
+int
libxrdp_orders_send_brush(struct xrdp_session *session,
int width, int height, int bpp, int type,
int size, char *data, int cache_id);
diff --git a/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c
index 4f4f3ef3..9662582e 100644
--- a/libxrdp/xrdp_channel.c
+++ b/libxrdp/xrdp_channel.c
@@ -31,6 +31,17 @@
#define CHANNEL_FLAG_LAST 0x02
#define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
+#define CMD_DVC_OPEN_CHANNEL 0x10
+#define CMD_DVC_DATA_FIRST 0x20
+#define CMD_DVC_DATA 0x30
+#define CMD_DVC_CLOSE_CHANNEL 0x40
+#define CMD_DVC_CAPABILITY 0x50
+
+#define XRDP_DRDYNVC_STATUS_CLOSED 0
+#define XRDP_DRDYNVC_STATUS_OPEN_SENT 1
+#define XRDP_DRDYNVC_STATUS_OPEN 2
+#define XRDP_DRDYNVC_STATUS_CLOSE_SENT 3
+
/*****************************************************************************/
/* returns pointer or nil on error */
static struct mcs_channel_item *
@@ -58,6 +69,7 @@ xrdp_channel_create(struct xrdp_sec *owner, struct xrdp_mcs *mcs_layer)
self = (struct xrdp_channel *)g_malloc(sizeof(struct xrdp_channel), 1);
self->sec_layer = owner;
self->mcs_layer = mcs_layer;
+ self->drdynvc_channel_id = -1;
return self;
}
@@ -70,7 +82,7 @@ xrdp_channel_delete(struct xrdp_channel *self)
{
return;
}
-
+ free_stream(self->s);
g_memset(self, 0, sizeof(struct xrdp_channel));
g_free(self);
}
@@ -106,6 +118,12 @@ xrdp_channel_send(struct xrdp_channel *self, struct stream *s, int channel_id,
return 1;
}
+ if (channel->disabled)
+ {
+ g_writeln("xrdp_channel_send, channel disabled");
+ return 0; /* not an error */
+ }
+
s_pop_layer(s, channel_hdr);
out_uint32_le(s, total_data_len);
@@ -176,6 +194,333 @@ xrdp_channel_call_callback(struct xrdp_channel *self, struct stream *s,
}
/*****************************************************************************/
+static int
+drdynvc_insert_uint_124(struct stream *s, uint32_t val)
+{
+ int ret_val;
+
+ if (val <= 0xff)
+ {
+ out_uint8(s, val);
+ ret_val = 0;
+ }
+ else if (val <= 0xffff)
+ {
+ out_uint16_le(s, val);
+ ret_val = 1;
+ }
+ else
+ {
+ out_uint32_le(s, val);
+ ret_val = 2;
+ }
+
+ return ret_val;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p)
+{
+ int cbChId;
+ int chan_id;
+
+ cbChId = cmd & 0x03;
+ if (cbChId == 0)
+ {
+ if (!s_check_rem(s, 1))
+ {
+ return 1;
+ }
+ in_uint8(s, chan_id);
+ }
+ else if (cbChId == 1)
+ {
+ if (!s_check_rem(s, 2))
+ {
+ return 1;
+ }
+ in_uint16_le(s, chan_id);
+ }
+ else
+ {
+ if (!s_check_rem(s, 4))
+ {
+ return 1;
+ }
+ in_uint32_le(s, chan_id);
+ }
+ *chan_id_p = chan_id;
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_process_capability_response(struct xrdp_channel *self,
+ int cmd, struct stream *s)
+{
+ struct xrdp_session *session;
+ int cap_version;
+ int rv;
+
+ /* skip padding */
+ in_uint8s(s, 1);
+ /* read client's version */
+ in_uint16_le(s, cap_version);
+ if ((cap_version != 2) && (cap_version != 3))
+ {
+ g_writeln("drdynvc_process_capability_response: incompatible DVC "
+ "version %d detected", cap_version);
+ return 1;
+ }
+ g_writeln("drdynvc_process_capability_response: DVC version %d selected",
+ cap_version);
+ self->drdynvc_state = 1;
+ session = self->sec_layer->rdp_layer->session;
+ rv = session->callback(session->id, 0x5558, 0, 0, 0, 0);
+ return rv;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_process_open_channel_response(struct xrdp_channel *self,
+ int cmd, struct stream *s)
+{
+ struct xrdp_session *session;
+ int creation_status;
+ uint32_t chan_id;
+ struct xrdp_drdynvc *drdynvc;
+
+ if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
+ {
+ return 1;
+ }
+ if (!s_check_rem(s, 4))
+ {
+ return 1;
+ }
+ in_uint32_le(s, creation_status);
+ //g_writeln("drdynvc_process_open_channel_response: chan_id 0x%x "
+ // "creation_status %d", chan_id, creation_status);
+ session = self->sec_layer->rdp_layer->session;
+ if (chan_id > 255)
+ {
+ return 1;
+ }
+ drdynvc = self->drdynvcs + chan_id;
+ if (creation_status == 0)
+ {
+ drdynvc->status = XRDP_DRDYNVC_STATUS_OPEN;
+ }
+ else
+ {
+ drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
+ }
+ if (drdynvc->open_response != NULL)
+ {
+ return drdynvc->open_response(session->id, chan_id, creation_status);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_process_close_channel_response(struct xrdp_channel *self,
+ int cmd, struct stream *s)
+{
+ struct xrdp_session *session;
+ uint32_t chan_id;
+ struct xrdp_drdynvc *drdynvc;
+
+ if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
+ {
+ return 1;
+ }
+ //g_writeln("drdynvc_process_close_channel_response: chan_id 0x%x", chan_id);
+ session = self->sec_layer->rdp_layer->session;
+ if (chan_id > 255)
+ {
+ return 1;
+ }
+ drdynvc = self->drdynvcs + chan_id;
+ drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
+ if (drdynvc->close_response != NULL)
+ {
+ return drdynvc->close_response(session->id, chan_id);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_process_data_first(struct xrdp_channel *self,
+ int cmd, struct stream *s)
+{
+ struct xrdp_session *session;
+ uint32_t chan_id;
+ int len;
+ int bytes;
+ int total_bytes;
+ struct xrdp_drdynvc *drdynvc;
+
+ if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
+ {
+ return 1;
+ }
+ len = (cmd >> 2) & 0x03;
+ if (len == 0)
+ {
+ if (!s_check_rem(s, 1))
+ {
+ return 1;
+ }
+ in_uint8(s, total_bytes);
+ }
+ else if (len == 1)
+ {
+ if (!s_check_rem(s, 2))
+ {
+ return 1;
+ }
+ in_uint16_le(s, total_bytes);
+ }
+ else
+ {
+ if (!s_check_rem(s, 4))
+ {
+ return 1;
+ }
+ in_uint32_le(s, total_bytes);
+ }
+ bytes = (int) (s->end - s->p);
+ //g_writeln("drdynvc_process_data_first: bytes %d total_bytes %d", bytes, total_bytes);
+ session = self->sec_layer->rdp_layer->session;
+ if (chan_id > 255)
+ {
+ return 1;
+ }
+ drdynvc = self->drdynvcs + chan_id;
+ if (drdynvc->data_first != NULL)
+ {
+ return drdynvc->data_first(session->id, chan_id, s->p,
+ bytes, total_bytes);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+drdynvc_process_data(struct xrdp_channel *self,
+ int cmd, struct stream *s)
+{
+ struct xrdp_session *session;
+ uint32_t chan_id;
+ int bytes;
+ struct xrdp_drdynvc *drdynvc;
+
+ if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
+ {
+ return 1;
+ }
+ bytes = (int) (s->end - s->p);
+ //g_writeln("drdynvc_process_data: bytes %d", bytes);
+ session = self->sec_layer->rdp_layer->session;
+ if (chan_id > 255)
+ {
+ return 1;
+ }
+ drdynvc = self->drdynvcs + chan_id;
+ if (drdynvc->data != NULL)
+ {
+ return drdynvc->data(session->id, chan_id, s->p, bytes);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+xrdp_channel_process_drdynvc(struct xrdp_channel *self,
+ struct mcs_channel_item *channel,
+ struct stream *s)
+{
+ int total_length;
+ int length;
+ int flags;
+ int cmd;
+ int rv;
+ struct stream *ls;
+
+ if (!s_check_rem(s, 8))
+ {
+ return 1;
+ }
+ in_uint32_le(s, total_length);
+ in_uint32_le(s, flags);
+ //g_writeln("xrdp_channel_process_drdynvc: total_length %d flags 0x%8.8x",
+ // total_length, flags);
+ ls = NULL;
+ switch (flags & 3)
+ {
+ case 0:
+ length = (int) (s->end - s->p);
+ out_uint8a(self->s, s->p, length);
+ in_uint8s(s, length);
+ return 0;
+ case 1:
+ free_stream(self->s);
+ make_stream(self->s);
+ init_stream(self->s, total_length);
+ length = (int) (s->end - s->p);
+ out_uint8a(self->s, s->p, length);
+ in_uint8s(s, length);
+ return 0;
+ case 2:
+ length = (int) (s->end - s->p);
+ out_uint8a(self->s, s->p, length);
+ in_uint8s(s, length);
+ ls = self->s;
+ break;
+ case 3:
+ ls = s;
+ break;
+ default:
+ g_writeln("xrdp_channel_process_drdynvc: error");
+ return 1;
+ }
+ if (ls == NULL)
+ {
+ return 1;
+ }
+ in_uint8(ls, cmd); /* read command */
+ //g_writeln("xrdp_channel_process_drdynvc: cmd 0x%x", cmd);
+ rv = 1;
+ switch (cmd & 0xf0)
+ {
+ case CMD_DVC_CAPABILITY:
+ rv = drdynvc_process_capability_response(self, cmd, s);
+ break;
+ case CMD_DVC_OPEN_CHANNEL:
+ rv = drdynvc_process_open_channel_response(self, cmd, s);
+ break;
+ case CMD_DVC_CLOSE_CHANNEL:
+ rv = drdynvc_process_close_channel_response(self, cmd, s);
+ break;
+ case CMD_DVC_DATA_FIRST:
+ rv = drdynvc_process_data_first(self, cmd, s);
+ break;
+ case CMD_DVC_DATA:
+ rv = drdynvc_process_data(self, cmd, s);
+ break;
+ default:
+ g_writeln("xrdp_channel_process_drdynvc: got unknown "
+ "command 0x%x", cmd);
+ break;
+ }
+ //g_writeln("xrdp_channel_process_drdynvc: rv %d", rv);
+ return rv;
+}
+
+/*****************************************************************************/
/* returns error */
/* This is called from the secure layer to process an incoming non global
channel packet.
@@ -191,23 +536,319 @@ xrdp_channel_process(struct xrdp_channel *self, struct stream *s,
int channel_id;
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 == NULL)
{
g_writeln("xrdp_channel_process, channel not found");
return 1;
}
-
+ if (channel->disabled)
+ {
+ g_writeln("xrdp_channel_process, channel disabled");
+ return 0; /* not an error */
+ }
+ if (channel_id == self->drdynvc_channel_id)
+ {
+ return xrdp_channel_process_drdynvc(self, channel, s);
+ }
rv = 0;
in_uint32_le(s, length);
in_uint32_le(s, flags);
rv = xrdp_channel_call_callback(self, s, channel_id, length, flags);
return rv;
}
+
+/*****************************************************************************/
+/* drdynvc */
+static int
+xrdp_channel_drdynvc_send_capability_request(struct xrdp_channel *self)
+{
+ struct stream *s;
+ int flags;
+ int total_data_len;
+ int channel_id;
+ char *phold;
+
+ /* setup stream */
+ make_stream(s);
+ init_stream(s, 8192);
+ if (xrdp_channel_init(self, s) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ phold = s->p;
+ out_uint8(s, 0x50); /* insert cmd */
+ out_uint8(s, 0x00); /* insert padding */
+ out_uint16_le(s, 2); /* insert version */
+ /* channel priority unused for now */
+ out_uint16_le(s, 0x0000); /* priority charge 0 */
+ out_uint16_le(s, 0x0000); /* priority charge 1 */
+ out_uint16_le(s, 0x0000); /* priority charge 2 */
+ out_uint16_le(s, 0x0000); /* priority charge 3 */
+ s_mark_end(s);
+ /* send command to client */
+ total_data_len = (int) (s->end - phold);
+ flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
+ channel_id = self->drdynvc_channel_id;
+ if (xrdp_channel_send(self, s, channel_id, total_data_len, flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ return 0;
+}
+
+/*****************************************************************************/
+int
+xrdp_channel_drdynvc_start(struct xrdp_channel *self)
+{
+ int index;
+ int count;
+ struct mcs_channel_item *ci;
+ struct mcs_channel_item *dci;
+
+ g_writeln("xrdp_channel_drdynvc_start:");
+ dci = NULL;
+ count = self->mcs_layer->channel_list->count;
+ for (index = 0; index < count; index++)
+ {
+ ci = (struct mcs_channel_item *)
+ list_get_item(self->mcs_layer->channel_list, index);
+ if (ci != NULL)
+ {
+ if (g_strcasecmp(ci->name, "drdynvc") == 0)
+ {
+ dci = ci;
+ }
+ }
+ }
+ if (dci != NULL)
+ {
+ self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
+ xrdp_channel_drdynvc_send_capability_request(self);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int
+xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
+ int flags, struct xrdp_drdynvc_procs *procs,
+ int *chan_id)
+{
+ struct stream *s;
+ int ChId;
+ int cbChId;
+ int chan_pri;
+ int static_channel_id;
+ int name_length;
+ int total_data_len;
+ int static_flags;
+ char *cmd_ptr;
+
+ make_stream(s);
+ init_stream(s, 8192);
+ if (xrdp_channel_init(self, s) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ cmd_ptr = s->p;
+ out_uint8(s, 0);
+ ChId = 1;
+ while (self->drdynvcs[ChId].status != XRDP_DRDYNVC_STATUS_CLOSED)
+ {
+ ChId++;
+ if (ChId > 255)
+ {
+ free_stream(s);
+ return 1;
+ }
+ }
+ cbChId = drdynvc_insert_uint_124(s, ChId);
+ name_length = g_strlen(name);
+ out_uint8a(s, name, name_length + 1);
+ chan_pri = 0;
+ cmd_ptr[0] = CMD_DVC_OPEN_CHANNEL | ((chan_pri << 2) & 0x0c) | cbChId;
+ static_channel_id = self->drdynvc_channel_id;
+ static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
+ s_mark_end(s);
+ total_data_len = (int) (s->end - cmd_ptr);
+ if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
+ static_flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ *chan_id = ChId;
+ self->drdynvcs[ChId].open_response = procs->open_response;
+ self->drdynvcs[ChId].close_response = procs->close_response;
+ self->drdynvcs[ChId].data_first = procs->data_first;
+ self->drdynvcs[ChId].data = procs->data;
+ self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_OPEN_SENT;
+ return 0;
+}
+
+/*****************************************************************************/
+int
+xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id)
+{
+ struct stream *s;
+ int ChId;
+ int cbChId;
+ int static_channel_id;
+ int total_data_len;
+ int static_flags;
+ char *cmd_ptr;
+
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ if ((self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN) &&
+ (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN_SENT))
+ {
+ /* not open */
+ return 1;
+ }
+ make_stream(s);
+ init_stream(s, 8192);
+ if (xrdp_channel_init(self, s) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ cmd_ptr = s->p;
+ out_uint8(s, 0);
+ ChId = chan_id;
+ cbChId = drdynvc_insert_uint_124(s, ChId);
+ cmd_ptr[0] = CMD_DVC_CLOSE_CHANNEL | cbChId;
+ static_channel_id = self->drdynvc_channel_id;
+ static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
+ s_mark_end(s);
+ total_data_len = (int) (s->end - cmd_ptr);
+ if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
+ static_flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_CLOSE_SENT;
+ return 0;
+}
+
+/*****************************************************************************/
+int
+xrdp_channel_drdynvc_data_first(struct xrdp_channel *self, int chan_id,
+ const char *data, int data_bytes,
+ int total_data_bytes)
+{
+ struct stream *s;
+ int ChId;
+ int cbChId;
+ int cbTotalDataSize;
+ int static_channel_id;
+ int total_data_len;
+ int static_flags;
+ char *cmd_ptr;
+
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
+ {
+ return 1;
+ }
+ if (data_bytes > 1590)
+ {
+ return 1;
+ }
+ make_stream(s);
+ init_stream(s, 8192);
+ if (xrdp_channel_init(self, s) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ cmd_ptr = s->p;
+ out_uint8(s, 0);
+ ChId = chan_id;
+ cbChId = drdynvc_insert_uint_124(s, ChId);
+ cbTotalDataSize = drdynvc_insert_uint_124(s, total_data_bytes);
+ out_uint8p(s, data, data_bytes);
+ cmd_ptr[0] = CMD_DVC_DATA_FIRST | (cbTotalDataSize << 2) | cbChId;
+ static_channel_id = self->drdynvc_channel_id;
+ static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
+ s_mark_end(s);
+ total_data_len = (int) (s->end - cmd_ptr);
+ if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
+ static_flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ return 0;
+}
+
+/*****************************************************************************/
+int
+xrdp_channel_drdynvc_data(struct xrdp_channel *self, int chan_id,
+ const char *data, int data_bytes)
+{
+ struct stream *s;
+ int ChId;
+ int cbChId;
+ int static_channel_id;
+ int total_data_len;
+ int static_flags;
+ char *cmd_ptr;
+
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
+ {
+ return 1;
+ }
+ if (data_bytes > 1590)
+ {
+ return 1;
+ }
+ make_stream(s);
+ init_stream(s, 8192);
+ if (xrdp_channel_init(self, s) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ cmd_ptr = s->p;
+ out_uint8(s, 0);
+ ChId = chan_id;
+ cbChId = drdynvc_insert_uint_124(s, ChId);
+ out_uint8p(s, data, data_bytes);
+ cmd_ptr[0] = CMD_DVC_DATA | cbChId;
+ static_channel_id = self->drdynvc_channel_id;
+ static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
+ s_mark_end(s);
+ total_data_len = (int) (s->end - cmd_ptr);
+ if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
+ static_flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ return 0;
+}
diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c
index 099cec47..494d23e8 100644
--- a/libxrdp/xrdp_rdp.c
+++ b/libxrdp/xrdp_rdp.c
@@ -1125,6 +1125,7 @@ xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s)
g_writeln("yeah, up_and_running");
DEBUG(("up_and_running set"));
xrdp_rdp_send_data_update_sync(self);
+ xrdp_channel_drdynvc_start(self->sec_layer->chan_layer);
}
DEBUG(("out xrdp_rdp_process_data_font"));
diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c
index 0436edf2..2fbad018 100644
--- a/libxrdp/xrdp_sec.c
+++ b/libxrdp/xrdp_sec.c
@@ -1840,57 +1840,54 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s)
{
int num_channels;
int index;
- struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL;
+ struct xrdp_client_info *client_info;
+ struct mcs_channel_item *channel_item;
client_info = &(self->rdp_layer->client_info);
-
-
- DEBUG(("processing channels, channels_allowed is %d", client_info->channels_allowed));
-
+ DEBUG(("processing channels, channels_allowed is %d",
+ client_info->channels_allowed));
/* this is an option set in xrdp.ini */
- if (client_info->channels_allowed != 1) /* are channels on? */
+ if (client_info->channels_allowed == 0) /* are channels on? */
{
- g_writeln("xrdp_sec_process_mcs_data_channels: all channels are disabled by configuration");
+ log_message(LOG_LEVEL_INFO, "all channels are disabled by "
+ "configuration");
return 0;
}
-
if (!s_check_rem(s, 4))
{
return 1;
}
-
in_uint32_le(s, num_channels);
-
if (num_channels > 31)
{
return 1;
}
-
for (index = 0; index < num_channels; index++)
{
- struct mcs_channel_item *channel_item;
-
- channel_item = (struct mcs_channel_item *)
- g_malloc(sizeof(struct mcs_channel_item), 1);
+ channel_item = g_new0(struct mcs_channel_item, 1);
if (!s_check_rem(s, 12))
{
g_free(channel_item);
return 1;
}
in_uint8a(s, channel_item->name, 8);
- if (g_strlen(channel_item->name) == 0)
+ in_uint32_le(s, channel_item->flags);
+ if (g_strlen(channel_item->name) > 0)
+ {
+ channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
+ log_message(LOG_LEVEL_INFO, "adding channel item name %s chan_id "
+ "%d flags 0x%8.8x", channel_item->name,
+ channel_item->chanid, channel_item->flags);
+ list_add_item(self->mcs_layer->channel_list,
+ (intptr_t) channel_item);
+ DEBUG(("got channel flags %8.8x name %s", channel_item->flags,
+ channel_item->name));
+ }
+ else
{
- log_message(LOG_LEVEL_WARNING, "xrdp_sec_process_mcs_data_channels: got an empty channel name, ignoring it");
g_free(channel_item);
- continue;
}
- in_uint32_le(s, channel_item->flags);
- channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
- list_add_item(self->mcs_layer->channel_list, (tintptr) channel_item);
- DEBUG(("got channel flags %8.8x name %s", channel_item->flags,
- channel_item->name));
}
-
return 0;
}