Split up vnc.c into modules and re-implement clipboard functions

This commit is contained in:
matt335672
2021-05-27 15:35:52 +01:00
parent 3ea19ef0cd
commit fe28af93e8
7 changed files with 1309 additions and 336 deletions
+67 -334
View File
@@ -31,57 +31,14 @@
#endif
#include "vnc.h"
#include "vnc_clip.h"
#include "rfb.h"
#include "log.h"
#include "trans.h"
#include "ssl_calls.h"
#include "string_calls.h"
#include "xrdp_client_info.h"
/* Client-to-server messages */
enum c2s
{
C2S_SET_PIXEL_FORMAT = 0,
C2S_SET_ENCODINGS = 2,
C2S_FRAMEBUFFER_UPDATE_REQUEST = 3,
C2S_KEY_EVENT = 4,
C2S_POINTER_EVENT = 5,
C2S_CLIENT_CUT_TEXT = 6,
};
/* Server to client messages */
enum s2c
{
S2C_FRAMEBUFFER_UPDATE = 0,
S2C_SET_COLOUR_MAP_ENTRIES = 1,
S2C_BELL = 2,
S2C_SERVER_CUT_TEXT = 3
};
/* Encodings and pseudo-encodings
*
* The RFC uses a signed type for these. We use an unsigned type as the
* binary representation for the negative values is standardised in C
* (which it wouldn't be for an enum value)
*/
typedef uint32_t encoding_type;
#define ENC_RAW (encoding_type)0
#define ENC_COPY_RECT (encoding_type)1
#define ENC_CURSOR (encoding_type)-239
#define ENC_DESKTOP_SIZE (encoding_type)-223
#define ENC_EXTENDED_DESKTOP_SIZE (encoding_type)-308
/* Messages for ExtendedDesktopSize status code */
static const char *eds_status_msg[] =
{
/* 0 */ "No error",
/* 1 */ "Resize is administratively prohibited",
/* 2 */ "Out of resources",
/* 3 */ "Invalid screen layout",
/* others */ "Unknown code"
};
/* elements in above list */
#define EDS_STATUS_MSG_COUNT \
(sizeof(eds_status_msg) / sizeof(eds_status_msg[0]))
@@ -92,11 +49,8 @@ enum
MSK_EXTENDED_DESKTOP_SIZE = (1 << 0)
};
static int
lib_mod_process_message(struct vnc *v, struct stream *s);
/******************************************************************************/
static int
int
lib_send_copy(struct vnc *v, struct stream *s)
{
return trans_write_copy_s(v->trans, s);
@@ -152,160 +106,6 @@ rfbHashEncryptBytes(char *bytes, const char *passwd)
rfbEncryptBytes(bytes, passwd_hash_text);
}
/******************************************************************************/
static int
lib_process_channel_data(struct vnc *v, int chanid, int flags, int size,
struct stream *s, int total_size)
{
int type;
int status;
int length;
int clip_bytes;
int index;
int format;
struct stream *out_s;
if (chanid == v->clip_chanid)
{
in_uint16_le(s, type);
in_uint16_le(s, status);
in_uint32_le(s, length);
LOG(LOG_LEVEL_DEBUG, "clip data type %d status %d length %d", type, status, length);
LOG_DEVEL_HEXDUMP(LOG_LEVEL_TRACE, "clipboard data", s->p, s->end - s->p);
switch (type)
{
case 2: /* CLIPRDR_FORMAT_ANNOUNCE */
LOG(LOG_LEVEL_DEBUG, "CLIPRDR_FORMAT_ANNOUNCE - "
"status %d length %d", status, length);
make_stream(out_s);
init_stream(out_s, 8192);
out_uint16_le(out_s, 3); // msg-type: CLIPRDR_FORMAT_ACK
out_uint16_le(out_s, 1); // msg-status-code: CLIPRDR_RESPONSE
out_uint32_le(out_s, 0); // null (?)
out_uint8s(out_s, 4); // pad
s_mark_end(out_s);
length = (int)(out_s->end - out_s->data);
v->server_send_to_channel(v, v->clip_chanid, out_s->data,
length, length, 3);
free_stream(out_s);
#if 0
// Send the CLIPRDR_DATA_REQUEST message to the cliprdr channel.
//
make_stream(out_s);
init_stream(out_s, 8192);
out_uint16_le(out_s, 4); // msg-type: CLIPRDR_DATA_REQUEST
out_uint16_le(out_s, 0); // msg-status-code: CLIPRDR_REQUEST
out_uint32_le(out_s, 4); // sizeof supported-format-list.
out_uint32_le(out_s, 1); // supported-format-list: CF_TEXT
out_uint8s(out_s, 0); // pad (garbage pad?)
s_mark_end(out_s);
length = (int)(out_s->end - out_s->data);
v->server_send_to_channel(v, v->clip_chanid, out_s->data,
length, length, 3);
free_stream(out_s);
#endif
break;
case 3: /* CLIPRDR_FORMAT_ACK */
LOG(LOG_LEVEL_DEBUG, "CLIPRDR_FORMAT_ACK - "
"status %d length %d", status, length);
break;
case 4: /* CLIPRDR_DATA_REQUEST */
LOG(LOG_LEVEL_DEBUG, "CLIPRDR_DATA_REQUEST - "
"status %d length %d", status, length);
format = 0;
if (length >= 4)
{
in_uint32_le(s, format);
}
/* only support CF_TEXT and CF_UNICODETEXT */
if ((format != 1) && (format != 13))
{
break;
}
make_stream(out_s);
init_stream(out_s, 8192);
out_uint16_le(out_s, 5);
out_uint16_le(out_s, 1);
if (format == 13) /* CF_UNICODETEXT */
{
out_uint32_le(out_s, v->clip_data_s->size * 2 + 2);
for (index = 0; index < v->clip_data_s->size; index++)
{
out_uint8(out_s, v->clip_data_s->data[index]);
out_uint8(out_s, 0);
}
out_uint8s(out_s, 2);
}
else if (format == 1) /* CF_TEXT */
{
out_uint32_le(out_s, v->clip_data_s->size + 1);
for (index = 0; index < v->clip_data_s->size; index++)
{
out_uint8(out_s, v->clip_data_s->data[index]);
}
out_uint8s(out_s, 1);
}
out_uint8s(out_s, 4); /* pad */
s_mark_end(out_s);
length = (int)(out_s->end - out_s->data);
v->server_send_to_channel(v, v->clip_chanid, out_s->data, length,
length, 3);
free_stream(out_s);
break;
case 5: /* CLIPRDR_DATA_RESPONSE */
LOG(LOG_LEVEL_DEBUG, "CLIPRDR_DATA_RESPONSE - "
"status %d length %d", status, length);
clip_bytes = MIN(length, 256);
// - Read the response data from the cliprdr channel, stream 's'.
// - Send the response data to the vnc server, stream 'out_s'.
//
make_stream(out_s);
// Send the RFB message type (CLIENT_CUT_TEXT) to the vnc server.
init_stream(out_s, clip_bytes + 1 + 3 + 4 + 16);
out_uint8(out_s, C2S_CLIENT_CUT_TEXT);
out_uint8s(out_s, 3); // padding
// Send the length of the cut-text to the vnc server.
out_uint32_be(out_s, clip_bytes);
// Send the cut-text (as read from 's') to the vnc server.
for (index = 0; index < clip_bytes; index++)
{
char cur_char = '\0';
in_uint8(s, cur_char); // text in from 's'
out_uint8(out_s, cur_char); // text out to 'out_s'
}
s_mark_end(out_s);
lib_send_copy(v, out_s);
free_stream(out_s);
break;
default:
{
LOG(LOG_LEVEL_DEBUG, "VNC clip information unhandled");
break;
}
}
}
else
{
LOG(LOG_LEVEL_DEBUG, "lib_process_channel_data: unknown chanid: "
"%d :(v->clip_chanid) %d", chanid, v->clip_chanid);
}
return 0;
}
/**************************************************************************//**
* Logs a debug message containing a screen layout
*
@@ -695,11 +495,16 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
if ((size >= 0) && (size <= (32 * 1024)) && (data != 0))
{
init_stream(s, size);
out_uint8a(s, data, size);
s_mark_end(s);
s->p = s->data;
error = lib_process_channel_data(v, chanid, flags, size, s, total_size);
if (chanid == v->clip_chanid)
{
error = vnc_clip_process_channel_data(v, data, size,
total_size, flags);
}
else
{
LOG(LOG_LEVEL_DEBUG, "lib_process_channel_data: unknown chanid: "
"%d :(v->clip_chanid) %d", chanid, v->clip_chanid);
}
}
else
{
@@ -718,7 +523,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
{
/* fix for mstsc sending left control down with altgr */
init_stream(s, 8192);
out_uint8(s, C2S_KEY_EVENT);
out_uint8(s, RFB_C2S_KEY_EVENT);
out_uint8(s, 0); /* down flag */
out_uint8s(s, 2);
out_uint32_be(s, 65507); /* left control */
@@ -728,7 +533,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
}
init_stream(s, 8192);
out_uint8(s, C2S_KEY_EVENT);
out_uint8(s, RFB_C2S_KEY_EVENT);
out_uint8(s, msg == 15); /* down flag */
out_uint8s(s, 2);
out_uint32_be(s, key);
@@ -780,7 +585,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
}
init_stream(s, 8192);
out_uint8(s, C2S_POINTER_EVENT);
out_uint8(s, RFB_C2S_POINTER_EVENT);
out_uint8(s, v->mod_mouse_state);
out_uint16_be(s, param1);
out_uint16_be(s, param2);
@@ -792,7 +597,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
if (v->suppress_output == 0)
{
init_stream(s, 8192);
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 0); /* incremental == 0 : Full contents */
x = (param1 >> 16) & 0xffff;
out_uint16_be(s, x);
@@ -1018,15 +823,22 @@ get_bytes_per_pixel(int bpp)
* @param bytes Bytes to skip
* @return != 0 for error
*/
static int
skip_trans_bytes(struct trans *trans, int bytes)
int
skip_trans_bytes(struct trans *trans, unsigned int bytes)
{
struct stream *s;
int error;
int error = 0;
make_stream(s);
init_stream(s, bytes);
error = trans_force_read_s(trans, s, bytes);
while (error == 0 && bytes > 0)
{
int chunk_size = MIN(32768, bytes);
init_stream(s, chunk_size);
error = trans_force_read_s(trans, s, chunk_size);
bytes -= chunk_size;
}
free_stream(s);
return error;
@@ -1054,40 +866,40 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
switch (encoding)
{
case ENC_RAW:
case RFB_ENC_RAW:
{
int need_size = cx * cy * get_bytes_per_pixel(v->server_bpp);
LOG(LOG_LEVEL_DEBUG, "Skipping ENC_RAW encoding");
LOG(LOG_LEVEL_DEBUG, "Skipping RFB_ENC_RAW encoding");
error = skip_trans_bytes(v->trans, need_size);
}
break;
case ENC_COPY_RECT:
case RFB_ENC_COPY_RECT:
{
LOG(LOG_LEVEL_DEBUG, "Skipping ENC_COPY_RECT encoding");
LOG(LOG_LEVEL_DEBUG, "Skipping RFB_ENC_COPY_RECT encoding");
error = skip_trans_bytes(v->trans, 4);
}
break;
case ENC_CURSOR:
case RFB_ENC_CURSOR:
{
int j = cx * cy * get_bytes_per_pixel(v->server_bpp);
int k = ((cx + 7) / 8) * cy;
LOG(LOG_LEVEL_DEBUG, "Skipping ENC_CURSOR encoding");
LOG(LOG_LEVEL_DEBUG, "Skipping RFB_ENC_CURSOR encoding");
error = skip_trans_bytes(v->trans, j + k);
}
break;
case ENC_DESKTOP_SIZE:
LOG(LOG_LEVEL_DEBUG, "Skipping ENC_DESKTOP_SIZE encoding");
case RFB_ENC_DESKTOP_SIZE:
LOG(LOG_LEVEL_DEBUG, "Skipping RFB_ENC_DESKTOP_SIZE encoding");
break;
case ENC_EXTENDED_DESKTOP_SIZE:
case RFB_ENC_EXTENDED_DESKTOP_SIZE:
{
struct vnc_screen_layout layout = {0};
LOG(LOG_LEVEL_DEBUG,
"Skipping ENC_EXTENDED_DESKTOP_SIZE encoding "
"Skipping RFB_ENC_EXTENDED_DESKTOP_SIZE encoding "
"x=%d, y=%d geom=%dx%d",
x, y, cx, cy);
error = read_extended_desktop_size_rect(v, &layout);
@@ -1165,7 +977,7 @@ find_matching_extended_rect(struct vnc *v,
in_uint16_be(s, cy);
in_uint32_be(s, encoding);
if (encoding == ENC_EXTENDED_DESKTOP_SIZE &&
if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE &&
match_layout->s == NULL &&
match(x, y, cx, cy))
{
@@ -1230,7 +1042,7 @@ send_update_request_for_resize_status(struct vnc *v)
/*
* Ask for an immediate, minimal update.
*/
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 0); /* incremental == 0 : Full update */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
@@ -1244,7 +1056,7 @@ send_update_request_for_resize_status(struct vnc *v)
/*
* Ask for a deferred minimal update.
*/
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 1); /* incremental == 1 : Changes only */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
@@ -1260,7 +1072,7 @@ send_update_request_for_resize_status(struct vnc *v)
*/
if (v->suppress_output == 0)
{
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 0); /* incremental == 0 : Full update */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
@@ -1297,20 +1109,6 @@ rect_is_reply_to_us(int x, int y, int cx, int cy)
return (x == 1);
}
/**************************************************************************//**
* Returns an error string for an ExtendedDesktopSize status code
*/
static const char *
get_eds_status_msg(unsigned int response_code)
{
if (response_code >= EDS_STATUS_MSG_COUNT)
{
response_code = EDS_STATUS_MSG_COUNT - 1;
}
return eds_status_msg[response_code];
}
/**************************************************************************//**
* Handles the first framebuffer update from the server
*
@@ -1431,7 +1229,7 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
LOG(LOG_LEVEL_WARNING,
"VNC server resize failed - error code %d [%s]",
response_code,
get_eds_status_msg(response_code));
rfb_get_eds_status_msg(response_code));
/* Force client to same size as server */
LOG(LOG_LEVEL_WARNING, "Resizing client to server %dx%d",
v->server_width, v->server_height);
@@ -1514,7 +1312,7 @@ lib_framebuffer_update(struct vnc *v)
in_uint16_be(s, cy);
in_uint32_be(s, encoding);
if (encoding == ENC_RAW)
if (encoding == RFB_ENC_RAW)
{
need_size = cx * cy * get_bytes_per_pixel(v->server_bpp);
init_stream(pixel_s, need_size);
@@ -1525,7 +1323,7 @@ lib_framebuffer_update(struct vnc *v)
error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0);
}
}
else if (encoding == ENC_COPY_RECT)
else if (encoding == RFB_ENC_COPY_RECT)
{
init_stream(s, 8192);
error = trans_force_read_s(v->trans, s, 4);
@@ -1537,7 +1335,7 @@ lib_framebuffer_update(struct vnc *v)
error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy);
}
}
else if (encoding == ENC_CURSOR)
else if (encoding == RFB_ENC_CURSOR)
{
g_memset(cursor_data, 0, 32 * (32 * 3));
g_memset(cursor_mask, 0, 32 * (32 / 8));
@@ -1582,14 +1380,14 @@ lib_framebuffer_update(struct vnc *v)
error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
}
}
else if (encoding == ENC_DESKTOP_SIZE)
else if (encoding == RFB_ENC_DESKTOP_SIZE)
{
/* Server end has resized */
v->server_width = cx;
v->server_height = cy;
error = resize_client(v, 1, cx, cy);
}
else if (encoding == ENC_EXTENDED_DESKTOP_SIZE)
else if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE)
{
layout.total_width = cx;
layout.total_height = cy;
@@ -1622,7 +1420,7 @@ lib_framebuffer_update(struct vnc *v)
if (v->suppress_output == 0)
{
init_stream(s, 8192);
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 1); /* incremental == 1 : Changes only */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
@@ -1638,57 +1436,6 @@ lib_framebuffer_update(struct vnc *v)
return error;
}
/******************************************************************************/
/* clip data from the vnc server */
int
lib_clip_data(struct vnc *v)
{
struct stream *s;
struct stream *out_s;
int size;
int error;
free_stream(v->clip_data_s);
v->clip_data_s = 0;
make_stream(s);
init_stream(s, 8192);
error = trans_force_read_s(v->trans, s, 7);
if (error == 0)
{
in_uint8s(s, 3);
in_uint32_be(s, size);
make_stream(v->clip_data_s);
init_stream(v->clip_data_s, size);
error = trans_force_read_s(v->trans, v->clip_data_s, size);
}
if (error == 0)
{
make_stream(out_s);
init_stream(out_s, 8192);
out_uint16_le(out_s, 2);
out_uint16_le(out_s, 0);
out_uint32_le(out_s, 0x90);
out_uint8(out_s, 0x0d);
out_uint8s(out_s, 35);
out_uint8(out_s, 0x10);
out_uint8s(out_s, 35);
out_uint8(out_s, 0x01);
out_uint8s(out_s, 35);
out_uint8(out_s, 0x07);
out_uint8s(out_s, 35);
out_uint8s(out_s, 4);
s_mark_end(out_s);
size = (int)(out_s->end - out_s->data);
error = v->server_send_to_channel(v, v->clip_chanid, out_s->data, size, size, 3);
free_stream(out_s);
}
free_stream(s);
return error;
}
/******************************************************************************/
int
lib_palette_update(struct vnc *v)
@@ -1775,7 +1522,7 @@ lib_mod_process_message(struct vnc *v, struct stream *s)
error = 0;
if (error == 0)
{
if (type == S2C_FRAMEBUFFER_UPDATE)
if (type == RFB_S2C_FRAMEBUFFER_UPDATE)
{
switch (v->resize_status)
{
@@ -1791,18 +1538,18 @@ lib_mod_process_message(struct vnc *v, struct stream *s)
error = lib_framebuffer_update(v);
}
}
else if (type == S2C_SET_COLOUR_MAP_ENTRIES)
else if (type == RFB_S2C_SET_COLOUR_MAP_ENTRIES)
{
error = lib_palette_update(v);
}
else if (type == S2C_BELL)
else if (type == RFB_S2C_BELL)
{
error = lib_bell_trigger(v);
}
else if (type == S2C_SERVER_CUT_TEXT) /* clipboard */
else if (type == RFB_S2C_SERVER_CUT_TEXT) /* clipboard */
{
LOG(LOG_LEVEL_DEBUG, "VNC got clip data");
error = lib_clip_data(v);
error = vnc_clip_process_rfb_data(v);
}
else
{
@@ -1826,22 +1573,6 @@ lib_mod_start(struct vnc *v, int w, int h, int bpp)
return 0;
}
/******************************************************************************/
static int
lib_open_clip_channel(struct vnc *v)
{
char init_data[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
v->clip_chanid = v->server_get_channel_id(v, "cliprdr");
if (v->clip_chanid >= 0)
{
v->server_send_to_channel(v, v->clip_chanid, init_data, 12, 12, 3);
}
return 0;
}
/******************************************************************************/
static int
lib_data_in(struct trans *trans)
@@ -2117,7 +1848,7 @@ lib_mod_connect(struct vnc *v)
if (error == 0)
{
init_stream(s, 8192);
out_uint8(s, C2S_SET_PIXEL_FORMAT);
out_uint8(s, RFB_C2S_SET_PIXEL_FORMAT);
out_uint8(s, 0);
out_uint8(s, 0);
out_uint8(s, 0);
@@ -2209,13 +1940,13 @@ lib_mod_connect(struct vnc *v)
unsigned int i;
/* These encodings are always supported */
e[n++] = ENC_RAW;
e[n++] = ENC_COPY_RECT;
e[n++] = ENC_CURSOR;
e[n++] = ENC_DESKTOP_SIZE;
e[n++] = RFB_ENC_RAW;
e[n++] = RFB_ENC_COPY_RECT;
e[n++] = RFB_ENC_CURSOR;
e[n++] = RFB_ENC_DESKTOP_SIZE;
if (v->enabled_encodings_mask & MSK_EXTENDED_DESKTOP_SIZE)
{
e[n++] = ENC_EXTENDED_DESKTOP_SIZE;
e[n++] = RFB_ENC_EXTENDED_DESKTOP_SIZE;
}
else
{
@@ -2224,7 +1955,7 @@ lib_mod_connect(struct vnc *v)
}
init_stream(s, 8192);
out_uint8(s, C2S_SET_ENCODINGS);
out_uint8(s, RFB_C2S_SET_ENCODINGS);
out_uint8(s, 0);
out_uint16_be(s, n); /* Number of encodings following */
for (i = 0 ; i < n; ++i)
@@ -2259,7 +1990,7 @@ lib_mod_connect(struct vnc *v)
if (error == 0)
{
v->server_msg(v, "VNC connection complete, connected ok", 0);
lib_open_clip_channel(v);
vnc_clip_open_clip_channel(v);
}
else
{
@@ -2292,7 +2023,6 @@ lib_mod_end(struct vnc *v)
{
}
free_stream(v->clip_data_s);
return 0;
}
@@ -2452,7 +2182,7 @@ lib_mod_suppress_output(struct vnc *v, int suppress,
{
make_stream(s);
init_stream(s, 8192);
out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 0); /* incremental == 0 : Full contents */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
@@ -2520,6 +2250,8 @@ mod_init(void)
/* Member variables */
v->enabled_encodings_mask = -1;
vnc_clip_init(v);
return (tintptr) v;
}
@@ -2536,6 +2268,7 @@ mod_exit(tintptr handle)
}
trans_delete(v->trans);
g_free(v->client_layout.s);
vnc_clip_exit(v);
g_free(v);
return 0;
}