diff options
author | jsorg71 <jsorg71> | 2005-11-03 02:01:50 +0000 |
---|---|---|
committer | jsorg71 <jsorg71> | 2005-11-03 02:01:50 +0000 |
commit | 523ea69fa574dbcbe9e261c8664c8e93f18eb09d (patch) | |
tree | 180fed20bd3e54ca7af1d0c02115769b54a0857b /rdp | |
parent | 05ec6aa2d59efcf4c489bd3d7decd83be384157c (diff) | |
download | xrdp-proprietary-523ea69fa574dbcbe9e261c8664c8e93f18eb09d.tar.gz xrdp-proprietary-523ea69fa574dbcbe9e261c8664c8e93f18eb09d.zip |
early rdp module work
Diffstat (limited to 'rdp')
-rw-r--r-- | rdp/rdp.c | 275 | ||||
-rw-r--r-- | rdp/rdp.h | 436 | ||||
-rw-r--r-- | rdp/rdp_bitmap.c | 917 | ||||
-rw-r--r-- | rdp/rdp_iso.c | 25 | ||||
-rw-r--r-- | rdp/rdp_lic.c | 354 | ||||
-rw-r--r-- | rdp/rdp_mcs.c | 53 | ||||
-rw-r--r-- | rdp/rdp_orders.c | 1017 | ||||
-rw-r--r-- | rdp/rdp_rdp.c | 974 | ||||
-rw-r--r-- | rdp/rdp_sec.c | 651 | ||||
-rw-r--r-- | rdp/rdp_tcp.c | 13 |
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; } |