summaryrefslogtreecommitdiffstats
path: root/rdp
diff options
context:
space:
mode:
authorjsorg71 <jsorg71>2005-11-03 02:01:50 +0000
committerjsorg71 <jsorg71>2005-11-03 02:01:50 +0000
commit523ea69fa574dbcbe9e261c8664c8e93f18eb09d (patch)
tree180fed20bd3e54ca7af1d0c02115769b54a0857b /rdp
parent05ec6aa2d59efcf4c489bd3d7decd83be384157c (diff)
downloadxrdp-proprietary-523ea69fa574dbcbe9e261c8664c8e93f18eb09d.tar.gz
xrdp-proprietary-523ea69fa574dbcbe9e261c8664c8e93f18eb09d.zip
early rdp module work
Diffstat (limited to 'rdp')
-rw-r--r--rdp/rdp.c275
-rw-r--r--rdp/rdp.h436
-rw-r--r--rdp/rdp_bitmap.c917
-rw-r--r--rdp/rdp_iso.c25
-rw-r--r--rdp/rdp_lic.c354
-rw-r--r--rdp/rdp_mcs.c53
-rw-r--r--rdp/rdp_orders.c1017
-rw-r--r--rdp/rdp_rdp.c974
-rw-r--r--rdp/rdp_sec.c651
-rw-r--r--rdp/rdp_tcp.c13
10 files changed, 4694 insertions, 21 deletions
diff --git a/rdp/rdp.c b/rdp/rdp.c
new file mode 100644
index 00000000..1a0d88d0
--- /dev/null
+++ b/rdp/rdp.c
@@ -0,0 +1,275 @@
+/*
+ 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 2005
+
+ librdp main file
+
+*/
+
+#include "rdp.h"
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_start(struct mod* mod, int w, int h, int bpp)
+{
+ DEBUG(("in lib_mod_start\r\n"));
+ mod->width = w;
+ mod->height = h;
+ mod->rdp_bpp = bpp;
+ mod->xrdp_bpp = bpp;
+ mod->keylayout = 0x409;
+ DEBUG(("out lib_mod_start\r\n"));
+ return 0;
+}
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_connect(struct mod* mod)
+{
+ DEBUG(("in lib_mod_connect\r\n"));
+ /* clear screen */
+ mod->server_begin_update(mod);
+ mod->server_set_fgcolor(mod, 0);
+ mod->server_fill_rect(mod, 0, 0, mod->width, mod->height);
+ mod->server_end_update(mod);
+ /* connect */
+ if (rdp_rdp_connect(mod->rdp_layer, mod->ip, mod->port) == 0)
+ {
+ mod->sck = mod->rdp_layer->sec_layer->mcs_layer->iso_layer->tcp_layer->sck;
+ DEBUG(("out lib_mod_connect\r\n"));
+ return 0;
+ }
+ DEBUG(("out lib_mod_connect error\r\n"));
+ return 1;
+}
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_event(struct mod* mod, int msg, long param1, long param2,
+ long param3, long param4)
+{
+ struct stream* s;
+
+ if (!mod->up_and_running)
+ {
+ return 0;
+ }
+ DEBUG(("in lib_mod_event\r\n"));
+ make_stream(s);
+ init_stream(s, 8192 * 2);
+ switch (msg)
+ {
+ case 15:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE,
+ param4, param3, 0);
+ break;
+ case 16:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE,
+ param4, param3, 0);
+ break;
+ case 17:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SYNCHRONIZE,
+ param4, param3, 0);
+ break;
+ case 100:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_MOVE, param1, param2);
+ break;
+ case 101:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON1, param1, param2);
+ break;
+ case 102:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN,
+ param1, param2);
+ break;
+ case 103:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON2, param1, param2);
+ break;
+ case 104:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN,
+ param1, param2);
+ break;
+ case 105:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON3, param1, param2);
+ break;
+ case 106:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN,
+ param1, param2);
+ break;
+ case 107:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON4, param1, param2);
+ break;
+ case 108:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON4 | MOUSE_FLAG_DOWN,
+ param1, param2);
+ break;
+ case 109:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON5, param1, param2);
+ break;
+ case 110:
+ rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE,
+ MOUSE_FLAG_BUTTON5 | MOUSE_FLAG_DOWN,
+ param1, param2);
+ break;
+ case 200:
+ rdp_rdp_send_invalidate(mod->rdp_layer, s,
+ (param1 >> 16) & 0xffff, param1 & 0xffff,
+ (param2 >> 16) & 0xffff, param2 & 0xffff);
+ break;
+ }
+ free_stream(s);
+ DEBUG(("out lib_mod_event\r\n"));
+ return 0;
+}
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_signal(struct mod* mod)
+{
+ int type;
+ int cont;
+ struct stream* s;
+
+ DEBUG(("in lib_mod_signal\r\n"));
+ if (mod->in_s == 0)
+ {
+ make_stream(mod->in_s);
+ }
+ s = mod->in_s;
+ init_stream(s, 8192 * 2);
+ cont = 1;
+ while (cont)
+ {
+ type = 0;
+ if (rdp_rdp_recv(mod->rdp_layer, s, &type) != 0)
+ {
+ DEBUG(("out lib_mod_signal error rdp_rdp_recv failed\r\n"));
+ return 1;
+ }
+ DEBUG(("lib_mod_signal type %d\r\n", type));
+ switch (type)
+ {
+ case RDP_PDU_DATA:
+ rdp_rdp_process_data_pdu(mod->rdp_layer, s);
+ break;
+ case RDP_PDU_DEMAND_ACTIVE:
+ rdp_rdp_process_demand_active(mod->rdp_layer, s);
+ mod->up_and_running = 1;
+ break;
+ case RDP_PDU_DEACTIVATE:
+ mod->up_and_running = 0;
+ break;
+ case RDP_PDU_REDIRECT:
+ break;
+ case 0:
+ break;
+ default:
+ break;
+ }
+ cont = s->next_packet < s->end;
+ }
+ DEBUG(("out lib_mod_signal\r\n"));
+ return 0;
+}
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_end(struct mod* mod)
+{
+ rdp_rdp_delete(mod->rdp_layer);
+ mod->rdp_layer = 0;
+ free_stream(mod->in_s);
+ mod->in_s = 0;
+ return 0;
+}
+
+/******************************************************************************/
+/* return error */
+int DEFAULT_CC
+lib_mod_set_param(struct mod* mod, char* name, char* value)
+{
+ if (g_strncasecmp(name, "ip", 255) == 0)
+ {
+ g_strncpy(mod->ip, value, 255);
+ }
+ else if (g_strncasecmp(name, "port", 255) == 0)
+ {
+ g_strncpy(mod->port, value, 255);
+ }
+ else if (g_strncasecmp(name, "username", 255) == 0)
+ {
+ g_strncpy(mod->username, value, 255);
+ }
+ else if (g_strncasecmp(name, "password", 255) == 0)
+ {
+ g_strncpy(mod->password, value, 255);
+ }
+ else if (g_strncasecmp(name, "hostname", 255) == 0)
+ {
+ g_strncpy(mod->hostname, value, 255);
+ }
+ else if (g_strncasecmp(name, "keylayout", 255) == 0)
+ {
+ mod->keylayout = g_atoi(value);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+struct mod* EXPORT_CC
+mod_init(void)
+{
+ struct mod* mod;
+
+ DEBUG(("in mod_init\r\n"));
+ mod = (struct mod*)g_malloc(sizeof(struct mod), 1);
+ mod->size = sizeof(struct mod);
+ mod->handle = (long)mod;
+ mod->mod_connect = lib_mod_connect;
+ mod->mod_start = lib_mod_start;
+ mod->mod_event = lib_mod_event;
+ mod->mod_signal = lib_mod_signal;
+ mod->mod_end = lib_mod_end;
+ mod->mod_set_param = lib_mod_set_param;
+ mod->rdp_layer = rdp_rdp_create(mod);
+ DEBUG(("out mod_init\r\n"));
+ return mod;
+}
+
+/******************************************************************************/
+int EXPORT_CC
+mod_exit(struct mod* mod)
+{
+ DEBUG(("in mod_exit\r\n"));
+ g_free(mod);
+ DEBUG(("out mod_exit\r\n"));
+ return 0;
+}
diff --git a/rdp/rdp.h b/rdp/rdp.h
new file mode 100644
index 00000000..bb5bbb3e
--- /dev/null
+++ b/rdp/rdp.h
@@ -0,0 +1,436 @@
+/*
+ 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 2005
+
+ librdp main header file
+
+*/
+
+/* include other h files */
+#include "arch.h"
+#include "parse.h"
+#include "os_calls.h"
+#include "ssl_calls.h"
+#include "xrdp_constants.h"
+#include "defines.h"
+
+struct rdp_brush
+{
+ int xorigin;
+ int yorigin;
+ int style;
+ char pattern[8];
+};
+
+struct rdp_pen
+{
+ int style;
+ int width;
+ int color;
+};
+
+struct rdp_colormap
+{
+ int ncolors;
+ int colors[256];
+};
+
+struct rdp_bitmap
+{
+ int width;
+ int height;
+ int bpp;
+ char* data;
+};
+
+struct rdp_cursor
+{
+ int x;
+ int y;
+ int width;
+ int height;
+ char mask[(32 * 32) / 8];
+ char data[(32 * 32) * 3];
+};
+
+/* tcp */
+struct rdp_tcp
+{
+ int sck;
+ int sck_closed;
+ struct rdp_iso* iso_layer; /* owner */
+};
+
+/* iso */
+struct rdp_iso
+{
+ struct rdp_mcs* mcs_layer; /* owner */
+ struct rdp_tcp* tcp_layer;
+};
+
+/* mcs */
+struct rdp_mcs
+{
+ struct rdp_sec* sec_layer; /* owner */
+ struct rdp_iso* iso_layer;
+ int userid;
+ struct stream* client_mcs_data;
+ struct stream* server_mcs_data;
+};
+
+/* sec */
+struct rdp_sec
+{
+ struct rdp_rdp* rdp_layer; /* owner */
+ struct rdp_mcs* mcs_layer;
+ struct rdp_lic* lic_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; /* 1 = 40-bit, 2 = 128-bit */
+ int rc4_key_len; /* 8 or 16 */
+ int crypt_level; /* 1 = low, 2 = medium, 3 = high */
+ char sign_key[16];
+ void* decrypt_rc4_info;
+ void* encrypt_rc4_info;
+};
+
+/* licence */
+struct rdp_lic
+{
+ struct rdp_sec* sec_layer; /* owner */
+ char licence_key[16];
+ char licence_sign_key[16];
+ int licence_issued;
+};
+
+/* rdp */
+struct rdp_rdp
+{
+ struct mod* mod;
+ struct rdp_sec* sec_layer;
+ struct rdp_orders* orders;
+ int share_id;
+ int use_rdp5;
+ int bitmap_compression;
+ int bitmap_cache;
+ int desktop_save;
+ int polygon_ellipse_orders;
+ /* cache */
+ struct rdp_colormap colormap;
+ struct rdp_cursor cursors[32];
+};
+
+struct rdp_orders_state
+{
+ /* order stuff */
+ int order_type;
+ /* clip state */
+ int clip_left;
+ int clip_top;
+ int clip_right;
+ int clip_bottom;
+ /* text order state */
+ int text_font;
+ int text_flags;
+ int text_opcode;
+ int text_mixmode;
+ int text_fgcolor;
+ int text_bgcolor;
+ int text_clipleft;
+ int text_cliptop;
+ int text_clipright;
+ int text_clipbottom;
+ int text_boxleft;
+ int text_boxtop;
+ int text_boxright;
+ int text_boxbottom;
+ struct rdp_brush text_brush;
+ int text_x;
+ int text_y;
+ int text_length;
+ char text_text[256];
+ /* destblt order state */
+ int dest_x;
+ int dest_y;
+ int dest_cx;
+ int dest_cy;
+ int dest_opcode;
+ /* patblt order state */
+ int pat_x;
+ int pat_y;
+ int pat_cx;
+ int pat_cy;
+ int pat_opcode;
+ int pat_bgcolor;
+ int pat_fgcolor;
+ struct rdp_brush pat_brush;
+ /* screenblt order state */
+ int screenblt_x;
+ int screenblt_y;
+ int screenblt_cx;
+ int screenblt_cy;
+ int screenblt_opcode;
+ int screenblt_srcx;
+ int screenblt_srcy;
+ /* line order state */
+ int line_mixmode;
+ int line_startx;
+ int line_starty;
+ int line_endx;
+ int line_endy;
+ int line_bgcolor;
+ int line_opcode;
+ struct rdp_pen line_pen;
+ /* rect order state */
+ int rect_x;
+ int rect_y;
+ int rect_cx;
+ int rect_cy;
+ int rect_color;
+ /* desksave order state */
+ int desksave_offset;
+ int desksave_left;
+ int desksave_top;
+ int desksave_right;
+ int desksave_bottom;
+ int desksave_action;
+ /* memblt order state */
+ int memblt_cache_id;
+ int memblt_color_table;
+ int memblt_x;
+ int memblt_y;
+ int memblt_cx;
+ int memblt_cy;
+ int memblt_opcode;
+ int memblt_srcx;
+ int memblt_srcy;
+ int memblt_cache_idx;
+ /* polyline order state */
+ int polyline_x;
+ int polyline_y;
+ int polyline_opcode;
+ int polyline_fgcolor;
+ int polyline_lines;
+ int polyline_datasize;
+ char polyline_data[256];
+};
+
+/* orders */
+struct rdp_orders
+{
+ struct rdp_rdp* rdp_layer;
+ /* order state */
+ struct rdp_orders_state state;
+ /* cache */
+ struct rdp_colormap* cache_colormap[6];
+ struct rdp_bitmap* cache_bitmap[3][600];
+};
+
+struct mod
+{
+ int size; /* size of this struct */
+ /* client functions */
+ int (*mod_start)(struct mod* v, int w, int h, int bpp);
+ int (*mod_connect)(struct mod* v);
+ int (*mod_event)(struct mod* v, int msg, long param1, long param2,
+ long param3, long param4);
+ int (*mod_signal)(struct mod* v);
+ int (*mod_end)(struct mod* v);
+ int (*mod_set_param)(struct mod* v, char* name, char* value);
+ /* server functions */
+ int (*server_begin_update)(struct mod* v);
+ int (*server_end_update)(struct mod* v);
+ int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy);
+ int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy,
+ int srcx, int srcy);
+ int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy,
+ char* data, int width, int height, int srcx, int srcy);
+ int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask);
+ int (*server_palette)(struct mod* v, int* palette);
+ int (*server_msg)(struct mod* v, char* msg, int code);
+ int (*server_is_term)(struct mod* v);
+ int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy);
+ int (*server_reset_clip)(struct mod* v);
+ int (*server_set_fgcolor)(struct mod* v, int fgcolor);
+ int (*server_set_bgcolor)(struct mod* v, int bgcolor);
+ int (*server_set_opcode)(struct mod* v, int opcode);
+ int (*server_set_mixmode)(struct mod* v, int mixmode);
+ int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin,
+ int style, char* pattern);
+ int (*server_set_pen)(struct mod* v, int style,
+ int width);
+ int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2);
+ int (*server_add_char)(struct mod* v, int font, int charactor,
+ int offset, int baseline,
+ int width, int height, char* data);
+ int (*server_draw_text)(struct mod* v, int font,
+ int flags, int mixmode, 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);
+ int (*server_reset)(struct mod* v, int width, int height, int bpp);
+ /* common */
+ long handle; /* pointer to self as long */
+ long wm;
+ long painter;
+ int sck;
+ /* mod data */
+ struct rdp_rdp* rdp_layer;
+ int width;
+ int height;
+ int rdp_bpp;
+ int xrdp_bpp;
+ char ip[256];
+ char port[256];
+ char username[256];
+ char password[256];
+ char hostname[256];
+ char domain[256];
+ char program[256];
+ char directory[256];
+ int keylayout;
+ int up_and_running;
+ struct stream* in_s;
+};
+
+/* rdp_tcp.c */
+struct rdp_tcp* APP_CC
+rdp_tcp_create(struct rdp_iso* owner);
+void APP_CC
+rdp_tcp_delete(struct rdp_tcp* self);
+int APP_CC
+rdp_tcp_init(struct rdp_tcp* self, struct stream* s);
+int APP_CC
+rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len);
+int APP_CC
+rdp_tcp_send(struct rdp_tcp* self, struct stream* s);
+int APP_CC
+rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port);
+int APP_CC
+rdp_tcp_disconnect(struct rdp_tcp* self);
+
+/* rdp_ico.c */
+struct rdp_iso* APP_CC
+rdp_iso_create(struct rdp_mcs* owner);
+void APP_CC
+rdp_iso_delete(struct rdp_iso* self);
+int APP_CC
+rdp_iso_recv(struct rdp_iso* self, struct stream* s);
+int APP_CC
+rdp_iso_init(struct rdp_iso* self, struct stream* s);
+int APP_CC
+rdp_iso_send(struct rdp_iso* self, struct stream* s);
+int APP_CC
+rdp_iso_connect(struct rdp_iso* self, char* ip, char* port);
+int APP_CC
+rdp_iso_disconnect(struct rdp_iso* self);
+
+/* rdp_mcs.c */
+struct rdp_mcs* APP_CC
+rdp_mcs_create(struct rdp_sec* owner,
+ struct stream* client_mcs_data,
+ struct stream* server_mcs_data);
+void APP_CC
+rdp_mcs_delete(struct rdp_mcs* self);
+int APP_CC
+rdp_mcs_init(struct rdp_mcs* self, struct stream* s);
+int APP_CC
+rdp_mcs_send(struct rdp_mcs* self, struct stream* s);
+int APP_CC
+rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port);
+int APP_CC
+rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan);
+
+/* rdp_sec.c */
+struct rdp_sec* APP_CC
+rdp_sec_create(struct rdp_rdp* owner);
+void APP_CC
+rdp_sec_delete(struct rdp_sec* self);
+int APP_CC
+rdp_sec_init(struct rdp_sec* self, struct stream* s, int flags);
+int APP_CC
+rdp_sec_send(struct rdp_sec* self, struct stream* s, int flags);
+int APP_CC
+rdp_sec_recv(struct rdp_sec* self, struct stream* s, int* chan);
+int APP_CC
+rdp_sec_connect(struct rdp_sec* self, char* ip, char* port);
+void APP_CC
+rdp_sec_buf_out_uint32(char* buffer, int value);
+void APP_CC
+rdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2);
+void APP_CC
+rdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt);
+void APP_CC
+rdp_sec_sign(char* signature, int siglen, char* session_key, int keylen,
+ char* data, int datalen);
+
+/* rdp_rdp.c */
+struct rdp_rdp* APP_CC
+rdp_rdp_create(struct mod* owner);
+void APP_CC
+rdp_rdp_delete(struct rdp_rdp* self);
+int APP_CC
+rdp_rdp_connect(struct rdp_rdp* self, char* ip, char* port);
+int APP_CC
+rdp_rdp_send_input(struct rdp_rdp* self, struct stream* s,
+ int time, int message_type,
+ int device_flags, int param1, int param2);
+int APP_CC
+rdp_rdp_send_invalidate(struct rdp_rdp* self, struct stream* s,
+ int left, int top, int width, int height);
+int APP_CC
+rdp_rdp_recv(struct rdp_rdp* self, struct stream* s, int* type);
+int APP_CC
+rdp_rdp_process_data_pdu(struct rdp_rdp* self, struct stream* s);
+int APP_CC
+rdp_rdp_process_demand_active(struct rdp_rdp* self, struct stream* s);
+void APP_CC
+rdp_rdp_out_unistr(struct stream* s, char* text);
+
+/* rdp_bitmap.c */
+int APP_CC
+rdp_bitmap_decompress(char* output, int width, int height, char* input,
+ int size, int Bpp);
+
+/* rdp_orders.c */
+struct rdp_orders* APP_CC
+rdp_orders_create(struct rdp_rdp* owner);
+void APP_CC
+rdp_orders_delete(struct rdp_orders* self);
+void APP_CC
+rdp_orders_reset_state(struct rdp_orders* self);
+int APP_CC
+rdp_orders_process_orders(struct rdp_orders* self, struct stream* s,
+ int num_orders);
+
+/* rdp_lic.c */
+struct rdp_lic* APP_CC
+rdp_lic_create(struct rdp_sec* owner);
+void APP_CC
+rdp_lic_delete(struct rdp_lic* self);
+void APP_CC
+rdp_lic_process(struct rdp_lic* self, struct stream* s);
diff --git a/rdp/rdp_bitmap.c b/rdp/rdp_bitmap.c
new file mode 100644
index 00000000..f5eade66
--- /dev/null
+++ b/rdp/rdp_bitmap.c
@@ -0,0 +1,917 @@
+/*
+ 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 2005
+
+ librdp bitmap routines
+
+*/
+
+#include "rdp.h"
+
+/******************************************************************************/
+#define CVAL(p) ((unsigned char)(*(p++)))
+
+/******************************************************************************/
+#define REPEAT(statement) \
+{ \
+ while ((count > 0) && (x < width)) \
+ { \
+ statement; \
+ count--; \
+ x++; \
+ } \
+}
+
+/******************************************************************************/
+#define MASK_UPDATE \
+{ \
+ mixmask <<= 1; \
+ if ((mixmask & 0xff) == 0) \
+ { \
+ mask = fom_mask ? fom_mask : CVAL(input); \
+ mixmask = 1; \
+ } \
+}
+
+/******************************************************************************/
+/* 1 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress1(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1;
+ char color2;
+ char mix;
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1 = 0;
+ color2 = 0;
+ mix = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1 = CVAL(input);
+ case 3: /* Color */
+ color2 = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ else
+ {
+ line[x] = prevline[x];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT(line[x] = color2)
+ break;
+ case 4: /* Copy */
+ REPEAT(line[x] = CVAL(input))
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x] = color2;
+ bicolor = 0;
+ }
+ else
+ {
+ line[x] = color1;
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/* 2 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress2(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1[2];
+ char color2[2];
+ char mix[2];
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1[0] = 0;
+ color1[1] = 0;
+ color2[0] = 0;
+ color2[1] = 0;
+ mix[0] = 0xff;
+ mix[1] = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1[0] = CVAL(input);
+ color1[1] = CVAL(input);
+ case 3: /* Color */
+ color2[0] = CVAL(input);
+ color2[1] = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix[0] = CVAL(input);
+ mix[1] = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * (width * 2);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = prevline[x * 2 + 0];
+ line[x * 2 + 1] = prevline[x * 2 + 1];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ )
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0];
+ line[x * 2 + 1] = prevline[x * 2 + 1];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT
+ (
+ line[x * 2 + 0] = color2[0];
+ line[x * 2 + 1] = color2[1];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 2 + 0] = CVAL(input);
+ line[x * 2 + 1] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x * 2 + 0] = color2[0];
+ line[x * 2 + 1] = color2[1];
+ bicolor = 0;
+ }
+ else
+ {
+ line[x * 2 + 0] = color1[0];
+ line[x * 2 + 1] = color1[1];
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 2 + 0] = 0xff;
+ line[x * 2 + 1] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ )
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/* 3 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress3(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1[3];
+ char color2[3];
+ char mix[3];
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1[0] = 0;
+ color1[1] = 0;
+ color1[2] = 0;
+ color2[0] = 0;
+ color2[1] = 0;
+ color2[2] = 0;
+ mix[0] = 0xff;
+ mix[1] = 0xff;
+ mix[2] = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1[0] = CVAL(input);
+ color1[1] = CVAL(input);
+ color1[2] = CVAL(input);
+ case 3: /* Color */
+ color2[0] = CVAL(input);
+ color2[1] = CVAL(input);
+ color2[2] = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix[0] = CVAL(input);
+ mix[1] = CVAL(input);
+ mix[2] = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * (width * 3);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = prevline[x * 3 + 0];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ )
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT
+ (
+ line[x * 3 + 0] = color2[0];
+ line[x * 3 + 1] = color2[1];
+ line[x * 3 + 2] = color2[2];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 3 + 0] = CVAL(input);
+ line[x * 3 + 1] = CVAL(input);
+ line[x * 3 + 2] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x * 3 + 0] = color2[0];
+ line[x * 3 + 1] = color2[1];
+ line[x * 3 + 2] = color2[2];
+ bicolor = 0;
+ }
+ else
+ {
+ line[x * 3 + 0] = color1[0];
+ line[x * 3 + 1] = color1[1];
+ line[x * 3 + 2] = color1[2];
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 3 + 0] = 0xff;
+ line[x * 3 + 1] = 0xff;
+ line[x * 3 + 2] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+/* returns boolean */
+int APP_CC
+rdp_bitmap_decompress(char* output, int width, int height, char* input,
+ int size, int Bpp)
+{
+ int rv;
+
+ switch (Bpp)
+ {
+ case 1:
+ rv = bitmap_decompress1(output, width, height, input, size);
+ break;
+ case 2:
+ rv = bitmap_decompress2(output, width, height, input, size);
+ break;
+ case 3:
+ rv = bitmap_decompress3(output, width, height, input, size);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+ return rv;
+}
diff --git a/rdp/rdp_iso.c b/rdp/rdp_iso.c
index ead91d40..6ca94e25 100644
--- a/rdp/rdp_iso.c
+++ b/rdp/rdp_iso.c
@@ -57,17 +57,20 @@ rdp_iso_recv_msg(struct rdp_iso* self, struct stream* s, int* code)
*code = 0;
if (rdp_tcp_recv(self->tcp_layer, s, 4) != 0)
{
+ DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 1 failed\r\n"));
return 1;
}
in_uint8(s, ver);
if (ver != 3)
{
+ DEBUG((" out rdp_iso_recv_msg error ver != 3\r\n"));
return 1;
}
in_uint8s(s, 1);
in_uint16_be(s, len);
if (rdp_tcp_recv(self->tcp_layer, s, len - 4) != 0)
{
+ DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 2 failed\r\n"));
return 1;
}
in_uint8s(s, 1);
@@ -94,7 +97,7 @@ rdp_iso_send_msg(struct rdp_iso* self, struct stream* s, int code)
out_uint8(s, 3);
out_uint8(s, 0);
out_uint16_be(s, 11); /* length */
- out_uint8(s, 8);
+ out_uint8(s, 6);
out_uint8(s, code);
out_uint16_le(s, 0);
out_uint16_le(s, 0);
@@ -165,17 +168,20 @@ rdp_iso_connect(struct rdp_iso* self, char* ip, char* port)
int code;
struct stream* s;
+ DEBUG((" in rdp_iso_connect\r\n"));
make_stream(s);
init_stream(s, 8192);
if (rdp_tcp_connect(self->tcp_layer, ip, port) != 0)
{
free_stream(s);
+ DEBUG((" out rdp_iso_connect error rdp_tcp_connect failed\r\n"));
return 1;
}
if (rdp_iso_send_msg(self, s, ISO_PDU_CR) != 0)
{
free_stream(s);
rdp_tcp_disconnect(self->tcp_layer);
+ DEBUG((" out rdp_iso_connect error rdp_iso_send_msg failed\r\n"));
return 1;
}
init_stream(s, 8192);
@@ -183,14 +189,31 @@ rdp_iso_connect(struct rdp_iso* self, char* ip, char* port)
{
free_stream(s);
rdp_tcp_disconnect(self->tcp_layer);
+ DEBUG((" out rdp_iso_connect error rdp_iso_recv_msg failed\r\n"));
return 1;
}
if (code != ISO_PDU_CC)
{
free_stream(s);
rdp_tcp_disconnect(self->tcp_layer);
+ DEBUG((" out rdp_iso_connect error code != ISO_PDU_CC\r\n"));
return 1;
}
free_stream(s);
+ DEBUG((" out rdp_iso_connect\r\n"));
+ return 0;
+}
+
+/*****************************************************************************/
+int APP_CC
+rdp_iso_disconnect(struct rdp_iso* self)
+{
+ struct stream* s;
+
+ make_stream(s);
+ init_stream(s, 8192);
+ rdp_iso_send_msg(self, s, ISO_PDU_DR);
+ rdp_tcp_disconnect(self->tcp_layer);
+ free_stream(s);
return 0;
}
diff --git a/rdp/rdp_lic.c b/rdp/rdp_lic.c
new file mode 100644
index 00000000..bc4d7283
--- /dev/null
+++ b/rdp/rdp_lic.c
@@ -0,0 +1,354 @@
+/*
+ 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 2005
+
+ licence
+
+*/
+
+#include "rdp.h"
+
+/*****************************************************************************/
+struct rdp_lic* APP_CC
+rdp_lic_create(struct rdp_sec* owner)
+{
+ struct rdp_lic* self;
+
+ self = (struct rdp_lic*)g_malloc(sizeof(struct rdp_lic), 1);
+ return self;
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_lic_delete(struct rdp_lic* self)
+{
+ if (self == 0)
+ {
+ return;
+ }
+ g_free(self);
+}
+
+/*****************************************************************************/
+/* Generate a session key and RC4 keys, given client and server randoms */
+static void APP_CC
+rdp_lic_generate_keys(struct rdp_lic* self, char* client_random,
+ char* server_random, char* pre_master_secret)
+{
+ char master_secret[48];
+ char key_block[48];
+
+ /* Generate master secret and then key material */
+ rdp_sec_hash_48(master_secret, pre_master_secret, client_random,
+ server_random, 65);
+ rdp_sec_hash_48(key_block, master_secret, server_random,
+ client_random, 65);
+ /* Store first 16 bytes of session key as MAC secret */
+ g_memcpy(self->licence_sign_key, key_block, 16);
+ /* Generate RC4 key from next 16 bytes */
+ rdp_sec_hash_16(self->licence_key, key_block + 16, client_random,
+ server_random);
+}
+
+/*****************************************************************************/
+static void APP_CC
+rdp_lic_generate_hwid(struct rdp_lic* self, char* hwid)
+{
+ rdp_sec_buf_out_uint32(hwid, 2);
+ g_strncpy(hwid + 4, self->sec_layer->rdp_layer->mod->hostname,
+ LICENCE_HWID_SIZE - 4);
+}
+
+/*****************************************************************************/
+/* Present an existing licence to the server */
+static void APP_CC
+rdp_lic_present(struct rdp_lic* self, char* client_random, char* rsa_data,
+ char* licence_data, int licence_size, char* hwid,
+ char* signature)
+{
+ int sec_flags;
+ int length;
+ struct stream* s;
+
+ sec_flags = SEC_LICENCE_NEG;
+ length = 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE +
+ licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE;
+ make_stream(s);
+ init_stream(s, 8192);
+ rdp_sec_init(self->sec_layer, s, sec_flags);
+ out_uint8(s, LICENCE_TAG_PRESENT);
+ out_uint8(s, 2); /* version */
+ out_uint16_le(s, length);
+ out_uint32_le(s, 1);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, 0x0201);
+ out_uint8p(s, client_random, SEC_RANDOM_SIZE);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
+ out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+ out_uint16_le(s, 1);
+ out_uint16_le(s, licence_size);
+ out_uint8p(s, licence_data, licence_size);
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_HWID_SIZE);
+ out_uint8p(s, hwid, LICENCE_HWID_SIZE);
+ out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
+ s_mark_end(s);
+ rdp_sec_send(self->sec_layer, s, sec_flags);
+ free_stream(s);
+}
+
+/*****************************************************************************/
+/* Send a licence request packet */
+static void APP_CC
+rdp_lic_send_request(struct rdp_lic* self, char* client_random,
+ char* rsa_data, char* user, char* host)
+{
+ int sec_flags;
+ int userlen;
+ int hostlen;
+ int length;
+ struct stream* s;
+
+ sec_flags = SEC_LICENCE_NEG;
+ userlen = g_strlen(self->sec_layer->rdp_layer->mod->username) + 1;
+ hostlen = g_strlen(self->sec_layer->rdp_layer->mod->hostname) + 1;
+ length = 128 + userlen + hostlen;
+ make_stream(s);
+ init_stream(s, 8192);
+ rdp_sec_init(self->sec_layer, s, sec_flags);
+ out_uint8(s, LICENCE_TAG_REQUEST);
+ out_uint8(s, 2); /* version */
+ out_uint16_le(s, length);
+ out_uint32_le(s, 1);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, 0xff01);
+ out_uint8p(s, client_random, SEC_RANDOM_SIZE);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
+ out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+ out_uint16_le(s, LICENCE_TAG_USER);
+ out_uint16_le(s, userlen);
+ out_uint8p(s, user, userlen);
+ out_uint16_le(s, LICENCE_TAG_HOST);
+ out_uint16_le(s, hostlen);
+ out_uint8p(s, host, hostlen);
+ s_mark_end(s);
+ rdp_sec_send(self->sec_layer, s, sec_flags);
+ free_stream(s);
+}
+
+/*****************************************************************************/
+/* Process a licence demand packet */
+static void APP_CC
+rdp_lic_process_demand(struct rdp_lic* self, struct stream* s)
+{
+ char null_data[SEC_MODULUS_SIZE];
+ char* server_random;
+ char signature[LICENCE_SIGNATURE_SIZE];
+ char hwid[LICENCE_HWID_SIZE];
+ char* licence_data;
+ int licence_size;
+ void* crypt_key;
+
+ /* Retrieve the server random from the incoming packet */
+ in_uint8p(s, server_random, SEC_RANDOM_SIZE);
+ /* We currently use null client keys. This is a bit naughty but, hey,
+ the security of licence negotiation isn't exactly paramount. */
+ g_memset(null_data, 0, sizeof(null_data));
+ rdp_lic_generate_keys(self, null_data, server_random, null_data);
+ licence_size = 0; /* todo load_licence(&licence_data); */
+ if (licence_size > 0)
+ {
+ /* Generate a signature for the HWID buffer */
+ rdp_lic_generate_hwid(self, hwid);
+ rdp_sec_sign(signature, 16, self->licence_sign_key, 16,
+ hwid, sizeof(hwid));
+ /* Now encrypt the HWID */
+ crypt_key = g_rc4_info_create();
+ g_rc4_set_key(crypt_key, self->licence_key, 16);
+ g_rc4_crypt(crypt_key, hwid, sizeof(hwid));
+ g_rc4_info_delete(crypt_key);
+ rdp_lic_present(self, null_data, null_data, licence_data,
+ licence_size, hwid, signature);
+ g_free(licence_data);
+ return;
+ }
+ rdp_lic_send_request(self, null_data, null_data,
+ self->sec_layer->rdp_layer->mod->username,
+ self->sec_layer->rdp_layer->mod->hostname);
+}
+
+/*****************************************************************************/
+/* Send an authentication response packet */
+static void APP_CC
+rdp_lic_send_authresp(struct rdp_lic* self, char* token, char* crypt_hwid,
+ char* signature)
+{
+ int sec_flags;
+ int length;
+ struct stream* s;
+
+ sec_flags = SEC_LICENCE_NEG;
+ length = 58;
+ make_stream(s);
+ init_stream(s, 8192);
+ rdp_sec_init(self->sec_layer, s, sec_flags);
+ out_uint8(s, LICENCE_TAG_AUTHRESP);
+ out_uint8(s, 2); /* version */
+ out_uint16_le(s, length);
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_TOKEN_SIZE);
+ out_uint8p(s, token, LICENCE_TOKEN_SIZE);
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_HWID_SIZE);
+ out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE);
+ out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
+ s_mark_end(s);
+ rdp_sec_send(self->sec_layer, s, sec_flags);
+ free_stream(s);
+}
+
+/*****************************************************************************/
+/* Parse an authentication request packet */
+/* returns boolean */
+static int APP_CC
+rdp_lic_parse_authreq(struct rdp_lic* self, struct stream* s,
+ char** token, char** signature)
+{
+ int tokenlen;
+
+ in_uint8s(s, 6); /* unknown: f8 3d 15 00 04 f6 */
+ in_uint16_le(s, tokenlen);
+ if (tokenlen != LICENCE_TOKEN_SIZE)
+ {
+ /* error("token len %d\n", tokenlen); */
+ return 0;
+ }
+ in_uint8p(s, *token, tokenlen);
+ in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE);
+ return s_check_end(s);
+}
+
+/*****************************************************************************/
+/* Process an authentication request packet */
+static void APP_CC
+rdp_lic_process_authreq(struct rdp_lic* self, struct stream* s)
+{
+ char* in_token;
+ char* in_sig;
+ char out_token[LICENCE_TOKEN_SIZE];
+ char decrypt_token[LICENCE_TOKEN_SIZE];
+ char hwid[LICENCE_HWID_SIZE];
+ char crypt_hwid[LICENCE_HWID_SIZE];
+ char sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE];
+ char out_sig[LICENCE_SIGNATURE_SIZE];
+ void* crypt_key;
+
+ /* Parse incoming packet and save the encrypted token */
+ rdp_lic_parse_authreq(self, s, &in_token, &in_sig);
+ g_memcpy(out_token, in_token, LICENCE_TOKEN_SIZE);
+ /* Decrypt the token. It should read TEST in Unicode. */
+ crypt_key = g_rc4_info_create();
+ g_rc4_set_key(crypt_key, self->licence_key, 16);
+ g_memcpy(decrypt_token, in_token, LICENCE_TOKEN_SIZE);
+ g_rc4_crypt(crypt_key, decrypt_token, LICENCE_TOKEN_SIZE);
+ /* Generate a signature for a buffer of token and HWID */
+ rdp_lic_generate_hwid(self, hwid);
+ g_memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE);
+ g_memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE);
+ rdp_sec_sign(out_sig, 16, self->licence_sign_key, 16, sealed_buffer,
+ sizeof(sealed_buffer));
+ /* Now encrypt the HWID */
+ g_rc4_set_key(crypt_key, self->licence_key, 16);
+ g_memcpy(crypt_hwid, hwid, LICENCE_HWID_SIZE);
+ g_rc4_crypt(crypt_key, crypt_hwid, LICENCE_HWID_SIZE);
+ rdp_lic_send_authresp(self, out_token, crypt_hwid, out_sig);
+ g_rc4_info_delete(crypt_key);
+}
+
+/*****************************************************************************/
+/* Process an licence issue packet */
+static void APP_CC
+rdp_lic_process_issue(struct rdp_lic* self, struct stream* s)
+{
+ void* crypt_key;
+ int length;
+ int check;
+ int i;
+
+ in_uint8s(s, 2); /* 3d 45 - unknown */
+ in_uint16_le(s, length);
+ if (!s_check_rem(s, length))
+ {
+ return;
+ }
+ crypt_key = g_rc4_info_create();
+ g_rc4_set_key(crypt_key, self->licence_key, 16);
+ g_rc4_crypt(crypt_key, s->p, length);
+ g_rc4_info_delete(crypt_key);
+ in_uint16_le(s, check);
+ if (check != 0)
+ {
+ return;
+ }
+ self->licence_issued = 1;
+ in_uint8s(s, 2); /* pad */
+ /* advance to fourth string */
+ length = 0;
+ for (i = 0; i < 4; i++)
+ {
+ in_uint8s(s, length);
+ in_uint32_le(s, length);
+ if (!s_check_rem(s, length))
+ {
+ return;
+ }
+ }
+ /* todo save_licence(s->p, length); */
+}
+
+/******************************************************************************/
+/* Process a licence packet */
+void APP_CC
+rdp_lic_process(struct rdp_lic* self, struct stream* s)
+{
+ int tag;
+
+ in_uint8(s, tag);
+ in_uint8s(s, 3); /* version, length */
+ switch (tag)
+ {
+ case LICENCE_TAG_DEMAND:
+ rdp_lic_process_demand(self, s);
+ break;
+ case LICENCE_TAG_AUTHREQ:
+ rdp_lic_process_authreq(self, s);
+ break;
+ case LICENCE_TAG_ISSUE:
+ rdp_lic_process_issue(self, s);
+ break;
+ case LICENCE_TAG_REISSUE:
+ case LICENCE_TAG_RESULT:
+ break;
+ default:
+ break;
+ /* todo unimpl("licence tag 0x%x\n", tag); */
+ }
+}
diff --git a/rdp/rdp_mcs.c b/rdp/rdp_mcs.c
index e472a1af..5023abda 100644
--- a/rdp/rdp_mcs.c
+++ b/rdp/rdp_mcs.c
@@ -33,7 +33,6 @@ rdp_mcs_create(struct rdp_sec* owner,
self = (struct rdp_mcs*)g_malloc(sizeof(struct rdp_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 = rdp_iso_create(self);
@@ -61,6 +60,7 @@ rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan)
int opcode;
int len;
+ DEBUG((" in rdp_mcs_recv\r\n"));
if (rdp_iso_recv(self->iso_layer, s) != 0)
{
return 1;
@@ -69,14 +69,18 @@ rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan)
appid = opcode >> 2;
if (appid != MCS_SDIN)
{
+ DEBUG((" out rdp_mcs_recv error\r\n"));
return 1;
}
- in_uint8s(s, 5);
+ 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 rdp_mcs_recv\r\n"));
return 0;
}
@@ -106,6 +110,7 @@ rdp_mcs_ber_out_header(struct rdp_mcs* self, struct stream* s,
return 0;
}
+#if 0
/*****************************************************************************/
/* returns error */
static int APP_CC
@@ -115,10 +120,10 @@ rdp_mcs_ber_out_int8(struct rdp_mcs* self, struct stream* s, int value)
out_uint8(s, value);
return 0;
}
+#endif
/*****************************************************************************/
/* returns error */
-#if 0
static int APP_CC
rdp_mcs_ber_out_int16(struct rdp_mcs* self, struct stream* s, int value)
{
@@ -127,8 +132,8 @@ rdp_mcs_ber_out_int16(struct rdp_mcs* self, struct stream* s, int value)
out_uint8(s, value);
return 0;
}
-#endif
+#if 0
/*****************************************************************************/
/* returns error */
static int APP_CC
@@ -140,6 +145,7 @@ rdp_mcs_ber_out_int24(struct rdp_mcs* self, struct stream* s, int value)
out_uint8(s, value);
return 0;
}
+#endif
/*****************************************************************************/
/* returns error */
@@ -150,14 +156,14 @@ rdp_mcs_out_domain_params(struct rdp_mcs* self, struct stream* s,
int max_pdu_size)
{
rdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26);
- rdp_mcs_ber_out_int8(self, s, max_channels);
- rdp_mcs_ber_out_int8(self, s, max_users);
- rdp_mcs_ber_out_int8(self, s, max_tokens);
- rdp_mcs_ber_out_int8(self, s, 1);
- rdp_mcs_ber_out_int8(self, s, 0);
- rdp_mcs_ber_out_int8(self, s, 1);
- rdp_mcs_ber_out_int24(self, s, max_pdu_size);
- rdp_mcs_ber_out_int8(self, s, 2);
+ rdp_mcs_ber_out_int16(self, s, max_channels);
+ rdp_mcs_ber_out_int16(self, s, max_users);
+ rdp_mcs_ber_out_int16(self, s, max_tokens);
+ rdp_mcs_ber_out_int16(self, s, 1);
+ rdp_mcs_ber_out_int16(self, s, 0);
+ rdp_mcs_ber_out_int16(self, s, 1);
+ rdp_mcs_ber_out_int16(self, s, max_pdu_size);
+ rdp_mcs_ber_out_int16(self, s, 2);
return 0;
}
@@ -172,7 +178,7 @@ rdp_mcs_send_connection_initial(struct rdp_mcs* self)
make_stream(s);
init_stream(s, 8192);
- data_len = self->server_mcs_data->end - self->server_mcs_data->data;
+ data_len = self->client_mcs_data->end - self->client_mcs_data->data;
len = 7 + 3 * 34 + 4 + data_len;
if (rdp_iso_init(self->iso_layer, s) != 0)
{
@@ -188,7 +194,7 @@ rdp_mcs_send_connection_initial(struct rdp_mcs* self)
rdp_mcs_out_domain_params(self, s, 1, 1, 1, 0x420); /* min params */
rdp_mcs_out_domain_params(self, s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */
rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len);
- out_uint8p(s, self->server_mcs_data->data, data_len);
+ out_uint8p(s, self->client_mcs_data->data, data_len);
s_mark_end(s);
if (rdp_iso_send(self->iso_layer, s) != 0)
{
@@ -297,13 +303,13 @@ rdp_mcs_recv_connection_response(struct rdp_mcs* self)
in_uint8s(s, len); /* connect id */
rdp_mcs_parse_domain_params(self, s);
rdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len);
- if (len > self->client_mcs_data->size)
+ if (len > self->server_mcs_data->size)
{
- len = self->client_mcs_data->size;
+ len = self->server_mcs_data->size;
}
- in_uint8a(s, self->client_mcs_data->data, len);
- self->client_mcs_data->p = self->client_mcs_data->data;
- self->client_mcs_data->end = self->client_mcs_data->data + len;
+ in_uint8a(s, self->server_mcs_data->data, len);
+ self->server_mcs_data->p = self->server_mcs_data->data;
+ self->server_mcs_data->end = self->server_mcs_data->data + len;
if (s_check_end(s))
{
free_stream(s);
@@ -468,7 +474,6 @@ rdp_mcs_recv_cjcf(struct rdp_mcs* self)
if (opcode & 2)
{
in_uint8s(s, 2); /* join_chanid */
- in_uint8s(s, self->userid);
}
if (!(s_check_end(s)))
{
@@ -484,14 +489,18 @@ rdp_mcs_recv_cjcf(struct rdp_mcs* self)
int APP_CC
rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port)
{
+ DEBUG((" in rdp_mcs_connect\r\n"));
if (rdp_iso_connect(self->iso_layer, ip, port) != 0)
{
+ DEBUG((" out rdp_mcs_connect error rdp_iso_connect failed\r\n"));
return 1;
}
rdp_mcs_send_connection_initial(self);
if (rdp_mcs_recv_connection_response(self) != 0)
{
rdp_iso_disconnect(self->iso_layer);
+ DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_connection_response \
+failed\r\n"));
return 1;
}
rdp_mcs_send_edrq(self);
@@ -499,20 +508,24 @@ rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port)
if (rdp_mcs_recv_aucf(self) != 0)
{
rdp_iso_disconnect(self->iso_layer);
+ DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_aucf failed\r\n"));
return 1;
}
rdp_mcs_send_cjrq(self, self->userid + 1001);
if (rdp_mcs_recv_cjcf(self) != 0)
{
rdp_iso_disconnect(self->iso_layer);
+ DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 1 failed\r\n"));
return 1;
}
rdp_mcs_send_cjrq(self, MCS_GLOBAL_CHANNEL);
if (rdp_mcs_recv_cjcf(self) != 0)
{
rdp_iso_disconnect(self->iso_layer);
+ DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 2 failed\r\n"));
return 1;
}
+ DEBUG((" out rdp_mcs_connect\r\n"));
return 0;
}
diff --git a/rdp/rdp_orders.c b/rdp/rdp_orders.c
new file mode 100644
index 00000000..a22faa27
--- /dev/null
+++ b/rdp/rdp_orders.c
@@ -0,0 +1,1017 @@
+/*
+ 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 2005
+
+ librdp orders
+
+*/
+
+#include "rdp.h"
+
+/*****************************************************************************/
+struct rdp_orders* APP_CC
+rdp_orders_create(struct rdp_rdp* owner)
+{
+ struct rdp_orders* self;
+
+ self = (struct rdp_orders*)g_malloc(sizeof(struct rdp_orders), 1);
+ self->rdp_layer = owner;
+ return self;
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_orders_delete(struct rdp_orders* self)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < 6; i++)
+ {
+ g_free(self->cache_colormap[i]);
+ }
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 600; j++)
+ {
+ if (self->cache_bitmap[i][j] != 0)
+ {
+ g_free(self->cache_bitmap[i][j]->data);
+ }
+ g_free(self->cache_bitmap[i][j]);
+ }
+ }
+ g_free(self);
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_orders_reset_state(struct rdp_orders* self)
+{
+ g_memset(&self->state, 0, sizeof(self->state));
+}
+
+/*****************************************************************************/
+/* Read field indicating which parameters are present */
+static void APP_CC
+rdp_orders_in_present(struct stream* s, int* present,
+ int flags, int size)
+{
+ int bits;
+ int i;
+
+ if (flags & RDP_ORDER_SMALL)
+ {
+ size--;
+ }
+ if (flags & RDP_ORDER_TINY)
+ {
+ if (size < 2)
+ {
+ size = 0;
+ }
+ else
+ {
+ size -= 2;
+ }
+ }
+ *present = 0;
+ for (i = 0; i < size; i++)
+ {
+ in_uint8(s, bits);
+ *present |= bits << (i * 8);
+ }
+}
+
+/*****************************************************************************/
+/* Read a co-ordinate (16-bit, or 8-bit delta) */
+static void APP_CC
+rdp_orders_in_coord(struct stream* s, int* coord, int delta)
+{
+ char change;
+
+ if (delta)
+ {
+ in_uint8(s, change);
+ *coord += change;
+ }
+ else
+ {
+ in_sint16_le(s, *coord);
+ }
+}
+
+/*****************************************************************************/
+/* Parse bounds information */
+static void APP_CC
+rdp_orders_parse_bounds(struct rdp_orders* self, struct stream* s)
+{
+ int present;
+
+ in_uint8(s, present);
+ if (present & 1)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_left, 0);
+ }
+ else if (present & 16)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_left, 1);
+ }
+ if (present & 2)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_top, 0);
+ }
+ else if (present & 32)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_top, 1);
+ }
+ if (present & 4)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_right, 0);
+ }
+ else if (present & 64)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_right, 1);
+ }
+ if (present & 8)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_bottom, 0);
+ }
+ else if (present & 128)
+ {
+ rdp_orders_in_coord(s, &self->state.clip_bottom, 1);
+ }
+}
+
+/*****************************************************************************/
+/* Process a colormap cache order */
+static void APP_CC
+rdp_orders_process_colcache(struct rdp_orders* self, struct stream* s,
+ int flags)
+{
+ struct rdp_colormap* colormap;
+ int cache_id;
+ int i;
+
+ colormap = (struct rdp_colormap*)g_malloc(sizeof(struct rdp_colormap), 1);
+ in_uint8(s, cache_id);
+ in_uint16_le(s, colormap->ncolors);
+ for (i = 0; i < colormap->ncolors; i++)
+ {
+ in_uint32_le(s, colormap->colors[i]);
+ }
+ g_free(self->cache_colormap[cache_id]);
+ self->cache_colormap[cache_id] = colormap;
+}
+
+/*****************************************************************************/
+/* Process a raw bitmap cache order */
+static void APP_CC
+rdp_orders_process_raw_bmpcache(struct rdp_orders* self, struct stream* s,
+ int flags)
+{
+ int cache_idx;
+ int bufsize;
+ int cache_id;
+ int width;
+ int height;
+ int bpp;
+ int Bpp;
+ int y;
+ char* data;
+ char* inverted;
+ char* src;
+ char* dst;
+ struct rdp_bitmap* bitmap;
+
+ in_uint8(s, cache_id);
+ in_uint8s(s, 1);
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, bufsize);
+ in_uint16_le(s, cache_idx);
+ in_uint8p(s, data, bufsize);
+ inverted = (char*)g_malloc(width * height * Bpp, 0);
+ for (y = 0; y < height; y++)
+ {
+ src = data + (y * (width * Bpp));
+ dst = inverted + (((height - y) - 1) * (width * Bpp));
+ g_memcpy(dst, src, width * Bpp);
+ }
+ bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0);
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->data = inverted;
+ if (self->cache_bitmap[cache_id][cache_idx] != 0)
+ {
+ g_free(self->cache_bitmap[cache_id][cache_idx]->data);
+ }
+ g_free(self->cache_bitmap[cache_id][cache_idx]);
+ self->cache_bitmap[cache_id][cache_idx] = bitmap;
+}
+
+/*****************************************************************************/
+/* Process a bitmap cache order */
+static void APP_CC
+rdp_orders_process_bmpcache(struct rdp_orders* self, struct stream* s,
+ int flags)
+{
+ char* data;
+ char* bmpdata;
+ int cache_idx;
+ int size;
+ int cache_id;
+ int width;
+ int height;
+ int bpp;
+ int Bpp;
+ int bufsize;
+ int pad1;
+ int pad2;
+ int row_size;
+ int final_size;
+ struct rdp_bitmap* bitmap;
+
+ in_uint8(s, cache_id);
+ in_uint8(s, pad1);
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, bufsize);
+ in_uint16_le(s, cache_idx);
+ if (flags & 1024)
+ {
+ size = bufsize;
+ }
+ else
+ {
+ in_uint16_le(s, pad2);
+ in_uint16_le(s, size);
+ in_uint16_le(s, row_size);
+ in_uint16_le(s, final_size);
+ }
+ in_uint8p(s, data, size);
+ bmpdata = (char*)g_malloc(width * height * Bpp, 0);
+ if (rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp))
+ {
+ }
+ else
+ {
+ /* error */
+ }
+ bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0);
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->data = bmpdata;
+ if (self->cache_bitmap[cache_id][cache_idx] != 0)
+ {
+ g_free(self->cache_bitmap[cache_id][cache_idx]->data);
+ }
+ g_free(self->cache_bitmap[cache_id][cache_idx]);
+ self->cache_bitmap[cache_id][cache_idx] = bitmap;
+}
+
+/*****************************************************************************/
+/* Process a font cache order */
+static void APP_CC
+rdp_orders_process_fontcache(struct rdp_orders* self, struct stream* s,
+ int flags)
+{
+ int font;
+ int nglyphs;
+ int character;
+ int offset;
+ int baseline;
+ int width;
+ int height;
+ int i;
+ int datasize;
+ char* data;
+
+ in_uint8(s, font);
+ in_uint8(s, nglyphs);
+ for (i = 0; i < nglyphs; i++)
+ {
+ in_uint16_le(s, character);
+ in_uint16_le(s, offset);
+ in_uint16_le(s, baseline);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+ datasize = (height * ((width + 7) / 8) + 3) & ~3;
+ in_uint8p(s, data, datasize);
+ self->rdp_layer->mod->server_add_char(self->rdp_layer->mod, font,
+ character, offset, baseline,
+ width, height, data);
+ }
+}
+
+/*****************************************************************************/
+/* Process a secondary order */
+static int APP_CC
+rdp_orders_process_secondary_order(struct rdp_orders* self, struct stream* s)
+{
+ short length;
+ int flags;
+ int type;
+ char* next_order;
+
+ in_uint16_le(s, length);
+ in_uint16_le(s, flags);
+ in_uint8(s, type);
+ next_order = s->p + length + 7;
+ switch (type)
+ {
+ case RDP_ORDER_COLCACHE:
+ rdp_orders_process_colcache(self, s, flags);
+ break;
+ case RDP_ORDER_RAW_BMPCACHE:
+ rdp_orders_process_raw_bmpcache(self, s, flags);
+ break;
+ case RDP_ORDER_BMPCACHE:
+ rdp_orders_process_bmpcache(self, s, flags);
+ break;
+ case RDP_ORDER_FONTCACHE:
+ rdp_orders_process_fontcache(self, s, flags);
+ break;
+ default:
+ /* error, unknown order */
+ break;
+ }
+ s->p = next_order;
+ return 0;
+}
+
+/*****************************************************************************/
+/* Read a color entry */
+static void APP_CC
+rdp_orders_in_color(struct stream* s, int* color)
+{
+ int i;
+
+ in_uint8(s, i);
+ *color = i;
+ in_uint8(s, i);
+ *color |= i << 8;
+ in_uint8(s, i);
+ *color |= i << 16;
+}
+
+/*****************************************************************************/
+/* Parse a brush */
+static void APP_CC
+rdp_orders_parse_brush(struct stream* s, struct rdp_brush* brush, int present)
+{
+ if (present & 1)
+ {
+ in_uint8(s, brush->xorigin);
+ }
+ if (present & 2)
+ {
+ in_uint8(s, brush->yorigin);
+ }
+ if (present & 4)
+ {
+ in_uint8(s, brush->style);
+ }
+ if (present & 8)
+ {
+ in_uint8(s, brush->pattern[0]);
+ }
+ if (present & 16)
+ {
+ in_uint8a(s, brush->pattern + 1, 7);
+ }
+}
+
+/*****************************************************************************/
+/* Parse a pen */
+static void APP_CC
+rdp_orders_parse_pen(struct stream* s, struct rdp_pen* pen, int present)
+{
+ if (present & 1)
+ {
+ in_uint8(s, pen->style);
+ }
+ if (present & 2)
+ {
+ in_uint8(s, pen->width);
+ }
+ if (present & 4)
+ {
+ rdp_orders_in_color(s, &pen->color);
+ }
+}
+
+/*****************************************************************************/
+/* Process a text order */
+static void APP_CC
+rdp_orders_process_text2(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x000001)
+ {
+ in_uint8(s, self->state.text_font);
+ }
+ if (present & 0x000002)
+ {
+ in_uint8(s, self->state.text_flags);
+ }
+ if (present & 0x000004)
+ {
+ in_uint8(s, self->state.text_opcode);
+ }
+ if (present & 0x000008)
+ {
+ in_uint8(s, self->state.text_mixmode);
+ }
+ if (present & 0x000010)
+ {
+ rdp_orders_in_color(s, &self->state.text_fgcolor);
+ }
+ if (present & 0x000020)
+ {
+ rdp_orders_in_color(s, &self->state.text_bgcolor);
+ }
+ if (present & 0x000040)
+ {
+ in_sint16_le(s, self->state.text_clipleft);
+ }
+ if (present & 0x000080)
+ {
+ in_sint16_le(s, self->state.text_cliptop);
+ }
+ if (present & 0x000100)
+ {
+ in_sint16_le(s, self->state.text_clipright);
+ }
+ if (present & 0x000200)
+ {
+ in_sint16_le(s, self->state.text_clipbottom);
+ }
+ if (present & 0x000400)
+ {
+ in_sint16_le(s, self->state.text_boxleft);
+ }
+ if (present & 0x000800)
+ {
+ in_sint16_le(s, self->state.text_boxtop);
+ }
+ if (present & 0x001000)
+ {
+ in_sint16_le(s, self->state.text_boxright);
+ }
+ if (present & 0x002000)
+ {
+ in_sint16_le(s, self->state.text_boxbottom);
+ }
+ rdp_orders_parse_brush(s, &self->state.text_brush, present >> 14);
+ if (present & 0x080000)
+ {
+ in_sint16_le(s, self->state.text_x);
+ }
+ if (present & 0x100000)
+ {
+ in_sint16_le(s, self->state.text_y);
+ }
+ if (present & 0x200000)
+ {
+ in_uint8(s, self->state.text_length);
+ in_uint8a(s, self->state.text_text, self->state.text_length);
+ }
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.text_opcode);
+ self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod,
+ self->state.text_fgcolor);
+ self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod,
+ self->state.text_bgcolor);
+ self->rdp_layer->mod->server_draw_text(self->rdp_layer->mod,
+ self->state.text_font,
+ self->state.text_flags,
+ self->state.text_mixmode,
+ self->state.text_clipleft,
+ self->state.text_cliptop,
+ self->state.text_clipright,
+ self->state.text_clipbottom,
+ self->state.text_boxleft,
+ self->state.text_boxtop,
+ self->state.text_boxright,
+ self->state.text_boxbottom,
+ self->state.text_x,
+ self->state.text_y,
+ self->state.text_text,
+ self->state.text_length);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+}
+
+/*****************************************************************************/
+/* Process a destination blt order */
+static void APP_CC
+rdp_orders_process_destblt(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x01)
+ {
+ rdp_orders_in_coord(s, &self->state.dest_x, delta);
+ }
+ if (present & 0x02)
+ {
+ rdp_orders_in_coord(s, &self->state.dest_y, delta);
+ }
+ if (present & 0x04)
+ {
+ rdp_orders_in_coord(s, &self->state.dest_cx, delta);
+ }
+ if (present & 0x08)
+ {
+ rdp_orders_in_coord(s, &self->state.dest_cy, delta);
+ }
+ if (present & 0x10)
+ {
+ in_uint8(s, self->state.dest_opcode);
+ }
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.dest_opcode);
+ self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod,
+ self->state.dest_x,
+ self->state.dest_y,
+ self->state.dest_cx,
+ self->state.dest_cy);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+}
+
+/*****************************************************************************/
+/* Process a pattern blt order */
+static void APP_CC
+rdp_orders_process_patblt(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x0001)
+ {
+ rdp_orders_in_coord(s, &self->state.pat_x, delta);
+ }
+ if (present & 0x0002)
+ {
+ rdp_orders_in_coord(s, &self->state.pat_y, delta);
+ }
+ if (present & 0x0004)
+ {
+ rdp_orders_in_coord(s, &self->state.pat_cx, delta);
+ }
+ if (present & 0x0008)
+ {
+ rdp_orders_in_coord(s, &self->state.pat_cy, delta);
+ }
+ if (present & 0x0010)
+ {
+ in_uint8(s, self->state.pat_opcode);
+ }
+ if (present & 0x0020)
+ {
+ rdp_orders_in_color(s, &self->state.pat_bgcolor);
+ }
+ if (present & 0x0040)
+ {
+ rdp_orders_in_color(s, &self->state.pat_fgcolor);
+ }
+ rdp_orders_parse_brush(s, &self->state.pat_brush, present >> 7);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.pat_opcode);
+ self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 1);
+ self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod,
+ self->state.pat_fgcolor);
+ self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod,
+ self->state.pat_bgcolor);
+ self->rdp_layer->mod->server_set_brush(self->rdp_layer->mod,
+ self->state.pat_brush.xorigin,
+ self->state.pat_brush.yorigin,
+ self->state.pat_brush.style,
+ self->state.pat_brush.pattern);
+ self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod,
+ self->state.pat_x,
+ self->state.pat_y,
+ self->state.pat_cx,
+ self->state.pat_cy);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+ self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 0);
+}
+
+/*****************************************************************************/
+/* Process a screen blt order */
+static void APP_CC
+rdp_orders_process_screenblt(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x0001)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_x, delta);
+ }
+ if (present & 0x0002)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_y, delta);
+ }
+ if (present & 0x0004)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_cx, delta);
+ }
+ if (present & 0x0008)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_cy, delta);
+ }
+ if (present & 0x0010)
+ {
+ in_uint8(s, self->state.screenblt_opcode);
+ }
+ if (present & 0x0020)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_srcx, delta);
+ }
+ if (present & 0x0040)
+ {
+ rdp_orders_in_coord(s, &self->state.screenblt_srcy, delta);
+ }
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.screenblt_opcode);
+ self->rdp_layer->mod->server_screen_blt(self->rdp_layer->mod,
+ self->state.screenblt_x,
+ self->state.screenblt_y,
+ self->state.screenblt_cx,
+ self->state.screenblt_cy,
+ self->state.screenblt_srcx,
+ self->state.screenblt_srcy);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+}
+
+/*****************************************************************************/
+/* Process a line order */
+static void APP_CC
+rdp_orders_process_line(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x0001)
+ {
+ in_uint16_le(s, self->state.line_mixmode);
+ }
+ if (present & 0x0002)
+ {
+ rdp_orders_in_coord(s, &self->state.line_startx, delta);
+ }
+ if (present & 0x0004)
+ {
+ rdp_orders_in_coord(s, &self->state.line_starty, delta);
+ }
+ if (present & 0x0008)
+ {
+ rdp_orders_in_coord(s, &self->state.line_endx, delta);
+ }
+ if (present & 0x0010)
+ {
+ rdp_orders_in_coord(s, &self->state.line_endy, delta);
+ }
+ if (present & 0x0020)
+ {
+ rdp_orders_in_color(s, &self->state.line_bgcolor);
+ }
+ if (present & 0x0040)
+ {
+ in_uint8(s, self->state.line_opcode);
+ }
+ rdp_orders_parse_pen(s, &self->state.line_pen, present >> 7);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.line_opcode);
+ self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod,
+ self->state.line_pen.color);
+ self->rdp_layer->mod->server_set_pen(self->rdp_layer->mod,
+ self->state.line_pen.style,
+ self->state.line_pen.width);
+ self->rdp_layer->mod->server_draw_line(self->rdp_layer->mod,
+ self->state.line_startx,
+ self->state.line_starty,
+ self->state.line_endx,
+ self->state.line_endy);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+}
+
+/*****************************************************************************/
+/* Process an opaque rectangle order */
+static void APP_CC
+rdp_orders_process_rect(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ int i;
+
+ if (present & 0x01)
+ {
+ rdp_orders_in_coord(s, &self->state.rect_x, delta);
+ }
+ if (present & 0x02)
+ {
+ rdp_orders_in_coord(s, &self->state.rect_y, delta);
+ }
+ if (present & 0x04)
+ {
+ rdp_orders_in_coord(s, &self->state.rect_cx, delta);
+ }
+ if (present & 0x08)
+ {
+ rdp_orders_in_coord(s, &self->state.rect_cy, delta);
+ }
+ if (present & 0x10)
+ {
+ in_uint8(s, i);
+ self->state.rect_color = (self->state.rect_color & 0xffffff00) | i;
+ }
+ if (present & 0x20)
+ {
+ in_uint8(s, i);
+ self->state.rect_color = (self->state.rect_color & 0xffff00ff) | (i << 8);
+ }
+ if (present & 0x40)
+ {
+ in_uint8(s, i);
+ self->state.rect_color = (self->state.rect_color & 0xff00ffff) | (i << 16);
+ }
+ self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod,
+ self->state.rect_color);
+ self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod,
+ self->state.rect_x,
+ self->state.rect_y,
+ self->state.rect_cx,
+ self->state.rect_cy);
+}
+
+/*****************************************************************************/
+/* Process a desktop save order */
+static void APP_CC
+rdp_orders_process_desksave(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ int width;
+ int height;
+
+ if (present & 0x01)
+ {
+ in_uint32_le(s, self->state.desksave_offset);
+ }
+ if (present & 0x02)
+ {
+ rdp_orders_in_coord(s, &self->state.desksave_left, delta);
+ }
+ if (present & 0x04)
+ {
+ rdp_orders_in_coord(s, &self->state.desksave_top, delta);
+ }
+ if (present & 0x08)
+ {
+ rdp_orders_in_coord(s, &self->state.desksave_right, delta);
+ }
+ if (present & 0x10)
+ {
+ rdp_orders_in_coord(s, &self->state.desksave_bottom, delta);
+ }
+ if (present & 0x20)
+ {
+ in_uint8(s, self->state.desksave_action);
+ }
+ width = (self->state.desksave_right - self->state.desksave_left) + 1;
+ height = (self->state.desksave_bottom - self->state.desksave_top) + 1;
+ if (self->state.desksave_action == 0)
+ {
+// ui_desktop_save(os->offset, os->left, os->top, width, height);
+ }
+ else
+ {
+// ui_desktop_restore(os->offset, os->left, os->top, width, height);
+ }
+}
+
+/*****************************************************************************/
+/* Process a memory blt order */
+static void APP_CC
+rdp_orders_process_memblt(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ struct rdp_bitmap* bitmap;
+
+ if (present & 0x0001)
+ {
+ in_uint8(s, self->state.memblt_cache_id);
+ in_uint8(s, self->state.memblt_color_table);
+ }
+ if (present & 0x0002)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_x, delta);
+ }
+ if (present & 0x0004)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_y, delta);
+ }
+ if (present & 0x0008)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_cx, delta);
+ }
+ if (present & 0x0010)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_cy, delta);
+ }
+ if (present & 0x0020)
+ {
+ in_uint8(s, self->state.memblt_opcode);
+ }
+ if (present & 0x0040)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_srcx, delta);
+ }
+ if (present & 0x0080)
+ {
+ rdp_orders_in_coord(s, &self->state.memblt_srcy, delta);
+ }
+ if (present & 0x0100)
+ {
+ in_uint16_le(s, self->state.memblt_cache_idx);
+ }
+ bitmap = self->cache_bitmap[self->state.memblt_cache_id]
+ [self->state.memblt_cache_idx];
+ if (bitmap != 0)
+ {
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod,
+ self->state.memblt_opcode);
+ self->rdp_layer->mod->server_paint_rect(self->rdp_layer->mod,
+ self->state.memblt_x,
+ self->state.memblt_y,
+ self->state.memblt_cx,
+ self->state.memblt_cy,
+ bitmap->data,
+ bitmap->width,
+ bitmap->height,
+ self->state.memblt_srcx,
+ self->state.memblt_srcy);
+ self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc);
+ }
+}
+
+/*****************************************************************************/
+/* Process a 3-way blt order */
+static void APP_CC
+rdp_orders_process_triblt(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ /* not used */
+}
+
+/*****************************************************************************/
+/* Process a polyline order */
+static void APP_CC
+rdp_orders_process_polyline(struct rdp_orders* self, struct stream* s,
+ int present, int delta)
+{
+ if (present & 0x01)
+ {
+ rdp_orders_in_coord(s, &self->state.polyline_x, delta);
+ }
+ if (present & 0x02)
+ {
+ rdp_orders_in_coord(s, &self->state.polyline_y, delta);
+ }
+ if (present & 0x04)
+ {
+ in_uint8(s, self->state.polyline_opcode);
+ }
+ if (present & 0x10)
+ {
+ rdp_orders_in_color(s, &self->state.polyline_fgcolor);
+ }
+ if (present & 0x20)
+ {
+ in_uint8(s, self->state.polyline_lines);
+ }
+ if (present & 0x40)
+ {
+ in_uint8(s, self->state.polyline_datasize);
+ in_uint8a(s, self->state.polyline_data, self->state.polyline_datasize);
+ }
+ /* todo */
+}
+
+/*****************************************************************************/
+int APP_CC
+rdp_orders_process_orders(struct rdp_orders* self, struct stream* s,
+ int num_orders)
+{
+ int processed;
+ int order_flags;
+ int size;
+ int present;
+ int delta;
+
+ processed = 0;
+ while (processed < num_orders)
+ {
+ in_uint8(s, order_flags);
+ if (!(order_flags & RDP_ORDER_STANDARD))
+ {
+ /* error, this should always be set */
+ break;
+ }
+ if (order_flags & RDP_ORDER_SECONDARY)
+ {
+ rdp_orders_process_secondary_order(self, s);
+ }
+ else
+ {
+ if (order_flags & RDP_ORDER_CHANGE)
+ {
+ in_uint8(s, self->state.order_type);
+ }
+ switch (self->state.order_type)
+ {
+ case RDP_ORDER_TRIBLT:
+ case RDP_ORDER_TEXT2:
+ size = 3;
+ break;
+ case RDP_ORDER_PATBLT:
+ case RDP_ORDER_MEMBLT:
+ case RDP_ORDER_LINE:
+ size = 2;
+ break;
+ default:
+ size = 1;
+ break;
+ }
+ rdp_orders_in_present(s, &present, order_flags, size);
+ if (order_flags & RDP_ORDER_BOUNDS)
+ {
+ if (!(order_flags & RDP_ORDER_LASTBOUNDS))
+ {
+ rdp_orders_parse_bounds(self, s);
+ }
+ self->rdp_layer->mod->server_set_clip(self->rdp_layer->mod,
+ self->state.clip_left,
+ self->state.clip_top,
+ (self->state.clip_right - self->state.clip_left) + 1,
+ (self->state.clip_bottom - self->state.clip_top) + 1);
+ }
+ delta = order_flags & RDP_ORDER_DELTA;
+ switch (self->state.order_type)
+ {
+ case RDP_ORDER_TEXT2:
+ rdp_orders_process_text2(self, s, present, delta);
+ break;
+ case RDP_ORDER_DESTBLT:
+ rdp_orders_process_destblt(self, s, present, delta);
+ break;
+ case RDP_ORDER_PATBLT:
+ rdp_orders_process_patblt(self, s, present, delta);
+ break;
+ case RDP_ORDER_SCREENBLT:
+ rdp_orders_process_screenblt(self, s, present, delta);
+ break;
+ case RDP_ORDER_LINE:
+ rdp_orders_process_line(self, s, present, delta);
+ break;
+ case RDP_ORDER_RECT:
+ rdp_orders_process_rect(self, s, present, delta);
+ break;
+ case RDP_ORDER_DESKSAVE:
+ rdp_orders_process_desksave(self, s, present, delta);
+ break;
+ case RDP_ORDER_MEMBLT:
+ rdp_orders_process_memblt(self, s, present, delta);
+ break;
+ case RDP_ORDER_TRIBLT:
+ rdp_orders_process_triblt(self, s, present, delta);
+ break;
+ case RDP_ORDER_POLYLINE:
+ rdp_orders_process_polyline(self, s, present, delta);
+ break;
+ default:
+ /* error unknown order */
+ break;
+ }
+ if (order_flags & RDP_ORDER_BOUNDS)
+ {
+ self->rdp_layer->mod->server_reset_clip(self->rdp_layer->mod);
+ }
+ }
+ processed++;
+ }
+ return 0;
+}
diff --git a/rdp/rdp_rdp.c b/rdp/rdp_rdp.c
new file mode 100644
index 00000000..972db54e
--- /dev/null
+++ b/rdp/rdp_rdp.c
@@ -0,0 +1,974 @@
+/*
+ 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 2005
+
+ librdp rdp layer
+
+*/
+
+#include "rdp.h"
+
+/*****************************************************************************/
+struct rdp_rdp* APP_CC
+rdp_rdp_create(struct mod* owner)
+{
+ struct rdp_rdp* self;
+
+ self = (struct rdp_rdp*)g_malloc(sizeof(struct rdp_rdp), 1);
+ self->mod = owner;
+ self->sec_layer = rdp_sec_create(self);
+ self->bitmap_compression = 1;
+ self->bitmap_cache = 1;
+ self->desktop_save = 0;
+ self->orders = rdp_orders_create(self);
+ return self;
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_rdp_delete(struct rdp_rdp* self)
+{
+ if (self == 0)
+ {
+ return;
+ }
+ rdp_orders_delete(self->orders);
+ rdp_sec_delete(self->sec_layer);
+ g_free(self);
+}
+
+/******************************************************************************/
+/* Initialise an RDP packet */
+int APP_CC
+rdp_rdp_init(struct rdp_rdp* self, struct stream* s)
+{
+ if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0)
+ {
+ return 1;
+ }
+ s_push_layer(s, rdp_hdr, 6);
+ return 0;
+}
+
+/******************************************************************************/
+/* Send an RDP packet */
+int APP_CC
+rdp_rdp_send(struct rdp_rdp* self, struct stream* s, int pdu_type)
+{
+ int len;
+ int sec_flags;
+
+ s_pop_layer(s, rdp_hdr);
+ len = s->end - s->p;
+ out_uint16_le(s, len);
+ out_uint16_le(s, pdu_type | 0x10);
+ out_uint16_le(s, self->sec_layer->mcs_layer->userid);
+ sec_flags = SEC_ENCRYPT;
+ if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Initialise an RDP data packet */
+int APP_CC
+rdp_rdp_init_data(struct rdp_rdp* self, struct stream* s)
+{
+ if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0)
+ {
+ return 1;
+ }
+ s_push_layer(s, rdp_hdr, 18);
+ return 0;
+}
+
+/******************************************************************************/
+/* Send an RDP data packet */
+int APP_CC
+rdp_rdp_send_data(struct rdp_rdp* self, struct stream* s, int pdu_data_type)
+{
+ int len;
+ int sec_flags;
+
+ s_pop_layer(s, rdp_hdr);
+ len = s->end - s->p;
+ out_uint16_le(s, len);
+ out_uint16_le(s, RDP_PDU_DATA | 0x10);
+ out_uint16_le(s, self->sec_layer->mcs_layer->userid);
+ out_uint32_le(s, self->share_id);
+ out_uint8(s, 0);
+ out_uint8(s, 1);
+ out_uint16_le(s, len - 14);
+ out_uint8(s, pdu_data_type);
+ out_uint8(s, 0); /* compress type */
+ out_uint16_le(s, 0); /* compress len */
+ sec_flags = SEC_ENCRYPT;
+ if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Output general capability set */
+static int APP_CC
+rdp_rdp_out_general_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_GENERAL);
+ out_uint16_le(s, RDP_CAPLEN_GENERAL);
+ 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, self->use_rdp5 ? 0x40d : 0);
+ 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 */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output bitmap capability set */
+static int APP_CC
+rdp_rdp_out_bitmap_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_BITMAP);
+ out_uint16_le(s, RDP_CAPLEN_BITMAP);
+ out_uint16_le(s, self->mod->rdp_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, 800); /* Desktop width */
+ out_uint16_le(s, 600); /* Desktop height */
+ out_uint16_le(s, 0); /* Pad */
+ out_uint16_le(s, 1); /* Allow resize */
+ out_uint16_le(s, self->bitmap_compression); /* Support compression */
+ out_uint16_le(s, 0); /* Unknown */
+ out_uint16_le(s, 1); /* Unknown */
+ out_uint16_le(s, 0); /* Pad */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output order capability set */
+static int APP_CC
+rdp_rdp_out_order_caps(struct rdp_rdp* self, struct stream* s)
+{
+ char order_caps[32];
+
+ g_memset(order_caps, 0, 32);
+ order_caps[0] = 1; /* dest blt */
+ order_caps[1] = 1; /* pat blt */
+ order_caps[2] = 1; /* screen blt */
+ order_caps[3] = self->bitmap_cache; /* memblt */
+ order_caps[4] = 0; /* triblt */
+ order_caps[8] = 1; /* line */
+ order_caps[9] = 1; /* line */
+ order_caps[10] = 1; /* rect */
+ order_caps[11] = self->desktop_save; /* desksave */
+ order_caps[13] = 1; /* memblt another above */
+ order_caps[14] = 1; /* triblt another above */
+ order_caps[20] = self->polygon_ellipse_orders; /* polygon */
+ order_caps[21] = self->polygon_ellipse_orders; /* polygon2 */
+ order_caps[22] = 0; /* todo polyline */
+ order_caps[25] = self->polygon_ellipse_orders; /* ellipse */
+ order_caps[26] = self->polygon_ellipse_orders; /* ellipse2 */
+ order_caps[27] = 1; /* text2 */
+ out_uint16_le(s, RDP_CAPSET_ORDER);
+ out_uint16_le(s, RDP_CAPLEN_ORDER);
+ out_uint8s(s, 20); /* Terminal desc, pad */
+ 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, 0x147); /* Number of fonts */
+ out_uint16_le(s, 0x2a); /* Capability flags */
+ out_uint8p(s, order_caps, 32); /* Orders supported */
+ out_uint16_le(s, 0x6a1); /* Text capability flags */
+ out_uint8s(s, 6); /* Pad */
+ out_uint32_le(s, self->desktop_save * 0x38400); /* Desktop cache size */
+ out_uint32_le(s, 0); /* Unknown */
+ out_uint32_le(s, 0x4e4); /* Unknown */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output bitmap cache capability set */
+static int APP_CC
+rdp_rdp_out_bmpcache_caps(struct rdp_rdp* self, struct stream* s)
+{
+ int Bpp;
+
+ out_uint16_le(s, RDP_CAPSET_BMPCACHE);
+ out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
+ Bpp = (self->mod->rdp_bpp + 7) / 8;
+ out_uint8s(s, 24); /* unused */
+ out_uint16_le(s, 0x258); /* entries */
+ out_uint16_le(s, 0x100 * Bpp); /* max cell size */
+ out_uint16_le(s, 0x12c); /* entries */
+ out_uint16_le(s, 0x400 * Bpp); /* max cell size */
+ out_uint16_le(s, 0x106); /* entries */
+ out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output control capability set */
+static int APP_CC
+rdp_rdp_out_control_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_CONTROL);
+ out_uint16_le(s, RDP_CAPLEN_CONTROL);
+ out_uint16_le(s, 0); /* Control capabilities */
+ out_uint16_le(s, 0); /* Remote detach */
+ out_uint16_le(s, 2); /* Control interest */
+ out_uint16_le(s, 2); /* Detach interest */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output activation capability set */
+static int APP_CC
+rdp_rdp_out_activate_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_ACTIVATE);
+ out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
+ out_uint16_le(s, 0); /* Help key */
+ out_uint16_le(s, 0); /* Help index key */
+ out_uint16_le(s, 0); /* Extended help key */
+ out_uint16_le(s, 0); /* Window activate */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output pointer capability set */
+static int APP_CC
+rdp_rdp_out_pointer_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_POINTER);
+ out_uint16_le(s, RDP_CAPLEN_POINTER);
+ out_uint16_le(s, 0); /* Color pointer */
+ out_uint16_le(s, 20); /* Cache size */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output share capability set */
+static int APP_CC
+rdp_rdp_out_share_caps(struct rdp_rdp* self, struct stream* s)
+{
+ out_uint16_le(s, RDP_CAPSET_SHARE);
+ out_uint16_le(s, RDP_CAPLEN_SHARE);
+ out_uint16_le(s, 0); /* userid */
+ out_uint16_le(s, 0); /* pad */
+ return 0;
+}
+
+/******************************************************************************/
+/* Output color cache capability set */
+static int APP_CC
+rdp_rdp_out_colcache_caps(struct rdp_rdp* self, struct stream* s)
+{
+ 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 */
+ return 0;
+}
+
+static char caps_0x0d[] = {
+0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
+0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00
+};
+
+static char caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
+
+static char caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
+
+static char caps_0x10[] = {
+0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
+0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
+0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
+0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
+0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
+0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
+};
+
+/******************************************************************************/
+/* Output unknown capability sets */
+static int APP_CC
+rdp_rdp_out_unknown_caps(struct rdp_rdp* self, struct stream* s, int id,
+ int length, char* caps)
+{
+ out_uint16_le(s, id);
+ out_uint16_le(s, length);
+ out_uint8p(s, caps, length - 4);
+ return 0;
+}
+
+#define RDP5_FLAG 0x0030
+
+/******************************************************************************/
+/* Send a confirm active PDU */
+static int APP_CC
+rdp_rdp_send_confirm_active(struct rdp_rdp* self, struct stream* s)
+{
+ int sec_flags;
+ int caplen;
+
+ sec_flags = SEC_ENCRYPT;
+ //sec_flags = RDP5_FLAG | SEC_ENCRYPT;
+ caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
+ RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
+ RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
+ RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
+ 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
+ 4 /* w2k fix, why? */ ;
+ if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0)
+ {
+ return 1;
+ }
+ out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
+ out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
+ out_uint16_le(s, (self->sec_layer->mcs_layer->userid + 1001));
+ out_uint32_le(s, self->share_id);
+ out_uint16_le(s, 0x3ea); /* userid */
+ out_uint16_le(s, sizeof(RDP_SOURCE));
+ out_uint16_le(s, caplen);
+ out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
+ out_uint16_le(s, 0xd); /* num_caps */
+ out_uint8s(s, 2); /* pad */
+ rdp_rdp_out_general_caps(self, s);
+ rdp_rdp_out_bitmap_caps(self, s);
+ rdp_rdp_out_order_caps(self, s);
+ rdp_rdp_out_bmpcache_caps(self, s);
+ rdp_rdp_out_colcache_caps(self, s);
+ rdp_rdp_out_activate_caps(self, s);
+ rdp_rdp_out_control_caps(self, s);
+ rdp_rdp_out_pointer_caps(self, s);
+ rdp_rdp_out_share_caps(self, s);
+ rdp_rdp_out_unknown_caps(self, s, 0x0d, 0x58, caps_0x0d); /* international? */
+ rdp_rdp_out_unknown_caps(self, s, 0x0c, 0x08, caps_0x0c);
+ rdp_rdp_out_unknown_caps(self, s, 0x0e, 0x08, caps_0x0e);
+ rdp_rdp_out_unknown_caps(self, s, 0x10, 0x34, caps_0x10); /* glyph cache? */
+ s_mark_end(s);
+ if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Process a color pointer PDU */
+static void APP_CC
+rdp_rdp_process_color_pointer_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int cache_idx;
+ int dlen;
+ int mlen;
+ struct rdp_cursor* cursor;
+
+ in_uint16_le(s, cache_idx);
+ cursor = self->cursors + cache_idx;
+ in_uint16_le(s, cursor->x);
+ in_uint16_le(s, cursor->y);
+ in_uint16_le(s, cursor->width);
+ in_uint16_le(s, cursor->height);
+ in_uint16_le(s, mlen); /* mask length */
+ in_uint16_le(s, dlen); /* data length */
+ in_uint8a(s, cursor->data, dlen);
+ in_uint8a(s, cursor->mask, mlen);
+ self->mod->server_set_cursor(self->mod, cursor->x, cursor->y,
+ cursor->data, cursor->mask);
+}
+
+/******************************************************************************/
+/* Process a cached pointer PDU */
+static void APP_CC
+rdp_rdp_process_cached_pointer_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int cache_idx;
+ struct rdp_cursor* cursor;
+
+ in_uint16_le(s, cache_idx);
+ cursor = self->cursors + cache_idx;
+ self->mod->server_set_cursor(self->mod, cursor->x, cursor->y,
+ cursor->data, cursor->mask);
+}
+
+/******************************************************************************/
+/* Process a system pointer PDU */
+static void APP_CC
+rdp_rdp_process_system_pointer_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int system_pointer_type;
+ struct rdp_cursor* cursor;
+
+ in_uint16_le(s, system_pointer_type);
+ switch (system_pointer_type)
+ {
+ case RDP_NULL_POINTER:
+ cursor = (struct rdp_cursor*)g_malloc(sizeof(struct rdp_cursor), 1);
+ g_memset(cursor->mask, 0xff, sizeof(cursor->mask));
+ self->mod->server_set_cursor(self->mod, cursor->x, cursor->y,
+ cursor->data, cursor->mask);
+ g_free(cursor);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************/
+/* Process a pointer PDU */
+static void APP_CC
+rdp_rdp_process_pointer_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int message_type;
+ int x;
+ int y;
+
+ in_uint16_le(s, message_type);
+ in_uint8s(s, 2); /* pad */
+ switch (message_type)
+ {
+ case RDP_POINTER_MOVE:
+ in_uint16_le(s, x);
+ in_uint16_le(s, y);
+ break;
+ case RDP_POINTER_COLOR:
+ rdp_rdp_process_color_pointer_pdu(self, s);
+ break;
+ case RDP_POINTER_CACHED:
+ rdp_rdp_process_cached_pointer_pdu(self, s);
+ break;
+ case RDP_POINTER_SYSTEM:
+ rdp_rdp_process_system_pointer_pdu(self, s);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************/
+/* Process bitmap updates */
+static void APP_CC
+rdp_rdp_process_bitmap_updates(struct rdp_rdp* self, struct stream* s)
+{
+ int num_updates;
+ int left;
+ int top;
+ int right;
+ int bottom;
+ int width;
+ int height;
+ int cx;
+ int cy;
+ int bpp;
+ int Bpp;
+ int compress;
+ int bufsize;
+ int size;
+ int i;
+ int y;
+ char* data;
+ char* bmpdata;
+
+ in_uint16_le(s, num_updates);
+ for (i = 0; i < num_updates; i++)
+ {
+ in_uint16_le(s, left);
+ in_uint16_le(s, top);
+ in_uint16_le(s, right);
+ in_uint16_le(s, bottom);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+ in_uint16_le(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, compress);
+ in_uint16_le(s, bufsize);
+ cx = (right - left) + 1;
+ cy = (bottom - top) + 1;
+ bmpdata = (char*)g_malloc(width * height * Bpp, 0);
+ if (compress)
+ {
+ if (compress & 0x400)
+ {
+ size = bufsize;
+ }
+ else
+ {
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, size);
+ in_uint8s(s, 4); /* line_size, final_size */
+ }
+ in_uint8p(s, data, size);
+ rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp);
+ self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata,
+ width, height, 0, 0);
+ }
+ else
+ {
+ for (y = 0; y < height; y++)
+ {
+ data = bmpdata + ((height - y) - 1) * (width * Bpp);
+ in_uint8a(s, data, width * Bpp);
+ }
+ self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata,
+ width, height, 0, 0);
+ }
+ g_free(bmpdata);
+ }
+}
+
+/******************************************************************************/
+/* Process a palette update */
+static void APP_CC
+rdp_rdp_process_palette(struct rdp_rdp* self, struct stream* s)
+{
+ int i;
+ int r;
+ int g;
+ int b;
+
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, self->colormap.ncolors);
+ in_uint8s(s, 2); /* pad */
+ for (i = 0; i < self->colormap.ncolors; i++)
+ {
+ in_uint8(s, r);
+ in_uint8(s, g);
+ in_uint8(s, b);
+ self->colormap.colors[i] = (r << 16) | (g << 8) | b;
+ }
+ //ui_set_colormap(hmap);
+}
+
+/******************************************************************************/
+/* Process an update PDU */
+static void APP_CC
+rdp_rdp_process_update_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int update_type;
+ int count;
+
+ in_uint16_le(s, update_type);
+ self->mod->server_begin_update(self->mod);
+ switch (update_type)
+ {
+ case RDP_UPDATE_ORDERS:
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, count);
+ in_uint8s(s, 2); /* pad */
+ rdp_orders_process_orders(self->orders, s, count);
+ break;
+ case RDP_UPDATE_BITMAP:
+ rdp_rdp_process_bitmap_updates(self, s);
+ break;
+ case RDP_UPDATE_PALETTE:
+ rdp_rdp_process_palette(self, s);
+ break;
+ case RDP_UPDATE_SYNCHRONIZE:
+ break;
+ default:
+ break;
+ }
+ self->mod->server_end_update(self->mod);
+}
+
+
+/******************************************************************************/
+void APP_CC
+rdp_rdp_out_unistr(struct stream* s, char* text)
+{
+ int i;
+
+ i = 0;
+ while (text[i] != 0)
+ {
+ out_uint8(s, text[i]);
+ out_uint8(s, 0);
+ i++;
+ }
+ out_uint8(s, 0);
+ out_uint8(s, 0);
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_send_login_info(struct rdp_rdp* self, int flags)
+{
+ int len_domain;
+ int len_username;
+ int len_password;
+ int len_program;
+ int len_directory;
+ int sec_flags;
+ struct stream* s;
+
+ DEBUG(("in rdp_rdp_send_login_info\r\n"));
+ make_stream(s);
+ init_stream(s, 8192);
+ len_domain = 2 * g_strlen(self->mod->domain);
+ len_username = 2 * g_strlen(self->mod->username);
+ len_password = 2 * g_strlen(self->mod->password);
+ len_program = 2 * g_strlen(self->mod->program);
+ len_directory = 2 * g_strlen(self->mod->directory);
+ sec_flags = SEC_LOGON_INFO | SEC_ENCRYPT;
+ if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0)
+ {
+ free_stream(s);
+ DEBUG(("out rdp_rdp_send_login_info error 1\r\n"));
+ return 1;
+ }
+ out_uint32_le(s, 0);
+ out_uint32_le(s, flags);
+ out_uint16_le(s, len_domain);
+ out_uint16_le(s, len_username);
+ out_uint16_le(s, len_password);
+ out_uint16_le(s, len_program);
+ out_uint16_le(s, len_directory);
+ rdp_rdp_out_unistr(s, self->mod->domain);
+ rdp_rdp_out_unistr(s, self->mod->username);
+ rdp_rdp_out_unistr(s, self->mod->password);
+ rdp_rdp_out_unistr(s, self->mod->program);
+ rdp_rdp_out_unistr(s, self->mod->directory);
+ s_mark_end(s);
+ if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0)
+ {
+ free_stream(s);
+ DEBUG(("out rdp_rdp_send_login_info error 2\r\n"));
+ return 1;
+ }
+ free_stream(s);
+ DEBUG(("out rdp_rdp_send_login_info\r\n"));
+ return 0;
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_connect(struct rdp_rdp* self, char* ip, char* port)
+{
+ int flags;
+
+ DEBUG(("in rdp_rdp_connect\r\n"));
+ flags = RDP_LOGON_NORMAL;
+ if (g_strlen(self->mod->password) > 0)
+ {
+ flags |= RDP_LOGON_AUTO;
+ }
+ if (rdp_sec_connect(self->sec_layer, ip, port) != 0)
+ {
+ DEBUG(("out rdp_rdp_connect error rdp_sec_connect failed\r\n"));
+ return 1;
+ }
+ if (rdp_rdp_send_login_info(self, flags) != 0)
+ {
+ DEBUG(("out rdp_rdp_connect error rdp_rdp_send_login_info failed\r\n"));
+ return 1;
+ }
+ DEBUG(("out rdp_rdp_connect\r\n"));
+ return 0;
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_send_input(struct rdp_rdp* self, struct stream* s,
+ int time, int message_type,
+ int device_flags, int param1, int param2)
+{
+ if (rdp_rdp_init_data(self, s) != 0)
+ {
+ return 1;
+ }
+ out_uint16_le(s, 1); /* number of events */
+ out_uint16_le(s, 0);
+ out_uint32_le(s, time);
+ out_uint16_le(s, message_type);
+ out_uint16_le(s, device_flags);
+ out_uint16_le(s, param1);
+ out_uint16_le(s, param2);
+ s_mark_end(s);
+ if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_INPUT) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_send_invalidate(struct rdp_rdp* self, struct stream* s,
+ int left, int top, int width, int height)
+{
+ if (rdp_rdp_init_data(self, s) != 0)
+ {
+ return 1;
+ }
+ out_uint32_le(s, 1);
+ out_uint16_le(s, left);
+ out_uint16_le(s, top);
+ out_uint16_le(s, (left + width) - 1);
+ out_uint16_le(s, (top + height) - 1);
+ s_mark_end(s);
+ if (rdp_rdp_send_data(self, s, 33) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_recv(struct rdp_rdp* self, struct stream* s, int* type)
+{
+ int len;
+ int pdu_type;
+ int chan;
+
+ chan = 0;
+ DEBUG(("in rdp_rdp_recv\r\n"));
+ if (s->next_packet >= s->end || s->next_packet == 0)
+ {
+ if (rdp_sec_recv(self->sec_layer, s, &chan) != 0)
+ {
+ DEBUG(("error in rdp_rdp_recv, rdp_sec_recv failed\r\n"));
+ return 1;
+ }
+ s->next_packet = s->p;
+ }
+ else
+ {
+ chan = MCS_GLOBAL_CHANNEL;
+ s->p = s->next_packet;
+ }
+ if (chan == MCS_GLOBAL_CHANNEL)
+ {
+ in_uint16_le(s, len);
+ DEBUG(("rdp_rdp_recv got %d len\r\n", len));
+ if (len == 0x8000)
+ {
+ s->next_packet += 8;
+ DEBUG(("out rdp_rdp_recv\r\n"));
+ return 0;
+ }
+ in_uint16_le(s, pdu_type);
+ in_uint8s(s, 2);
+ *type = pdu_type & 0xf;
+ s->next_packet += len;
+ }
+ else
+ {
+ /* todo, process channel data */
+ DEBUG(("got channel data channel %d\r\n", chan));
+ s->next_packet = s->end;
+ }
+ DEBUG(("out rdp_rdp_recv\r\n"));
+ return 0;
+}
+
+
+/******************************************************************************/
+static int APP_CC
+rdp_rdp_process_disconnect_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ return 0;
+}
+
+/******************************************************************************/
+int APP_CC
+rdp_rdp_process_data_pdu(struct rdp_rdp* self, struct stream* s)
+{
+ int data_pdu_type;
+ int ctype;
+ int clen;
+ int len;
+
+ in_uint8s(s, 6); /* shareid, pad, streamid */
+ in_uint16_le(s, len);
+ in_uint8(s, data_pdu_type);
+ in_uint8(s, ctype);
+ in_uint16_le(s, clen);
+ clen -= 18;
+ switch (data_pdu_type)
+ {
+ case RDP_DATA_PDU_UPDATE:
+ rdp_rdp_process_update_pdu(self, s);
+ break;
+ case RDP_DATA_PDU_CONTROL:
+ break;
+ case RDP_DATA_PDU_SYNCHRONISE:
+ break;
+ case RDP_DATA_PDU_POINTER:
+ rdp_rdp_process_pointer_pdu(self, s);
+ break;
+ case RDP_DATA_PDU_BELL:
+ break;
+ case RDP_DATA_PDU_LOGON:
+ break;
+ case RDP_DATA_PDU_DISCONNECT:
+ rdp_rdp_process_disconnect_pdu(self, s);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Process server capabilities */
+static int APP_CC
+rdp_rdp_process_server_caps(struct rdp_rdp* self, struct stream* s, int len)
+{
+ int n;
+ int ncapsets;
+ int capset_type;
+ int capset_length;
+ char* next;
+ char* start;
+
+ start = s->p;
+ in_uint16_le(s, ncapsets);
+ in_uint8s(s, 2); /* pad */
+ for (n = 0; n < ncapsets; n++)
+ {
+ if (s->p > start + len)
+ {
+ return 0;
+ }
+ in_uint16_le(s, capset_type);
+ in_uint16_le(s, capset_length);
+ next = (s->p + capset_length) - 4;
+ switch (capset_type)
+ {
+ case RDP_CAPSET_GENERAL:
+ //rdp_process_general_caps(s);
+ break;
+ case RDP_CAPSET_BITMAP:
+ //rdp_process_bitmap_caps(s);
+ break;
+ }
+ s->p = next;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Send a control PDU */
+/* returns error */
+static int APP_CC
+rdp_rdp_send_control(struct rdp_rdp* self, struct stream* s, int action)
+{
+ if (rdp_rdp_init_data(self, s) != 0)
+ {
+ return 1;
+ }
+ out_uint16_le(s, action);
+ out_uint16_le(s, 0); /* userid */
+ out_uint32_le(s, 0); /* control id */
+ s_mark_end(s);
+ if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Send a synchronisation PDU */
+/* returns error */
+static int APP_CC
+rdp_rdp_send_synchronise(struct rdp_rdp* self, struct stream* s)
+{
+ if (rdp_rdp_init_data(self, s) != 0)
+ {
+ return 1;
+ }
+ out_uint16_le(s, 1); /* type */
+ out_uint16_le(s, 1002);
+ s_mark_end(s);
+ if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Send an (empty) font information PDU */
+static int APP_CC
+rdp_rdp_send_fonts(struct rdp_rdp* self, struct stream* s, int seq)
+{
+ if (rdp_rdp_init_data(self, s) != 0)
+ {
+ return 1;
+ }
+ out_uint16_le(s, 0); /* number of fonts */
+ out_uint16_le(s, 0); /* pad? */
+ out_uint16_le(s, seq); /* unknown */
+ out_uint16_le(s, 0x32); /* entry size */
+ s_mark_end(s);
+ if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_FONT2) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/* Respond to a demand active PDU */
+int APP_CC
+rdp_rdp_process_demand_active(struct rdp_rdp* self, struct stream* s)
+{
+ int type;
+ int len_src_descriptor;
+ int len_combined_caps;
+
+ in_uint32_le(s, self->share_id);
+ in_uint16_le(s, len_src_descriptor);
+ in_uint16_le(s, len_combined_caps);
+ in_uint8s(s, len_src_descriptor);
+ rdp_rdp_process_server_caps(self, s, len_combined_caps);
+ rdp_rdp_send_confirm_active(self, s);
+ rdp_rdp_send_synchronise(self, s);
+ rdp_rdp_send_control(self, s, RDP_CTL_COOPERATE);
+ rdp_rdp_send_control(self, s, RDP_CTL_REQUEST_CONTROL);
+ rdp_rdp_recv(self, s, &type); /* RDP_PDU_SYNCHRONIZE */
+ rdp_rdp_recv(self, s, &type); /* RDP_CTL_COOPERATE */
+ rdp_rdp_recv(self, s, &type); /* RDP_CTL_GRANT_CONTROL */
+ rdp_rdp_send_input(self, s, 0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0);
+ rdp_rdp_send_fonts(self, s, 1);
+ rdp_rdp_send_fonts(self, s, 2);
+ rdp_rdp_recv(self, s, &type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
+ rdp_orders_reset_state(self->orders);
+ return 0;
+}
diff --git a/rdp/rdp_sec.c b/rdp/rdp_sec.c
new file mode 100644
index 00000000..0bd727ee
--- /dev/null
+++ b/rdp/rdp_sec.c
@@ -0,0 +1,651 @@
+/*
+ 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 2005
+
+ librdp secure layer
+
+*/
+
+#include "rdp.h"
+
+static char g_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 g_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 };
+
+/*****************************************************************************/
+struct rdp_sec* APP_CC
+rdp_sec_create(struct rdp_rdp* owner)
+{
+ struct rdp_sec* self;
+
+ self = (struct rdp_sec*)g_malloc(sizeof(struct rdp_sec), 1);
+ self->rdp_layer = owner;
+ make_stream(self->client_mcs_data);
+ init_stream(self->client_mcs_data, 8192);
+ make_stream(self->server_mcs_data);
+ init_stream(self->server_mcs_data, 8192);
+ self->mcs_layer = rdp_mcs_create(self, self->client_mcs_data,
+ self->server_mcs_data);
+ self->decrypt_rc4_info = g_rc4_info_create();
+ self->encrypt_rc4_info = g_rc4_info_create();
+ self->lic_layer = rdp_lic_create(self);
+ return self;
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_sec_delete(struct rdp_sec* self)
+{
+ if (self == 0)
+ {
+ return;
+ }
+ rdp_lic_delete(self->lic_layer);
+ rdp_mcs_delete(self->mcs_layer);
+ free_stream(self->client_mcs_data);
+ free_stream(self->server_mcs_data);
+ g_rc4_info_delete(self->decrypt_rc4_info);
+ g_rc4_info_delete(self->encrypt_rc4_info);
+ g_free(self);
+}
+
+/*****************************************************************************/
+/* Reduce key entropy from 64 to 40 bits */
+static void APP_CC
+rdp_sec_make_40bit(char* key)
+{
+ key[0] = 0xd1;
+ key[1] = 0x26;
+ key[2] = 0x9e;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* update an encryption key */
+static int APP_CC
+rdp_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, g_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, g_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)
+ {
+ rdp_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
+rdp_sec_decrypt(struct rdp_sec* self, char* data, int len)
+{
+ if (self->decrypt_use_count == 4096)
+ {
+ rdp_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 */
+int APP_CC
+rdp_sec_recv(struct rdp_sec* self, struct stream* s, int* chan)
+{
+ int flags;
+
+ DEBUG((" in rdp_sec_recv\r\n"));
+ if (rdp_mcs_recv(self->mcs_layer, s, chan) != 0)
+ {
+ DEBUG((" error in rdp_sec_recv, rdp_mcs_recv failed\r\n"));
+ return 1;
+ }
+ in_uint32_le(s, flags);
+ DEBUG((" rdp_sec_recv flags %8.8x\r\n", flags));
+ if (flags & SEC_ENCRYPT) /* 0x08 */
+ {
+ in_uint8s(s, 8); /* signature */
+ rdp_sec_decrypt(self, s->p, s->end - s->p);
+ }
+ if (flags & SEC_LICENCE_NEG) /* 0x80 */
+ {
+ DEBUG((" in rdp_sec_recv, got SEC_LICENCE_NEG\r\n"));
+ rdp_lic_process(self->lic_layer, s);
+ *chan = 0;
+ }
+ DEBUG((" out rdp_sec_recv\r\n"));
+ return 0;
+}
+
+/*****************************************************************************/
+/* prepare client mcs data to send in mcs layer */
+static void APP_CC
+rdp_sec_out_mcs_data(struct rdp_sec* self)
+{
+ struct stream* s;
+ int hostlen;
+ int length;
+
+ s = self->client_mcs_data;
+ init_stream(s, 512);
+ self->rdp_layer->mod->hostname[15] = 0; /* limit length to 15 */
+ hostlen = 2 * g_strlen(self->rdp_layer->mod->hostname);
+ length = 158 + 76 + 12 + 4;
+ /* Generic Conference Control (T.124) ConferenceCreateRequest */
+ out_uint16_be(s, 5);
+ out_uint16_be(s, 0x14);
+ out_uint8(s, 0x7c);
+ out_uint16_be(s, 1);
+ out_uint16_be(s, (length | 0x8000)); /* remaining length */
+ out_uint16_be(s, 8); /* length? */
+ out_uint16_be(s, 16);
+ out_uint8(s, 0);
+ out_uint16_le(s, 0xc001);
+ out_uint8(s, 0);
+ out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */
+ out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */
+ /* Client information */
+ out_uint16_le(s, SEC_TAG_CLI_INFO);
+ out_uint16_le(s, 212); /* length */
+ out_uint16_le(s, 1); /* RDP version. 1 == RDP4, 4 == RDP5. */
+ out_uint16_le(s, 8);
+ out_uint16_le(s, self->rdp_layer->mod->width);
+ out_uint16_le(s, self->rdp_layer->mod->height);
+ out_uint16_le(s, 0xca01);
+ out_uint16_le(s, 0xaa03);
+ out_uint32_le(s, self->rdp_layer->mod->keylayout);
+ out_uint32_le(s, 2600); /* Client build */
+ /* Unicode name of client, padded to 32 bytes */
+ rdp_rdp_out_unistr(s, self->rdp_layer->mod->hostname);
+ out_uint8s(s, 30 - hostlen);
+ out_uint32_le(s, 4);
+ out_uint32_le(s, 0);
+ out_uint32_le(s, 12);
+ out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */
+ out_uint16_le(s, 0xca01); /* color depth? */
+ out_uint16_le(s, 1);
+ out_uint32_le(s, 0);
+ out_uint8(s, self->rdp_layer->mod->rdp_bpp);
+ out_uint16_le(s, 0x0700);
+ out_uint8(s, 0);
+ out_uint32_le(s, 1);
+ out_uint8s(s, 64); /* End of client info */
+ out_uint16_le(s, SEC_TAG_CLI_4);
+ out_uint16_le(s, 12);
+ out_uint32_le(s, 9);
+ out_uint32_le(s, 0);
+ /* Client encryption settings */
+ out_uint16_le(s, SEC_TAG_CLI_CRYPT);
+ out_uint16_le(s, 12); /* length */
+ /* encryption supported, 128-bit supported */
+ out_uint32_le(s, 0x3);
+ out_uint32_le(s, 0); /* Unknown */
+ s_mark_end(s);
+}
+
+/*****************************************************************************/
+/* Parse a public key structure */
+/* returns boolean */
+static int APP_CC
+rdp_sec_parse_public_key(struct rdp_sec* self, struct stream* s,
+ char* modulus, char* exponent)
+{
+ int magic;
+ int modulus_len;
+
+ in_uint32_le(s, magic);
+ if (magic != SEC_RSA_MAGIC)
+ {
+ return 0;
+ }
+ in_uint32_le(s, modulus_len);
+ if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE)
+ {
+ return 0;
+ }
+ in_uint8s(s, 8);
+ in_uint8a(s, exponent, SEC_EXPONENT_SIZE);
+ in_uint8a(s, modulus, SEC_MODULUS_SIZE);
+ in_uint8s(s, SEC_PADDING_SIZE);
+ return s_check(s);
+}
+
+/*****************************************************************************/
+/* Parse a crypto information structure */
+/* returns boolean */
+static int APP_CC
+rdp_sec_parse_crypt_info(struct rdp_sec* self, struct stream* s,
+ char* modulus, char* exponent)
+{
+ int random_len;
+ int rsa_info_len;
+ int flags;
+ int tag;
+ int length;
+ char* next_tag;
+ char* end;
+
+ in_uint32_le(s, self->rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */
+ in_uint32_le(s, self->crypt_level); /* 1 = low, 2 = medium, 3 = high */
+ if (self->crypt_level == 0) /* no encryption */
+ {
+ return 0;
+ }
+ in_uint32_le(s, random_len);
+ in_uint32_le(s, rsa_info_len);
+ if (random_len != SEC_RANDOM_SIZE)
+ {
+ return 0;
+ }
+ in_uint8a(s, self->server_random, random_len);
+ /* RSA info */
+ end = s->p + rsa_info_len;
+ if (end > s->end)
+ {
+ return 0;
+ }
+ in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */
+ if (flags & 1)
+ {
+ in_uint8s(s, 8); /* unknown */
+ while (s->p < end)
+ {
+ in_uint16_le(s, tag);
+ in_uint16_le(s, length);
+ next_tag = s->p + length;
+ DEBUG((" rdp_sec_parse_crypt_info tag %d length %d\r\n", tag, length));
+ switch (tag)
+ {
+ case SEC_TAG_PUBKEY:
+ if (!rdp_sec_parse_public_key(self, s, modulus, exponent))
+ {
+ return 0;
+ }
+ break;
+ case SEC_TAG_KEYSIG:
+ break;
+ default:
+ break;
+ }
+ s->p = next_tag;
+ }
+ }
+ else
+ {
+ /* todo */
+ return 0;
+ }
+ return s_check_end(s);
+}
+
+/*****************************************************************************/
+static void APP_CC
+rdp_sec_rsa_op(char* out, char* in, char* mod, char* exp)
+{
+ g_mod_exp(out, SEC_MODULUS_SIZE, /* 64 */
+ in, SEC_RANDOM_SIZE, /* 32 */
+ mod, SEC_MODULUS_SIZE, /* 64 */
+ exp, SEC_EXPONENT_SIZE); /* 4 */
+ //g_hexdump(out, SEC_MODULUS_SIZE);
+ //g_hexdump(in, SEC_RANDOM_SIZE);
+ //g_hexdump(mod, SEC_MODULUS_SIZE);
+ //g_hexdump(exp, SEC_EXPONENT_SIZE);
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_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);
+}
+
+/*****************************************************************************/
+void APP_CC
+rdp_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 int APP_CC
+rdp_sec_generate_keys(struct rdp_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);
+ rdp_sec_hash_48(temp_hash, input, self->client_random,
+ self->server_random, 65);
+ rdp_sec_hash_48(session_key, temp_hash, self->client_random,
+ self->server_random, 88);
+ g_memcpy(self->sign_key, session_key, 16);
+ rdp_sec_hash_16(self->decrypt_key, session_key + 16, self->client_random,
+ self->server_random);
+ rdp_sec_hash_16(self->encrypt_key, session_key + 32, self->client_random,
+ self->server_random);
+ DEBUG((" rdp_sec_generate_keys, rc4_key_size is %d\r\n", self->rc4_key_size));
+ DEBUG((" rdp_sec_generate_keys, crypt_level is %d\r\n", self->crypt_level));
+ if (self->rc4_key_size == 1)
+ {
+ rdp_sec_make_40bit(self->sign_key);
+ rdp_sec_make_40bit(self->encrypt_key);
+ rdp_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);
+ return 0;
+}
+
+/*****************************************************************************/
+/* Process crypto information blob */
+static void APP_CC
+rdp_sec_process_crypt_info(struct rdp_sec* self, struct stream* s)
+{
+ char modulus[64];
+ char exponent[64];
+
+ g_memset(modulus, 0, sizeof(modulus));
+ g_memset(exponent, 0, sizeof(exponent));
+ if (!rdp_sec_parse_crypt_info(self, s, modulus, exponent))
+ {
+ DEBUG((" error in rdp_sec_process_crypt_info\r\n"));
+ return;
+ }
+ /* Generate a client random, and determine encryption keys */
+ g_random(self->client_random, 32);
+ rdp_sec_rsa_op(self->client_crypt_random, self->client_random,
+ modulus, exponent);
+ rdp_sec_generate_keys(self);
+}
+
+/*****************************************************************************/
+/* Process connect response data blob */
+static void APP_CC
+rdp_sec_process_mcs_data(struct rdp_sec* self)
+{
+ int tag;
+ int length;
+ int len;
+ char* next_tag;
+ struct stream* s;
+
+ s = self->server_mcs_data;
+ s->p = s->data;
+ in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */
+ in_uint8(s, len);
+ if (len & 0x80)
+ {
+ in_uint8(s, len);
+ }
+ while (s->p < s->end)
+ {
+ in_uint16_le(s, tag);
+ in_uint16_le(s, length);
+ DEBUG((" rdp_sec_process_mcs_data tag %d length %d\r\n", tag, length));
+ if (length <= 4)
+ {
+ return;
+ }
+ next_tag = (s->p + length) - 4;
+ switch (tag)
+ {
+ case SEC_TAG_SRV_INFO:
+ //rdp_sec_process_srv_info(self, s);
+ break;
+ case SEC_TAG_SRV_CRYPT:
+ rdp_sec_process_crypt_info(self, s);
+ break;
+ case SEC_TAG_SRV_CHANNELS:
+ break;
+ default:
+ break;
+ }
+ s->p = next_tag;
+ }
+}
+
+/*****************************************************************************/
+/* Transfer the client random to the server */
+/* returns error */
+static int APP_CC
+rdp_sec_establish_key(struct rdp_sec* self)
+{
+ int length;
+ int flags;
+ struct stream* s;
+
+ DEBUG((" sending client random\r\n"));
+ make_stream(s);
+ init_stream(s, 8192);
+ length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE;
+ flags = SEC_CLIENT_RANDOM;
+ if (rdp_sec_init(self, s, flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ out_uint32_le(s, length);
+ out_uint8p(s, self->client_crypt_random, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+ s_mark_end(s);
+ if (rdp_sec_send(self, s, flags) != 0)
+ {
+ free_stream(s);
+ return 1;
+ }
+ free_stream(s);
+ return 0;
+}
+
+/*****************************************************************************/
+/* Establish a secure connection */
+int APP_CC
+rdp_sec_connect(struct rdp_sec* self, char* ip, char* port)
+{
+ DEBUG((" in rdp_sec_connect\r\n"));
+ rdp_sec_out_mcs_data(self);
+ if (rdp_mcs_connect(self->mcs_layer, ip, port) != 0)
+ {
+ DEBUG((" out rdp_sec_connect error rdp_mcs_connect failed\r\n"));
+ return 1;
+ }
+ rdp_sec_process_mcs_data(self);
+ if (rdp_sec_establish_key(self) != 0)
+ {
+ DEBUG((" out rdp_sec_connect error rdp_sec_establish_key failed\r\n"));
+ return 1;
+ }
+ DEBUG((" out rdp_sec_connect\r\n"));
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+int APP_CC
+rdp_sec_init(struct rdp_sec* self, struct stream* s, int flags)
+{
+ if (rdp_mcs_init(self->mcs_layer, s) != 0)
+ {
+ return 1;
+ }
+ if (flags & SEC_ENCRYPT)
+ {
+ s_push_layer(s, sec_hdr, 12);
+ }
+ else
+ {
+ s_push_layer(s, sec_hdr, 4);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* Output a uint32 into a buffer (little-endian) */
+void APP_CC
+rdp_sec_buf_out_uint32(char* buffer, int value)
+{
+ buffer[0] = value & 0xff;
+ buffer[1] = (value >> 8) & 0xff;
+ buffer[2] = (value >> 16) & 0xff;
+ buffer[3] = (value >> 24) & 0xff;
+}
+
+/*****************************************************************************/
+/* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */
+void APP_CC
+rdp_sec_sign(char* signature, int siglen, char* session_key, int keylen,
+ char* data, int datalen)
+{
+ char shasig[20];
+ char md5sig[16];
+ char lenhdr[4];
+ void* sha1_context;
+ void* md5_context;
+
+ rdp_sec_buf_out_uint32(lenhdr, datalen);
+ sha1_context = g_sha1_info_create();
+ g_sha1_clear(sha1_context);
+ g_sha1_transform(sha1_context, session_key, keylen);
+ g_sha1_transform(sha1_context, g_pad_54, 40);
+ g_sha1_transform(sha1_context, lenhdr, 4);
+ g_sha1_transform(sha1_context, data, datalen);
+ g_sha1_complete(sha1_context, shasig);
+ g_sha1_info_delete(sha1_context);
+ md5_context = g_md5_info_create();
+ g_md5_clear(md5_context);
+ g_md5_transform(md5_context, session_key, keylen);
+ g_md5_transform(md5_context, g_pad_92, 48);
+ g_md5_transform(md5_context, shasig, 20);
+ g_md5_complete(md5_context, md5sig);
+ g_md5_info_delete(md5_context);
+ g_memcpy(signature, md5sig, siglen);
+}
+
+/*****************************************************************************/
+/* Encrypt data using RC4 */
+static void APP_CC
+rdp_sec_encrypt(struct rdp_sec* self, char* data, int length)
+{
+ if (self->encrypt_use_count == 4096)
+ {
+ rdp_sec_update(self->encrypt_key, self->encrypt_update_key,
+ self->rc4_key_len);
+ g_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key,
+ self->rc4_key_len);
+ self->encrypt_use_count = 0;
+ }
+ g_rc4_crypt(self->encrypt_rc4_info, data, length);
+ self->encrypt_use_count++;
+}
+
+/*****************************************************************************/
+/* returns error */
+int APP_CC
+rdp_sec_send(struct rdp_sec* self, struct stream* s, int flags)
+{
+ int datalen;
+
+ DEBUG((" in rdp_sec_send flags %8.8x\r\n", flags));
+ s_pop_layer(s, sec_hdr);
+ out_uint32_le(s, flags);
+ if (flags & SEC_ENCRYPT)
+ {
+ datalen = (s->end - s->p) - 8;
+ rdp_sec_sign(s->p, 8, self->sign_key, self->rc4_key_len, s->p + 8,
+ datalen);
+ rdp_sec_encrypt(self, s->p + 8, datalen);
+ }
+ if (rdp_mcs_send(self->mcs_layer, s) != 0)
+ {
+ DEBUG((" out rdp_sec_send, rdp_mcs_send failed\r\n"));
+ return 1;
+ }
+ DEBUG((" out rdp_sec_send\r\n"));
+ return 0;
+}
diff --git a/rdp/rdp_tcp.c b/rdp/rdp_tcp.c
index d5a13c9b..d136a8be 100644
--- a/rdp/rdp_tcp.c
+++ b/rdp/rdp_tcp.c
@@ -57,8 +57,11 @@ rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len)
{
int rcvd;
+ DEBUG((" in rdp_tcp_recv gota get %d bytes on sck %d\r\n",
+ len, self->sck));
if (self->sck_closed)
{
+ DEBUG((" out rdp_tcp_recv error sck closed\r\n"));
return 1;
}
init_stream(s, len);
@@ -74,12 +77,14 @@ rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len)
else
{
self->sck_closed = 1;
+ DEBUG((" out rdp_tcp_recv error unknown\r\n"));
return 1;
}
}
else if (rcvd == 0)
{
self->sck_closed = 1;
+ DEBUG((" out rdp_tcp_recv error connection dropped\r\n"));
return 1;
}
else
@@ -102,9 +107,12 @@ rdp_tcp_send(struct rdp_tcp* self, struct stream* s)
if (self->sck_closed)
{
+ DEBUG((" out rdp_tcp_send error sck closed\r\n"));
return 1;
}
len = s->end - s->data;
+ DEBUG((" in rdp_tcp_send gota send %d bytes on sck %d\r\n", len,
+ self->sck));
total = 0;
while (total < len)
{
@@ -118,12 +126,14 @@ rdp_tcp_send(struct rdp_tcp* self, struct stream* s)
else
{
self->sck_closed = 1;
+ DEBUG((" out rdp_tcp_send error unknown\r\n"));
return 1;
}
}
else if (sent == 0)
{
self->sck_closed = 1;
+ DEBUG((" out rdp_tcp_send error connection dropped\r\n"));
return 1;
}
else
@@ -139,6 +149,7 @@ rdp_tcp_send(struct rdp_tcp* self, struct stream* s)
int APP_CC
rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port)
{
+ DEBUG((" in rdp_tcp_connect ip %s port %s\r\n", ip, port));
self->sck = g_tcp_socket();
if (g_tcp_connect(self->sck, ip, port) == 0)
{
@@ -146,8 +157,10 @@ rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port)
}
else
{
+ DEBUG((" out rdp_tcp_connect error g_tcp_connect failed\r\n"));
return 1;
}
+ DEBUG((" out rdp_tcp_connect\r\n"));
return 0;
}