diff --git a/common/arch.h b/common/arch.h index b8780926..6a29b0a9 100644 --- a/common/arch.h +++ b/common/arch.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/os_calls.h b/common/os_calls.h index 2dbbe660..443a1840 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -125,6 +125,7 @@ int APP_CC g_get_errno(void); int APP_CC g_execvp(const char* p1, char* args[]); int APP_CC g_execlp3(const char* a1, const char* a2, const char* a3); void APP_CC g_signal_child_stop(void (*func)(int)); +void APP_CC g_signal_segfault(void (*func)(int)); void APP_CC g_signal_hang_up(void (*func)(int)); void APP_CC g_signal_user_interrupt(void (*func)(int)); void APP_CC g_signal_kill(void (*func)(int)); diff --git a/common/parse.h b/common/parse.h index 3ec37104..69a57ff8 100644 --- a/common/parse.h +++ b/common/parse.h @@ -55,6 +55,9 @@ struct stream /******************************************************************************/ #define s_check_rem(s, n) ((s)->p + (n) <= (s)->end) +/******************************************************************************/ +#define s_check_rem_out(s, n) ((s)->p + (n) <= (s)->data + (s)->size) + /******************************************************************************/ #define s_check_end(s) ((s)->p == (s)->end) diff --git a/common/trans.c b/common/trans.c index 0b672168..8313b606 100644 --- a/common/trans.c +++ b/common/trans.c @@ -221,8 +221,12 @@ trans_force_read_s(struct trans *self, struct stream *in_s, int size) while (size > 0) { + /* make sure stream has room */ + if ((in_s->end + size) > (in_s->data + in_s->size)) + { + return 1; + } rcvd = g_tcp_recv(self->sck, in_s->end, size, 0); - if (rcvd == -1) { if (g_tcp_last_error_would_block(self->sck)) diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index b978d2de..a163df07 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -559,4 +559,7 @@ #define CMDTYPE_FRAME_MARKER 0x0004 #define CMDTYPE_STREAM_SURFACE_BITS 0x0006 +#define XRDP_MAX_BITMAP_CACHE_ID 3 +#define XRDP_MAX_BITMAP_CACHE_IDX 2000 + #endif diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c index d851c1bb..feba6814 100644 --- a/libxrdp/xrdp_iso.c +++ b/libxrdp/xrdp_iso.c @@ -72,20 +72,38 @@ xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code) in_uint8s(s, 1); in_uint16_be(s, len); + if (len < 4) + { + return 1; + } + if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) { return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } + in_uint8s(s, 1); in_uint8(s, *code); if (*code == ISO_PDU_DT) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8s(s, 1); } else { + if (!s_check_rem(s, 5)) + { + return 1; + } in_uint8s(s, 5); } diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 4bf3d025..d110c987 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -132,6 +132,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 1)) + { + return 1; + } + in_uint8(s, opcode); appid = opcode >> 2; @@ -145,6 +150,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) /* this is channels getting added from the client */ if (appid == MCS_CJRQ) { + if (!s_check_rem(s, 4)) + { + return 1; + } + in_uint16_be(s, userid); in_uint16_be(s, chanid); log_message(LOG_LEVEL_DEBUG,"MCS_CJRQ - channel join request received"); @@ -176,6 +186,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 6)) + { + return 1; + } + in_uint8s(s, 2); in_uint16_be(s, *chan); in_uint8s(s, 1); @@ -183,6 +198,10 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) if (len & 0x80) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8s(s, 1); } @@ -202,10 +221,18 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, if (tag_val > 0xff) { + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_be(s, tag); } else { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8(s, tag); } @@ -214,6 +241,11 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, return 1; } + if (!s_check_rem(s, 1)) + { + return 1; + } + in_uint8(s, l); if (l & 0x80) @@ -223,6 +255,10 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, while (l > 0) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8(s, i); *len = (*len << 8) | i; l--; @@ -255,6 +291,11 @@ xrdp_mcs_parse_domain_params(struct xrdp_mcs *self, struct stream *s) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + return 1; + } + in_uint8s(s, len); if (s_check(s)) @@ -276,7 +317,7 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) struct stream *s; make_stream(s); - init_stream(s, 8192); + init_stream(s, 16 * 1024); if (xrdp_iso_recv(self->iso_layer, s) != 0) { @@ -296,6 +337,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) @@ -304,6 +351,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) @@ -312,6 +365,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_parse_domain_params(self, s) != 0) @@ -338,6 +397,19 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + /* mcs data can not be zero length */ + if ((len <= 0) || (len > 16 * 1024)) + { + free_stream(s); + return 1; + } + + if (!s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + /* make a copy of client mcs data */ init_stream(self->client_mcs_data, len); out_uint8a(self->client_mcs_data, s->p, len); @@ -372,6 +444,12 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) free_stream(s); return 1; } + + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } in_uint8(s, opcode); @@ -381,11 +459,22 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 4)) + { + free_stream(s); + return 1; + } + in_uint8s(s, 2); in_uint8s(s, 2); if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint16_be(s, self->userid); } @@ -416,6 +505,12 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); if ((opcode >> 2) != MCS_AURQ) @@ -426,6 +521,11 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint16_be(s, self->userid); } @@ -491,6 +591,12 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJRQ) @@ -499,10 +605,21 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 4)) + { + free_stream(s); + return 1; + } + in_uint8s(s, 4); if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint8s(s, 2); } diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 2d90485f..214202f5 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -514,6 +514,11 @@ xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp *self) p = &(self->sec_layer->client_mcs_data); p->p = p->data; + if (!s_check_rem(p, 31 + 2 + 2 + 120 + 2)) + { + g_writeln("xrdp_rdp_parse_client_mcs_data: error"); + return 1; + } in_uint8s(p, 31); in_uint16_le(p, self->client_info.width); in_uint16_le(p, self->client_info.height); @@ -524,6 +529,10 @@ xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp *self) switch (i) { case 0xca01: + if (!s_check_rem(p, 6 + 1)) + { + return 1; + } in_uint8s(p, 6); in_uint8(p, i); @@ -837,6 +846,11 @@ xrdp_process_capset_general(struct xrdp_rdp *self, struct stream *s, { int i; + if (len < 10 + 2) + { + g_writeln("xrdp_process_capset_general: error"); + return 1; + } in_uint8s(s, 10); in_uint16_le(s, i); /* use_compact_packets is pretty much 'use rdp5' */ @@ -858,6 +872,11 @@ xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, int cap_flags; DEBUG(("order capabilities")); + if (len < 20 + 2 + 2 + 2 + 2 + 2 + 2 + 32 + 2 + 2 + 4 + 4 + 4 + 4) + { + g_writeln("xrdp_process_capset_order: error"); + return 1; + } in_uint8s(s, 20); /* Terminal desc, pad */ in_uint8s(s, 2); /* Cache X granularity */ in_uint8s(s, 2); /* Cache Y granularity */ @@ -915,13 +934,32 @@ static int APP_CC xrdp_process_capset_bmpcache(struct xrdp_rdp *self, struct stream *s, int len) { + int i; + + if (len < 24 + 2 + 2 + 2 + 2 + 2 + 2) + { + g_writeln("xrdp_process_capset_bmpcache: error"); + return 1; + } self->client_info.bitmap_cache_version |= 1; in_uint8s(s, 24); - in_uint16_le(s, self->client_info.cache1_entries); + /* cache 1 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache1_entries = i; in_uint16_le(s, self->client_info.cache1_size); - in_uint16_le(s, self->client_info.cache2_entries); + /* cache 2 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache2_entries = i; in_uint16_le(s, self->client_info.cache2_size); - in_uint16_le(s, self->client_info.cache3_entries); + /* caceh 3 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache3_entries = i; in_uint16_le(s, self->client_info.cache3_size); DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, self->client_info.cache1_size)); @@ -941,22 +979,30 @@ xrdp_process_capset_bmpcache2(struct xrdp_rdp *self, struct stream *s, int Bpp = 0; int i = 0; + if (len < 2 + 2 + 4 + 4 + 4) + { + g_writeln("xrdp_process_capset_bmpcache2: error"); + return 1; + } self->client_info.bitmap_cache_version |= 2; Bpp = (self->client_info.bpp + 7) / 8; in_uint16_le(s, i); /* cache flags */ self->client_info.bitmap_cache_persist_enable = i; in_uint8s(s, 2); /* number of caches in set, 3 */ in_uint32_le(s, i); - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache1_entries = i; self->client_info.cache1_size = 256 * Bpp; in_uint32_le(s, i); - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache2_entries = i; self->client_info.cache2_size = 1024 * Bpp; in_uint32_le(s, i); i = i & 0x7fffffff; - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache3_entries = i; self->client_info.cache3_size = 4096 * Bpp; DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, @@ -975,6 +1021,11 @@ xrdp_process_capset_cache_v3_codec_id(struct xrdp_rdp *self, struct stream *s, { int codec_id; + if (len < 1) + { + g_writeln("xrdp_process_capset_cache_v3_codec_id: error"); + return 1; + } in_uint8(s, codec_id); g_writeln("xrdp_process_capset_cache_v3_codec_id: cache_v3_codec_id %d", codec_id); @@ -992,6 +1043,11 @@ xrdp_process_capset_pointercache(struct xrdp_rdp *self, struct stream *s, int colorPointerFlag; int no_new_cursor; + if (len < 2 + 2 + 2) + { + g_writeln("xrdp_process_capset_pointercache: error"); + return 1; + } no_new_cursor = self->client_info.pointer_flags & 2; in_uint16_le(s, colorPointerFlag); self->client_info.pointer_flags = colorPointerFlag; @@ -1028,6 +1084,11 @@ xrdp_process_capset_brushcache(struct xrdp_rdp *self, struct stream *s, { int code; + if (len < 4) + { + g_writeln("xrdp_process_capset_brushcache: error"); + return 1; + } in_uint32_le(s, code); self->client_info.brush_cache_code = code; return 0; @@ -1040,12 +1101,11 @@ xrdp_process_offscreen_bmpcache(struct xrdp_rdp *self, struct stream *s, { int i32; - if (len - 4 < 8) + if (len < 4 + 2 + 2) { - g_writeln("xrdp_process_offscreen_bmpcache: bad len"); + g_writeln("xrdp_process_offscreen_bmpcache: error"); return 1; } - in_uint32_le(s, i32); self->client_info.offscreen_support_level = i32; in_uint16_le(s, i32); @@ -1066,12 +1126,11 @@ xrdp_process_capset_rail(struct xrdp_rdp *self, struct stream *s, int len) { int i32; - if (len - 4 < 4) + if (len < 4) { - g_writeln("xrdp_process_capset_rail: bad len"); + g_writeln("xrdp_process_capset_rail: error"); return 1; } - in_uint32_le(s, i32); self->client_info.rail_support_level = i32; g_writeln("xrdp_process_capset_rail: rail_support_level %d", @@ -1085,12 +1144,11 @@ xrdp_process_capset_window(struct xrdp_rdp *self, struct stream *s, int len) { int i32; - if (len - 4 < 7) + if (len < 4 + 1 + 2) { - g_writeln("xrdp_process_capset_window: bad len"); + g_writeln("xrdp_process_capset_window: error"); return 1; } - in_uint32_le(s, i32); self->client_info.wnd_support_level = i32; in_uint8(s, i32); @@ -1117,14 +1175,32 @@ xrdp_process_capset_codecs(struct xrdp_rdp *self, struct stream *s, int len) char *codec_guid; char *next_guid; + if (len < 1) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } in_uint8(s, codec_count); + len--; for (index = 0; index < codec_count; index++) { codec_guid = s->p; + if (len < 16 + 1 + 2) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } in_uint8s(s, 16); in_uint8(s, codec_id); in_uint16_le(s, codec_properties_length); + len -= 16 + 1 + 2; + if (len < codec_properties_length) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } + len -= codec_properties_length; next_guid = s->p + codec_properties_length; if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0) @@ -1190,9 +1266,19 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp *self, struct stream *s) for (index = 0; index < num_caps; index++) { p = s->p; + if (!s_check_rem(s, 4)) + { + g_writeln("xrdp_rdp_process_confirm_active: error 1"); + return 1; + } in_uint16_le(s, type); in_uint16_le(s, len); - + if ((len < 4) || !s_check_rem(s, len - 4)) + { + g_writeln("xrdp_rdp_process_confirm_active: error len %d", len, s->end - s->p); + return 1; + } + len -= 4; switch (type) { case RDP_CAPSET_GENERAL: /* 1 */ @@ -1278,7 +1364,7 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp *self, struct stream *s) break; } - s->p = p + len; + s->p = p + len + 4; } DEBUG(("out xrdp_rdp_process_confirm_active")); @@ -1305,12 +1391,20 @@ xrdp_rdp_process_data_input(struct xrdp_rdp *self, struct stream *s) int param2; int time; + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint16_le(s, num_events); in_uint8s(s, 2); /* pad */ DEBUG(("in xrdp_rdp_process_data_input %d events", num_events)); for (index = 0; index < num_events; index++) { + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint32_le(s, time); in_uint16_le(s, msg_type); in_uint16_le(s, device_flags); diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 726fcde4..fbdc99a4 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -331,12 +331,20 @@ unicode_in(struct stream *s, int uni_len, char *dst, int dst_len) break; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, dst[dst_index]); in_uint8s(s, 1); dst_index++; src_index += 2; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8s(s, 2); return 0; } @@ -359,6 +367,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) /* initialize (zero out) local variables */ g_memset(tmpdata, 0, sizeof(char) * 256); + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 4); in_uint32_le(s, flags); DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); @@ -398,6 +410,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_domain); if (len_domain > 511) @@ -406,6 +422,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_user); if (len_user > 511) @@ -414,6 +434,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_password); if (len_password > 511) @@ -422,6 +446,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_program); if (len_program > 511) @@ -430,6 +458,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_directory); if (len_directory > 511) @@ -438,35 +470,75 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } - unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); + if (unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255) != 0) + { + return 1; + } DEBUG(("domain %s", self->rdp_layer->client_info.domain)); - unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); + if (unicode_in(s, len_user, self->rdp_layer->client_info.username, 255) != 0) + { + return 1; + } DEBUG(("username %s", self->rdp_layer->client_info.username)); if (flags & RDP_LOGON_AUTO) { - unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); + if (unicode_in(s, len_password, self->rdp_layer->client_info.password, 255) != 0) + { + return 1; + } DEBUG(("flag RDP_LOGON_AUTO found")); } else { + if (!s_check_rem(s, len_password + 2)) + { + return 1; + } in_uint8s(s, len_password + 2); if (self->rdp_layer->client_info.require_credentials) + { + g_writeln("xrdp_sec_process_logon_info: credentials on cmd line is mandatory"); return 1; /* credentials on cmd line is mandatory */ + } } - unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); + if (unicode_in(s, len_program, self->rdp_layer->client_info.program, 255) != 0) + { + return 1; + } DEBUG(("program %s", self->rdp_layer->client_info.program)); - unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); + if (unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255) != 0) + { + return 1; + } DEBUG(("directory %s", self->rdp_layer->client_info.directory)); if (flags & RDP_LOGON_BLOB) { + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint8s(s, 2); /* unknown */ in_uint16_le(s, len_ip); - unicode_in(s, len_ip - 2, tmpdata, 255); + if (unicode_in(s, len_ip - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_dll); - unicode_in(s, len_dll - 2, tmpdata, 255); + if (unicode_in(s, len_dll - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 4 + 62 + 22 + 62 + 26 + 4)) + { + return 1; + } in_uint32_le(s, tzone); /* len of timetone */ in_uint8s(s, 62); /* skip */ in_uint8s(s, 22); /* skip misc. */ @@ -676,17 +748,29 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint32_le(s, flags); DEBUG((" in xrdp_sec_recv flags $%x", flags)); if (flags & SEC_ENCRYPT) /* 0x08 */ { + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 8); /* signature */ xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); } if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ { + if (!s_check_rem(s, 4 + 64)) + { + return 1; + } in_uint32_le(s, len); in_uint8a(s, self->client_crypt_random, 64); xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, @@ -836,16 +920,30 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) 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++) { channel_item = (struct mcs_channel_item *) g_malloc(sizeof(struct mcs_channel_item), 1); + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint8a(s, channel_item->name, 8); in_uint32_le(s, channel_item->flags); channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); - list_add_item(self->mcs_layer->channel_list, (long)channel_item); + list_add_item(self->mcs_layer->channel_list, (tintptr)channel_item); DEBUG(("got channel flags %8.8x name %s", channel_item->flags, channel_item->name)); } @@ -864,10 +962,14 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) int tag = 0; int size = 0; - s = &self->client_mcs_data; + s = &(self->client_mcs_data); /* set p to beginning */ s->p = s->data; /* skip header */ + if (!s_check_rem(s, 23)) + { + return 1; + } in_uint8s(s, 23); while (s_check_rem(s, 4)) @@ -890,7 +992,10 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) case SEC_TAG_CLI_CRYPT: break; case SEC_TAG_CLI_CHANNELS: - xrdp_sec_process_mcs_data_channels(self, s); + if (xrdp_sec_process_mcs_data_channels(self, s) != 0) + { + return 1; + } break; case SEC_TAG_CLI_4: break; @@ -999,7 +1104,7 @@ xrdp_sec_out_mcs_data(struct xrdp_sec *self) /*****************************************************************************/ /* process the mcs client data we received from the mcs layer */ -static void APP_CC +static int APP_CC xrdp_sec_in_mcs_data(struct xrdp_sec *self) { struct stream *s = (struct stream *)NULL; @@ -1011,6 +1116,10 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) s = &(self->client_mcs_data); /* get hostname, its unicode */ s->p = s->data; + if (!s_check_rem(s, 47)) + { + return 1; + } in_uint8s(s, 47); g_memset(client_info->hostname, 0, 32); c = 1; @@ -1018,6 +1127,10 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) while (index < 16 && c != 0) { + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, c); in_uint8s(s, 1); client_info->hostname[index] = c; @@ -1026,13 +1139,22 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) /* get build */ s->p = s->data; + if (!s_check_rem(s, 43 + 4)) + { + return 1; + } in_uint8s(s, 43); in_uint32_le(s, client_info->build); /* get keylayout */ s->p = s->data; + if (!s_check_rem(s, 39 + 4)) + { + return 1; + } in_uint8s(s, 39); in_uint32_le(s, client_info->keylayout); s->p = s->data; + return 0; } /*****************************************************************************/ @@ -1105,7 +1227,10 @@ xrdp_sec_incoming(struct xrdp_sec *self) (int)(self->server_mcs_data.end - self->server_mcs_data.data)); #endif DEBUG((" out xrdp_sec_incoming")); - xrdp_sec_in_mcs_data(self); + if (xrdp_sec_in_mcs_data(self) != 0) + { + return 1; + } return 0; } diff --git a/xorg/X11R7.6/rdp/rdp.h b/xorg/X11R7.6/rdp/rdp.h index c9afd285..91f50c26 100644 --- a/xorg/X11R7.6/rdp/rdp.h +++ b/xorg/X11R7.6/rdp/rdp.h @@ -471,6 +471,8 @@ int rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv); int rdpup_remove_os_bitmap(int rdpindex); +int +rdpup_update_os_use(int rdpindex); void rdpup_get_screen_image_rect(struct image_data* id); void diff --git a/xorg/X11R7.6/rdp/rdpCopyArea.c b/xorg/X11R7.6/rdp/rdpCopyArea.c index 169ec347..254590ee 100644 --- a/xorg/X11R7.6/rdp/rdpCopyArea.c +++ b/xorg/X11R7.6/rdp/rdpCopyArea.c @@ -429,6 +429,8 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, pSrcPixmap = (PixmapPtr)pSrc; pSrcPriv = GETPIXPRIV(pSrcPixmap); + LLOGLN(10, ("rdpCopyArea: 3 %d %d", pSrcPixmap->usage_hint, pSrcPriv->is_scratch)); + if (xrdp_is_os(pSrcPixmap, pSrcPriv)) { if (pDst->type == DRAWABLE_WINDOW) @@ -468,7 +470,7 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, } else { - LLOGLN(10, ("rdpCopyArea: 2")); + LLOGLN(10, ("rdpCopyArea: 2 %d %d", pSrcPixmap->usage_hint, pSrcPriv->is_scratch)); } } @@ -495,7 +497,7 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, LLOGLN(10, ("rdpCopyArea: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; + dirty_type = RDI_IMGLY; } else { @@ -525,7 +527,7 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, LLOGLN(10, ("rdpCopyArea: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; + dirty_type = RDI_IMGLY; } else { @@ -541,6 +543,8 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, return rv; } + LLOGLN(10, ("rdpCopyArea: post_process")); + RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, pDst, pGC); diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index 6b6c9581..f9dff80a 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -739,13 +739,12 @@ rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, width, org_width, depth, g_rdpScreen.depth)); pScreen->CreatePixmap = g_rdpScreen.CreatePixmap; rv = pScreen->CreatePixmap(pScreen, width, height, depth, usage_hint); + pScreen->CreatePixmap = rdpCreatePixmap; priv = GETPIXPRIV(rv); priv->rdpindex = -1; - priv->con_number = g_con_number; priv->kind_width = width; pScreen->ModifyPixmapHeader(rv, org_width, 0, 0, 0, 0, 0); - pScreen->CreatePixmap = rdpCreatePixmap; - if (org_width == 0 && height == 0) + if ((org_width == 0) && (height == 0)) { priv->is_scratch = 1; } @@ -793,14 +792,19 @@ xrdp_is_os(PixmapPtr pix, rdpPixmapPtr priv) int height; struct image_data id; - if (!XRDP_IS_OS(priv)) + if (XRDP_IS_OS(priv)) + { + /* update time stamp */ + rdpup_update_os_use(priv->rdpindex); + } + else { width = pix->drawable.width; height = pix->drawable.height; if ((pix->usage_hint == 0) && (pix->drawable.depth >= g_rdpScreen.depth) && (width > 0) && (height > 0) && (priv->kind_width > 0) && - (priv->is_scratch == 0)) + (priv->is_scratch == 0) && (priv->use_count >= 0)) { LLOGLN(10, ("%d %d", priv->kind_width, pix->drawable.width)); priv->rdpindex = rdpup_add_os_bitmap(pix, priv); @@ -815,8 +819,12 @@ xrdp_is_os(PixmapPtr pix, rdpPixmapPtr priv) box.y2 = height; if (g_do_dirty_os) { + LLOGLN(10, ("xrdp_is_os: priv->con_number %d g_con_number %d", + priv->con_number, g_con_number)); + LLOGLN(10, ("xrdp_is_os: priv->use_count %d", priv->use_count)); if (priv->con_number != g_con_number) { + LLOGLN(10, ("xrdp_is_os: queuing invalidating all")); draw_item_remove_all(priv); RegionInit(®1, &box, 0); draw_item_add_img_region(priv, ®1, GXcopy, RDI_IMGLL, 16); @@ -1350,7 +1358,7 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, rdpPixmapRec *pDirtyPriv; struct image_data id; - LLOGLN(10, ("rdpComposite:")); + LLOGLN(10, ("rdpComposite: op %d width %d height %d", op, width, height)); ps = GetPictureScreen(g_pScreen); ps->Composite = g_rdpScreen.Composite; ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, @@ -1424,6 +1432,8 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, return; } + LLOGLN(10, ("rdpComposite: post_process")); + if (pDst->pCompositeClip != 0) { box.x1 = p->x + xDst; diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index b8a763a7..0277fc20 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -39,6 +39,9 @@ static char *g_shmemptr = 0; static int g_shmem_lineBytes = 0; static RegionPtr g_shm_reg = 0; +static int g_rect_id_ack = 0; +static int g_rect_id = 0; + static int g_listen_sck = 0; static int g_sck = 0; static int g_sck_closed = 0; @@ -82,9 +85,11 @@ struct rdpup_os_bitmap int stamp; }; +#define MAX_OS_BYTES (16 * 1024 * 1024) static struct rdpup_os_bitmap *g_os_bitmaps = 0; static int g_max_os_bitmaps = 0; static int g_os_bitmap_stamp = 0; +static int g_os_bitmap_alloc_size = 0; static int g_pixmap_byte_total = 0; static int g_pixmap_num_used = 0; @@ -217,6 +222,7 @@ rdpup_disconnect(void) } } } + g_os_bitmap_alloc_size = 0; g_max_os_bitmaps = 0; g_free(g_os_bitmaps); @@ -233,6 +239,7 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) int rv; int oldest; int oldest_index; + int this_bytes; if (!g_connected) { @@ -244,6 +251,17 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) return -1; } + this_bytes = pixmap->devKind * pixmap->drawable.height; + if (this_bytes > MAX_OS_BYTES) + { + LLOGLN(10, ("rdpup_add_os_bitmap: error, too big this_bytes %d " + "width %d height %d", this_bytes, + pixmap->drawable.height, pixmap->drawable.height)); + return -1; + } + + oldest = 0x7fffffff; + oldest_index = -1; rv = -1; index = 0; @@ -260,42 +278,77 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) rv = index; break; } - + else + { + if (g_os_bitmaps[index].stamp < oldest) + { + oldest = g_os_bitmaps[index].stamp; + oldest_index = index; + } + } index++; } if (rv == -1) { + if (oldest_index == -1) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error")); + } + else + { + rdpup_remove_os_bitmap(oldest_index); + g_os_bitmaps[index].used = 1; + g_os_bitmaps[index].pixmap = pixmap; + g_os_bitmaps[index].priv = priv; + g_os_bitmaps[index].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + g_pixmap_num_used++; + rv = oldest_index; + } + } + + if (rv < 0) + { + return rv; + } + + g_os_bitmap_alloc_size += this_bytes; + LLOGLN(10, ("rdpup_add_os_bitmap: this_bytes %d g_os_bitmap_alloc_size %d", + this_bytes, g_os_bitmap_alloc_size)); + while (g_os_bitmap_alloc_size > MAX_OS_BYTES) + { + LLOGLN(10, ("rdpup_add_os_bitmap: must delete g_pixmap_num_used %d", + g_pixmap_num_used)); /* find oldest */ oldest = 0x7fffffff; - oldest_index = 0; + oldest_index = -1; index = 0; - while (index < g_max_os_bitmaps) { - if (g_os_bitmaps[index].stamp < oldest) + if (g_os_bitmaps[index].used && g_os_bitmaps[index].stamp < oldest) { oldest = g_os_bitmaps[index].stamp; oldest_index = index; } - index++; } - - LLOGLN(10, ("rdpup_add_os_bitmap: evicting old, oldest_index %d", oldest_index)); - /* evict old */ - g_os_bitmaps[oldest_index].priv->status = 0; - g_os_bitmaps[oldest_index].priv->con_number = 0; - /* set new */ - g_os_bitmaps[oldest_index].pixmap = pixmap; - g_os_bitmaps[oldest_index].priv = priv; - g_os_bitmaps[oldest_index].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - rv = oldest_index; + if (oldest_index == -1) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error 1")); + break; + } + if (oldest_index == rv) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error 2")); + break; + } + rdpup_remove_os_bitmap(oldest_index); + rdpup_delete_os_surface(oldest_index); } - LLOGLN(10, ("rdpup_add_os_bitmap: new bitmap index %d", rv)); - LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); + LLOGLN(10, ("rdpup_add_os_bitmap: g_pixmap_num_used %d " + "g_os_bitmap_stamp 0x%8.8x", g_pixmap_num_used, g_os_bitmap_stamp)); return rv; } @@ -303,8 +356,12 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) int rdpup_remove_os_bitmap(int rdpindex) { + PixmapPtr pixmap; + rdpPixmapPtr priv; + int this_bytes; + LLOGLN(10, ("rdpup_remove_os_bitmap: index %d stamp %d", - rdpindex, g_os_bitmaps[rdpindex].stamp)); + rdpindex, g_os_bitmaps[rdpindex].stamp)); if (g_os_bitmaps == 0) { @@ -318,16 +375,66 @@ rdpup_remove_os_bitmap(int rdpindex) if (g_os_bitmaps[rdpindex].used) { + pixmap = g_os_bitmaps[rdpindex].pixmap; + priv = g_os_bitmaps[rdpindex].priv; + draw_item_remove_all(priv); + this_bytes = pixmap->devKind * pixmap->drawable.height; + g_os_bitmap_alloc_size -= this_bytes; + LLOGLN(10, ("rdpup_remove_os_bitmap: this_bytes %d " + "g_os_bitmap_alloc_size %d", this_bytes, + g_os_bitmap_alloc_size)); g_os_bitmaps[rdpindex].used = 0; g_os_bitmaps[rdpindex].pixmap = 0; g_os_bitmaps[rdpindex].priv = 0; g_pixmap_num_used--; + priv->status = 0; + priv->con_number = 0; + priv->use_count = 0; + } + else + { + LLOGLN(0, ("rdpup_remove_os_bitmap: error")); } LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); return 0; } +/*****************************************************************************/ +int +rdpup_update_os_use(int rdpindex) +{ + PixmapPtr pixmap; + rdpPixmapPtr priv; + int this_bytes; + + LLOGLN(10, ("rdpup_update_use: index %d stamp %d", + rdpindex, g_os_bitmaps[rdpindex].stamp)); + + if (g_os_bitmaps == 0) + { + return 1; + } + + if ((rdpindex < 0) && (rdpindex >= g_max_os_bitmaps)) + { + return 1; + } + + if (g_os_bitmaps[rdpindex].used) + { + g_os_bitmaps[rdpindex].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + } + else + { + LLOGLN(0, ("rdpup_update_use: error rdpindex %d", rdpindex)); + } + + return 0; +} + + /*****************************************************************************/ /* returns error */ static int @@ -433,7 +540,14 @@ rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) if (g_do_dirty_ons) { - rdpup_check_dirty_screen(&g_screenPriv); + if (g_rect_id == g_rect_id_ack) + { + rdpup_check_dirty_screen(&g_screenPriv); + } + else + { + LLOGLN(0, ("rdpDeferredUpdateCallback: skipping")); + } } else { @@ -909,11 +1023,13 @@ rdpup_process_msg(struct stream *s) { LLOGLN(10, ("rdpup_process_msg: got msg 105")); in_uint32_le(s, flags); + in_uint32_le(s, g_rect_id_ack); in_uint32_le(s, x); in_uint32_le(s, y); in_uint32_le(s, cx); in_uint32_le(s, cy); LLOGLN(10, (" %d %d %d %d", x, y, cx ,cy)); + LLOGLN(10, (" rect_id %d rect_id_ack %d", g_rect_id, g_rect_id_ack)); box.x1 = x; box.y1 = y; @@ -926,6 +1042,8 @@ rdpup_process_msg(struct stream *s) RegionUninit(®); } + + else { rdpLog("unknown message type in rdpup_process_msg %d\n", msg_type); @@ -1870,7 +1988,7 @@ rdpup_send_area(struct image_data *id, int x, int y, int w, int h) d += id->shmem_lineBytes; ly += 1; } - size = 32; + size = 36; rdpup_pre_check(size); out_uint16_le(g_out_s, 60); out_uint16_le(g_out_s, size); @@ -1880,6 +1998,8 @@ rdpup_send_area(struct image_data *id, int x, int y, int w, int h) out_uint16_le(g_out_s, w); out_uint16_le(g_out_s, h); out_uint32_le(g_out_s, 0); + g_rect_id++; + out_uint32_le(g_out_s, g_rect_id); out_uint32_le(g_out_s, id->shmem_id); out_uint32_le(g_out_s, id->shmem_offset); out_uint16_le(g_out_s, id->width); @@ -2128,10 +2248,6 @@ rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) return 0; } - /* update use time / count */ - g_os_bitmaps[pDirtyPriv->rdpindex].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - LLOGLN(10, ("rdpup_check_dirty: got dirty")); rdpup_switch_os_surface(pDirtyPriv->rdpindex); rdpup_get_pixmap_image_rect(pDirtyPixmap, &id); @@ -2293,8 +2409,8 @@ rdpup_check_dirty_screen(rdpPixmapRec *pDirtyPriv) for (index = 0; index < count; index++) { box = REGION_RECTS(di->reg)[index]; - LLOGLN(10, (" RDI_IMGLL %d %d %d %d", box.x1, box.y1, - box.x2, box.y2)); + LLOGLN(10, (" RDI_IMGLL x %d y %d w %d h %d", box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1)); rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); } diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 081adf3c..6adf17f0 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -27,8 +27,8 @@ #include "trans.h" #include "list.h" #include "libxrdpinc.h" -#include "xrdp_types.h" #include "xrdp_constants.h" +#include "xrdp_types.h" #include "defines.h" #include "os_calls.h" #include "ssl_calls.h" diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index f421371d..b5787763 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -33,16 +33,27 @@ xrdp_cache_create(struct xrdp_wm *owner, self->wm = owner; self->session = session; self->use_bitmap_comp = client_info->use_bitmap_comp; - self->cache1_entries = client_info->cache1_entries; + + self->cache1_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache1_entries); + self->cache1_entries = MAX(self->cache1_entries, 0); self->cache1_size = client_info->cache1_size; - self->cache2_entries = client_info->cache2_entries; + + self->cache2_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache2_entries); + self->cache2_entries = MAX(self->cache2_entries, 0); self->cache2_size = client_info->cache2_size; - self->cache3_entries = client_info->cache3_entries; + + self->cache3_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache3_entries); + self->cache3_entries = MAX(self->cache3_entries, 0); self->cache3_size = client_info->cache3_size; + self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; self->bitmap_cache_version = client_info->bitmap_cache_version; self->pointer_cache_entries = client_info->pointer_cache_entries; self->xrdp_os_del_list = list_create(); + return self; } diff --git a/xrdp/xrdp_process.c b/xrdp/xrdp_process.c index 228bf630..4c52eaac 100644 --- a/xrdp/xrdp_process.c +++ b/xrdp/xrdp_process.c @@ -203,6 +203,9 @@ xrdp_process_main_loop(struct xrdp_process *self) else { g_writeln("xrdp_process_main_loop: libxrdp_process_incomming failed"); + /* this will try to send a disconnect, + maybe should check that connection got far enough */ + libxrdp_disconnect(self->session); } /* Run end in module */ xrdp_process_mod_end(self); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index e7bb7baf..5a43d9a9 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -195,7 +195,8 @@ struct xrdp_cache struct xrdp_palette_item palette_items[6]; /* bitmap */ int bitmap_stamp; - struct xrdp_bitmap_item bitmap_items[3][2000]; + struct xrdp_bitmap_item bitmap_items[XRDP_MAX_BITMAP_CACHE_ID] + [XRDP_MAX_BITMAP_CACHE_IDX]; int use_bitmap_comp; int cache1_entries; int cache1_size; diff --git a/xup/xup.c b/xup/xup.c index 475e64ed..da29f9f2 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -516,7 +516,8 @@ process_server_set_pointer_ex(struct mod *mod, struct stream *s) /******************************************************************************/ /* return error */ static int APP_CC -send_paint_rect_ack(struct mod *mod, int flags, int x, int y, int cx, int cy) +send_paint_rect_ack(struct mod *mod, int flags, int x, int y, int cx, int cy, + int frame_id) { int len; struct stream *s; @@ -526,6 +527,7 @@ send_paint_rect_ack(struct mod *mod, int flags, int x, int y, int cx, int cy) s_push_layer(s, iso_hdr, 4); out_uint16_le(s, 105); out_uint32_le(s, flags); + out_uint32_le(s, frame_id); out_uint32_le(s, x); out_uint32_le(s, y); out_uint32_le(s, cx); @@ -568,6 +570,7 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) int flags; int shmem_id; int shmem_offset; + int frame_id; char *bmpdata; char cur_data[32 * (32 * 3)]; char cur_mask[32 * (32 / 8)]; @@ -699,6 +702,7 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) in_uint16_le(s, cx); in_uint16_le(s, cy); in_uint32_le(s, flags); + in_uint32_le(s, frame_id); in_uint32_le(s, shmem_id); in_uint32_le(s, shmem_offset); in_uint16_le(s, width); @@ -728,7 +732,7 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) { rv = 1; } - send_paint_rect_ack(mod, flags, x, y, cx, cy); + send_paint_rect_ack(mod, flags, x, y, cx, cy, frame_id); break; default: