diff --git a/Makefile b/Makefile index 239f7d64..28121e40 100644 --- a/Makefile +++ b/Makefile @@ -5,17 +5,20 @@ all: world world: make -C vnc + make -C libxrdp make -C xrdp make -C sesman clean: make -C vnc clean + make -C libxrdp clean make -C xrdp clean make -C sesman clean install: mkdir -p $(DESTDIR) install xrdp/xrdp $(DESTDIR)/xrdp + install libxrdp/libxrdp.so $(DESTDIR)/libxrdp.so install xrdp/ad256.bmp $(DESTDIR)/ad256.bmp install xrdp/xrdp256.bmp $(DESTDIR)/xrdp256.bmp install xrdp/cursor0.cur $(DESTDIR)/cursor0.cur diff --git a/libxrdp/Makefile b/libxrdp/Makefile new file mode 100644 index 00000000..e19b0c80 --- /dev/null +++ b/libxrdp/Makefile @@ -0,0 +1,25 @@ + +LIBXRDPOBJ = libxrdp.o xrdp_tcp.o xrdp_iso.o xrdp_mcs.o \ + xrdp_sec.o xrdp_rdp.o xrdp_orders.o \ + xrdp_bitmap_compress.o \ + ../common/os_calls.o \ + ../common/ssl_calls.o + +CFLAGS = -Wall -O2 -I../common -fPIC +LDFLAGS = -shared +LIBS = -ldl -lcrypto +CC = gcc + +all: libxrdp + +static: $(LIBXRDPOBJ) + $(AR) rvu libxrdp.a $(LIBXRDPOBJ) + ranlib libxrdp.a + +libxrdp: $(LIBXRDPOBJ) + $(CC) $(LDFLAGS) -o libxrdp.so $(LIBXRDPOBJ) $(LIBS) + strip libxrdp.so + +clean: + rm -f $(LIBXRDPOBJ) libxrdp.a libxrdp.so + diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c new file mode 100644 index 00000000..263a99ae --- /dev/null +++ b/libxrdp/libxrdp.c @@ -0,0 +1,530 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + this is the interface to libxrdp + +*/ + +#include "libxrdp.h" + +/******************************************************************************/ +struct xrdp_session* EXPORT_CC +libxrdp_init(long id, int sck) +{ + struct xrdp_session* session; + + session = (struct xrdp_session*)g_malloc(sizeof(struct xrdp_session), 1); + session->id = id; + session->rdp = xrdp_rdp_create(session, sck); + session->orders = xrdp_orders_create(session, (struct xrdp_rdp*)session->rdp); + session->client_info = &(((struct xrdp_rdp*)session->rdp)->client_info); + return session; +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_exit(struct xrdp_session* session) +{ + if (session == 0) + { + return 0; + } + xrdp_orders_delete((struct xrdp_orders*)session->orders); + xrdp_rdp_delete((struct xrdp_rdp*)session->rdp); + g_free(session); + return 0; +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_disconnect(struct xrdp_session* session) +{ + return xrdp_rdp_disconnect((struct xrdp_rdp*)session->rdp); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_process_incomming(struct xrdp_session* session) +{ + return xrdp_rdp_incoming((struct xrdp_rdp*)session->rdp); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_process_data(struct xrdp_session* session) +{ + struct stream* s; + int cont; + int rv; + int code; + + cont = 1; + rv = 0; + make_stream(s); + init_stream(s, 8192); + while (cont && !session->term) + { + code = 0; + if (xrdp_rdp_recv((struct xrdp_rdp*)session->rdp, s, &code) != 0) + { + rv = 1; + break; + } + DEBUG(("libxrdp_process_data code %d\n\r", code)); + switch (code) + { + case -1: + xrdp_rdp_send_demand_active((struct xrdp_rdp*)session->rdp); + break; + case 0: + break; + case RDP_PDU_CONFIRM_ACTIVE: /* 3 */ + xrdp_rdp_process_confirm_active((struct xrdp_rdp*)session->rdp, s); + break; + case RDP_PDU_DATA: /* 7 */ + if (xrdp_rdp_process_data((struct xrdp_rdp*)session->rdp, s) != 0) + { + DEBUG(("libxrdp_process_data returned non zero\n\r")); + cont = 0; + session->term = 1; + } + break; + default: + g_printf("unknown in libxrdp_process_data\n\r"); + break; + } + if (cont) + { + cont = s->next_packet < s->end; + } + } + free_stream(s); + return rv; +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_send_palette(struct xrdp_session* session, int* palette) +{ + int i; + int color; + struct stream* s; + + if (session->client_info->bpp > 8) + { + return 0; + } + /* clear orders */ + libxrdp_orders_force_send(session); + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_PALETTE); + out_uint16_le(s, 0); + out_uint16_le(s, 256); /* # of colors */ + out_uint16_le(s, 0); + for (i = 0; i < 256; i++) + { + color = palette[i]; + out_uint8(s, color >> 16); + out_uint8(s, color >> 8); + out_uint8(s, color); + } + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_UPDATE); + free_stream(s); + /* send the orders palette too */ + libxrdp_orders_init(session); + libxrdp_orders_send_palette(session, palette, 0); + libxrdp_orders_send(session); + return 0; +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, + int bpp, char* data, int x, int y, int cx, int cy) +{ + int data_size; + int line_size; + int i; + int j; + int total_lines; + int lines_sending; + int Bpp; + int e; + int bufsize; + int total_bufsize; + int num_updates; + char* p_num_updates; + char* p; + char* q; + struct stream* s; + struct stream* temp_s; + + Bpp = (bpp + 7) / 8; + e = width % 4; + if (e != 0) + { + e = 4 - e; + } + line_size = width * Bpp; + make_stream(s); + init_stream(s, 8192); + if (session->client_info->use_bitmap_comp) + { + make_stream(temp_s); + init_stream(temp_s, 65536); + i = 0; + if (cy <= height) + { + i = cy; + } + while (i > 0) + { + total_bufsize = 0; + num_updates = 0; + xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_BITMAP); + p_num_updates = s->p; + out_uint8s(s, 2); /* num_updates set later */ + do + { + if (session->client_info->op1) + { + s_push_layer(s, channel_hdr, 18); + } + else + { + s_push_layer(s, channel_hdr, 26); + } + p = s->p; + lines_sending = xrdp_bitmap_compress(data, width, height, + s, bpp, + 4096 - total_bufsize, + i - 1, temp_s, e); + if (lines_sending == 0) + { + break; + } + num_updates++; + bufsize = s->p - p; + total_bufsize += bufsize; + i = i - lines_sending; + s_mark_end(s); + s_pop_layer(s, channel_hdr); + out_uint16_le(s, x); /* left */ + out_uint16_le(s, y + i); /* top */ + out_uint16_le(s, (x + cx) - 1); /* right */ + out_uint16_le(s, (y + i + lines_sending) - 1); /* bottom */ + out_uint16_le(s, width + e); /* width */ + out_uint16_le(s, lines_sending); /* height */ + out_uint16_le(s, bpp); /* bpp */ + if (session->client_info->op1) + { + out_uint16_le(s, 0x401); /* compress */ + out_uint16_le(s, bufsize); /* compressed size */ + j = (width + e) * Bpp; + j = j * lines_sending; + } + else + { + out_uint16_le(s, 0x1); /* compress */ + out_uint16_le(s, bufsize + 8); + out_uint8s(s, 2); /* pad */ + out_uint16_le(s, bufsize); /* compressed size */ + j = (width + e) * Bpp; + out_uint16_le(s, j); /* line size */ + j = j * lines_sending; + out_uint16_le(s, j); /* final size */ + } + if (j > 32768) + { + g_printf("error, decompressed size too big, its %d\n\r", j); + } + if (bufsize > 8192) + { + g_printf("error, compressed size too big, its %d\n\r", bufsize); + } + s->p = s->end; + } while (total_bufsize < 4096 && i > 0); + p_num_updates[0] = num_updates; + p_num_updates[1] = num_updates >> 8; + xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, + RDP_DATA_PDU_UPDATE); + if (total_bufsize > 8192) + { + g_printf("error, total compressed size too big, its %d\n\r", + total_bufsize); + } + } + free_stream(temp_s); + } + else + { + lines_sending = 0; + data_size = width * height * Bpp; + total_lines = height; + i = 0; + p = data; + if (line_size > 0 && total_lines > 0) + { + while (i < total_lines) + { + lines_sending = 4096 / (line_size + e * Bpp); + if (i + lines_sending > total_lines) + { + lines_sending = total_lines - i; + } + p = p + line_size * lines_sending; + xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_BITMAP); + out_uint16_le(s, 1); /* num updates */ + out_uint16_le(s, x); + out_uint16_le(s, y + i); + out_uint16_le(s, (x + cx) - 1); + out_uint16_le(s, (y + i + lines_sending) - 1); + out_uint16_le(s, width + e); + out_uint16_le(s, lines_sending); + out_uint16_le(s, bpp); /* bpp */ + out_uint16_le(s, 0); /* compress */ + out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */ + q = p; + for (j = 0; j < lines_sending; j++) + { + q = q - line_size; + out_uint8a(s, q, line_size) + out_uint8s(s, e * Bpp); + } + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, + RDP_DATA_PDU_UPDATE); + i = i + lines_sending; + } + } + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, + char* data, char* mask, int x, int y) +{ + struct stream* s; + char* p; + int i; + int j; + + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); + out_uint16_le(s, RDP_POINTER_COLOR); + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, cache_idx); /* cache_idx */ + out_uint16_le(s, x); + out_uint16_le(s, y); + out_uint16_le(s, 32); + out_uint16_le(s, 32); + out_uint16_le(s, 128); + out_uint16_le(s, 3072); + p = data; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; + } + } + out_uint8a(s, mask, 128); /* mask */ + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_set_pointer(struct xrdp_session* session, int cache_idx) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); + out_uint16_le(s, RDP_POINTER_CACHED); + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, cache_idx); /* cache_idx */ + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); + free_stream(s); + return 0; +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_init(struct xrdp_session* session) +{ + return xrdp_orders_init((struct xrdp_orders*)session->orders); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_send(struct xrdp_session* session) +{ + return xrdp_orders_send((struct xrdp_orders*)session->orders); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_force_send(struct xrdp_session* session) +{ + return xrdp_orders_force_send((struct xrdp_orders*)session->orders); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_rect(struct xrdp_session* session, int x, int y, + int cx, int cy, int color, struct xrdp_rect* rect) +{ + return xrdp_orders_rect((struct xrdp_orders*)session->orders, + x, y, cx, cy, color, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_screen_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int srcx, int srcy, + int rop, struct xrdp_rect* rect) +{ + return xrdp_orders_screen_blt((struct xrdp_orders*)session->orders, + x, y, cx, cy, srcx, srcy, rop, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_pat_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int rop, int bg_color, + int fg_color, struct xrdp_brush* brush, + struct xrdp_rect* rect) +{ + return xrdp_orders_pat_blt((struct xrdp_orders*)session->orders, + x, y, cx, cy, rop, bg_color, fg_color, + brush, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_dest_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int rop, + struct xrdp_rect* rect) +{ + return xrdp_orders_dest_blt((struct xrdp_orders*)session->orders, + x, y, cx, cy, rop, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_line(struct xrdp_session* session, int mix_mode, + int startx, int starty, + int endx, int endy, int rop, int bg_color, + struct xrdp_pen* pen, + struct xrdp_rect* rect) +{ + return xrdp_orders_line((struct xrdp_orders*)session->orders, + mix_mode, startx, starty, endx, endy, + rop, bg_color, pen, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, + int color_table, int x, int y, int cx, int cy, + int rop, int srcx, int srcy, + int cache_idx, struct xrdp_rect* rect) +{ + return xrdp_orders_mem_blt((struct xrdp_orders*)session->orders, + cache_id, color_table, x, y, cx, cy, rop, + srcx, srcy, cache_idx, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_text(struct xrdp_session* session, + int font, int flags, int mixmode, + int fg_color, int bg_color, + int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char* data, int data_len, + struct xrdp_rect* rect) +{ + return xrdp_orders_text((struct xrdp_orders*)session->orders, + font, flags, mixmode, fg_color, bg_color, + clip_left, clip_top, clip_right, clip_bottom, + box_left, box_top, box_right, box_bottom, + x, y, data, data_len, rect); +} + +/******************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_palette(struct xrdp_session* session, int* palette, + int cache_id) +{ + return xrdp_orders_send_palette((struct xrdp_orders*)session->orders, + palette, cache_id); +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_raw_bitmap(struct xrdp_session* session, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx) +{ + return xrdp_orders_send_raw_bitmap((struct xrdp_orders*)session->orders, + width, height, bpp, data, + cache_id, cache_idx); +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_bitmap(struct xrdp_session* session, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx) +{ + return xrdp_orders_send_bitmap((struct xrdp_orders*)session->orders, + width, height, bpp, data, + cache_id, cache_idx); +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_font(struct xrdp_session* session, + struct xrdp_font_char* font_char, + int font_index, int char_index) +{ + return xrdp_orders_send_font((struct xrdp_orders*)session->orders, + font_char, font_index, char_index); +} diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h new file mode 100644 index 00000000..29c2bdb6 --- /dev/null +++ b/libxrdp/libxrdp.h @@ -0,0 +1,342 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + libxrdp header + +*/ + +#if !defined(LIBXRDP_H) +#define LIBXRDP_H + +#include "arch.h" +#include "parse.h" +#include "xrdp_constants.h" +#include "defines.h" +#include "os_calls.h" +#include "ssl_calls.h" +#include "list.h" +#include "file.h" +#include "libxrdpinc.h" + +/* tcp */ +struct xrdp_tcp +{ + int sck; + int sck_closed; + struct xrdp_iso* iso_layer; /* owner */ +}; + +/* iso */ +struct xrdp_iso +{ + struct xrdp_mcs* mcs_layer; /* owner */ + struct xrdp_tcp* tcp_layer; +}; + +/* mcs */ +struct xrdp_mcs +{ + struct xrdp_sec* sec_layer; /* owner */ + struct xrdp_iso* iso_layer; + int userid; + int chanid; + struct stream* client_mcs_data; + struct stream* server_mcs_data; +}; + +/* sec */ +struct xrdp_sec +{ + struct xrdp_rdp* rdp_layer; /* owner */ + struct xrdp_mcs* mcs_layer; + char server_random[32]; + char client_random[64]; + char client_crypt_random[72]; + struct stream client_mcs_data; + struct stream server_mcs_data; + int decrypt_use_count; + int encrypt_use_count; + char decrypt_key[16]; + char encrypt_key[16]; + char decrypt_update_key[16]; + char encrypt_update_key[16]; + int rc4_key_size; + int rc4_key_len; + char sign_key[16]; + void* decrypt_rc4_info; + void* encrypt_rc4_info; +}; + +/* rdp */ +struct xrdp_rdp +{ + struct xrdp_session* session; + struct xrdp_sec* sec_layer; + int share_id; + int mcs_channel; + struct xrdp_client_info client_info; +}; + +/* orders */ +struct xrdp_orders +{ + struct stream* out_s; + struct xrdp_rdp* rdp_layer; + struct xrdp_session* session; + struct xrdp_wm* wm; + + char* order_count_ptr; /* pointer to count, set when sending */ + int order_count; + int order_level; /* inc for every call to xrdp_orders_init */ + + int last_order; /* last order sent */ + + int clip_left; /* RDP_ORDER_BOUNDS, RDP_ORDER_LASTBOUNDS */ + int clip_top; + int clip_right; + int clip_bottom; + + int rect_x; /* RDP_ORDER_RECT */ + int rect_y; + int rect_cx; + int rect_cy; + int rect_color; + + int scr_blt_x; /* RDP_ORDER_SCREENBLT */ + int scr_blt_y; + int scr_blt_cx; + int scr_blt_cy; + int scr_blt_rop; + int scr_blt_srcx; + int scr_blt_srcy; + + int pat_blt_x; /* RDP_ORDER_PATBLT */ + int pat_blt_y; + int pat_blt_cx; + int pat_blt_cy; + int pat_blt_rop; + int pat_blt_bg_color; + int pat_blt_fg_color; + struct xrdp_brush pat_blt_brush; + + int dest_blt_x; /* RDP_ORDER_DESTBLT */ + int dest_blt_y; + int dest_blt_cx; + int dest_blt_cy; + int dest_blt_rop; + + int line_mix_mode; /* RDP_ORDER_LINE */ + int line_startx; + int line_starty; + int line_endx; + int line_endy; + int line_bg_color; + int line_rop; + struct xrdp_pen line_pen; + + int mem_blt_color_table; /* RDP_ORDER_MEMBLT */ + int mem_blt_cache_id; + int mem_blt_x; + int mem_blt_y; + int mem_blt_cx; + int mem_blt_cy; + int mem_blt_rop; + int mem_blt_srcx; + int mem_blt_srcy; + int mem_blt_cache_idx; + + int text_font; /* RDP_ORDER_TEXT2 */ + int text_flags; + int text_unknown; + int text_mixmode; + int text_fg_color; + int text_bg_color; + int text_clip_left; + int text_clip_top; + int text_clip_right; + int text_clip_bottom; + int text_box_left; + int text_box_top; + int text_box_right; + int text_box_bottom; + int text_x; + int text_y; + int text_len; + char* text_data; +}; + +/* xrdp_tcp.c */ +struct xrdp_tcp* APP_CC +xrdp_tcp_create(struct xrdp_iso* owner, int sck); +void APP_CC +xrdp_tcp_delete(struct xrdp_tcp* self); +int APP_CC +xrdp_tcp_init(struct xrdp_tcp* self, struct stream* s); +int APP_CC +xrdp_tcp_recv(struct xrdp_tcp* self, struct stream* s, int len); +int APP_CC +xrdp_tcp_send(struct xrdp_tcp* self, struct stream* s); + +/* xrdp_iso.c */ +struct xrdp_iso* APP_CC +xrdp_iso_create(struct xrdp_mcs* owner, int sck); +void APP_CC +xrdp_iso_delete(struct xrdp_iso* self); +int APP_CC +xrdp_iso_init(struct xrdp_iso* self, struct stream* s); +int APP_CC +xrdp_iso_recv(struct xrdp_iso* self, struct stream* s); +int APP_CC +xrdp_iso_send(struct xrdp_iso* self, struct stream* s); +int APP_CC +xrdp_iso_incoming(struct xrdp_iso* self); + +/* xrdp_mcs.c */ +struct xrdp_mcs* APP_CC +xrdp_mcs_create(struct xrdp_sec* owner, int sck, + struct stream* client_mcs_data, + struct stream* server_mcs_data); +void APP_CC +xrdp_mcs_delete(struct xrdp_mcs* self); +int APP_CC +xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s); +int APP_CC +xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan); +int APP_CC +xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s); +int APP_CC +xrdp_mcs_incoming(struct xrdp_mcs* self); +int APP_CC +xrdp_mcs_disconnect(struct xrdp_mcs* self); + +/* xrdp_sec.c */ +struct xrdp_sec* APP_CC +xrdp_sec_create(struct xrdp_rdp* owner, int sck); +void APP_CC +xrdp_sec_delete(struct xrdp_sec* self); +int APP_CC +xrdp_sec_init(struct xrdp_sec* self, struct stream* s); +int APP_CC +xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan); +int APP_CC +xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int flags); +int APP_CC +xrdp_sec_incoming(struct xrdp_sec* self); +int APP_CC +xrdp_sec_disconnect(struct xrdp_sec* self); + +/* xrdp_rdp.c */ +struct xrdp_rdp* APP_CC +xrdp_rdp_create(struct xrdp_session* session, int sck); +void APP_CC +xrdp_rdp_delete(struct xrdp_rdp* self); +int APP_CC +xrdp_rdp_init(struct xrdp_rdp* self, struct stream* s); +int APP_CC +xrdp_rdp_init_data(struct xrdp_rdp* self, struct stream* s); +int APP_CC +xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code); +int APP_CC +xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type); +int APP_CC +xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s, + int data_pdu_type); +int APP_CC +xrdp_rdp_incoming(struct xrdp_rdp* self); +int APP_CC +xrdp_rdp_send_demand_active(struct xrdp_rdp* self); +int APP_CC +xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s); +int APP_CC +xrdp_rdp_process_data(struct xrdp_rdp* self, struct stream* s); +int APP_CC +xrdp_rdp_disconnect(struct xrdp_rdp* self); + +/* xrdp_orders.c */ +struct xrdp_orders* APP_CC +xrdp_orders_create(struct xrdp_session* session, + struct xrdp_rdp* rdp_layer); +void APP_CC +xrdp_orders_delete(struct xrdp_orders* self); +int APP_CC +xrdp_orders_init(struct xrdp_orders* self); +int APP_CC +xrdp_orders_send(struct xrdp_orders* self); +int APP_CC +xrdp_orders_force_send(struct xrdp_orders* self); +int APP_CC +xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, + int color, struct xrdp_rect* rect); +int APP_CC +xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int srcx, int srcy, + int rop, struct xrdp_rect* rect); +int APP_CC +xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int rop, int bg_color, + int fg_color, struct xrdp_brush* brush, + struct xrdp_rect* rect); +int APP_CC +xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int rop, + struct xrdp_rect* rect); +int APP_CC +xrdp_orders_line(struct xrdp_orders* self, int mix_mode, + int startx, int starty, + int endx, int endy, int rop, int bg_color, + struct xrdp_pen* pen, + struct xrdp_rect* rect); +int APP_CC +xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, + int color_table, int x, int y, int cx, int cy, + int rop, int srcx, int srcy, + int cache_idx, struct xrdp_rect* rect); +int APP_CC +xrdp_orders_text(struct xrdp_orders* self, + int font, int flags, int mixmode, + int fg_color, int bg_color, + int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char* data, int data_len, + struct xrdp_rect* rect); +int APP_CC +xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, + int cache_id); +int APP_CC +xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx); +int APP_CC +xrdp_orders_send_bitmap(struct xrdp_orders* self, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx); +int APP_CC +xrdp_orders_send_font(struct xrdp_orders* self, + struct xrdp_font_char* font_char, + int font_index, int char_index); + +/* xrdp_bitmap_compress.c */ +int APP_CC +xrdp_bitmap_compress(char* in_data, int width, int height, + struct stream* s, int bpp, int byte_limit, + int start_line, struct stream* temp, + int e); + +#endif diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h new file mode 100644 index 00000000..38857208 --- /dev/null +++ b/libxrdp/libxrdpinc.h @@ -0,0 +1,170 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + header file for use with libxrdp.so / xrdp.dll + +*/ + +#if !defined(LIBXRDPINC_H) +#define LIBXRDPINC_H + +struct xrdp_client_info +{ + int bpp; + int width; + int height; + int cache1_entries; + int cache1_size; + int cache2_entries; + int cache2_size; + int cache3_entries; + int cache3_size; + int pointer_cache_entries; + int use_bitmap_comp; + int use_bitmap_cache; + int op1; /* use smaller bitmap header, todo */ + int desktop_cache; + int use_compact_packets; /* rdp5 smaller packets */ +}; + +struct xrdp_brush +{ + int x_orgin; + int y_orgin; + int style; + char pattern[8]; +}; + +struct xrdp_pen +{ + int style; + int width; + int color; +}; + +struct xrdp_font_char +{ + int offset; + int baseline; + int width; + int height; + int incby; + char* data; +}; + +struct xrdp_rect +{ + int left; + int top; + int right; + int bottom; +}; + +struct xrdp_session +{ + long id; + int sck; + int term; /* do we need this */ + int (*callback)(long id, int msg, long param1, long param2, long param3, + long param4); + void* rdp; + void* orders; + struct xrdp_client_info* client_info; + int up_and_running; +}; + +struct xrdp_session* +libxrdp_init(long id, int sck); +int +libxrdp_exit(struct xrdp_session* session); +int +libxrdp_disconnect(struct xrdp_session* session); +int +libxrdp_process_incomming(struct xrdp_session* session); +int +libxrdp_process_data(struct xrdp_session* session); +int +libxrdp_send_palette(struct xrdp_session* session, int* palette); +int +libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, + int bpp, char* data, int x, int y, int cx, int cy); +int +libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, + char* data, char* mask, int x, int y); +int +libxrdp_set_pointer(struct xrdp_session* session, int cache_idx); +int +libxrdp_orders_init(struct xrdp_session* session); +int +libxrdp_orders_send(struct xrdp_session* session); +int +libxrdp_orders_force_send(struct xrdp_session* session); +int +libxrdp_orders_rect(struct xrdp_session* session, int x, int y, + int cx, int cy, int color, struct xrdp_rect* rect); +int +libxrdp_orders_screen_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int srcx, int srcy, + int rop, struct xrdp_rect* rect); +int +libxrdp_orders_pat_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int rop, int bg_color, + int fg_color, struct xrdp_brush* brush, + struct xrdp_rect* rect); +int +libxrdp_orders_dest_blt(struct xrdp_session* session, int x, int y, + int cx, int cy, int rop, + struct xrdp_rect* rect); +int +libxrdp_orders_line(struct xrdp_session* session, int mix_mode, + int startx, int starty, + int endx, int endy, int rop, int bg_color, + struct xrdp_pen* pen, + struct xrdp_rect* rect); +int +libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, + int color_table, int x, int y, int cx, int cy, + int rop, int srcx, int srcy, + int cache_idx, struct xrdp_rect* rect); +int +libxrdp_orders_text(struct xrdp_session* session, + int font, int flags, int mixmode, + int fg_color, int bg_color, + int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char* data, int data_len, + struct xrdp_rect* rect); +int +libxrdp_orders_send_palette(struct xrdp_session* session, int* palette, + int cache_id); +int +libxrdp_orders_send_raw_bitmap(struct xrdp_session* session, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx); +int +libxrdp_orders_send_bitmap(struct xrdp_session* session, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx); +int +libxrdp_orders_send_font(struct xrdp_session* session, + struct xrdp_font_char* font_char, + int font_index, int char_index); + +#endif diff --git a/libxrdp/makefile_win32 b/libxrdp/makefile_win32 new file mode 100755 index 00000000..4ab297ef --- /dev/null +++ b/libxrdp/makefile_win32 @@ -0,0 +1,42 @@ +# borland windows makefile +# +# this assumes openssl and borland free command line tools are installed +# this assumes c:\windows is windows directory +# +# run 'set PATH=c:\borland\bcc55\bin' and run 'make -f makefile_win32 all' +# + +XRDPOBJ = libxrdp.obj xrdp_tcp.obj xrdp_iso.obj xrdp_mcs.obj \ + xrdp_sec.obj xrdp_rdp.obj xrdp_orders.obj \ + xrdp_bitmap_compress.obj \ + list.obj \ + file.obj \ + os_calls.obj \ + ssl_calls.obj + +CFLAGS = -w- -O2 -I../common -Ic:/borland/bcc55/include -Ic:/openssl/include +LDFLAGS = -Lc:/borland/bcc55/lib + +xrdp: $(XRDPOBJ) + $(CC) $(LDFLAGS) -WD -exrdp.dll libeay32.lib $(XRDPOBJ) + +all: lib xrdp + +clean: + del $(XRDPOBJ) xrdp.dll + +lib: + implib -a -w libeay32.lib c:/windows/system32/libeay32.dll + +list.obj: + $(CC) $(CFLAGS) -c ../common/list.c + +file.obj: + $(CC) $(CFLAGS) -c ../common/file.c + +os_calls.obj: + $(CC) $(CFLAGS) -c ../common/os_calls.c + +ssl_calls.obj: + $(CC) $(CFLAGS) -c ../common/ssl_calls.c + diff --git a/libxrdp/xrdp_bitmap_compress.c b/libxrdp/xrdp_bitmap_compress.c new file mode 100644 index 00000000..b85162f2 --- /dev/null +++ b/libxrdp/xrdp_bitmap_compress.c @@ -0,0 +1,1002 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + bitmap compressor + +*/ + +#include "libxrdp.h" + +/*****************************************************************************/ +#define IN_PIXEL8(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ +{ \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ +} + +/*****************************************************************************/ +#define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ +{ \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ +} + +/*****************************************************************************/ +/* color */ +#define OUT_COLOR_COUNT1(in_count, in_s, in_data) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x60); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf3); \ + out_uint16_le(in_s, in_count); \ + out_uint8(in_s, in_data); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* color */ +#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x60); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_data); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf3); \ + out_uint16_le(in_s, in_count); \ + out_uint16_le(in_s, in_data); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* copy */ +#define OUT_COPY_COUNT1(in_count, in_s, in_data) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x80); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf4); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + } \ + in_count = 0; \ + init_stream(in_data, 0); \ +} + +/*****************************************************************************/ +/* copy */ +#define OUT_COPY_COUNT2(in_count, in_s, in_data) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + out_uint8(in_s, temp); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x80); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf4); \ + out_uint16_le(in_s, in_count); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + } \ + in_count = 0; \ + init_stream(in_data, 0); \ +} + +/*****************************************************************************/ +/* bicolor */ +#define OUT_BICOLOR_COUNT1(in_count, in_s, in_color1, in_color2) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + out_uint8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf8); \ + temp = in_count / 2; \ + out_uint16_le(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* bicolor */ +#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + out_uint8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf8); \ + temp = in_count / 2; \ + out_uint16_le(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* fill */ +#define OUT_FILL_COUNT1(in_count, in_s) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + out_uint8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x0); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf0); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* fill */ +#define OUT_FILL_COUNT2(in_count, in_s) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + out_uint8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x0); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf0); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* mix */ +#define OUT_MIX_COUNT1(in_count, in_s) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + out_uint8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x20); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf1); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* mix */ +#define OUT_MIX_COUNT2(in_count, in_s) \ +{ \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + out_uint8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x20); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf1); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* fom */ +#define OUT_FOM_COUNT1(in_count, in_s, in_mask, in_mask_len) \ +{ \ + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + out_uint8(in_s, 0x40); \ + temp = in_count - 1; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf2); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +/* fom */ +#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ +{ \ + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + out_uint8(in_s, 0x40); \ + temp = in_count - 1; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf2); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ +} + +/*****************************************************************************/ +#define TEST_FILL \ +((last_line == 0 && pixel == 0) || \ + (last_line != 0 && pixel == ypixel)) +#define TEST_MIX \ +((last_line == 0 && pixel == mix) || \ + (last_line != 0 && pixel == (ypixel ^ mix))) +#define TEST_FOM (TEST_FILL || TEST_MIX) +#define TEST_COLOR (pixel == last_pixel) +#define TEST_BICOLOR \ +( \ + (pixel != last_pixel) && \ + ( \ + (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ + (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ + ) \ +) +#define RESET_COUNTS \ +{ \ + bicolor_count = 0; \ + fill_count = 0; \ + color_count = 0; \ + mix_count = 0; \ + fom_count = 0; \ + fom_mask_len = 0; \ + bicolor_spin = 0; \ +} + +/*****************************************************************************/ +int APP_CC +xrdp_bitmap_compress(char* in_data, int width, int height, + struct stream* s, int bpp, int byte_limit, + int start_line, struct stream* temp_s, + int e) +{ + char* line; + char* last_line; + char fom_mask[8192]; + int lines_sent; + int pixel; + int count; + int color_count; + int last_pixel; + int bicolor_count; + int bicolor1; + int bicolor2; + int bicolor_spin; + int end; + int i; + int out_count; + int ypixel; + int last_ypixel; + int fill_count; + int mix_count; + int mix; + int fom_count; + int fom_mask_len; + int temp; /* used in macros */ + + init_stream(temp_s, 0); + fom_mask_len = 0; + last_line = 0; + lines_sent = 0; + end = width + e; + count = 0; + color_count = 0; + last_pixel = 0; + last_ypixel = 0; + bicolor_count = 0; + bicolor1 = 0; + bicolor2 = 0; + bicolor_spin = 0; + fill_count = 0; + mix_count = 0; + fom_count = 0; + if (bpp == 8) + { + mix = 0xff; + out_count = end; + line = in_data + width * start_line; + while (start_line >= 0 && out_count < 32768) + { + i = (s->p - s->data) + count; + if (i - color_count >= byte_limit && + i - bicolor_count >= byte_limit && + i - fill_count >= byte_limit && + i - mix_count >= byte_limit && + i - fom_count >= byte_limit) + { + break; + } + out_count += end; + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL8(line, i, 0, width, last_pixel, pixel); + IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel); + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + fill_count = 0; + } + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + mix_count = 0; + } + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_COLOR_COUNT1(color_count, s, last_pixel); + RESET_COUNTS; + } + color_count = 0; + } + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + } + RESET_COUNTS; + } + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + fom_count = 0; + fom_mask_len = 0; + } + if (TEST_FILL) + { + fill_count++; + } + if (TEST_MIX) + { + mix_count++; + } + if (TEST_COLOR) + { + color_count++; + } + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + fom_count++; + } + out_uint8(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + fill_count = 0; + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + mix_count = 0; + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + fom_count = 0; + fom_mask_len = 0; + } + last_line = line; + line = line - width; + start_line--; + lines_sent++; + } + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_COLOR_COUNT1(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + } + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT1(count, s, temp_s); + } + } + else if (bpp == 16) + { + mix = 0xffff; + out_count = end * 2; + line = in_data + width * start_line * 2; + while (start_line >= 0 && out_count < 32768) + { + i = (s->p - s->data) + count * 2; + if (i - (color_count * 2) >= byte_limit && + i - (bicolor_count * 2) >= byte_limit && + i - (fill_count * 2) >= byte_limit && + i - (mix_count * 2) >= byte_limit && + i - (fom_count * 2) >= byte_limit) + { + break; + } + out_count += end * 2; + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL16(line, i, 0, width, last_pixel, pixel); + IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + fill_count = 0; + } + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + mix_count = 0; + } + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + RESET_COUNTS; + } + color_count = 0; + } + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + } + RESET_COUNTS; + } + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + fom_count = 0; + fom_mask_len = 0; + } + if (TEST_FILL) + { + fill_count++; + } + if (TEST_MIX) + { + mix_count++; + } + if (TEST_COLOR) + { + color_count++; + } + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + fom_count++; + } + out_uint16_le(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + fill_count = 0; + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + mix_count = 0; + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + fom_count = 0; + fom_mask_len = 0; + } + last_line = line; + line = line - width * 2; + start_line--; + lines_sent++; + } + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + } + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT2(count, s, temp_s); + } + } + return lines_sent; +} diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c new file mode 100644 index 00000000..7cd56bf9 --- /dev/null +++ b/libxrdp/xrdp_iso.c @@ -0,0 +1,195 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + iso layer + +*/ + +#include "libxrdp.h" + +/*****************************************************************************/ +struct xrdp_iso* APP_CC +xrdp_iso_create(struct xrdp_mcs* owner, int sck) +{ + struct xrdp_iso* self; + + self = (struct xrdp_iso*)g_malloc(sizeof(struct xrdp_iso), 1); + self->mcs_layer = owner; + self->tcp_layer = xrdp_tcp_create(self, sck); + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_iso_delete(struct xrdp_iso* self) +{ + if (self == 0) + { + return; + } + xrdp_tcp_delete(self->tcp_layer); + g_free(self); +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_iso_recv_msg(struct xrdp_iso* self, struct stream* s, int* code) +{ + int ver; + int len; + + *code = 0; + if (xrdp_tcp_recv(self->tcp_layer, s, 4) != 0) + { + return 1; + } + in_uint8(s, ver); + if (ver != 3) + { + return 1; + } + in_uint8s(s, 1); + in_uint16_be(s, len); + if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) + { + return 1; + } + in_uint8s(s, 1); + in_uint8(s, *code); + if (*code == ISO_PDU_DT) + { + in_uint8s(s, 1); + } + else + { + in_uint8s(s, 5); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_iso_recv(struct xrdp_iso* self, struct stream* s) +{ + int code; + + DEBUG((" in xrdp_iso_recv\n\r")); + if (xrdp_iso_recv_msg(self, s, &code) != 0) + { + DEBUG((" out xrdp_iso_recv xrdp_iso_recv_msg return non zero\n\r")); + return 1; + } + if (code != ISO_PDU_DT) + { + DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT\n\r")); + return 1; + } + DEBUG((" out xrdp_iso_recv\n\r")); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_iso_send_msg(struct xrdp_iso* self, struct stream* s, int code) +{ + if (xrdp_tcp_init(self->tcp_layer, s) != 0) + { + return 1; + } + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 11); /* length */ + out_uint8(s, 8); + out_uint8(s, code); + out_uint16_le(s, 0); + out_uint16_le(s, 0); + out_uint8(s, 0); + s_mark_end(s); + if (xrdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_iso_incoming(struct xrdp_iso* self) +{ + int code; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + DEBUG((" in xrdp_iso_incoming\n\r")); + if (xrdp_iso_recv_msg(self, s, &code) != 0) + { + free_stream(s); + return 1; + } + if (code != ISO_PDU_CR) + { + free_stream(s); + return 1; + } + if (xrdp_iso_send_msg(self, s, ISO_PDU_CC) != 0) + { + free_stream(s); + return 1; + } + DEBUG((" out xrdp_iso_incoming\n\r")); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_iso_init(struct xrdp_iso* self, struct stream* s) +{ + xrdp_tcp_init(self->tcp_layer, s); + s_push_layer(s, iso_hdr, 7); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_iso_send(struct xrdp_iso* self, struct stream* s) +{ + int len; + + DEBUG((" in xrdp_iso_send\n\r")); + s_pop_layer(s, iso_hdr); + len = s->end - s->p; + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, len); + out_uint8(s, 2); + out_uint8(s, ISO_PDU_DT); + out_uint8(s, 0x80); + if (xrdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + DEBUG((" out xrdp_iso_send\n\r")); + return 0; +} diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c new file mode 100644 index 00000000..3fed1a0b --- /dev/null +++ b/libxrdp/xrdp_mcs.c @@ -0,0 +1,629 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + mcs layer + +*/ + +#include "libxrdp.h" + +/*****************************************************************************/ +struct xrdp_mcs* APP_CC +xrdp_mcs_create(struct xrdp_sec* owner, int sck, + struct stream* client_mcs_data, + struct stream* server_mcs_data) +{ + struct xrdp_mcs* self; + + self = (struct xrdp_mcs*)g_malloc(sizeof(struct xrdp_mcs), 1); + self->sec_layer = owner; + self->userid = 1; + self->chanid = 1001; + self->client_mcs_data = client_mcs_data; + self->server_mcs_data = server_mcs_data; + self->iso_layer = xrdp_iso_create(self, sck); + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_mcs_delete(struct xrdp_mcs* self) +{ + if (self == 0) + { + return; + } + xrdp_iso_delete(self->iso_layer); + g_free(self); +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int chanid) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8(s, (MCS_CJCF << 2) | 2); + out_uint8(s, 0); + out_uint16_be(s, self->userid); + out_uint16_be(s, chanid); + out_uint16_be(s, chanid); + s_mark_end(s); + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan) +{ + int appid; + int opcode; + int len; + + DEBUG((" in xrdp_mcs_recv\n\r")); + while (1) + { + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + DEBUG((" out xrdp_mcs_recv xrdp_iso_recv returned non zero\n\r")); + return 1; + } + in_uint8(s, opcode); + appid = opcode >> 2; + if (appid == MCS_DPUM) + { + DEBUG((" out xrdp_mcs_recv appid != MCS_DPUM\n\r")); + return 1; + } + if (appid == MCS_CJRQ) + { + xrdp_mcs_send_cjcf(self, self->userid + MCS_USERCHANNEL_BASE); + continue; + } + break; + } + if (appid != MCS_SDRQ) + { + DEBUG((" out xrdp_mcs_recv err got 0x%x need MCS_SDRQ\n\r", appid)); + return 1; + } + in_uint8s(s, 2); + in_uint16_be(s, *chan); + in_uint8s(s, 1); + in_uint8(s, len); + if (len & 0x80) + { + in_uint8s(s, 1); + } + DEBUG((" out xrdp_mcs_recv\n\r")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_parse_header(struct xrdp_mcs* self, struct stream* s, + int tag_val, int* len) +{ + int tag; + int l; + int i; + + if (tag_val > 0xff) + { + in_uint16_be(s, tag); + } + else + { + in_uint8(s, tag); + } + if (tag != tag_val) + { + return 1; + } + in_uint8(s, l); + if (l & 0x80) + { + l = l & ~0x80; + *len = 0; + while (l > 0) + { + in_uint8(s, i); + *len = (*len << 8) | i; + l--; + } + } + else + { + *len = l; + } + if (s_check(s)) + { + return 0; + } + else + { + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_parse_domain_params(struct xrdp_mcs* self, struct stream* s) +{ + int len; + + if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) + { + return 1; + } + in_uint8s(s, len); + if (s_check(s)) + { + return 0; + } + else + { + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_recv_connect_initial(struct xrdp_mcs* self) +{ + int len; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0) + { + free_stream(s); + return 1; + } + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + 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); + in_uint8s(s, len); + s_mark_end(self->client_mcs_data); + if (s_check_end(s)) + { + free_stream(s); + return 0; + } + else + { + free_stream(s); + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_recv_edrq(struct xrdp_mcs* self) +{ + int opcode; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); + if ((opcode >> 2) != MCS_EDRQ) + { + free_stream(s); + return 1; + } + in_uint8s(s, 2); + in_uint8s(s, 2); + if (opcode & 2) + { + in_uint16_be(s, self->userid); + } + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_recv_aurq(struct xrdp_mcs* self) +{ + int opcode; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); + if ((opcode >> 2) != MCS_AURQ) + { + free_stream(s); + return 1; + } + if (opcode & 2) + { + in_uint16_be(s, self->userid); + } + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_send_aucf(struct xrdp_mcs* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8(s, ((MCS_AUCF << 2) | 2)); + out_uint8s(s, 1); + out_uint16_be(s, self->userid); + s_mark_end(s); + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_recv_cjrq(struct xrdp_mcs* self) +{ + int opcode; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); + if ((opcode >> 2) != MCS_CJRQ) + { + free_stream(s); + return 1; + } + in_uint8s(s, 4); + if (opcode & 2) + { + in_uint8s(s, 2); + } + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_out_header(struct xrdp_mcs* self, struct stream* s, + int tag_val, int len) +{ + if (tag_val > 0xff) + { + out_uint16_be(s, tag_val); + } + else + { + out_uint8(s, tag_val); + } + if (len >= 0x80) + { + out_uint8(s, 0x82); + out_uint16_be(s, len); + } + else + { + out_uint8(s, len); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_out_int8(struct xrdp_mcs* self, struct stream* s, int value) +{ + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); + out_uint8(s, value); + return 0; +} + +#if 0 /* not used */ +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_out_int16(struct xrdp_mcs* self, struct stream* s, int value) +{ + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; +} +#endif + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_out_int24(struct xrdp_mcs* self, struct stream* s, int value) +{ + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); + out_uint8(s, (value >> 16)); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_out_domain_params(struct xrdp_mcs* self, struct stream* s, + int max_channels, + int max_users, int max_tokens, + int max_pdu_size) +{ + xrdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26); + xrdp_mcs_ber_out_int8(self, s, max_channels); + xrdp_mcs_ber_out_int8(self, s, max_users); + xrdp_mcs_ber_out_int8(self, s, max_tokens); + xrdp_mcs_ber_out_int8(self, s, 1); + xrdp_mcs_ber_out_int8(self, s, 0); + xrdp_mcs_ber_out_int8(self, s, 1); + xrdp_mcs_ber_out_int24(self, s, max_pdu_size); + xrdp_mcs_ber_out_int8(self, s, 2); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_send_connect_response(struct xrdp_mcs* self) +{ + int data_len; + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + data_len = self->server_mcs_data->end - self->server_mcs_data->data; + xrdp_iso_init(self->iso_layer, s); + xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, 313); + xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1); + out_uint8(s, 0); + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); + out_uint8(s, 0); + xrdp_mcs_out_domain_params(self, s, 2, 2, 0, 0xffff); + xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); + /* mcs data */ + out_uint8a(s, self->server_mcs_data->data, data_len); + s_mark_end(s); + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_mcs_incoming(struct xrdp_mcs* self) +{ + DEBUG((" in xrdp_mcs_incoming\n\r")); + if (xrdp_iso_incoming(self->iso_layer) != 0) + { + return 1; + } + if (xrdp_mcs_recv_connect_initial(self) != 0) + { + return 1; + } + if (xrdp_mcs_send_connect_response(self) != 0) + { + return 1; + } + if (xrdp_mcs_recv_edrq(self) != 0) + { + return 1; + } + if (xrdp_mcs_recv_aurq(self) != 0) + { + return 1; + } + if (xrdp_mcs_send_aucf(self) != 0) + { + return 1; + } + if (xrdp_mcs_recv_cjrq(self) != 0) + { + return 1; + } + if (xrdp_mcs_send_cjcf(self, self->userid + MCS_USERCHANNEL_BASE) != 0) + { + return 1; + } + if (xrdp_mcs_recv_cjrq(self) != 0) + { + return 1; + } + if (xrdp_mcs_send_cjcf(self, MCS_GLOBAL_CHANNEL) != 0) + { + return 1; + } + DEBUG((" out xrdp_mcs_incoming\n\r")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s) +{ + xrdp_iso_init(self->iso_layer, s); + s_push_layer(s, mcs_hdr, 8); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s) +{ + int len; + + DEBUG((" in xrdp_mcs_send\n\r")); + s_pop_layer(s, mcs_hdr); + len = (s->end - s->p) - 8; + len = len | 0x8000; + out_uint8(s, MCS_SDIN << 2); + out_uint16_be(s, self->userid); + out_uint16_be(s, MCS_GLOBAL_CHANNEL); + out_uint8(s, 0x70); + out_uint16_be(s, len); + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + return 1; + } + DEBUG((" out xrdp_mcs_send\n\r")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_mcs_disconnect(struct xrdp_mcs* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8(s, (MCS_DPUM << 2) | 1); + out_uint8(s, 0x80); + s_mark_end(s); + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c new file mode 100644 index 00000000..4ee7cae0 --- /dev/null +++ b/libxrdp/xrdp_orders.c @@ -0,0 +1,1553 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + orders + +*/ + +#include "libxrdp.h" + +/*****************************************************************************/ +struct xrdp_orders* APP_CC +xrdp_orders_create(struct xrdp_session* session, struct xrdp_rdp* rdp_layer) +{ + struct xrdp_orders* self; + + self = (struct xrdp_orders*)g_malloc(sizeof(struct xrdp_orders), 1); + self->session = session; + self->rdp_layer = rdp_layer; + make_stream(self->out_s); + init_stream(self->out_s, 8192); + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_orders_delete(struct xrdp_orders* self) +{ + if (self == 0) + { + return; + } + free_stream(self->out_s); + g_free(self); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_orders_init(struct xrdp_orders* self) +{ + self->order_level++; + if (self->order_level == 1) + { + self->order_count = 0; + /* is this big enough */ + if (xrdp_rdp_init_data(self->rdp_layer, self->out_s) != 0) + { + return 1; + } + out_uint16_le(self->out_s, RDP_UPDATE_ORDERS); + out_uint8s(self->out_s, 2); /* pad */ + self->order_count_ptr = self->out_s->p; + out_uint8s(self->out_s, 2); /* number of orders, set later */ + out_uint8s(self->out_s, 2); /* pad */ + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_orders_send(struct xrdp_orders* self) +{ + int rv; + + rv = 0; + if (self->order_level > 0) + { + self->order_level--; + if (self->order_level == 0 && self->order_count > 0) + { + s_mark_end(self->out_s); + DEBUG(("xrdp_orders_send sending %d orders\n\r", self->order_count)); + self->order_count_ptr[0] = self->order_count; + self->order_count_ptr[1] = self->order_count >> 8; + if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, + RDP_DATA_PDU_UPDATE) != 0) + { + rv = 1; + } + } + } + return rv; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_orders_force_send(struct xrdp_orders* self) +{ + if (self->order_count > 0) + { + s_mark_end(self->out_s); + DEBUG(("xrdp_orders_force_send sending %d orders\n\r", self->order_count)); + self->order_count_ptr[0] = self->order_count; + self->order_count_ptr[1] = self->order_count >> 8; + if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, + RDP_DATA_PDU_UPDATE) != 0) + { + return 1; + } + } + self->order_count = 0; + self->order_level = 0; + return 0; +} + +/*****************************************************************************/ +/* check if the current order will fix in packet size of 8192, if not */ +/* send what we got and init a new one */ +/* returns error */ +static int APP_CC +xrdp_orders_check(struct xrdp_orders* self, int max_size) +{ + int size; + + if (self->order_level < 1) + { + if (max_size > 8000) + { + return 1; + } + else + { + return 0; + } + } + size = self->out_s->p - self->order_count_ptr; + if (size < 0 || size > 8192) + { + return 1; + } + if (size + max_size + 100 > 8000) + { + xrdp_orders_force_send(self); + xrdp_orders_init(self); + } + return 0; +} + +/*****************************************************************************/ +/* check if rect is the same as the last one sent */ +/* returns boolean */ +static int APP_CC +xrdp_orders_last_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) +{ + if (rect == 0) + { + return 0; + } + if (rect->left == self->clip_left && + rect->top == self->clip_top && + rect->right == self->clip_right && + rect->bottom == self->clip_bottom) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* check if all coords are withing 256 bytes */ +/* returns boolean */ +static int APP_CC +xrdp_orders_send_delta(struct xrdp_orders* self, int* vals, int count) +{ + int i; + + for (i = 0; i < count; i += 2) + { + if (g_abs(vals[i] - vals[i + 1]) >= 128) + { + return 0; + } + } + return 1; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_orders_out_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) +{ + char* bounds_flags_ptr; + int bounds_flags; + + bounds_flags = 0; + bounds_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + /* left */ + if (rect->left == self->clip_left) + { + } + else if (g_abs(rect->left - self->clip_left) < 128) + { + bounds_flags |= 0x10; + } + else + { + bounds_flags |= 0x01; + } + /* top */ + if (rect->top == self->clip_top) + { + } + else if (g_abs(rect->top - self->clip_top) < 128) + { + bounds_flags |= 0x20; + } + else + { + bounds_flags |= 0x02; + } + /* right */ + if (rect->right == self->clip_right) + { + } + else if (g_abs(rect->right - self->clip_right) < 128) + { + bounds_flags |= 0x40; + } + else + { + bounds_flags |= 0x04; + } + /* bottom */ + if (rect->bottom == self->clip_bottom) + { + } + else if (g_abs(rect->bottom - self->clip_bottom) < 128) + { + bounds_flags |= 0x80; + } + else + { + bounds_flags |= 0x08; + } + /* left */ + if (bounds_flags & 0x01) + { + out_uint16_le(self->out_s, rect->left); + } + else if (bounds_flags & 0x10) + { + out_uint8(self->out_s, rect->left - self->clip_left); + } + self->clip_left = rect->left; + /* top */ + if (bounds_flags & 0x02) + { + out_uint16_le(self->out_s, rect->top); + } + else if (bounds_flags & 0x20) + { + out_uint8(self->out_s, rect->top - self->clip_top); + } + self->clip_top = rect->top; + /* right */ + if (bounds_flags & 0x04) + { + out_uint16_le(self->out_s, rect->right); + } + else if (bounds_flags & 0x40) + { + out_uint8(self->out_s, rect->right - self->clip_right); + } + self->clip_right = rect->right; + /* bottom */ + if (bounds_flags & 0x08) + { + out_uint16_le(self->out_s, rect->bottom); + } + else if (bounds_flags & 0x80) + { + out_uint8(self->out_s, rect->bottom - self->clip_bottom); + } + self->clip_bottom = rect->bottom; + /* set flags */ + *bounds_flags_ptr = bounds_flags; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a solid rect to client */ +/* max size 23 */ +int APP_CC +xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, + int color, struct xrdp_rect* rect) +{ + int order_flags; + int vals[8]; + int present; + char* present_ptr; + + xrdp_orders_check(self, 23); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_RECT) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_RECT; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = x; + vals[1] = self->rect_x; + vals[2] = y; + vals[3] = self->rect_y; + vals[4] = cx; + vals[5] = self->rect_cx; + vals[6] = cy; + vals[7] = self->rect_cy; + if (xrdp_orders_send_delta(self, vals, 8)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags) + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order); + } + present = 0; + present_ptr = self->out_s->p; /* hold 1 byte present pointer */ + out_uint8s(self->out_s, 1) + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (x != self->rect_x) + { + present |= 0x01; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->rect_x); + } + else + { + out_uint16_le(self->out_s, x); + } + self->rect_x = x; + } + if (y != self->rect_y) + { + present |= 0x02; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->rect_y); + } + else + { + out_uint16_le(self->out_s, y); + } + self->rect_y = y; + } + if (cx != self->rect_cx) + { + present |= 0x04; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->rect_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + self->rect_cx = cx; + } + if (cy != self->rect_cy) + { + present |= 0x08; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->rect_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + self->rect_cy = cy; + } + if ((color & 0xff) != (self->rect_color & 0xff)) + { + present |= 0x10; + self->rect_color = (self->rect_color & 0xffff00) | (color & 0xff); + out_uint8(self->out_s, color); + } + if ((color & 0xff00) != (self->rect_color & 0xff00)) + { + present |= 0x20; + self->rect_color = (self->rect_color & 0xff00ff) | (color & 0xff00); + out_uint8(self->out_s, color >> 8); + } + if ((color & 0xff0000) != (self->rect_color & 0xff0000)) + { + present |= 0x40; + self->rect_color = (self->rect_color & 0x00ffff) | (color & 0xff0000); + out_uint8(self->out_s, color >> 16); + } + present_ptr[0] = present; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a screen blt order */ +/* max size 25 */ +int APP_CC +xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int srcx, int srcy, + int rop, struct xrdp_rect* rect) +{ + int order_flags; + int vals[12]; + int present; + char* present_ptr; + + xrdp_orders_check(self, 25); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_SCREENBLT) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_SCREENBLT; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = x; + vals[1] = self->scr_blt_x; + vals[2] = y; + vals[3] = self->scr_blt_y; + vals[4] = cx; + vals[5] = self->scr_blt_cx; + vals[6] = cy; + vals[7] = self->scr_blt_cy; + vals[8] = srcx; + vals[9] = self->scr_blt_srcx; + vals[10] = srcy; + vals[11] = self->scr_blt_srcy; + if (xrdp_orders_send_delta(self, vals, 12)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order); + } + present = 0; + present_ptr = self->out_s->p; /* hold 1 byte present pointer */ + out_uint8s(self->out_s, 1) + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (x != self->scr_blt_x) + { + present |= 0x01; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->scr_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + self->scr_blt_x = x; + } + if (y != self->scr_blt_y) + { + present |= 0x02; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->scr_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + self->scr_blt_y = y; + } + if (cx != self->scr_blt_cx) + { + present |= 0x04; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->scr_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + self->scr_blt_cx = cx; + } + if (cy != self->scr_blt_cy) + { + present |= 0x08; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->scr_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + self->scr_blt_cy = cy; + } + if (rop != self->scr_blt_rop) + { + present |= 0x10; + out_uint8(self->out_s, rop); + self->scr_blt_rop = rop; + } + if (srcx != self->scr_blt_srcx) + { + present |= 0x20; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcx - self->scr_blt_srcx); + } + else + { + out_uint16_le(self->out_s, srcx); + } + self->scr_blt_srcx = srcx; + } + if (srcy != self->scr_blt_srcy) + { + present |= 0x40; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcy - self->scr_blt_srcy) + } + else + { + out_uint16_le(self->out_s, srcy) + } + self->scr_blt_srcy = srcy; + } + present_ptr[0] = present; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a pat blt order */ +/* max size 39 */ +int APP_CC +xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int rop, int bg_color, + int fg_color, struct xrdp_brush* brush, + struct xrdp_rect* rect) +{ + int order_flags; + int vals[8]; + int present; + char* present_ptr; + struct xrdp_brush blank_brush; + + xrdp_orders_check(self, 39); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_PATBLT) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_PATBLT; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = x; + vals[1] = self->pat_blt_x; + vals[2] = y; + vals[3] = self->pat_blt_y; + vals[4] = cx; + vals[5] = self->pat_blt_cx; + vals[6] = cy; + vals[7] = self->pat_blt_cy; + if (xrdp_orders_send_delta(self, vals, 8)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order); + } + present = 0; + present_ptr = self->out_s->p; /* hold 2 byte present pointer, todo */ + out_uint8s(self->out_s, 2) /* this can be smaller, */ + /* see RDP_ORDER_SMALL and RDP_ORDER_TINY */ + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (x != self->pat_blt_x) + { + present |= 0x0001; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->pat_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + self->pat_blt_x = x; + } + if (y != self->pat_blt_y) + { + present |= 0x0002; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->pat_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + self->pat_blt_y = y; + } + if (cx != self->pat_blt_cx) + { + present |= 0x0004; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->pat_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + self->pat_blt_cx = cx; + } + if (cy != self->pat_blt_cy) + { + present |= 0x0008; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->pat_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + self->pat_blt_cy = cy; + } + if (rop != self->pat_blt_rop) + { + present |= 0x0010; + /* PATCOPY PATPAINT PATINVERT DSTINVERT BLACKNESS WHITENESS */ + out_uint8(self->out_s, rop); + self->pat_blt_rop = rop; + } + if (bg_color != self->pat_blt_bg_color) + { + present |= 0x0020; + out_uint8(self->out_s, bg_color); + out_uint8(self->out_s, bg_color >> 8); + out_uint8(self->out_s, bg_color >> 16); + self->pat_blt_bg_color = bg_color; + } + if (fg_color != self->pat_blt_fg_color) + { + present |= 0x0040; + out_uint8(self->out_s, fg_color); + out_uint8(self->out_s, fg_color >> 8); + out_uint8(self->out_s, fg_color >> 16); + self->pat_blt_fg_color = fg_color; + } + if (brush == 0) /* if nil use blank one */ + { /* todo can we just set style to zero */ + g_memset(&blank_brush, 0, sizeof(struct xrdp_brush)); + brush = &blank_brush; + } + if (brush->x_orgin != self->pat_blt_brush.x_orgin) + { + present |= 0x0080; + out_uint8(self->out_s, brush->x_orgin); + self->pat_blt_brush.x_orgin = brush->x_orgin; + } + if (brush->y_orgin != self->pat_blt_brush.y_orgin) + { + present |= 0x0100; + out_uint8(self->out_s, brush->y_orgin); + self->pat_blt_brush.y_orgin = brush->y_orgin; + } + if (brush->style != self->pat_blt_brush.style) + { + present |= 0x0200; + out_uint8(self->out_s, brush->style); + self->pat_blt_brush.style = brush->style; + } + if (brush->pattern[0] != self->pat_blt_brush.pattern[0]) + { + present |= 0x0400; + out_uint8(self->out_s, brush->pattern[0]); + self->pat_blt_brush.pattern[0] = brush->pattern[0]; + } + if (g_memcmp(brush->pattern + 1, self->pat_blt_brush.pattern + 1, 7) != 0) + { + present |= 0x0800; + out_uint8a(self->out_s, brush->pattern + 1, 7); + g_memcpy(self->pat_blt_brush.pattern + 1, brush->pattern + 1, 7); + } + present_ptr[0] = present; + present_ptr[1] = present >> 8; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a dest blt order */ +/* max size 21 */ +int APP_CC +xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, + int cx, int cy, int rop, + struct xrdp_rect* rect) +{ + int order_flags; + int vals[8]; + int present; + char* present_ptr; + + xrdp_orders_check(self, 21); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_DESTBLT) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_DESTBLT; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = x; + vals[1] = self->dest_blt_x; + vals[2] = y; + vals[3] = self->dest_blt_y; + vals[4] = cx; + vals[5] = self->dest_blt_cx; + vals[6] = cy; + vals[7] = self->dest_blt_cy; + if (xrdp_orders_send_delta(self, vals, 8)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order) + } + present = 0; + present_ptr = self->out_s->p; /* hold 1 byte present pointer */ + out_uint8s(self->out_s, 1) + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (x != self->dest_blt_x) + { + present |= 0x01; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->dest_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + self->dest_blt_x = x; + } + if (y != self->dest_blt_y) + { + present |= 0x02; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->dest_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + self->dest_blt_y = y; + } + if (cx != self->dest_blt_cx) + { + present |= 0x04; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->dest_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + self->dest_blt_cx = cx; + } + if (cy != self->dest_blt_cy) + { + present |= 0x08; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->dest_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + self->dest_blt_cy = cy; + } + if (rop != self->dest_blt_rop) + { + present |= 0x10; + out_uint8(self->out_s, rop); + self->dest_blt_rop = rop; + } + present_ptr[0] = present; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a line order */ +/* max size 32 */ +int APP_CC +xrdp_orders_line(struct xrdp_orders* self, int mix_mode, + int startx, int starty, + int endx, int endy, int rop, int bg_color, + struct xrdp_pen* pen, + struct xrdp_rect* rect) +{ + int order_flags; + int vals[8]; + int present; + char* present_ptr; + struct xrdp_pen blank_pen; + + xrdp_orders_check(self, 32); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_LINE) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_LINE; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = startx; + vals[1] = self->line_startx; + vals[2] = starty; + vals[3] = self->line_starty; + vals[4] = endx; + vals[5] = self->line_endx; + vals[6] = endy; + vals[7] = self->line_endy; + if (xrdp_orders_send_delta(self, vals, 8)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order); + } + present = 0; + present_ptr = self->out_s->p; /* hold 2 byte present pointer */ + out_uint8s(self->out_s, 2) + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (mix_mode != self->line_mix_mode) + { + present |= 0x0001; + out_uint16_le(self->out_s, mix_mode) + self->line_mix_mode = mix_mode; + } + if (startx != self->line_startx) + { + present |= 0x0002; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, startx - self->line_startx); + } + else + { + out_uint16_le(self->out_s, startx); + } + self->line_startx = startx; + } + if (starty != self->line_starty) + { + present |= 0x0004; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, starty - self->line_starty); + } + else + { + out_uint16_le(self->out_s, starty); + } + self->line_starty = starty; + } + if (endx != self->line_endx) + { + present |= 0x0008; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, endx - self->line_endx); + } + else + { + out_uint16_le(self->out_s, endx); + } + self->line_endx = endx; + } + if (endy != self->line_endy) + { + present |= 0x0010; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, endy - self->line_endy); + } + else + { + out_uint16_le(self->out_s, endy); + } + self->line_endy = endy; + } + if (bg_color != self->line_bg_color) + { + present |= 0x0020; + out_uint8(self->out_s, bg_color) + out_uint8(self->out_s, bg_color >> 8) + out_uint8(self->out_s, bg_color >> 16) + self->line_bg_color = bg_color; + } + if (rop != self->line_rop) + { + present |= 0x0040; + out_uint8(self->out_s, rop) + self->line_rop = rop; + } + if (pen == 0) + { + g_memset(&blank_pen, 0, sizeof(struct xrdp_pen)); + pen = &blank_pen; + } + if (pen->style != self->line_pen.style) + { + present |= 0x0080; + out_uint8(self->out_s, pen->style) + self->line_pen.style = pen->style; + } + if (pen->width != self->line_pen.width) + { + present |= 0x0100; + out_uint8(self->out_s, pen->width) + self->line_pen.width = pen->width; + } + if (pen->color != self->line_pen.color) + { + present |= 0x0200; + out_uint8(self->out_s, pen->color) + out_uint8(self->out_s, pen->color >> 8) + out_uint8(self->out_s, pen->color >> 16) + self->line_pen.color = pen->color; + } + present_ptr[0] = present; + present_ptr[1] = present >> 8; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* send a mem blt order */ +/* max size 30 */ +int APP_CC +xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, + int color_table, int x, int y, int cx, int cy, + int rop, int srcx, int srcy, + int cache_idx, struct xrdp_rect* rect) +{ + int order_flags; + int vals[12]; + int present; + char* present_ptr; + + xrdp_orders_check(self, 30); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_MEMBLT) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_MEMBLT; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + vals[0] = x; + vals[1] = self->mem_blt_x; + vals[2] = y; + vals[3] = self->mem_blt_y; + vals[4] = cx; + vals[5] = self->mem_blt_cx; + vals[6] = cy; + vals[7] = self->mem_blt_cy; + vals[8] = srcx; + vals[9] = self->mem_blt_srcx; + vals[10] = srcy; + vals[11] = self->mem_blt_srcy; + if (xrdp_orders_send_delta(self, vals, 12)) + { + order_flags |= RDP_ORDER_DELTA; + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order) + } + present = 0; + present_ptr = self->out_s->p; /* hold 2 byte present pointer, todo */ + out_uint8s(self->out_s, 2) /* this can be smaller, */ + /* see RDP_ORDER_SMALL and RDP_ORDER_TINY */ + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (cache_id != self->mem_blt_cache_id || + color_table != self->mem_blt_color_table) + { + present |= 0x0001; + out_uint8(self->out_s, cache_id); + out_uint8(self->out_s, color_table); + self->mem_blt_cache_id = cache_id; + self->mem_blt_color_table = color_table; + } + if (x != self->mem_blt_x) + { + present |= 0x0002; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->mem_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + self->mem_blt_x = x; + } + if (y != self->mem_blt_y) + { + present |= 0x0004; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->mem_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + self->mem_blt_y = y; + } + if (cx != self->mem_blt_cx) + { + present |= 0x0008; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->mem_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + self->mem_blt_cx = cx; + } + if (cy != self->mem_blt_cy) + { + present |= 0x0010; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->mem_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + self->mem_blt_cy = cy; + } + if (rop != self->mem_blt_rop) + { + present |= 0x0020; + out_uint8(self->out_s, rop); + self->mem_blt_rop = rop; + } + if (srcx != self->mem_blt_srcx) + { + present |= 0x0040; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcx - self->mem_blt_srcx); + } + else + { + out_uint16_le(self->out_s, srcx); + } + self->mem_blt_srcx = srcx; + } + if (srcy != self->mem_blt_srcy) + { + present |= 0x0080; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcy - self->mem_blt_srcy); + } + else + { + out_uint16_le(self->out_s, srcy); + } + self->mem_blt_srcy = srcy; + } + if (cache_idx != self->mem_blt_cache_idx) + { + present |= 0x0100; + out_uint16_le(self->out_s, cache_idx); + self->mem_blt_cache_idx = cache_idx; + } + present_ptr[0] = present; + present_ptr[1] = present >> 8; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_orders_text(struct xrdp_orders* self, + int font, int flags, int mixmode, + int fg_color, int bg_color, + int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char* data, int data_len, + struct xrdp_rect* rect) +{ + int order_flags; + int present; + char* present_ptr; + + xrdp_orders_check(self, 100); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->last_order != RDP_ORDER_TEXT2) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->last_order = RDP_ORDER_TEXT2; + if (rect != 0) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + out_uint8(self->out_s, order_flags); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->last_order); + } + present = 0; + present_ptr = self->out_s->p; /* hold 3 byte present pointer, todo */ + out_uint8s(self->out_s, 3) /* this can be smaller, */ + /* see RDP_ORDER_SMALL and RDP_ORDER_TINY */ + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + if (font != self->text_font) + { + present |= 0x000001; + out_uint8(self->out_s, font); + self->text_font = font; + } + if (flags != self->text_flags) + { + present |= 0x000002; + out_uint8(self->out_s, flags); + self->text_flags = flags; + } + /* unknown */ + if (mixmode != self->text_mixmode) + { + present |= 0x000008; + out_uint8(self->out_s, mixmode); + self->text_mixmode = mixmode; + } + if (fg_color != self->text_fg_color) + { + present |= 0x000010; + out_uint8(self->out_s, fg_color) + out_uint8(self->out_s, fg_color >> 8) + out_uint8(self->out_s, fg_color >> 16) + self->text_fg_color = fg_color; + } + if (bg_color != self->text_bg_color) + { + present |= 0x000020; + out_uint8(self->out_s, bg_color) + out_uint8(self->out_s, bg_color >> 8) + out_uint8(self->out_s, bg_color >> 16) + self->text_bg_color = bg_color; + } + if (clip_left != self->text_clip_left) + { + present |= 0x000040; + out_uint16_le(self->out_s, clip_left); + self->text_clip_left = clip_left; + } + if (clip_top != self->text_clip_top) + { + present |= 0x000080; + out_uint16_le(self->out_s, clip_top); + self->text_clip_top = clip_top; + } + if (clip_right != self->text_clip_right) + { + present |= 0x000100; + out_uint16_le(self->out_s, clip_right); + self->text_clip_right = clip_right; + } + if (clip_bottom != self->text_clip_bottom) + { + present |= 0x000200; + out_uint16_le(self->out_s, clip_bottom); + self->text_clip_bottom = clip_bottom; + } + if (box_left != self->text_box_left) + { + present |= 0x000400; + out_uint16_le(self->out_s, box_left); + self->text_box_left = box_left; + } + if (box_top != self->text_box_top) + { + present |= 0x000800; + out_uint16_le(self->out_s, box_top); + self->text_box_top = box_top; + } + if (box_right != self->text_box_right) + { + present |= 0x001000; + out_uint16_le(self->out_s, box_right); + self->text_box_right = box_right; + } + if (box_bottom != self->text_box_bottom) + { + present |= 0x002000; + out_uint16_le(self->out_s, box_bottom); + self->text_box_bottom = box_bottom; + } + if (x != self->text_x) + { + present |= 0x080000; + out_uint16_le(self->out_s, x); + self->text_x = x; + } + if (y != self->text_y) + { + present |= 0x100000; + out_uint16_le(self->out_s, y); + self->text_y = y; + } + { + /* always send text */ + present |= 0x200000; + out_uint8(self->out_s, data_len); + out_uint8a(self->out_s, data, data_len); + } + /* send 3 byte present */ + present_ptr[0] = present; + present_ptr[1] = present >> 8; + present_ptr[2] = present >> 16; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* when a palette gets sent, send the main palette too */ +int APP_CC +xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, + int cache_id) +{ + int order_flags; + int len; + int i; + + xrdp_orders_check(self, 2000); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = 1027 - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 0); /* flags */ + out_uint8(self->out_s, RDP_ORDER_COLCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint16_le(self->out_s, 256); /* num colors */ + for (i = 0; i < 256; i++) + { + out_uint8(self->out_s, palette[i]); + out_uint8(self->out_s, palette[i] >> 8); + out_uint8(self->out_s, palette[i] >> 16); + out_uint8(self->out_s, 0); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* max size width * height * Bpp + 16 */ +int APP_CC +xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx) +{ + int order_flags; + int len; + int bufsize; + int Bpp; + int i; + int j; + int pixel; + int e; + + e = width % 4; + if (e != 0) + { + e = 4 - e; + } + Bpp = (bpp + 7) / 8; + bufsize = (width + e) * height * Bpp; + xrdp_orders_check(self, bufsize + 16); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 9) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8s(self->out_s, 1); /* pad */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint8(self->out_s, bpp); + out_uint16_le(self->out_s, bufsize); + out_uint16_le(self->out_s, cache_idx); + for (i = height - 1; i >= 0; i--) + { + for (j = 0; j < width; j++) + { + if (Bpp == 3) + { + pixel = GETPIXEL32(data, j, i, width); + out_uint8(self->out_s, pixel >> 16); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel); + } + else if (Bpp == 2) + { + pixel = GETPIXEL16(data, j, i, width); + out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + } + else if (Bpp == 1) + { + pixel = GETPIXEL8(data, j, i, width); + out_uint8(self->out_s, pixel); + } + } + for (j = 0; j < e; j++) + { + out_uint8s(self->out_s, Bpp); + } + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* max size width * height * Bpp + 16 */ +int APP_CC +xrdp_orders_send_bitmap(struct xrdp_orders* self, + int width, int height, int bpp, char* data, + int cache_id, int cache_idx) +{ + int order_flags; + int len; + int bufsize; + int Bpp; + int i; + int lines_sending; + int e; + struct stream* s; + struct stream* temp_s; + char* p; + + if (width > 64) + { + g_printf("error, width > 64\n\r"); + return 1; + } + if (height > 64) + { + g_printf("error, height > 64\n\r"); + return 1; + } + e = width % 4; + if (e != 0) + { + e = 4 - e; + } + make_stream(s); + init_stream(s, 8192); + make_stream(temp_s); + init_stream(temp_s, 8192); + p = s->p; + i = height; + lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 8192, + i - 1, temp_s, e); + if (lines_sending != height) + { + free_stream(s); + free_stream(temp_s); + g_printf("error in xrdp_orders_send_bitmap, lines_sending(%d) != \ +height(%d)\n\r", lines_sending, height); + return 1; + } + bufsize = s->p - p; + Bpp = (bpp + 7) / 8; + xrdp_orders_check(self, bufsize + 16); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 9 + 8) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + out_uint8(self->out_s, RDP_ORDER_BMPCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8s(self->out_s, 1); /* pad */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint8(self->out_s, bpp); + out_uint16_le(self->out_s, bufsize + 8); + out_uint16_le(self->out_s, cache_idx); + out_uint8s(self->out_s, 2); /* pad */ + out_uint16_le(self->out_s, bufsize); + out_uint16_le(self->out_s, (width + e) * Bpp); /* line size */ + out_uint16_le(self->out_s, (width + e) * + Bpp * height); /* final size */ + out_uint8a(self->out_s, s->data, bufsize); + free_stream(s); + free_stream(temp_s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* max size datasize + 18*/ +/* todo, only sends one for now */ +int APP_CC +xrdp_orders_send_font(struct xrdp_orders* self, + struct xrdp_font_char* font_char, + int font_index, int char_index) +{ + int order_flags; + int datasize; + int len; + + datasize = FONT_DATASIZE(font_char); + xrdp_orders_check(self, datasize + 18); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (datasize + 12) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + out_uint8(self->out_s, RDP_ORDER_FONTCACHE); /* type */ + out_uint8(self->out_s, font_index); + out_uint8(self->out_s, 1); /* num of chars */ + out_uint16_le(self->out_s, char_index); + out_uint16_le(self->out_s, font_char->offset); + out_uint16_le(self->out_s, font_char->baseline); + out_uint16_le(self->out_s, font_char->width); + out_uint16_le(self->out_s, font_char->height); + out_uint8a(self->out_s, font_char->data, datasize); + return 0; +} diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c new file mode 100644 index 00000000..155e109c --- /dev/null +++ b/libxrdp/xrdp_rdp.c @@ -0,0 +1,847 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + rdp layer + +*/ + +#include "libxrdp.h" + +static char unknown1[172] = +{ 0xff, 0x02, 0xb6, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x27, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x01, 0x00, 0x1e, 0x00, + 0x02, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x1d, 0x00, + 0x04, 0x00, 0x27, 0x00, 0x05, 0x00, 0x0b, 0x00, + 0x06, 0x00, 0x28, 0x00, 0x08, 0x00, 0x21, 0x00, + 0x09, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x22, 0x00, + 0x0b, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x24, 0x00, + 0x0d, 0x00, 0x23, 0x00, 0x0e, 0x00, 0x19, 0x00, + 0x0f, 0x00, 0x16, 0x00, 0x10, 0x00, 0x15, 0x00, + 0x11, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x1b, 0x00, + 0x13, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x17, 0x00, + 0x15, 0x00, 0x18, 0x00, 0x16, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, + 0x1a, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x14, 0x00, + 0x1f, 0x00, 0x13, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x06, 0x00, + 0x23, 0x00, 0x07, 0x00, 0x24, 0x00, 0x08, 0x00, + 0x25, 0x00, 0x09, 0x00, 0x26, 0x00, 0x04, 0x00, + 0x27, 0x00, 0x03, 0x00, 0x28, 0x00, 0x02, 0x00, + 0x29, 0x00, 0x01, 0x00, 0x2a, 0x00, 0x05, 0x00, + 0x2b, 0x00, 0x2a, 0x00 }; + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_read_config(struct xrdp_client_info* client_info) +{ + int fd; + int index; + struct list* items; + struct list* values; + char* item; + char* value; + + fd = g_file_open("xrdp.ini"); + if (fd > 0) + { + items = list_create(); + items->auto_free = 1; + values = list_create(); + values->auto_free = 1; + file_read_section(fd, "globals", items, values); + for (index = 0; index < items->count; index++) + { + item = (char*)list_get_item(items, index); + value = (char*)list_get_item(values, index); + if (g_strcmp(item, "bitmap_cache") == 0) + { + if (g_strcmp(value, "yes") == 0) + { + client_info->use_bitmap_cache = 1; + } + } + else if (g_strcmp(item, "bitmap_compression") == 0) + { + if (g_strcmp(value, "yes") == 0) + { + client_info->use_bitmap_comp = 1; + } + } + } + list_delete(items); + list_delete(values); + g_file_close(fd); + } + return 0; +} + +/*****************************************************************************/ +struct xrdp_rdp* APP_CC +xrdp_rdp_create(struct xrdp_session* session, int sck) +{ + struct xrdp_rdp* self; + + self = (struct xrdp_rdp*)g_malloc(sizeof(struct xrdp_rdp), 1); + self->session = session; + self->share_id = 66538; + self->sec_layer = xrdp_sec_create(self, sck); + /* read ini settings */ + xrdp_rdp_read_config(&self->client_info); + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_rdp_delete(struct xrdp_rdp* self) +{ + if (self == 0) + { + return; + } + xrdp_sec_delete(self->sec_layer); + g_free(self); +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_init(struct xrdp_rdp* self, struct stream* s) +{ + if (xrdp_sec_init(self->sec_layer, s) != 0) + { + return 1; + } + s_push_layer(s, rdp_hdr, 6); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_init_data(struct xrdp_rdp* self, struct stream* s) +{ + if (xrdp_sec_init(self->sec_layer, s) != 0) + { + return 1; + } + s_push_layer(s, rdp_hdr, 18); + return 0; +} + +/*****************************************************************************/ +/* returns erros */ +int APP_CC +xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code) +{ + int error; + int len; + int pdu_code; + int chan; + + DEBUG(("in xrdp_rdp_recv\n\r")); + if (s->next_packet == 0 || s->next_packet >= s->end) + { + chan = 0; + error = xrdp_sec_recv(self->sec_layer, s, &chan); + if (error == -1) /* special code for send demand active */ + { + s->next_packet = 0; + *code = -1; + DEBUG(("out xrdp_rdp_recv\n\r")); + return 0; + } + if (error != 0) + { + DEBUG(("out xrdp_rdp_recv error\n\r")); + return 1; + } + if (chan != MCS_GLOBAL_CHANNEL && chan > 0) + { + s->next_packet = 0; + *code = 0; + DEBUG(("out xrdp_rdp_recv\n\r")); + return 0; + } + s->next_packet = s->p; + } + else + { + s->p = s->next_packet; + } + in_uint16_le(s, len); + if (len == 0x8000) + { + s->next_packet += 8; + *code = 0; + DEBUG(("out xrdp_rdp_recv\n\r")); + return 0; + } + in_uint16_le(s, pdu_code); + *code = pdu_code & 0xf; + in_uint8s(s, 2); /* mcs user id */ + s->next_packet += len; + DEBUG(("out xrdp_rdp_recv\n\r")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type) +{ + int len; + + DEBUG(("in xrdp_rdp_send\n\r")); + s_pop_layer(s, rdp_hdr); + len = s->end - s->p; + out_uint16_le(s, len); + out_uint16_le(s, 0x10 | pdu_type); + out_uint16_le(s, self->mcs_channel); + if (xrdp_sec_send(self->sec_layer, s, 0) != 0) + { + DEBUG(("out xrdp_rdp_send error\n\r")); + return 1; + } + DEBUG(("out xrdp_rdp_send\n\r")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s, + int data_pdu_type) +{ + int len; + + DEBUG(("in xrdp_rdp_send_data\n\r")); + s_pop_layer(s, rdp_hdr); + len = s->end - s->p; + out_uint16_le(s, len); + out_uint16_le(s, 0x10 | RDP_PDU_DATA); + out_uint16_le(s, self->mcs_channel); + out_uint32_le(s, self->share_id); + out_uint8(s, 0); + out_uint8(s, 1); + out_uint16_le(s, len - 14); + out_uint8(s, data_pdu_type); + out_uint8(s, 0); + out_uint16_le(s, 0); + if (xrdp_sec_send(self->sec_layer, s, 0) != 0) + { + DEBUG(("out xrdp_rdp_send_data error\n\r")); + return 1; + } + DEBUG(("out xrdp_rdp_send_data\n\r")); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp* self) +{ + struct stream* p; + int i; + + p = &self->sec_layer->client_mcs_data; + p->p = p->data; + in_uint8s(p, 31); + in_uint16_le(p, self->client_info.width); + in_uint16_le(p, self->client_info.height); + in_uint8s(p, 120); + self->client_info.bpp = 8; + in_uint16_le(p, i); + switch (i) + { + case 0xca01: + in_uint8s(p, 6); + in_uint8(p, i); + if (i > 8) + { + self->client_info.bpp = i; + } + break; + case 0xca02: + self->client_info.bpp = 15; + break; + case 0xca03: + self->client_info.bpp = 16; + break; + case 0xca04: + self->client_info.bpp = 24; + break; + } + p->p = p->data; + DEBUG(("client width %d, client height %d bpp %d\n\r", + self->client_info.width, self->client_info.height, + self->client_info.bpp)); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_incoming(struct xrdp_rdp* self) +{ + DEBUG(("in xrdp_rdp_incoming\n\r")); + if (xrdp_sec_incoming(self->sec_layer) != 0) + { + return 1; + } + self->mcs_channel = self->sec_layer->mcs_layer->userid + + MCS_USERCHANNEL_BASE; + xrdp_rdp_parse_client_mcs_data(self); + DEBUG(("out xrdp_rdp_incoming mcs channel %d\n\r", self->mcs_channel)); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_send_demand_active(struct xrdp_rdp* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init(self, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint32_le(s, self->share_id); + out_uint32_be(s, 0x04000401); + out_uint32_be(s, 0x524e5300); + out_uint32_be(s, 0x08000000); + out_uint32_be(s, 0x09000800); + out_uint16_le(s, self->mcs_channel); + out_uint16_be(s, 0xb5e2); + + /* Output general capability set */ + out_uint16_le(s, RDP_CAPSET_GENERAL); /* 1 */ + out_uint16_le(s, RDP_CAPLEN_GENERAL); /* 24(0x18) */ + out_uint16_le(s, 1); /* OS major type */ + out_uint16_le(s, 3); /* OS minor type */ + out_uint16_le(s, 0x200); /* Protocol version */ + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, 0); /* Compression types */ + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, 0); /* Update capability */ + out_uint16_le(s, 0); /* Remote unshare capability */ + out_uint16_le(s, 0); /* Compression level */ + out_uint16_le(s, 0); /* Pad */ + + /* Output bitmap capability set */ + out_uint16_le(s, RDP_CAPSET_BITMAP); /* 2 */ + out_uint16_le(s, RDP_CAPLEN_BITMAP); /* 28(0x1c) */ + out_uint16_le(s, self->client_info.bpp); /* Preferred BPP */ + out_uint16_le(s, 1); /* Receive 1 BPP */ + out_uint16_le(s, 1); /* Receive 4 BPP */ + out_uint16_le(s, 1); /* Receive 8 BPP */ + out_uint16_le(s, self->client_info.width); /* width */ + out_uint16_le(s, self->client_info.height); /* height */ + out_uint16_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* Allow resize */ + out_uint16_le(s, 1); /* bitmap compression */ + out_uint16_le(s, 0); /* unknown */ + out_uint16_le(s, 0); /* unknown */ + out_uint16_le(s, 0); /* pad */ + + /* Output ? */ + out_uint16_le(s, 14); + out_uint16_le(s, 4); + + /* Output order capability set */ + out_uint16_le(s, RDP_CAPSET_ORDER); /* 3 */ + out_uint16_le(s, RDP_CAPLEN_ORDER); /* 88(0x58) */ + out_uint8s(s, 16); + out_uint32_be(s, 0x40420f00); + out_uint16_le(s, 1); /* Cache X granularity */ + out_uint16_le(s, 20); /* Cache Y granularity */ + out_uint16_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* Max order level */ + out_uint16_le(s, 0x2f); /* Number of fonts */ + out_uint16_le(s, 0x22); /* Capability flags */ + /* caps */ + out_uint8(s, 1); /* dest blt */ + out_uint8(s, 1); /* pat blt */ + out_uint8(s, 1); /* screen blt */ + out_uint8(s, 1); /* memblt */ + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 0); + out_uint8(s, 0); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 0); + out_uint8(s, 0); + out_uint8(s, 0); + out_uint16_le(s, 0x6a1); + out_uint8s(s, 6); /* ? */ + out_uint32_le(s, 0x0f4240); /* desk save */ + out_uint32_le(s, 0); /* ? */ + out_uint32_le(s, 0); /* ? */ + + /* Output color cache capability set */ + out_uint16_le(s, RDP_CAPSET_COLCACHE); + out_uint16_le(s, RDP_CAPLEN_COLCACHE); + out_uint16_le(s, 6); /* cache size */ + out_uint16_le(s, 0); /* pad */ + + /* Output pointer capability set */ + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_POINTER); + out_uint16_le(s, 1); /* Colour pointer */ + out_uint16_le(s, 0x19); /* Cache size */ + + /* Output ? */ + out_uint16_le(s, 0xd); + out_uint16_le(s, 0x58); /* 88 */ + out_uint8(s, 1); + out_uint8s(s, 83); + + s_mark_end(s); + + if (xrdp_rdp_send(self, s, RDP_PDU_DEMAND_ACTIVE) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_process_capset_general(struct xrdp_rdp* self, struct stream* s, + int len) +{ + int i; + + in_uint8s(s, 10); + in_uint16_le(s, i); + self->client_info.use_compact_packets = (i != 0); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_process_capset_order(struct xrdp_rdp* self, struct stream* s, + int len) +{ + int i; + + in_uint8s(s, 72); + in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ + self->client_info.desktop_cache = i; + return 0; +} + +/*****************************************************************************/ +/* get the bitmap cache size */ +static int APP_CC +xrdp_process_capset_bmpcache(struct xrdp_rdp* self, struct stream* s, + int len) +{ + in_uint8s(s, 24); + in_uint16_le(s, self->client_info.cache1_entries); + in_uint16_le(s, self->client_info.cache1_size); + in_uint16_le(s, self->client_info.cache2_entries); + in_uint16_le(s, self->client_info.cache2_size); + in_uint16_le(s, self->client_info.cache3_entries); + in_uint16_le(s, self->client_info.cache3_size); + return 0; +} + +/*****************************************************************************/ +/* get the number of client cursor cache */ +static int APP_CC +xrdp_process_capset_pointercache(struct xrdp_rdp* self, struct stream* s, + int len) +{ + int i; + + in_uint8s(s, 2); /* color pointer */ + in_uint16_le(s, i); + i = MIN(i, 32); + self->client_info.pointer_cache_entries = i; + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s) +{ + int cap_len; + int source_len; + int num_caps; + int index; + int type; + int len; + char* p; + + in_uint8s(s, 4); /* rdp_shareid */ + in_uint8s(s, 2); /* userid */ + in_uint16_le(s, source_len); /* sizeof RDP_SOURCE */ + in_uint16_le(s, cap_len); + in_uint8s(s, source_len); + in_uint16_le(s, num_caps); + in_uint8s(s, 2); /* pad */ + for (index = 0; index < num_caps; index++) + { + p = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + switch (type) + { + case RDP_CAPSET_GENERAL: /* 1 */ + xrdp_process_capset_general(self, s, len); + break; + case RDP_CAPSET_ORDER: /* 3 */ + xrdp_process_capset_order(self, s, len); + break; + case RDP_CAPSET_BMPCACHE: /* 4 */ + xrdp_process_capset_bmpcache(self, s, len); + break; + case RDP_CAPSET_POINTER: /* 8 */ + xrdp_process_capset_pointercache(self, s, len); + break; + } + s->p = p + len; + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_pointer(struct xrdp_rdp* self, struct stream* s) +{ + return 0; +} + +/*****************************************************************************/ +/* RDP_DATA_PDU_INPUT */ +static int APP_CC +xrdp_rdp_process_data_input(struct xrdp_rdp* self, struct stream* s) +{ + int num_events; + int index; + int msg_type; + int device_flags; + int param1; + int param2; + int time; + + in_uint16_le(s, num_events); + in_uint8s(s, 2); /* pad */ + DEBUG(("xrdp_rdp_process_data_input %d events\n\r", num_events)); + for (index = 0; index < num_events; index++) + { + in_uint32_le(s, time); + in_uint16_le(s, msg_type); + in_uint16_le(s, device_flags); + in_sint16_le(s, param1); + in_sint16_le(s, param2); + DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d \ +param2 %d time %d\n\r", msg_type, device_flags, param1, param2, time)); + if (self->session->callback != 0) + { + /* msg_type can be + RDP_INPUT_SYNCHRONIZE - 0 + RDP_INPUT_SCANCODE - 4 + RDP_INPUT_MOUSE - 0x8001 */ + self->session->callback(self->session->id, msg_type, param1, param2, + device_flags, time); + } + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_send_synchronise(struct xrdp_rdp* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + out_uint16_le(s, 1); + out_uint16_le(s, 1002); + s_mark_end(s); + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_send_control(struct xrdp_rdp* self, int action) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + out_uint16_le(s, action); + out_uint16_le(s, 0); /* userid */ + out_uint32_le(s, 1002); /* control id */ + s_mark_end(s); + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_control(struct xrdp_rdp* self, struct stream* s) +{ + int action; + + in_uint16_le(s, action); + in_uint8s(s, 2); /* user id */ + in_uint8s(s, 4); /* control id */ + if (action == RDP_CTL_REQUEST_CONTROL) + { + xrdp_rdp_send_synchronise(self); + xrdp_rdp_send_control(self, RDP_CTL_COOPERATE); + xrdp_rdp_send_control(self, RDP_CTL_GRANT_CONTROL); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_sync(struct xrdp_rdp* self) +{ + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_screen_update(struct xrdp_rdp* self, struct stream* s) +{ + int op; + int left; + int top; + int right; + int bottom; + int cx; + int cy; + + in_uint32_le(s, op); + in_uint16_le(s, left); + in_uint16_le(s, top); + in_uint16_le(s, right); + in_uint16_le(s, bottom); + cx = (right - left) + 1; + cy = (bottom - top) + 1; + if (self->session->callback != 0) + { + self->session->callback(self->session->id, 0x4444, left, top, cx, cy); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_send_unknown1(struct xrdp_rdp* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8a(s, unknown1, 172); + s_mark_end(s); + if (xrdp_rdp_send_data(self, s, 0x28) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_font(struct xrdp_rdp* self, struct stream* s) +{ + int seq; + + in_uint8s(s, 2); /* num of fonts */ + in_uint8s(s, 2); /* unknown */ + in_uint16_le(s, seq); + /* 419 client sends Seq 1, then 2 */ + /* 2600 clients sends only Seq 3 */ + if (seq == 2 || seq == 3) /* after second font message, we are up and */ + { /* running */ + xrdp_rdp_send_unknown1(self); + self->session->up_and_running = 1; + } + return 0; +} + +/*****************************************************************************/ +/* sent 37 pdu */ +static int APP_CC +xrdp_rdp_send_disconnect_query_response(struct xrdp_rdp* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + s_mark_end(s); + if (xrdp_rdp_send_data(self, s, 37) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +#if 0 /* not used */ +/*****************************************************************************/ +/* sent RDP_DATA_PDU_DISCONNECT 47 pdu */ +static int APP_CC +xrdp_rdp_send_disconnect_reason(struct xrdp_rdp* self, int reason) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + out_uint32_le(s, reason); + s_mark_end(s); + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_DISCONNECT) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} +#endif + +/*****************************************************************************/ +/* RDP_PDU_DATA */ +int APP_CC +xrdp_rdp_process_data(struct xrdp_rdp* self, struct stream* s) +{ + int len; + int data_type; + int ctype; + int clen; + + in_uint8s(s, 6); + in_uint16_le(s, len); + in_uint8(s, data_type); + in_uint8(s, ctype); + in_uint16_le(s, clen); + DEBUG(("xrdp_rdp_process_data code %d\n\r", data_type)); + switch (data_type) + { + case RDP_DATA_PDU_POINTER: /* 27 */ + xrdp_rdp_process_data_pointer(self, s); + break; + case RDP_DATA_PDU_INPUT: /* 28 */ + xrdp_rdp_process_data_input(self, s); + break; + case RDP_DATA_PDU_CONTROL: /* 20 */ + xrdp_rdp_process_data_control(self, s); + break; + case RDP_DATA_PDU_SYNCHRONISE: /* 31 */ + xrdp_rdp_process_data_sync(self); + break; + case 33: /* 33 ?? Invalidate an area I think */ + xrdp_rdp_process_screen_update(self, s); + break; + case 35: + /* 35 ?? this comes when minimuzing a full screen mstsc.exe 2600 */ + /* I think this is saying the client no longer wants screen */ + /* updates and it will issue a 33 above to catch up */ + /* so minimized apps don't take bandwidth */ + break; + case 36: /* 36 ?? disconnect query? */ + /* when this message comes, send a 37 back so the client */ + /* is sure the connection is alive and it can ask if user */ + /* really wants to disconnect */ + xrdp_rdp_send_disconnect_query_response(self); /* send a 37 back */ + break; + case RDP_DATA_PDU_FONT2: /* 39 */ + xrdp_rdp_process_data_font(self, s); + break; + default: + g_printf("unknown in xrdp_rdp_process_data %d\n\r", data_type); + break; + } + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_disconnect(struct xrdp_rdp* self) +{ + return xrdp_sec_disconnect(self->sec_layer); +} diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c new file mode 100644 index 00000000..0616b656 --- /dev/null +++ b/libxrdp/xrdp_sec.c @@ -0,0 +1,606 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + secure layer + +*/ + +#include "libxrdp.h" + +static char pad_54[40] = +{ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54 }; + +static char pad_92[48] = +{ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92 }; + +static char pub_exp[4] = { 0x01, 0x00, 0x01, 0x00 }; + +static char pub_mod[64] = +{ 0x67, 0xab, 0x0e, 0x6a, 0x9f, 0xd6, 0x2b, 0xa3, + 0x32, 0x2f, 0x41, 0xd1, 0xce, 0xee, 0x61, 0xc3, + 0x76, 0x0b, 0x26, 0x11, 0x70, 0x48, 0x8a, 0x8d, + 0x23, 0x81, 0x95, 0xa0, 0x39, 0xf7, 0x5b, 0xaa, + 0x3e, 0xf1, 0xed, 0xb8, 0xc4, 0xee, 0xce, 0x5f, + 0x6a, 0xf5, 0x43, 0xce, 0x5f, 0x60, 0xca, 0x6c, + 0x06, 0x75, 0xae, 0xc0, 0xd6, 0xa4, 0x0c, 0x92, + 0xa4, 0xc6, 0x75, 0xea, 0x64, 0xb2, 0x50, 0x5b }; + +static char pub_sig[64] = +{ 0x6a, 0x41, 0xb1, 0x43, 0xcf, 0x47, 0x6f, 0xf1, + 0xe6, 0xcc, 0xa1, 0x72, 0x97, 0xd9, 0xe1, 0x85, + 0x15, 0xb3, 0xc2, 0x39, 0xa0, 0xa6, 0x26, 0x1a, + 0xb6, 0x49, 0x01, 0xfa, 0xa6, 0xda, 0x60, 0xd7, + 0x45, 0xf7, 0x2c, 0xee, 0xe4, 0x8e, 0x64, 0x2e, + 0x37, 0x49, 0xf0, 0x4c, 0x94, 0x6f, 0x08, 0xf5, + 0x63, 0x4c, 0x56, 0x29, 0x55, 0x5a, 0x63, 0x41, + 0x2c, 0x20, 0x65, 0x95, 0x99, 0xb1, 0x15, 0x7c }; + +static char pri_exp[64] = +{ 0x41, 0x93, 0x05, 0xB1, 0xF4, 0x38, 0xFC, 0x47, + 0x88, 0xC4, 0x7F, 0x83, 0x8C, 0xEC, 0x90, 0xDA, + 0x0C, 0x8A, 0xB5, 0xAE, 0x61, 0x32, 0x72, 0xF5, + 0x2B, 0xD1, 0x7B, 0x5F, 0x44, 0xC0, 0x7C, 0xBD, + 0x8A, 0x35, 0xFA, 0xAE, 0x30, 0xF6, 0xC4, 0x6B, + 0x55, 0xA7, 0x65, 0xEF, 0xF4, 0xB2, 0xAB, 0x18, + 0x4E, 0xAA, 0xE6, 0xDC, 0x71, 0x17, 0x3B, 0x4C, + 0xC2, 0x15, 0x4C, 0xF7, 0x81, 0xBB, 0xF0, 0x03 }; + +static char lic1[322] = +{ 0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01, + 0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6, + 0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39, + 0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05, + 0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81, + 0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, + 0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, + 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4, + 0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e, + 0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18, + 0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5, + 0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a, + 0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3, + 0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71, + 0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9, + 0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6, + 0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54, + 0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75, + 0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82, + 0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf, + 0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68, + 0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03, + 0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x00 }; + +static char lic2[20] = +{ 0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x28, 0x14, 0x00, 0x00 }; + +/*****************************************************************************/ +struct xrdp_sec* APP_CC +xrdp_sec_create(struct xrdp_rdp* owner, int sck) +{ + struct xrdp_sec* self; + + self = (struct xrdp_sec*)g_malloc(sizeof(struct xrdp_sec), 1); + self->rdp_layer = owner; + self->rc4_key_size = 1; + self->decrypt_rc4_info = g_rc4_info_create(); + self->encrypt_rc4_info = g_rc4_info_create(); + g_random(self->server_random, 32); + self->mcs_layer = xrdp_mcs_create(self, sck, &self->client_mcs_data, + &self->server_mcs_data); + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_sec_delete(struct xrdp_sec* self) +{ + if (self == 0) + { + return; + } + xrdp_mcs_delete(self->mcs_layer); + g_rc4_info_delete(self->decrypt_rc4_info); + g_rc4_info_delete(self->encrypt_rc4_info); + g_free(self->client_mcs_data.data); + g_free(self->server_mcs_data.data); + g_free(self); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_sec_init(struct xrdp_sec* self, struct stream* s) +{ + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + return 1; + } + s_push_layer(s, sec_hdr, 4); + return 0; +} + +/*****************************************************************************/ +/* Reduce key entropy from 64 to 40 bits */ +static void APP_CC +xrdp_sec_make_40bit(char* key) +{ + key[0] = 0xd1; + key[1] = 0x26; + key[2] = 0x9e; +} + +/*****************************************************************************/ +/* returns error */ +/* update an encryption key */ +static int APP_CC +xrdp_sec_update(char* key, char* update_key, int key_len) +{ + char shasig[20]; + void* sha1_info; + void* md5_info; + void* rc4_info; + + sha1_info = g_sha1_info_create(); + md5_info = g_md5_info_create(); + rc4_info = g_rc4_info_create(); + g_sha1_clear(sha1_info); + g_sha1_transform(sha1_info, update_key, key_len); + g_sha1_transform(sha1_info, pad_54, 40); + g_sha1_transform(sha1_info, key, key_len); + g_sha1_complete(sha1_info, shasig); + g_md5_clear(md5_info); + g_md5_transform(md5_info, update_key, key_len); + g_md5_transform(md5_info, pad_92, 48); + g_md5_transform(md5_info, shasig, 20); + g_md5_complete(md5_info, key); + g_rc4_set_key(rc4_info, key, key_len); + g_rc4_crypt(rc4_info, key, key_len); + if (key_len == 8) + { + xrdp_sec_make_40bit(key); + } + g_sha1_info_delete(sha1_info); + g_md5_info_delete(md5_info); + g_rc4_info_delete(rc4_info); + return 0; +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_decrypt(struct xrdp_sec* self, char* data, int len) +{ + if (self->decrypt_use_count == 4096) + { + xrdp_sec_update(self->decrypt_key, self->decrypt_update_key, + self->rc4_key_len); + g_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, + self->rc4_key_len); + self->decrypt_use_count = 0; + } + g_rc4_crypt(self->decrypt_rc4_info, data, len); + self->decrypt_use_count++; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_process_logon_info(struct xrdp_sec* self, struct stream* s) +{ + int flags; + int len_domain; + int len_user; + int len_password; + int len_program; + int len_directory; + + in_uint8s(s, 4); + in_uint32_le(s, flags); + DEBUG(("in xrdp_sec_process_logon_info flags $%x\n\r", flags)); + /* this is the first test that the decrypt is working */ + if ((flags & RDP_LOGON_NORMAL) != RDP_LOGON_NORMAL) /* 0x33 */ + { /* must be or error */ + return 1; + } + if (flags & RDP_LOGON_AUTO) + { + } + if (flags & RDP_COMPRESSION) + { + } + in_uint16_le(s, len_domain); + in_uint16_le(s, len_user); + in_uint16_le(s, len_password); + in_uint16_le(s, len_program); + in_uint16_le(s, len_directory); + in_uint8s(s, len_domain + 2); + in_uint8s(s, len_user + 2); + in_uint8s(s, len_password + 2); + in_uint8s(s, len_program + 2); + in_uint8s(s, len_directory + 2); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_send_lic_initial(struct xrdp_sec* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8a(s, lic1, 322); + s_mark_end(s); + if (xrdp_mcs_send(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_send_lic_response(struct xrdp_sec* self) +{ + struct stream* s; + + make_stream(s); + init_stream(s, 8192); + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + out_uint8a(s, lic2, 20); + s_mark_end(s); + if (xrdp_mcs_send(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_reverse(char* p, int len) +{ + int i; + int j; + char temp; + + i = 0; + j = len - 1; + while (i < j) + { + temp = p[i]; + p[i] = p[j]; + p[j] = temp; + i++; + j--; + } +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_rsa_op(char* out, char* in, char* mod, char* exp) +{ + char lexp[64]; + char lmod[64]; + char lin[64]; + char lout[64]; + int len; + + g_memcpy(lexp, exp, 64); + g_memcpy(lmod, mod, 64); + g_memcpy(lin, in, 64); + xrdp_sec_reverse(lexp, 64); + xrdp_sec_reverse(lmod, 64); + xrdp_sec_reverse(lin, 64); + g_memset(lout, 0, 64); + len = g_mod_exp(lout, lin, lmod, lexp); + xrdp_sec_reverse(lout, len); + g_memcpy(out, lout, 64); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt) +{ + int i; + void* sha1_info; + void* md5_info; + char pad[4]; + char sha1_sig[20]; + char md5_sig[16]; + + sha1_info = g_sha1_info_create(); + md5_info = g_md5_info_create(); + for (i = 0; i < 3; i++) + { + g_memset(pad, salt + i, 4); + g_sha1_clear(sha1_info); + g_sha1_transform(sha1_info, pad, i + 1); + g_sha1_transform(sha1_info, in, 48); + g_sha1_transform(sha1_info, salt1, 32); + g_sha1_transform(sha1_info, salt2, 32); + g_sha1_complete(sha1_info, sha1_sig); + g_md5_clear(md5_info); + g_md5_transform(md5_info, in, 48); + g_md5_transform(md5_info, sha1_sig, 20); + g_md5_complete(md5_info, md5_sig); + g_memcpy(out + i * 16, md5_sig, 16); + } + g_sha1_info_delete(sha1_info); + g_md5_info_delete(md5_info); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2) +{ + void* md5_info; + + md5_info = g_md5_info_create(); + g_md5_clear(md5_info); + g_md5_transform(md5_info, in, 16); + g_md5_transform(md5_info, salt1, 32); + g_md5_transform(md5_info, salt2, 32); + g_md5_complete(md5_info, out); + g_md5_info_delete(md5_info); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_establish_keys(struct xrdp_sec* self) +{ + char session_key[48]; + char temp_hash[48]; + char input[48]; + + g_memcpy(input, self->client_random, 24); + g_memcpy(input + 24, self->server_random, 24); + xrdp_sec_hash_48(temp_hash, input, self->client_random, + self->server_random, 65); + xrdp_sec_hash_48(session_key, temp_hash, self->client_random, + self->server_random, 88); + g_memcpy(self->sign_key, session_key, 16); + xrdp_sec_hash_16(self->encrypt_key, session_key + 16, self->client_random, + self->server_random); + xrdp_sec_hash_16(self->decrypt_key, session_key + 32, self->client_random, + self->server_random); + if (self->rc4_key_size == 1) + { + xrdp_sec_make_40bit(self->sign_key); + xrdp_sec_make_40bit(self->encrypt_key); + xrdp_sec_make_40bit(self->decrypt_key); + self->rc4_key_len = 8; + } + else + { + self->rc4_key_len = 16; + } + g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); + g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); + g_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); + g_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan) +{ + int flags; + int len; + + DEBUG((" in xrdp_sec_recv\n\r")); + if (xrdp_mcs_recv(self->mcs_layer, s, chan) != 0) + { + DEBUG((" out xrdp_sec_recv error\n\r")); + return 1; + } + in_uint32_le(s, flags); + DEBUG((" in xrdp_sec_recv flags $%x\n\r", flags)); + if (flags & SEC_ENCRYPT) /* 0x08 */ + { + in_uint8s(s, 8); /* signature */ + xrdp_sec_decrypt(self, s->p, s->end - s->p); + } + if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ + { + in_uint32_le(s, len); + in_uint8a(s, self->client_crypt_random, 64); + xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, + pub_mod, pri_exp); + xrdp_sec_establish_keys(self); + *chan = 1; /* just set a non existing channel and exit */ + return 0; + } + if (flags & SEC_LOGON_INFO) /* 0x40 */ + { + if (xrdp_sec_process_logon_info(self, s) != 0) + { + return 1; + } + if (xrdp_sec_send_lic_initial(self) != 0) + { + return 1; + } + *chan = 1; /* just set a non existing channel and exit */ + return 0; + } + if (flags & SEC_LICENCE_NEG) /* 0x80 */ + { + if (xrdp_sec_send_lic_response(self) != 0) + { + return 1; + } + return -1; /* special error that means send demand active */ + } + DEBUG((" out xrdp_sec_recv error\n\r")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +/* TODO needs outgoing encryption */ +int APP_CC +xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int flags) +{ + DEBUG((" in xrdp_sec_send\n\r")); + s_pop_layer(s, sec_hdr); + out_uint32_le(s, flags); + if (xrdp_mcs_send(self->mcs_layer, s) != 0) + { + return 1; + } + DEBUG((" out xrdp_sec_send\n\r")); + return 0; +} + +/*****************************************************************************/ +/* prepare server mcs data to send in mcs layer */ +static void APP_CC +xrdp_sec_out_mcs_data(struct xrdp_sec* self) +{ + struct stream* p; + + p = &self->server_mcs_data; + init_stream(p, 512); + out_uint16_be(p, 5); + out_uint16_be(p, 0x14); + out_uint8(p, 0x7c); + out_uint16_be(p, 1); + out_uint8(p, 0x2a); + out_uint8(p, 0x14); + out_uint8(p, 0x76); + out_uint8(p, 0x0a); + out_uint8(p, 1); + out_uint8(p, 1); + out_uint8(p, 0); + out_uint16_le(p, 0xc001); + out_uint8(p, 0); + out_uint8(p, 0x4d); /* M */ + out_uint8(p, 0x63); /* c */ + out_uint8(p, 0x44); /* D */ + out_uint8(p, 0x6e); /* n */ + out_uint16_be(p, 0x80fc); + out_uint16_le(p, SEC_TAG_SRV_INFO); + out_uint16_le(p, 8); /* len */ + out_uint8(p, 4); /* 4 = rdp5 1 = rdp4 */ + out_uint8(p, 0); + out_uint8(p, 8); + out_uint8(p, 0); + out_uint16_le(p, SEC_TAG_SRV_CHANNELS); + out_uint16_le(p, 8); /* len */ + out_uint8(p, 0xeb); + out_uint8(p, 3); + out_uint8(p, 0); + out_uint8(p, 0); + out_uint16_le(p, SEC_TAG_SRV_CRYPT); + out_uint16_le(p, 0x00ec); /* len is 236 */ + out_uint32_le(p, 1); /* key len 1 = 40 bit 2 = 128 bit */ + out_uint32_le(p, 1); /* crypt level 1 = low 2 = medium 3 = high */ + out_uint32_le(p, 32); /* 32 bytes random len */ + out_uint32_le(p, 0xb8); /* 184 bytes rsa info(certificate) len */ + out_uint8a(p, self->server_random, 32); + /* here to end is certificate */ + /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ + /* TermService\Parameters\Certificate */ + out_uint32_le(p, 1); + out_uint32_le(p, 1); + out_uint32_le(p, 1); + out_uint16_le(p, SEC_TAG_PUBKEY); + out_uint16_le(p, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */ + out_uint32_le(p, SEC_RSA_MAGIC); + out_uint32_le(p, 0x48); /* 72 bytes modulus len */ + out_uint32_be(p, 0x00020000); + out_uint32_be(p, 0x3f000000); + out_uint8a(p, pub_exp, 4); /* pub exp */ + out_uint8a(p, pub_mod, 64); /* pub mod */ + out_uint8s(p, 8); /* pad */ + out_uint16_le(p, SEC_TAG_KEYSIG); + out_uint16_le(p, 72); /* len */ + out_uint8a(p, pub_sig, 64); /* pub sig */ + out_uint8s(p, 8); /* pad */ + /* end certificate */ + s_mark_end(p); +} + +/*****************************************************************************/ +int APP_CC +xrdp_sec_incoming(struct xrdp_sec* self) +{ + DEBUG(("in xrdp_sec_incoming\n\r")); + xrdp_sec_out_mcs_data(self); + if (xrdp_mcs_incoming(self->mcs_layer) != 0) + { + return 1; + } +#ifdef XRDP_DEBUG + g_printf("client mcs data received\n\r"); + g_hexdump(self->client_mcs_data.data, + self->client_mcs_data.end - self->client_mcs_data.data); + g_printf("server mcs data sent\n\r"); + g_hexdump(self->server_mcs_data.data, + self->server_mcs_data.end - self->server_mcs_data.data); +#endif + DEBUG(("out xrdp_sec_incoming\n\r")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_sec_disconnect(struct xrdp_sec* self) +{ + return xrdp_mcs_disconnect(self->mcs_layer); +} diff --git a/libxrdp/xrdp_tcp.c b/libxrdp/xrdp_tcp.c new file mode 100644 index 00000000..59d4a615 --- /dev/null +++ b/libxrdp/xrdp_tcp.c @@ -0,0 +1,146 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2004-2005 + + tcp layer + +*/ + +#include "libxrdp.h" + +/*****************************************************************************/ +struct xrdp_tcp* APP_CC +xrdp_tcp_create(struct xrdp_iso* owner, int sck) +{ + struct xrdp_tcp* self; + + self = (struct xrdp_tcp*)g_malloc(sizeof(struct xrdp_tcp), 1); + self->iso_layer = owner; + self->sck = sck; + return self; +} + +/*****************************************************************************/ +void APP_CC +xrdp_tcp_delete(struct xrdp_tcp* self) +{ + g_free(self); +} + +/*****************************************************************************/ +/* get out stream ready for data */ +/* returns error */ +int APP_CC +xrdp_tcp_init(struct xrdp_tcp* self, struct stream* s) +{ + init_stream(s, 8192); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_tcp_recv(struct xrdp_tcp* self, struct stream* s, int len) +{ + int rcvd; + + if (self->sck_closed) + { + DEBUG((" in xrdp_tcp_recv, sck closed\n\r")); + return 1; + } + DEBUG((" in xrdp_tcp_recv, gota get %d bytes\n\r", len)); + init_stream(s, len); + while (len > 0) + { + rcvd = g_tcp_recv(self->sck, s->end, len, 0); + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + g_sleep(1); + } + else + { + self->sck_closed = 1; + DEBUG((" error = -1 in xrdp_tcp_recv socket %d\n\r", self->sck)); + return 1; + } + } + else if (rcvd == 0) + { + self->sck_closed = 1; + DEBUG((" error = 0 in xrdp_tcp_recv socket %d\n\r", self->sck)); + return 1; + } + else + { + s->end += rcvd; + len -= rcvd; + } + } + DEBUG((" out xrdp_tcp_recv\n\r")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_tcp_send(struct xrdp_tcp* self, struct stream* s) +{ + int len; + int total; + int sent; + + if (self->sck_closed) + { + DEBUG((" in xrdp_tcp_send, sck closed\n\r")); + return 1; + } + len = s->end - s->data; + DEBUG((" in xrdp_tcp_send, gota send %d bytes\n\r", len)); + total = 0; + while (total < len) + { + sent = g_tcp_send(self->sck, s->data + total, len - total, 0); + if (sent == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + g_sleep(1); + } + else + { + self->sck_closed = 1; + DEBUG((" error = -1 in xrdp_tcp_send socket %d\n\r", self->sck)); + return 1; + } + } + else if (sent == 0) + { + self->sck_closed = 1; + DEBUG((" error = 0 in xrdp_tcp_send socket %d\n\r", self->sck)); + return 1; + } + else + { + total = total + sent; + } + } + DEBUG((" out xrdp_tcp_send, sent %d bytes ok\n\r", len)); + return 0; +} diff --git a/sesman/Makefile b/sesman/Makefile index d75f3e04..7ef8d3f9 100644 --- a/sesman/Makefile +++ b/sesman/Makefile @@ -3,7 +3,7 @@ # in verify_user.c #USE_PAM = "" -SESMANOBJ = sesman.o verify_user.o os_calls.o d3des.o +SESMANOBJ = sesman.o verify_user.o ../common/os_calls.o ../common/d3des.o ifdef USE_PAM CFLAGS = -Wall -O2 -I../common -DUSE_PAM @@ -27,9 +27,3 @@ sesman: $(SESMANOBJ) clean: rm -f $(SESMANOBJ) sesman - -os_calls.o: - $(CC) $(C_OS_FLAGS) ../common/os_calls.c - -d3des.o: - $(CC) $(C_OS_FLAGS) ../common/d3des.c diff --git a/vnc/vnc.c b/vnc/vnc.c index 63c1e2f2..1e895b81 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -121,7 +121,8 @@ int lib_send(struct vnc* v, char* data, int len) } /******************************************************************************/ -int lib_mod_event(struct vnc* v, int msg, int param1, int param2) +int lib_mod_event(struct vnc* v, int msg, long param1, long param2, + long param3, long param4) { struct stream* s; int key; diff --git a/vnc/vnc.h b/vnc/vnc.h index e7ea0ba1..53c9beff 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -32,7 +32,8 @@ struct vnc /* client functions */ int (*mod_start)(struct vnc* v, int w, int h, int bpp); int (*mod_connect)(struct vnc* v); - int (*mod_event)(struct vnc* v, int msg, int param1, int param2); + int (*mod_event)(struct vnc* v, int msg, long param1, long param2, + long param3, long param4); int (*mod_signal)(struct vnc* v); int (*mod_end)(struct vnc* v); int (*mod_set_param)(struct vnc* v, char* name, char* value);