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
master
jsorg71 6 years ago committed by GitHub
parent 6049cf8dad
commit ae1514c167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

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

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

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

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

@ -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);
if (g_strlen(channel_item->name) > 0)
{
channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
list_add_item(self->mcs_layer->channel_list, (tintptr) channel_item);
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;
}

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

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

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

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

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

@ -679,72 +679,29 @@ 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);
}
}
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);
case 8: /* channel data */
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, s);
break;
case 4: /* channel setup response */
case 12:
rv = xrdp_mm_trans_process_drdynvc_channel_open(self, s);
break;
case 6: /* channel data response */
case 14:
rv = xrdp_mm_trans_process_drdynvc_channel_close(self, s);
break;
case 8: /* channel data */
rv = xrdp_mm_trans_process_channel_data(self, trans);
case 16:
rv = xrdp_mm_trans_process_drdynvc_data_first(self, s);
break;
case 10: /* rail alternate secondary drawing orders */
rv = xrdp_mm_process_rail_drawing_orders(self, trans);
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;
}
if (trans->extra_flags == 0)
{
in_uint8s(s, 4); /* id */
in_uint32_le(s, size);
error = trans_force_read(trans, size - 8);
if (error == 0)
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,8 +3317,6 @@ 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)
{
/*
@ -3249,11 +3329,6 @@ server_send_to_channel(struct xrdp_mod *mod, int channel_id,
/* vnc proxy mode reaches here */
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
total_data_len, flags);
}
else
{
return 1;
}
}
/*****************************************************************************/

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

@ -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,14 +1833,9 @@ 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)
{
@ -1781,7 +1851,6 @@ xrdp_wm_process_channel_data(struct xrdp_wm *self,
}
}
}
}
return rv;
}
@ -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;
}

@ -45,23 +45,20 @@
struct wts_obj
{
int fd;
int status;
char name[9];
char dname[128];
int display_num;
uint32_t flags;
};
/* 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
@ -103,19 +100,24 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
struct wts_obj *wts;
char *display_text;
int bytes;
unsigned long llong;
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)
{
lerrno = errno;
if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) ||
(lerrno == EINPROGRESS))
{
/* 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(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
strncpy(wts->name, pVirtualName, 8);
LLOGLN(0, ("WTSVirtualChannelOpenEx: can_recv failed"));
free(wts);
return NULL;
}
/* wait for connection to complete and send init */
if (send_init(wts) == 0)
/* get response */
if (myrecv(wts->fd, connect_data, 4) != 4)
{
/* all ok */
wts->status = 1;
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
*
@ -218,7 +327,6 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
{
struct wts_obj *wts;
int rv;
int header[4];
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;
}
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++;
}

Loading…
Cancel
Save