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
This commit is contained in:
jsorg71 2018-10-11 22:09:20 -07:00 committed by GitHub
parent 6049cf8dad
commit ae1514c167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2225 additions and 1655 deletions

View File

@ -1263,6 +1263,93 @@ libxrdp_send_to_channel(struct xrdp_session *session, int channel_id,
return 0;
}
/*****************************************************************************/
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,

View File

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

View File

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

View File

@ -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);
@ -175,6 +193,333 @@ xrdp_channel_call_callback(struct xrdp_channel *self, struct stream *s,
return rv;
}
/*****************************************************************************/
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
@ -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;
}

View File

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

View File

@ -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)
{
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));
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
{
g_free(channel_item);
}
}
return 0;
}

View File

@ -56,8 +56,6 @@ xrdp_chansrv_SOURCES = \
clipboard_file.h \
devredir.c \
devredir.h \
drdynvc.c \
drdynvc.h \
fifo.c \
fifo.h \
irp.c \

File diff suppressed because it is too large Load Diff

View File

@ -24,46 +24,20 @@
#include "parse.h"
#include "log.h"
#define MAX_DVC_CHANNELS 32
struct chan_out_data
{
struct stream *s;
struct chan_out_data *next;
};
struct chan_item
{
int id;
int flags;
char name[16];
struct chan_out_data *head;
struct chan_out_data *tail;
};
/* data in struct trans::callback_data */
struct xrdp_api_data
{
int chan_id;
char header[64];
int flags;
/* for dynamic virtual channels */
struct trans *transp;
int dvc_chan_id;
int is_connected;
};
int
g_is_term(void);
int send_channel_data(int chan_id, char *data, int size);
int send_channel_data(int chan_id, const char *data, int size);
int send_rail_drawing_orders(char* data, int size);
int main_cleanup(void);
int add_timeout(int msoffset, void (*callback)(void* data), void* data);
int find_empty_slot_in_dvc_channels(void);
struct xrdp_api_data * struct_from_dvc_chan_id(tui32 dvc_chan_id);
int remove_struct_with_chan_id(tui32 dvc_chan_id);
#define LOG_LEVEL 5
@ -97,4 +71,25 @@ int remove_struct_with_chan_id(tui32 dvc_chan_id);
((GGET_UINT16(_ptr, (_offset) + 2)) << 16)
#endif
struct chansrv_drdynvc_procs
{
int (*open_response)(int chan_id, int creation_status);
int (*close_response)(int chan_id);
int (*data_first)(int chan_id, char *data, int bytes, int total_bytes);
int (*data)(int chan_id, char *data, int bytes);
};
int
chansrv_drdynvc_open(const char *name, int flags,
struct chansrv_drdynvc_procs *procs, int *chan_id);
int
chansrv_drdynvc_close(int chan_id);
int
chansrv_drdynvc_data_first(int chan_id, const char *data, int data_bytes,
int total_data_bytes);
int
chansrv_drdynvc_data(int chan_id, const char *data, int data_bytes);
int
chansrv_drdynvc_send_data(int chan_id, const char *data, int data_bytes);
#endif

View File

@ -1,531 +0,0 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "drdynvc.h"
extern int g_drdynvc_chan_id; /* in chansrv.c */
int g_drdynvc_inited = 0;
static int drdynvc_send_capability_request(uint16_t version);
static int drdynvc_process_capability_response(struct stream* s, unsigned char cmd);
static int drdynvc_process_open_channel_response(struct stream *s, unsigned char cmd);
static int drdynvc_process_close_channel_response(struct stream *s, unsigned char cmd);
static int drdynvc_process_data_first(struct stream* s, unsigned char cmd);
static int drdynvc_process_data(struct stream* s, unsigned char cmd);
static int drdynvc_insert_uint_124(struct stream *s, uint32_t val);
static int drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p);
/**
* bring up dynamic virtual channel
*
* @return 0 on success, -1 on response
******************************************************************************/
int
drdynvc_init(void)
{
/* bring up X11 */
xcommon_init();
/* let client know what version of DVC we support */
drdynvc_send_capability_request(2);
return 0;
}
/**
* let DVC Manager on client end know what version of protocol we support
* client will respond with version that it supports
*
* @return 0 on success, -1 on response
******************************************************************************/
static int
drdynvc_send_capability_request(uint16_t version)
{
struct stream *s;
int bytes_in_stream;
/* setup stream */
make_stream(s);
init_stream(s, MAX_PDU_SIZE);
out_uint8(s, 0x50); /* insert cmd */
out_uint8(s, 0x00); /* insert padding */
out_uint16_le(s, version); /* 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 */
/* send command to client */
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
free_stream(s);
return 0;
}
/**
* process capability response received from DVC manager at client end
*
* @param s stream containing client response
*
* @return 0 on success, -1 on failure
******************************************************************************/
static int
drdynvc_process_capability_response(struct stream *s, unsigned char cmd)
{
int cap_version;
/* skip padding */
in_uint8s(s, 1);
/* read client's version */
in_uint16_le(s, cap_version);
if ((cap_version != 2) && (cap_version != 3))
{
LOG(0, ("drdynvc_process_capability_response: incompatible DVC "
"version %d detected", cap_version));
return -1;
}
LOG(0, ("drdynvc_process_capability_response: DVC version %d selected",
cap_version));
g_drdynvc_inited = 1;
return 0;
}
/**
* create a new dynamic virtual channel
*
* @pram channel_id channel id number
* @pram channel_name name of channel
*
* @return 0 on success, -1 on failure
******************************************************************************/
int
drdynvc_send_open_channel_request(int chan_pri, unsigned int chan_id,
char *chan_name)
{
struct stream *s;
int bytes_in_stream;
int cbChId;
int name_length;
if ((chan_name == NULL) || (strlen(chan_name) == 0))
{
LOG(0, ("drdynvc_send_open_channel_request: bad channel name specified"));
return -1;
}
make_stream(s);
init_stream(s, MAX_PDU_SIZE);
name_length = strlen(chan_name);
/* dummy command for now */
out_uint8(s, 0);
/* insert channel id */
cbChId = drdynvc_insert_uint_124(s, chan_id);
/* insert channel name */
out_uint8a(s, chan_name, name_length + 1);
/* insert command */
s->data[0] = CMD_DVC_OPEN_CHANNEL | ((chan_pri << 2) & 0x0c) | cbChId;
/* send command */
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
free_stream(s);
return 0;
}
static int
drdynvc_process_open_channel_response(struct stream *s, unsigned char cmd)
{
struct xrdp_api_data *adp;
uint32_t chan_id;
int creation_status;
drdynvc_get_chan_id(s, cmd, &chan_id);
in_uint32_le(s, creation_status);
/* LK_TODO now do something using useful! */
if (creation_status < 0)
{
// TODO
}
else
{
/* get struct xrdp_api_data containing this channel id */
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
{
LOG(0, ("drdynvc_process_open_channel_response: error : "
"could not find xrdp_api_data containing chan_id %d", chan_id));
return -1;
}
adp->is_connected = 1;
}
return 0;
}
int
drdynvc_send_close_channel_request(unsigned int chan_id)
{
struct stream *s;
int bytes_in_stream;
int cbChId;
make_stream(s);
init_stream(s, MAX_PDU_SIZE);
/* insert dummy cmd for now */
out_uint8(s, 0);
/* insert channel id */
cbChId = drdynvc_insert_uint_124(s, chan_id);
/* insert command */
s->data[0] = CMD_DVC_CLOSE_CHANNEL | cbChId;
/* send command */
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
free_stream(s);
return 0;
}
static int
drdynvc_process_close_channel_response(struct stream *s, unsigned char cmd)
{
uint32_t chan_id;
drdynvc_get_chan_id(s, cmd, &chan_id);
/* LK_TODO now do something using useful! */
return 0;
}
/*
* send data to client
*
* @param chan_id the virtual channel to write to
* @param data data to write
* @param data_size number of bytes to write
*
* @return 0 on success, -1 on failure
******************************************************************************/
int drdynvc_write_data(uint32_t chan_id, char *data, int data_size)
{
struct stream *s;
char *saved_ptr;
int cbChId;
int Len;
int bytes_in_stream;
int frag_size;
if (data == NULL)
{
LOG(0, ("drdynvc_write_data: data is NULL\n"));
return -1;
}
if (data_size <= 0)
{
return 0;
}
make_stream(s);
init_stream(s, MAX_PDU_SIZE);
/* this is a dummy write */
out_uint8(s, 0);
/* insert channel id */
cbChId = drdynvc_insert_uint_124(s, chan_id);
/* will data fit into one pkt? */
bytes_in_stream = stream_length_before_p(s);
if ((bytes_in_stream + data_size) <= MAX_PDU_SIZE)
{
/* yes it will - insert data */
out_uint8p(s, data, data_size);
/* insert command */
s->data[0] = CMD_DVC_DATA | cbChId;
/* write data to client */
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
free_stream(s);
return 0;
}
/* no it won't - fragment it */
saved_ptr = s->p;
/* let client know how much data to expect */
Len = drdynvc_insert_uint_124(s, data_size);
/* insert data into first fragment */
frag_size = MAX_PDU_SIZE - stream_length_before_p(s);
out_uint8p(s, data, frag_size);
/* insert command */
s->data[0] = CMD_DVC_DATA_FIRST | Len << 2 | cbChId;
/* write first fragment to client */
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
data_size -= frag_size;
data += frag_size;
s->data[0] = CMD_DVC_DATA | cbChId;
s->p = saved_ptr;
/* now send rest of the data using CMD_DVC_DATA */
while (data_size > 0)
{
frag_size = MAX_PDU_SIZE - stream_length_before_p(s);
if (frag_size > data_size)
{
frag_size = data_size;
}
out_uint8p(s, data, frag_size);
bytes_in_stream = stream_length_before_p(s);
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
data_size -= frag_size;
data += frag_size;
s->p = saved_ptr;
}
free_stream(s);
return 0;
}
static int
drdynvc_process_data_first(struct stream *s, unsigned char cmd)
{
struct xrdp_api_data *adp;
struct stream *ls;
uint32_t chan_id;
int bytes_in_stream;
int Len;
drdynvc_get_chan_id(s, cmd, &chan_id);
Len = (cmd >> 2) & 0x03;
/* skip data_len */
if (Len == 0)
{
in_uint8s(s, 1);
}
else if (Len == 1)
{
in_uint8s(s, 2);
}
else
{
in_uint8s(s, 4);
}
bytes_in_stream = stream_length_after_p(s);
/* get struct xrdp_api_data containing this channel id */
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
{
LOG(0, ("drdynvc_process_data_first: error : "
"could not find xrdp_api_data containing chan_id %d", chan_id));
return -1;
}
ls = trans_get_out_s(adp->transp, MAX_PDU_SIZE);
out_uint8p(ls, s->p, bytes_in_stream);
s_mark_end(ls);
trans_force_write(adp->transp);
return 0;
}
static int
drdynvc_process_data(struct stream *s, unsigned char cmd)
{
struct xrdp_api_data *adp;
struct stream *ls;
uint32_t chan_id;
int bytes_in_stream;
drdynvc_get_chan_id(s, cmd, &chan_id);
bytes_in_stream = stream_length_after_p(s);
/* get struct xrdp_api_data containing this channel id */
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
{
LOG(0, ("drdynvc_process_data: error : "
"could not find xrdp_api_data containing chan_id %d", chan_id));
return -1;
}
ls = trans_get_out_s(adp->transp, MAX_PDU_SIZE);
out_uint8p(ls, s->p, bytes_in_stream);
s_mark_end(ls);
trans_force_write(adp->transp);
return 0;
}
/**
* process incoming data on a dynamic virtual channel
*
* @pram s stream containing the incoming data
* @pram chan_id LK_TODO
* @pram chan_flags LK_TODO
* @pram length LK_TODO
* @pram total_length LK_TODO
*
* @return 0 on success, -1 on failure
******************************************************************************/
int
drdynvc_data_in(struct stream *s, int chan_id, int chan_flags, int length,
int total_length)
{
unsigned char cmd;
in_uint8(s, cmd); /* read command */
switch (cmd & 0xf0)
{
case CMD_DVC_CAPABILITY:
drdynvc_process_capability_response(s, cmd);
break;
case CMD_DVC_OPEN_CHANNEL:
drdynvc_process_open_channel_response(s, cmd);
break;
case CMD_DVC_CLOSE_CHANNEL:
drdynvc_process_close_channel_response(s, cmd);
break;
case CMD_DVC_DATA_FIRST:
drdynvc_process_data_first(s, cmd);
break;
case CMD_DVC_DATA:
drdynvc_process_data(s, cmd);
break;
default:
LOG(0, ("drdynvc_data_in: got unknown command 0x%x", cmd));
break;
}
return 0;
}
/*
* insert a byte, short or 32bit value into specified stream
*
* @param s stream used for insertion
* @param val value to insert
*
* @return 0 for byte insertions
* @return 1 for short insertion
* @return 2 for uint32_t insertions
******************************************************************************/
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;
}
/*
* extract channel id from stream
*
* @param s stream containing channel id
* @param cmd first byte in stream
* @param chan_id return channel id here
******************************************************************************/
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)
{
in_uint8(s, chan_id);
}
else if (cbChId == 1)
{
in_uint16_le(s, chan_id);
}
else
{
in_uint32_le(s, chan_id);
}
*chan_id_p = chan_id;
return 0;
}

View File

@ -1,67 +0,0 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DRDYNVC_H_
#define _DRDYNVC_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "arch.h"
#include "chansrv.h"
#include "xcommon.h"
#include "log.h"
#include "os_calls.h"
#include "trans.h"
/* move this to tsmf.c */
#define TSMF_CHAN_ID 0x1000
/* get number of bytes in stream before s->p */
#define stream_length_before_p(s) (int) ((s)->p - (s)->data)
/* get number of bytes in stream after s->p */
#define stream_length_after_p(s) (int) ((s)->end - (s)->p)
#define rewind_stream(s) do \
{ \
(s)->p = (s)->data; \
(s)->end = (s)->data; \
} while (0)
/* max number of bytes we can send in one pkt */
#define MAX_PDU_SIZE 1600
/* commands used to manage dynamic virtual channels */
#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
int drdynvc_init(void);
int drdynvc_send_open_channel_request(int chan_pri, unsigned int chan_id,
char *chan_name);
int drdynvc_send_close_channel_request(unsigned int chan_id);
int drdynvc_write_data(uint32_t chan_id, char *data, int data_size);
int drdynvc_data_in(struct stream* s, int chan_id, int chan_flags,
int length, int total_length);
#endif

View File

@ -138,6 +138,8 @@ int
callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
intptr_t param3, intptr_t param4);
int
xrdp_wm_drdynvc_up(intptr_t id);
int
xrdp_wm_delete_all_children(struct xrdp_wm* self);
int
xrdp_wm_show_log(struct xrdp_wm *self);
@ -367,6 +369,8 @@ xrdp_bitmap_compress(char* in_data, int width, int height,
int e);
/* xrdp_mm.c */
int
xrdp_mm_drdynvc_up(struct xrdp_mm* self);
struct xrdp_mm*
xrdp_mm_create(struct xrdp_wm* owner);
void

View File

@ -679,71 +679,28 @@ xrdp_mm_trans_send_channel_setup(struct xrdp_mm *self, struct trans *trans)
return trans_force_write(trans);
}
/*****************************************************************************/
/* returns error */
static int
xrdp_mm_trans_send_channel_data_response(struct xrdp_mm *self,
struct trans *trans)
{
struct stream *s;
s = trans_get_out_s(trans, 8192);
if (s == 0)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8); /* size */
out_uint32_le(s, 7); /* msg id */
out_uint32_le(s, 8); /* size */
s_mark_end(s);
return trans_force_write(trans);
}
/*****************************************************************************/
/* returns error
init is done, sent channel setup */
static int
xrdp_mm_trans_process_init_response(struct xrdp_mm *self, struct trans *trans)
{
return xrdp_mm_trans_send_channel_setup(self, trans);
}
/*****************************************************************************/
/* returns error
data coming in from the channel handler, send it to the client */
static int
xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct trans *trans)
xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct stream *s)
{
struct stream *s;
int size;
int total_size;
int chan_id;
int chan_flags;
int rv;
s = trans_get_in_s(trans);
if (s == 0)
{
return 1;
}
in_uint16_le(s, chan_id);
in_uint16_le(s, chan_flags);
in_uint16_le(s, size);
in_uint32_le(s, total_size);
rv = xrdp_mm_trans_send_channel_data_response(self, trans);
rv = 0;
if (rv == 0)
{
if (is_channel_allowed(self->wm, chan_id))
{
rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size,
chan_flags);
}
rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size,
chan_flags);
}
return rv;
@ -970,12 +927,11 @@ xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s)
{
int size;
int flags;
int rv = 0;
int rv;
int window_id;
struct rail_window_state_order rwso;
g_writeln("xrdp_mm_process_rail_update_window_text:");
in_uint32_le(s, window_id);
in_uint32_le(s, flags);
g_writeln(" update window title info: 0x%8.8x", window_id);
@ -1006,17 +962,12 @@ xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s)
/* returns error
process alternate secondary drawing orders for rail channel */
static int
xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans)
xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct stream *s)
{
struct stream* s;
int order_type;
int rv = 0;
int rv;
s = trans_get_in_s(trans);
if (s == 0)
{
return 1;
}
rv = 0;
in_uint32_le(s, order_type);
switch(order_type)
@ -1040,6 +991,302 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans)
return rv;
}
/******************************************************************************/
int
xrdp_mm_drdynvc_up(struct xrdp_mm* self)
{
LLOGLN(0, ("xrdp_mm_drdynvc_up:"));
return 0;
}
/*****************************************************************************/
/* open response from client going to channel server */
static int
xrdp_mm_drdynvc_open_response(intptr_t id, int chan_id, int creation_status)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
LLOGLN(10, ("xrdp_mm_drdynvc_open_response: chan_id %d creation_status %d",
chan_id, creation_status));
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 24); /* size */
out_uint32_le(s, 13); /* msg id */
out_uint32_le(s, 16); /* size */
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, creation_status); /* status */
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* close response from client going to channel server */
static int
xrdp_mm_drdynvc_close_response(intptr_t id, int chan_id)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 20); /* size */
out_uint32_le(s, 15); /* msg id */
out_uint32_le(s, 12); /* size */
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* part data from client going to channel server */
static int
xrdp_mm_drdynvc_data_first(intptr_t id, int chan_id, char *data,
int bytes, int total_bytes)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8 + 4 + 4 + 4 + bytes);
out_uint32_le(s, 17); /* msg id */
out_uint32_le(s, 8 + 4 + 4 + 4 + bytes);
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, bytes);
out_uint32_le(s, total_bytes);
out_uint8a(s, data, bytes);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* data from client going to channel server */
static int
xrdp_mm_drdynvc_data(intptr_t id, int chan_id, char *data, int bytes)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8 + 4 + 4 + bytes);
out_uint32_le(s, 19); /* msg id */
out_uint32_le(s, 8 + 4 + 4 + bytes);
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, bytes);
out_uint8a(s, data, bytes);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* open message from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_channel_open(struct xrdp_mm* self,
struct stream *s)
{
int name_bytes;
int flags;
int error;
int chan_id;
int chansrv_chan_id;
char *name;
struct xrdp_drdynvc_procs procs;
if (!s_check_rem(s, 2))
{
return 1;
}
in_uint32_le(s, name_bytes);
if ((name_bytes < 1) || (name_bytes > 1024))
{
return 1;
}
name = g_new(char, name_bytes + 1);
if (name == NULL)
{
return 1;
}
if (!s_check_rem(s, name_bytes))
{
g_free(name);
return 1;
}
in_uint8a(s, name, name_bytes);
name[name_bytes] = 0;
if (!s_check_rem(s, 8))
{
g_free(name);
return 1;
}
in_uint32_le(s, flags);
in_uint32_le(s, chansrv_chan_id);
if (flags == 0)
{
/* open static channel, not supported */
g_free(name);
return 1;
}
else
{
/* dynamic channel */
g_memset(&procs, 0, sizeof(procs));
procs.open_response = xrdp_mm_drdynvc_open_response;
procs.close_response = xrdp_mm_drdynvc_close_response;
procs.data_first = xrdp_mm_drdynvc_data_first;
procs.data = xrdp_mm_drdynvc_data;
chan_id = 0;
error = libxrdp_drdynvc_open(self->wm->session, name, flags, &procs,
&chan_id);
if (error != 0)
{
g_free(name);
return 1;
}
self->xr2cr_cid_map[chan_id] = chansrv_chan_id;
self->cs2xr_cid_map[chansrv_chan_id] = chan_id;
}
g_free(name);
return 0;
}
/*****************************************************************************/
/* close message from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_channel_close(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
if (!s_check_rem(s, 4))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
/* close dynamic channel */
error = libxrdp_drdynvc_close(self->wm->session, chan_id);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* data from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_data_first(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
int data_bytes;
int total_bytes;
char *data;
if (!s_check_rem(s, 12))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
in_uint32_le(s, data_bytes);
in_uint32_le(s, total_bytes);
if ((!s_check_rem(s, data_bytes)))
{
return 1;
}
in_uint8p(s, data, data_bytes);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
error = libxrdp_drdynvc_data_first(self->wm->session, chan_id, data,
data_bytes, total_bytes);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* data from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_data(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
int data_bytes;
char *data;
if (!s_check_rem(s, 8))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
in_uint32_le(s, data_bytes);
if ((!s_check_rem(s, data_bytes)))
{
return 1;
}
in_uint8p(s, data, data_bytes);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
error = libxrdp_drdynvc_data(self->wm->session, chan_id, data, data_bytes);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* returns error
process a message for the channel handler */
@ -1051,6 +1298,7 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans,
int id;
int size;
char *next_msg;
char *s_end;
rv = 0;
@ -1059,31 +1307,47 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans,
next_msg = s->p;
in_uint32_le(s, id);
in_uint32_le(s, size);
if (size < 8)
{
return 1;
}
if (!s_check_rem(s, size - 8))
{
return 1;
}
next_msg += size;
s_end = s->end;
s->end = next_msg;
LLOGLN(10, ("xrdp_mm_chan_process_msg: got msg id %d", id));
switch (id)
{
case 2: /* channel init response */
rv = xrdp_mm_trans_process_init_response(self, trans);
break;
case 4: /* channel setup response */
break;
case 6: /* channel data response */
break;
case 8: /* channel data */
rv = xrdp_mm_trans_process_channel_data(self, trans);
rv = xrdp_mm_trans_process_channel_data(self, s);
break;
case 10: /* rail alternate secondary drawing orders */
rv = xrdp_mm_process_rail_drawing_orders(self, trans);
rv = xrdp_mm_process_rail_drawing_orders(self, s);
break;
case 12:
rv = xrdp_mm_trans_process_drdynvc_channel_open(self, s);
break;
case 14:
rv = xrdp_mm_trans_process_drdynvc_channel_close(self, s);
break;
case 16:
rv = xrdp_mm_trans_process_drdynvc_data_first(self, s);
break;
case 18:
rv = xrdp_mm_trans_process_drdynvc_data(self, s);
break;
default:
log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id);
break;
}
s->end = s_end;
if (rv != 0)
{
break;
LLOGLN(0, ("xrdp_mm_chan_process_msg: error rv %d id %d", rv, id));
rv = 0;
}
s->p = next_msg;
@ -1116,40 +1380,28 @@ xrdp_mm_chan_data_in(struct trans *trans)
return 1;
}
in_uint8s(s, 4); /* id */
in_uint32_le(s, size);
error = trans_force_read(trans, size - 8);
if (error == 0)
if (trans->extra_flags == 0)
{
/* here, the entire message block is read in, process it */
error = xrdp_mm_chan_process_msg(self, trans, s);
in_uint8s(s, 4); /* id */
in_uint32_le(s, size);
LLOGLN(10, ("xrdp_mm_chan_data_in: got header, size %d", size));
if (size > 8)
{
self->chan_trans->header_size = size;
trans->extra_flags = 1;
return 0;
}
}
/* here, the entire message block is read in, process it */
error = xrdp_mm_chan_process_msg(self, trans, s);
self->chan_trans->header_size = 8;
trans->extra_flags = 0;
init_stream(s, 0);
LLOGLN(10, ("xrdp_mm_chan_data_in: got whole message, reset for "
"next header"));
return error;
}
/*****************************************************************************/
static int
xrdp_mm_chan_send_init(struct xrdp_mm *self)
{
struct stream *s;
s = trans_get_out_s(self->chan_trans, 8192);
if (s == 0)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8); /* size */
out_uint32_le(s, 1); /* msg id */
out_uint32_le(s, 8); /* size */
s_mark_end(s);
return trans_force_write(self->chan_trans);
}
/*****************************************************************************/
/* connect to chansrv */
static int
@ -1177,6 +1429,8 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
self->chan_trans->trans_data_in = xrdp_mm_chan_data_in;
self->chan_trans->header_size = 8;
self->chan_trans->callback_data = self;
self->chan_trans->no_stream_init_on_data_in = 1;
self->chan_trans->extra_flags = 0;
/* try to connect up to 4 times */
for (index = 0; index < 4; index++)
@ -1200,10 +1454,10 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
if (self->chan_trans_up)
{
if (xrdp_mm_chan_send_init(self) != 0)
if (xrdp_mm_trans_send_channel_setup(self, self->chan_trans) != 0)
{
log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in "
"xrdp_mm_chan_send_init");
"xrdp_mm_trans_send_channel_setup");
}
else
{
@ -1227,6 +1481,47 @@ static void cleanup_sesman_connection(struct xrdp_mm *self)
}
}
/*****************************************************************************/
/* does the section in xrdp.ini has any channel.*=true | false */
static int
xrdp_mm_update_allowed_channels(struct xrdp_mm *self)
{
int index;
int count;
int chan_id;
int disabled;
const char *name;
const char *value;
const char *chan_name;
struct xrdp_session *session;
session = self->wm->session;
count = self->login_names->count;
for (index = 0; index < count; index++)
{
name = (const char *) list_get_item(self->login_names, index);
if (g_strncasecmp(name, "channel.", 8) == 0)
{
value = (const char *) list_get_item(self->login_values, index);
chan_name = name + 8;
chan_id = libxrdp_get_channel_id(session, chan_name);
disabled = !g_text2bool(value);
libxrdp_disable_channel(session, chan_id, disabled);
if (disabled)
{
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
"channel id %d is disabled", chan_name, chan_id);
}
else
{
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
"channel id %d is allowed", chan_name, chan_id);
}
}
}
return 0;
}
/*****************************************************************************/
static int
xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
@ -1271,7 +1566,7 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
{
g_snprintf(port, 255, "%d", 7200 + display);
}
xrdp_mm_update_allowed_channels(self);
xrdp_mm_connect_chansrv(self, ip, port);
}
}
@ -2068,7 +2363,8 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self,
if ((self->chan_trans != 0) && self->chan_trans_up)
{
trans_get_wait_objs(self->chan_trans, read_objs, rcount);
trans_get_wait_objs_rw(self->chan_trans, read_objs, rcount,
write_objs, wcount, timeout);
}
if (self->mod != 0)
@ -2975,220 +3271,6 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
return 0;
}
/* read the channel section of the ini file into lists
* return 1 on success 0 on failure */
int read_allowed_channel_names(struct list *names, struct list *values)
{
int fd;
int ret = 0;
char cfg_file[256];
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
fd = g_file_open(cfg_file);
if (fd != -1)
{
names->auto_free = 1;
values->auto_free = 1;
/* all values in this section can be valid channel names */
if (file_read_section(fd, "channels", names, values) == 0)
{
ret = 1;
}
else
{
log_message(LOG_LEVEL_ERROR,"Failure reading channel section of configuration");
}
g_file_close(fd);
}
return ret;
}
/* internal function return -1 if name is not in list
* otherwise return the index 0->count-1*/
int
find_name_in_lists(char *inName, struct list *names)
{
int reply = -1; /*means not in the list*/
int index;
char *name;
for (index = 0; index < names->count; index++)
{
name = (char *)list_get_item(names, index);
if ( (name != 0) && (g_strncasecmp(name, inName, MAX_CHANNEL_NAME) == 0) )
{
reply = index;
break; /* stop loop - item found*/
}
}
return reply;
}
#define CHANNEL_NAME_PREFIX "channel."
/* update the channel lists from connection specific overrides
* return 1 on success 0 on failure */
int update_allowed_channel_names(struct xrdp_wm *wm, struct list *names, struct list *values)
{
int ret = 1;
int index;
int oldindex;
char *val;
char *name;
//wm->mm->login_names,wm->mm->login_values
for (index = 0; index < wm->mm->login_names->count; index++)
{
name = (char *)list_get_item(wm->mm->login_names, index);
if ( (name != 0) && (g_strncmp( name, CHANNEL_NAME_PREFIX, g_strlen(CHANNEL_NAME_PREFIX)) == 0 ) )
{
name += g_strlen(CHANNEL_NAME_PREFIX);
// locate and remove from list
oldindex = find_name_in_lists(name, names);
if (oldindex >= 0)
{
list_remove_item(names, oldindex);
list_remove_item(values, oldindex);
}
val = (char *)list_get_item(wm->mm->login_values, index);
// (re)add to lists
list_add_item(names, (tbus)g_strdup(name));
list_add_item(values, (tbus)g_strdup(val));
}
}
return ret;
}
/* internal function return 1 if name is in list of channels
* and if the value is allowed */
int
is_channel_enabled(char *inName, struct list *names, struct list *values)
{
int reply = 0; /*means not in the list*/
int index;
char *val;
index = find_name_in_lists(inName, names);
if ( index >= 0 )
{
val = (char *)list_get_item(values, index);
reply = g_text2bool(val);
if (reply == 0)
{
log_message(LOG_LEVEL_INFO,"This channel is disabled: %s", inName);
}
}
else
{
log_message(LOG_LEVEL_INFO,"This channel is disabled (not in List): %s", inName);
}
return reply;
}
/* internal function only used once per session
* creates the list of allowed channels and store the information
* in wm struct */
void init_channel_allowed(struct xrdp_wm *wm)
{
int error;
int i;
char channelname[MAX_CHANNEL_NAME];
int index = 0;
int allowindex = 0;
struct list *names;
struct list *values;
/* first reset allowedchannels */
for (i = 0; i < MAX_NR_CHANNELS; i++)
{
/* 0 is a valid channel so we use -1 to mark the index as unused */
wm->allowedchannels[i] = -1;
}
names = list_create();
values = list_create();
/* You can override the list of allowed channels individually for each
* session type. */
if ( read_allowed_channel_names(names, values)
&& update_allowed_channel_names(wm, names, values) )
{
do
{
/* libxrdp_query_channel return 1 on error*/
error = libxrdp_query_channel(wm->session, index, channelname, NULL);
if (error == 0)
{
/* examples of channel names: rdpdr ; rdpsnd ; drdynvc ; cliprdr */
if (is_channel_enabled(channelname, names, values))
{
log_message(LOG_LEVEL_INFO,"The following channel is allowed: %s (%d)", channelname, index);
wm->allowedchannels[allowindex] = index;
allowindex++;
if (allowindex >= MAX_NR_CHANNELS)
{
log_message(LOG_LEVEL_ALWAYS,"Programming error in is_channel_allowed");
error = 1; /* end loop */
}
}
else
{
log_message(LOG_LEVEL_INFO,"The following channel is not allowed: %s (%d)", channelname, index);
}
index++;
}
}
while ((error == 0) && (index < MAX_NR_CHANNELS));
}
else
{
log_message(LOG_LEVEL_ERROR,"Error reading channel section in inifile");
}
list_delete(names);
list_delete(values);
}
/*****************************************************************************/
/* This function returns 1 if the channelID is allowed by rule set
* returns 0 if not allowed */
int is_channel_allowed(struct xrdp_wm *wm, int channel_id)
{
int i;
int reply = 0; /* not allowed */
/* The first time each client is using this function we have to
* define the list of allowed channels */
if (wm->allowedinitialized == 0)
{
init_channel_allowed(wm);
log_message(LOG_LEVEL_DEBUG,"The allow channel list now initialized for this session");
wm->allowedinitialized = 1;
}
for (i = 0; i < MAX_NR_CHANNELS; i++)
{
if (channel_id == wm->allowedchannels[i])
{
/*g_writeln("Channel allowed: %d",channel_id);*/
reply = 1; /*channel allowed*/
break;
}
else if (wm->allowedchannels[i] == -1)
{
/* We are in the unused space of the allowedchannels list
* We can end the loop */
break;
}
}
return reply;
}
/*****************************************************************************/
/*return 0 if the index is not found*/
int
@ -3235,25 +3317,18 @@ server_send_to_channel(struct xrdp_mod *mod, int channel_id,
wm = (struct xrdp_wm *)(mod->wm);
if (is_channel_allowed(wm, channel_id))
if (wm->mm->usechansrv)
{
if (wm->mm->usechansrv)
{
/*
* Xvnc backend reaches here
* should not return 1 as this case is not an error
*/
return 0;
}
/*
* Xvnc backend reaches here
* should not return 1 as this case is not an error
*/
return 0;
}
/* vnc proxy mode reaches here */
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
total_data_len, flags);
}
else
{
return 1;
}
/* vnc proxy mode reaches here */
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
total_data_len, flags);
}
/*****************************************************************************/

View File

@ -295,6 +295,8 @@ struct xrdp_mm
int delete_chan_trans; /* boolean set when done with channel connection */
int usechansrv; /* true if chansrvport is set in xrdp.ini or using sesman */
struct xrdp_encoder *encoder;
int cs2xr_cid_map[256];
int xr2cr_cid_map[256];
};
struct xrdp_key_info
@ -376,8 +378,6 @@ struct xrdp_wm
struct xrdp_bitmap* target_surface; /* either screen or os surface */
int current_surface_index;
int hints;
int allowedchannels[MAX_NR_CHANNELS];
int allowedinitialized ;
char pamerrortxt[256];
/* configuration derived from xrdp.ini */

View File

@ -27,6 +27,18 @@
#include "xrdp.h"
#include "log.h"
#define LLOG_LEVEL 1
#define LLOGLN(_level, _args) \
do \
{ \
if (_level < LLOG_LEVEL) \
{ \
g_write("xrdp:xrdp_wm [%10.10u]: ", g_time3()); \
g_writeln _args ; \
} \
} \
while (0)
/*****************************************************************************/
struct xrdp_wm *
xrdp_wm_create(struct xrdp_process *owner,
@ -563,6 +575,69 @@ xrdp_wm_init(struct xrdp_wm *self)
load_xrdp_config(self->xrdp_config, self->screen->bpp);
/* global channels allow */
names = list_create();
names->auto_free = 1;
values = list_create();
values->auto_free = 1;
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
if (file_by_name_read_section(cfg_file, "Channels", names, values) == 0)
{
int error;
int ii;
int chan_id;
int chan_flags;
int disabled;
char chan_name[16];
ii = 0;
error = libxrdp_query_channel(self->session, ii, chan_name,
&chan_flags);
while (error == 0)
{
r = NULL;
for (index = 0; index < names->count; index++)
{
q = (char *) list_get_item(names, index);
if (g_strcasecmp(q, chan_name) == 0)
{
r = (char *) list_get_item(values, index);
break;
}
}
if (r == NULL)
{
/* not found, disable the channel */
chan_id = libxrdp_get_channel_id(self->session, chan_name);
libxrdp_disable_channel(self->session, chan_id, 1);
g_writeln("xrdp_wm_init: channel %s channel id %d is "
"disabled", chan_name, chan_id);
}
else
{
/* found */
chan_id = libxrdp_get_channel_id(self->session, q);
disabled = !g_text2bool(r);
libxrdp_disable_channel(self->session, chan_id, disabled);
if (disabled)
{
g_writeln("xrdp_wm_init: channel %s channel id %d is "
"disabled", chan_name, chan_id);
}
else
{
g_writeln("xrdp_wm_init: channel %s channel id %d is "
"allowed", chan_name, chan_id);
}
}
ii++;
error = libxrdp_query_channel(self->session, ii, chan_name,
&chan_flags);
}
}
list_delete(names);
list_delete(values);
xrdp_wm_load_static_colors_plus(self, autorun_name);
xrdp_wm_load_static_pointers(self);
self->screen->bg_color = self->xrdp_config->cfg_globals.ls_top_window_bg_color;
@ -1758,27 +1833,21 @@ xrdp_wm_process_channel_data(struct xrdp_wm *self,
tbus param3, tbus param4)
{
int rv;
int chanid ;
rv = 1;
if (self->mm->mod != 0)
{
chanid = LOWORD(param1);
if (is_channel_allowed(self, chanid))
if (self->mm->usechansrv)
{
if (self->mm->usechansrv)
rv = xrdp_mm_process_channel_data(self->mm, param1, param2,
param3, param4);
}
else
{
if (self->mm->mod->mod_event != 0)
{
rv = xrdp_mm_process_channel_data(self->mm, param1, param2,
param3, param4);
}
else
{
if (self->mm->mod->mod_event != 0)
{
rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2,
param3, param4);
}
rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2,
param3, param4);
}
}
}
@ -1844,6 +1913,9 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
//g_writeln("callback: frame ack %d", param1);
xrdp_mm_frame_ack(wm->mm, param1);
break;
case 0x5558:
xrdp_mm_drdynvc_up(wm->mm);
break;
}
return rv;
}

View File

@ -44,24 +44,21 @@
struct wts_obj
{
int fd;
int status;
char name[9];
char dname[128];
int display_num;
uint32_t flags;
int fd;
int display_num;
};
/* helper functions used by WTSxxx API - do not invoke directly */
static int get_display_num_from_display(char *display_text);
static int send_init(struct wts_obj *wts);
static int can_send(int sck, int millis);
static int can_recv(int sck, int millis);
static const unsigned char g_xrdpapi_magic[12] =
{
0x78, 0x32, 0x10, 0x67, 0x00, 0x92, 0x30, 0x56, 0xff, 0xd8, 0xa9, 0x1f
};
static int
get_display_num_from_display(char *display_text);
static int
can_send(int sck, int millis);
static int
can_recv(int sck, int millis);
static int
mysend(int sck, const void* adata, int bytes);
static int
myrecv(int sck, void* adata, int bytes);
/*
* Opens a handle to the server end of a specified virtual channel - this
@ -100,22 +97,27 @@ void *
WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
unsigned int flags)
{
struct wts_obj *wts;
char *display_text;
int bytes;
unsigned long llong;
struct sockaddr_un s;
struct wts_obj *wts;
char *display_text;
int bytes;
unsigned long long1;
struct sockaddr_un s;
char *connect_data;
int chan_name_bytes;
int lerrno;
if (SessionId != WTS_CURRENT_SESSION)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
return 0;
}
wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
if (wts == NULL)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: calloc failed"));
return 0;
}
wts->fd = -1;
wts->flags = flags;
display_text = getenv("DISPLAY");
if (display_text != 0)
@ -133,16 +135,17 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
/* we use unix domain socket to communicate with chansrv */
if ((wts->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: socket failed"));
free(wts);
return NULL;
}
/* set non blocking */
llong = fcntl(wts->fd, F_GETFL);
llong = llong | O_NONBLOCK;
if (fcntl(wts->fd, F_SETFL, llong) < 0)
long1 = fcntl(wts->fd, F_GETFL);
long1 = long1 | O_NONBLOCK;
if (fcntl(wts->fd, F_SETFL, long1) < 0)
{
LLOGLN(10, ("WTSVirtualChannelOpenEx: set non-block mode failed"));
LLOGLN(0, ("WTSVirtualChannelOpenEx: set non-block mode failed"));
}
/* connect to chansrv session */
@ -153,17 +156,93 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
s.sun_path[bytes - 1] = 0;
bytes = sizeof(struct sockaddr_un);
if (connect(wts->fd, (struct sockaddr *) &s, bytes) == 0)
if (connect(wts->fd, (struct sockaddr *) &s, bytes) < 0)
{
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
strncpy(wts->name, pVirtualName, 8);
/* wait for connection to complete and send init */
if (send_init(wts) == 0)
lerrno = errno;
if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) ||
(lerrno == EINPROGRESS))
{
/* all ok */
wts->status = 1;
/* ok */
}
else
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: connect failed"));
free(wts);
return NULL;
}
}
/* wait for connection to complete */
if (!can_send(wts->fd, 500))
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: can_send failed"));
free(wts);
return NULL;
}
chan_name_bytes = strlen(pVirtualName);
bytes = 4 + 4 + 4 + chan_name_bytes + 4;
LLOGLN(10, ("WTSVirtualChannelOpenEx: chan_name_bytes %d bytes %d pVirtualName %s", chan_name_bytes, bytes, pVirtualName));
connect_data = (char *) calloc(bytes, 1);
if (connect_data == NULL)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: calloc failed"));
free(wts);
return NULL;
}
connect_data[0] = (bytes >> 0) & 0xFF;
connect_data[1] = (bytes >> 8) & 0xFF;
connect_data[2] = (bytes >> 16) & 0xFF;
connect_data[3] = (bytes >> 24) & 0xFF;
/* version here(4-7), just leave 0 */
connect_data[8] = (chan_name_bytes >> 0) & 0xFF;
connect_data[9] = (chan_name_bytes >> 8) & 0xFF;
connect_data[10] = (chan_name_bytes >> 16) & 0xFF;
connect_data[11] = (chan_name_bytes >> 24) & 0xFF;
memcpy(connect_data + 12, pVirtualName, chan_name_bytes);
connect_data[4 + 4 + 4 + chan_name_bytes + 0] = (flags >> 0) & 0xFF;
connect_data[4 + 4 + 4 + chan_name_bytes + 1] = (flags >> 8) & 0xFF;
connect_data[4 + 4 + 4 + chan_name_bytes + 2] = (flags >> 16) & 0xFF;
connect_data[4 + 4 + 4 + chan_name_bytes + 3] = (flags >> 24) & 0xFF;
LLOGLN(10, ("WTSVirtualChannelOpenEx: calling mysend with %d bytes", bytes));
if (mysend(wts->fd, connect_data, bytes) != bytes)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: mysend failed"));
free(wts);
return NULL;
}
LLOGLN(10, ("WTSVirtualChannelOpenEx: sent ok"));
if (!can_recv(wts->fd, 500))
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: can_recv failed"));
free(wts);
return NULL;
}
/* get response */
if (myrecv(wts->fd, connect_data, 4) != 4)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: myrecv failed"));
free(wts);
return NULL;
}
if ((connect_data[0] != 0) || (connect_data[1] != 0) ||
(connect_data[2] != 0) || (connect_data[3] != 0))
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: connect_data not ok"));
free(wts);
return NULL;
}
return wts;
@ -179,18 +258,18 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
/*****************************************************************************/
static int
mysend(int sck, const void* adata, int bytes)
mysend(int sck, const void *adata, int bytes)
{
int sent;
int error;
const char* data;
const char *data;
#if defined(SO_NOSIGPIPE)
const int on = 1;
setsockopt(sck, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
#endif
data = (const char*)adata;
data = (const char *) adata;
sent = 0;
while (sent < bytes)
{
@ -207,6 +286,36 @@ mysend(int sck, const void* adata, int bytes)
return sent;
}
/*****************************************************************************/
static int
myrecv(int sck, void *adata, int bytes)
{
int recd;
int error;
char *data;
#if defined(SO_NOSIGPIPE)
const int on = 1;
setsockopt(sck, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
#endif
data = (char *) adata;
recd = 0;
while (recd < bytes)
{
if (can_recv(sck, 100))
{
error = recv(sck, data + recd, bytes - recd, MSG_NOSIGNAL);
if (error < 1)
{
return -1;
}
recd += error;
}
}
return recd;
}
/*
* write data to client connection
*
@ -217,8 +326,7 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
unsigned int Length, unsigned int *pBytesWritten)
{
struct wts_obj *wts;
int rv;
int header[4];
int rv;
wts = (struct wts_obj *) hChannelHandle;
@ -230,29 +338,12 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
return 0;
}
if (wts->status != 1)
{
LLOGLN(10, ("WTSVirtualChannelWrite: wts->status != 1"));
return 0;
}
if (!can_send(wts->fd, 0))
{
return 1; /* can't write now, ok to try again */
}
rv = 0;
memcpy(header, g_xrdpapi_magic, 12);
header[3] = Length;
if (mysend(wts->fd, header, 16) == 16)
{
rv = mysend(wts->fd, Buffer, Length);
}
else
{
LLOGLN(0, ("WTSVirtualChannelWrite: header write failed"));
return 0;
}
rv = mysend(wts->fd, Buffer, Length);
LLOGLN(10, ("WTSVirtualChannelWrite: mysend() returned %d", rv));
@ -263,14 +354,6 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
return 1;
}
#if 0 /* coverity: this is dead code */
/* error, but is it ok to try again? */
if ((rv == EWOULDBLOCK) || (rv == EAGAIN) || (rv == EINPROGRESS))
{
return 0; /* failed to send, but should try again */
}
#endif
/* fatal error */
return 0;
}
@ -296,11 +379,6 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
return 0;
}
if (wts->status != 1)
{
return 0;
}
if (can_recv(wts->fd, TimeOut))
{
rv = recv(wts->fd, Buffer, BufferSize, 0);
@ -341,7 +419,7 @@ WTSVirtualChannelClose(void *hChannelHandle)
wts = (struct wts_obj *)hChannelHandle;
if (wts == 0)
if (wts == NULL)
{
return 0;
}
@ -364,12 +442,7 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
wts = (struct wts_obj *)hChannelHandle;
if (wts == 0)
{
return 0;
}
if (wts->status != 1)
if (wts == NULL)
{
return 0;
}
@ -378,6 +451,10 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
{
*pBytesReturned = 4;
*ppBuffer = malloc(4);
if (*ppBuffer == NULL)
{
return 0;
}
memcpy(*ppBuffer, &(wts->fd), 4);
}
@ -388,7 +465,7 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
void
WTSFreeMemory(void *pMemory)
{
if (pMemory != 0)
if (pMemory != NULL)
{
free(pMemory);
}
@ -452,39 +529,6 @@ can_recv(int sck, int millis)
return 0;
}
/*****************************************************************************/
static int
send_init(struct wts_obj *wts)
{
char initmsg[64];
memset(initmsg, 0, 64);
/* insert channel name */
strncpy(initmsg, wts->name, 8);
/* insert open mode flags */
initmsg[16] = (wts->flags >> 0) & 0xff;
initmsg[17] = (wts->flags >> 8) & 0xff;
initmsg[18] = (wts->flags >> 16) & 0xff;
initmsg[19] = (wts->flags >> 24) & 0xff;
if (!can_send(wts->fd, 500))
{
LLOGLN(10, ("send_init: send() will block!"));
return 1;
}
if (send(wts->fd, initmsg, 64, 0) != 64)
{
LLOGLN(10, ("send_init: send() failed!"));
return 1;
}
LLOGLN(10, ("send_init: sent ok!"));
return 0;
}
/*****************************************************************************/
static int
get_display_num_from_display(char *display_text)
@ -513,7 +557,6 @@ get_display_num_from_display(char *display_text)
disp[disp_index] = display_text[index];
disp_index++;
}
index++;
}