/******************************************************************************/ /* taken from vncauth.c */ /* performing the des3 crypt on the password so it can not be seen onthewire 'bytes'in,contains16bytesserverrandom
out, random and 'passwd' conbined */ staticvoid
rfbEncryptBytes(char *bytes, constchar *passwd)
{ char key[24]; void *des; int len;
/* key is simply password padded with nulls */
g_memset(key, 0, sizeof(key));
len = MIN(g_strlen(passwd), 8);
g_mirror_memcpy(key, passwd, len);
des = ssl_des3_encrypt_info_create(key, 0);
ssl_des3_encrypt(des, 8, bytes, bytes);
ssl_des3_info_delete(des);
des = ssl_des3_encrypt_info_create(key, 0);
ssl_des3_encrypt(des, 8, bytes + 8, bytes + 8);
ssl_des3_info_delete(des);
}
/******************************************************************************/ /* sha1 hash 'passwd', create a string from the hash and call rfbEncryptBytes */ staticvoid
rfbHashEncryptBytes(char *bytes, constchar *passwd)
{ char passwd_hash[20]; char passwd_hash_text[40]; void *sha1; int passwd_bytes;
/**************************************************************************//**
* Logs a debug message containing a screen layout
*
* @param lvl Level to log at
* @param source Where the layout came from
* @param layout Layout to log
*/ staticvoid
log_screen_layout(constenum logLevels lvl, constchar *source, conststruct vnc_screen_layout *layout)
{ unsignedint i; char text[256];
size_t pos; int res;
pos = 0;
res = g_snprintf(text, sizeof(text) - pos, "Layout from %s (geom=%dx%d #screens=%u) :",
source, layout->total_width, layout->total_height,
layout->count);
i = 0; while (res > 0 && (size_t)res < sizeof(text) - pos && i < layout->count)
{
pos += res;
res = g_snprintf(&text[pos], sizeof(text) - pos, " %d:(%dx%d+%d+%d)",
layout->s[i].id,
layout->s[i].width, layout->s[i].height,
layout->s[i].x, layout->s[i].y);
++i;
}
LOG(lvl, "%s", text);
}
/**************************************************************************//**
* Compares two vnc_screen structures
*
* @param a First structure
* @param b Second structure
*
* @return Suitable for sorting structures on (x, y, width, height)
*/ staticint cmp_vnc_screen(conststruct vnc_screen *a, conststruct vnc_screen *b)
{ int result = 0; if (a->x != b->x)
{
result = a->x - b->x;
} elseif (a->y != b->y)
{
result = a->y - b->y;
} elseif (a->width != b->width)
{
result = a->width - b->width;
} elseif (a->height != b->height)
{
result = a->height - b->height;
}
return result;
}
/**************************************************************************//**
* Compares two vnc_screen_layout structures for equality
* @param a First layout
* @param b First layout
* @return != 0if structures are equal
*/ staticint vnc_screen_layouts_equal(conststruct vnc_screen_layout *a, conststruct vnc_screen_layout *b)
{ unsignedint i; int result = (a->total_width == b->total_width &&
a->total_height == b->total_height &&
a->count == b->count); if (result)
{ for (i = 0 ; result && i < a->count ; ++i)
{
result = (cmp_vnc_screen(&a->s[i], &b->s[i]) == 0);
}
}
return result;
}
/**************************************************************************//**
* Reads an extended desktop size rectangle from the VNC server
*
* @param v VNC object
* @param [out] layout Desired layout for server
* @return != 0for error
*
* @pre The next octet read from v->trans is the number of screens
*
* @post Returned structure is in increasing ID order
* @post layout->total_width is untouched
* @post layout->total_height is untouched
*/ staticint
read_extended_desktop_size_rect(struct vnc *v, struct vnc_screen_layout *layout)
{ struct stream *s; int error; unsignedint count;
layout->count = 0;
make_stream(s);
init_stream(s, 8192);
/* Read in the current screen config */
error = trans_force_read_s(v->trans, s, 4); if (error == 0)
{ /* Get the number of screens */
in_uint8(s, count); if (count <= 0 || count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
LOG(LOG_LEVEL_ERROR, "Bad monitor count %d in ExtendedDesktopSize rectangle",
count);
error = 1;
} else
{
in_uint8s(s, 3);
error = trans_force_read_s(v->trans, s, 16 * count); if (error == 0)
{ unsignedint i; for (i = 0 ; i < count ; ++i)
{
in_uint32_be(s, layout->s[i].id);
in_uint16_be(s, layout->s[i].x);
in_uint16_be(s, layout->s[i].y);
in_uint16_be(s, layout->s[i].width);
in_uint16_be(s, layout->s[i].height);
in_uint32_be(s, layout->s[i].flags);
}
/**************************************************************************//**
* Sends a SetDesktopSize message
*
* @param v VNC object
* @param layout Desired layout for server
* @return != 0for error
*
* The SetDesktopSize message is documented in the RFB community wiki
* "SetDesktopSize" section.
*/ staticint
send_set_desktop_size(struct vnc *v, conststruct vnc_screen_layout *layout)
{ unsignedint i; struct stream *s; int error;
/**************************************************************************//**
* Resize the client to match the server_layout
*
* @param v VNC object
* @param update_in_progress Trueif there's a painter update in progress
* @return != 0for error
*
* The new client layout is recorded in v->client_layout.
*/ staticint
resize_client_to_server(struct vnc *v, int update_in_progress)
{ int error = 0; unsignedint i; conststruct vnc_screen_layout *sl = &v->server_layout; struct monitor_info client_mons[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS] = {0};
if (sl->count <= 0 ||
sl->count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
LOG(LOG_LEVEL_ERROR, "%s: Programming error. Bad monitors %d",
__func__, sl->count); return1;
}
// Convert the server monitors into client monitors for (i = 0; i < sl->count; ++i)
{
client_mons[i].left = sl->s[i].x;
client_mons[i].top = sl->s[i].y;
client_mons[i].right = sl->s[i].x + sl->s[i].width - 1;
client_mons[i].bottom = sl->s[i].y + sl->s[i].height - 1;
}
/**************************************************************************//**
* Resize the server to the client layout
*
* @param v VNC object
* @return != 0for error
*
* The new client layout is recorded in v->client_layout.
*/ staticint
resize_server_to_client_layout(struct vnc *v)
{ int error = 0;
/* Before checking the 'resize_supported' flag, see if this *isanulloperation.Wecangethereiftheserverdoesn't *supportresize,andwe'vequeuedarequesttoresizetheclient
* to the server size */ if (vnc_screen_layouts_equal(&v->server_layout, &v->client_layout))
{
LOG(LOG_LEVEL_DEBUG, "Server layout is the same " "as the client layout");
v->resize_status = VRS_DONE;
} elseif (v->resize_supported != VRSS_SUPPORTED)
{
LOG(LOG_LEVEL_ERROR, "%s: Asked to resize server, but not possible",
__func__);
error = 1;
} else
{ /* *Ifwe'veonlygotonescreen,andtheothersidehas *onlygotonescreen,wewillpreservetheirscreenID *andanyflags.Thismaypreventussendinganunwanted *SetDesktopSizemessageifthescreendimensionsare *amatch.Wecan'tdothiswithmorethanonescreen, *aswehavenowaytomapdifferentIDs
*/ if (v->server_layout.count == 1 && v->client_layout.count == 1)
{
LOG(LOG_LEVEL_DEBUG, "VNC " "setting screen id to %d from server",
v->server_layout.s[0].id);
/*****************************************************************************/ int
lib_mod_event(struct vnc *v, int msg, long param1, long param2, long param3, long param4)
{ struct stream *s; int key; int error; int x; int y; int cx; int cy; int size; int total_size; int chanid; int flags; char *data;
if (key > 0)
{ if (key == 65027) /* altgr */
{ if (v->shift_state)
{ /* fix for mstsc sending left control down with altgr */
init_stream(s, 8192);
out_uint8(s, RFB_C2S_KEY_EVENT);
out_uint8(s, 0); /* down flag */
out_uint8s(s, 2);
out_uint32_be(s, 65507); /* left control */
s_mark_end(s);
lib_send_copy(v, s);
}
}
//****************************************************************************** int
get_pixel_safe(char *data, int x, int y, int width, int height, int bpp)
{ int start = 0; int shift = 0;
/******************************************************************************/ void
set_pixel_safe(char *data, int x, int y, int width, int height, int bpp, int pixel)
{ int start = 0; int shift = 0;
if (x < 0)
{ return;
}
if (y < 0)
{ return;
}
if (x >= width)
{ return;
}
if (y >= height)
{ return;
}
if (bpp == 1)
{
width = (width + 7) / 8;
start = (y * width) + x / 8;
shift = x % 8;
/******************************************************************************/ int
make_color(int r, int g, int b, int bpp)
{ if (bpp == 24)
{ return (r << 16) | (g << 8) | b;
} else
{
LOG(LOG_LEVEL_ERROR, "error in make_color bpp %d", bpp);
}
return0;
}
/** *Convertsabits-per-pixelvaluetobytes-per-pixel
*/ staticint
get_bytes_per_pixel(int bpp)
{ int result = (bpp + 7) / 8;
if (result == 3)
{
result = 4;
}
return result;
}
/**************************************************************************//**
* Skips the specified number of bytes from the transport
*
* @param transport Transport to read
* @param bytes Bytes to skip
* @return != 0for error
*/ int
skip_trans_bytes(struct trans *trans, unsignedint bytes)
{ struct stream *s; int error = 0;
/**************************************************************************//**
* Reads an encoding from the input stream and discards it
*
* @param v VNC object
* @param x Encoding X value
* @param y Encoding Y value
* @param cx Encoding CX value
* @param cy Encoding CY value
* @param encoding Code for encoding
* @return != 0for error
*
* @pre On entry the input stream is positioned after the encoding header
*/ staticint
skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
encoding_type encoding)
{ char text[256]; int error = 0;
/**************************************************************************//**
* Checks the size parameters from a framebuffer update are sane
* @param cx Width of update
* @param cy height of update
* @return0if the proposed sizes could result in overflow
*
* [MS-RDPBCGR] allows for a max desktop size of
* CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH x
* CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
* Each pixel needs up to 4 bytes
*/ staticint
framebuffer_update_size_ok(int cx, int cy)
{ return (cx <= CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH &&
cy <= CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT &&
(cx * cy) <= (INT_MAX / 4));
}
/**************************************************************************//**
* Parses an entire framebuffer update message from the wire, and returns the
* first matching ExtendedDesktopSize encoding if found.
*
* Caller can check for a match by examining match_layout.count after the call
*
* @param v VNC object
* @param match Function to call to check for a match
* @param [out] match_x Matching x parameter for an encoding (if needed)
* @param [out] match_y Matching y parameter for an encoding (if needed)
* @param [out] match_layout Returned layout for the encoding
* @return != 0for error
*/ staticint
find_matching_extended_rect(struct vnc *v, int (*match)(int x, int y, int cx, int cy), int *match_x, int *match_y, struct vnc_screen_layout *match_layout)
{ int error; struct stream *s; unsignedint num_rects; unsignedint i; int x; int y; int cx; int cy;
encoding_type encoding; int found = 0;
/**************************************************************************//**
* Sends a FramebufferUpdateRequest for the resize status state machine
*
* The state machine is used at the start of the connection to negotiate
* a common geometry between the client and the server.
*
* The RFB community wiki contains the following paragraph not present
* in RFC6143:-
*
* Note that an empty area can still solicit a FramebufferUpdate
* even though that update will only contain pseudo-encodings
*
* This doesn't seem to be as widely supported as we would like at
* present. We will always request at least a single pixel update to
* avoid confusing the server.
*
* @param v VNC object
* @return != 0for error
*/ staticint
send_update_request_for_resize_status(struct vnc *v)
{ int error = 0; struct stream *s;
make_stream(s);
init_stream(s, 8192);
/**************************************************************************//**
* Tests if extended desktop size rect is an initial geometry specification
*
* This should be x == 0, but the specification says to treat undefined
* values as 0 also */ staticint
rect_is_initial_geometry(int x, int y, int cx, int cy)
{ return (x != 1 && x != 2);
}
/**************************************************************************//**
* Tests if extended desktop size rect is a reply to a request from us
*/ staticint
rect_is_reply_to_us(int x, int y, int cx, int cy)
{ return (x == 1);
}
/**************************************************************************//**
* Handles the first framebuffer update from the server
*
* This is used to determine if the server supports resizes from
* us. See The RFB community wiki for details.
*
* If the server does support resizing, we send our client geometry over.
*
* @param v VNC object
* @return != 0for error
*/ staticint
lib_framebuffer_first_update(struct vnc *v)
{ int error; struct vnc_screen_layout layout = {0};
error = find_matching_extended_rect(v,
rect_is_initial_geometry,
NULL,
NULL,
&layout); if (error == 0)
{ if (layout.count > 0)
{
LOG(LOG_LEVEL_DEBUG, "VNC server supports resizing");
v->resize_supported = VRSS_SUPPORTED;
v->server_layout = layout;
/* Force the client geometry over to the server */
log_screen_layout(LOG_LEVEL_INFO, "ClientLayout", &v->client_layout);
log_screen_layout(LOG_LEVEL_INFO, "OldServerLayout", &layout);
/* *Ifwe'veonlygotonescreen,andtheothersidehas *onlygotonescreen,wewillpreservetheirscreenID *andanyflags.Thismaypreventussendinganunwanted *SetDesktopSizemessageifthescreendimensionsare *amatch.Wecan'tdothiswithmorethanonescreen, *aswehavenowaytomapdifferentIDs
*/ if (layout.count == 1 && v->client_layout.count == 1)
{
LOG(LOG_LEVEL_DEBUG, "VNC " "setting screen id to %d from server",
layout.s[0].id);
resize_server_to_client_layout(v);
} else
{
LOG(LOG_LEVEL_DEBUG, "VNC server does not support resizing");
v->resize_supported = VRSS_NOT_SUPPORTED;
/* Force client to same size as server */
LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d",
v->server_layout.total_width, v->server_layout.total_height);
error = resize_client_to_server(v, 0);
v->resize_status = VRS_DONE;
}
}
if (error == 0)
{
error = send_update_request_for_resize_status(v);
}
return error;
}
/**************************************************************************//**
* Looks for a resize confirm in a framebuffer update request
*
* If the server supports resizes from us, this is used to find the
* reply to our resize request. See The RFB community wiki for details.
*
* @param v VNC object
* @return != 0for error
*/ staticint
lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
{ int error; struct vnc_screen_layout layout = {0}; int response_code = 0;
error = find_matching_extended_rect(v,
rect_is_reply_to_us,
NULL,
&response_code,
&layout); if (error == 0)
{ if (layout.count > 0)
{ if (response_code == 0)
{
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
v->server_layout = layout;
} else
{
LOG(LOG_LEVEL_WARNING, "VNC server resize failed - error code %d [%s]",
response_code,
rfb_get_eds_status_msg(response_code)); // This is awkward. The client has asked for a specific size // which we can't support. // // Currently we handle this by queueing a resize to our // supported size, and continuing with the resize state // machine in xrdp_mm.c
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
error = resize_client_to_server(v, 0);
}
if (error == 0)
{ // If this resize was requested by the client mid-session // (dynamic resize), we need to tell xrdp_mm that // it's OK to continue with the resize state machine.
error = v->server_monitor_resize_done(v);
}
v->resize_status = VRS_DONE;
}
}
if (error == 0)
{
error = send_update_request_for_resize_status(v);
}
return error;
}
/******************************************************************************/ int
lib_framebuffer_update(struct vnc *v)
{ char *d1; char *d2; char cursor_data[32 * (32 * 3)]; char cursor_mask[32 * (32 / 8)]; char text[256]; int num_recs; int i; int j; int k; int x; int y; int cx; int cy; int srcx; int srcy; unsignedint encoding; int pixel; int r; int g; int b; int error; int need_size; struct stream *s; struct stream *pixel_s; struct vnc_screen_layout layout = { 0 };
/******************************************************************************/ int
lib_palette_update(struct vnc *v)
{ struct stream *s; int first_color; int num_colors; int i; int r; int g; int b; int error;
if (error == 0)
{ for (i = 0; i < num_colors; i++)
{
in_uint16_be(s, r);
in_uint16_be(s, g);
in_uint16_be(s, b);
r = r >> 8;
g = g >> 8;
b = b >> 8;
v->palette[first_color + i] = (r << 16) | (g << 8) | b;
}
error = v->server_begin_update(v);
}
if (error == 0)
{
error = v->server_palette(v, v->palette);
}
if (error == 0)
{
error = v->server_end_update(v);
}
free_stream(s); return error;
}
/******************************************************************************/ int
lib_bell_trigger(struct vnc *v)
{ int error;
v->server_msg(v, "VNC started connecting", 0);
check_sec_result = 1;
/* check if bpp is supported for rdp connection */ switch (v->server_bpp)
{ case8: case15: case16: case24: case32: break; default:
v->server_msg(v, "VNC error - only supporting 8, 15, 16, 24 and 32 " "bpp rdp connections", 0); return1;
}
/* Assume a TCP-port based connection (i.e. not a UDS connection)
* if the port is not an absolute path */ if (con_port[0] == '/')
{
socket_mode = TRANS_MODE_UNIX;
} else
{
socket_mode = TRANS_MODE_TCP; if (g_strcmp(v->ip, "") == 0)
{
v->server_msg(v, "VNC error - no IP set for TCP connection", 0); return1;
}
}
if (i == 1) /* none */
{
check_sec_result = 0;
} elseif (i == 2) /* dec the password and the server random */
{
init_stream(s, 8192);
error = trans_force_read_s(v->trans, s, 16);
/* Save monitor information from the client *Useminfo_wm,asthisisnormalisedforatop-leftof(0,0)
* as required by RFC6143 */
init_client_layout(v,
client_info->display_sizes.session_width,
client_info->display_sizes.session_height,
client_info->display_sizes.monitorCount,
client_info->display_sizes.minfo_wm);
log_screen_layout(LOG_LEVEL_DEBUG, "client_info", &v->client_layout);
}
return0;
}
/******************************************************************************/ /* return error */ int
lib_mod_get_wait_objs(struct vnc *v, tbus *read_objs, int *rcount,
tbus *write_objs, int *wcount, int *timeout)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_get_wait_objs:");
if (v != 0)
{ if (v->trans != 0)
{
trans_get_wait_objs_rw(v->trans, read_objs, rcount,
write_objs, wcount, timeout);
}
}
return0;
}
/******************************************************************************/ /* return error */ int
lib_mod_check_wait_objs(struct vnc *v)
{ int rv;
rv = 0; if (v != 0)
{ if (v->trans != 0)
{
rv = trans_check_wait_objs(v->trans); if (rv != 0)
{
LOG(LOG_LEVEL_ERROR, "VNC server closed connection");
}
}
} return rv;
}
/******************************************************************************/ /* return error */ int
lib_mod_frame_ack(struct vnc *v, int flags, int frame_id)
{ return0;
}
/******************************************************************************/ /* return error */ int
lib_mod_suppress_output(struct vnc *v, int suppress, int left, int top, int right, int bottom)
{ int error; struct stream *s;
/******************************************************************************/ /* return error */ int
lib_mod_server_monitor_resize(struct vnc *v, int width, int height, int num_monitors, conststruct monitor_info *monitors, int *in_progress)
{ int error;
*in_progress = 0;
init_client_layout(v, width, height, num_monitors, monitors);
if ((error = resize_server_to_client_layout(v)) == 0)
{ // If we're waiting for a confirmation, send an update request. // According to the spec this should not be needed, but // it works around a buggy VNC server not sending an // ExtendedDesktopSize rectangle if the desktop change is // small (eg. same dimensions, but 2 monitors -> 1 monitor) if (v->resize_status == VRS_WAITING_FOR_RESIZE_CONFIRM &&
(error = send_update_request_for_resize_status(v)) == 0)
{
*in_progress = 1;
}
}
return error;
}
/******************************************************************************/ /* return error */ int
lib_mod_server_monitor_full_invalidate(struct vnc *v, int param1, int param2)
{ return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.