21 files changed, 7054 insertions, 0 deletions
diff --git a/noncore/net/opierdesktop/.cvsignore b/noncore/net/opierdesktop/.cvsignore new file mode 100644 index 0000000..df6ec24 --- a/dev/null +++ b/noncore/net/opierdesktop/.cvsignore @@ -0,0 +1,4 @@ +*.o +*~ +Makefile* +moc_* diff --git a/noncore/net/opierdesktop/bitmap.cpp b/noncore/net/opierdesktop/bitmap.cpp new file mode 100644 index 0000000..378623f --- a/dev/null +++ b/noncore/net/opierdesktop/bitmap.cpp @@ -0,0 +1,282 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Bitmap decompression routines + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +#define CVAL(p) (*(p++)) + +static uint32 +cvalx(unsigned char **input, int Bpp) +{ + uint32 rv = 0; + memcpy(&rv, *input, Bpp); + *input += Bpp; + return rv; +} + +static void +setli(unsigned char *input, int offset, uint32 value, int Bpp) +{ + input += offset * Bpp; + memcpy(input, &value, Bpp); +} + +static uint32 +getli(unsigned char *input, int offset, int Bpp) +{ + uint32 rv = 0; + input += offset * Bpp; + memcpy(&rv, input, Bpp); + return rv; +} + +#define UNROLL8(exp) { exp exp exp exp exp exp exp exp } + +#define REPEAT(statement) \ +{ \ + while((count & ~0x7) && ((x+8) < width)) \ + UNROLL8( statement; count--; x++; ); \ + \ + while((count > 0) && (x < width)) { statement; count--; x++; } \ +} + +#define MASK_UPDATE() \ +{ \ + mixmask <<= 1; \ + if (mixmask == 0) \ + { \ + mask = fom_mask ? fom_mask : CVAL(input); \ + mixmask = 1; \ + } \ +} + +BOOL +bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, + int Bpp) +{ + unsigned char *end = input + size; + unsigned char *prevline = NULL, *line = NULL; + int opcode, count, offset, isfillormix, x = width; + int lastopcode = -1, insertmix = False, bicolour = False; + uint8 code; + uint32 colour1 = 0, colour2 = 0; + uint8 mixmask, mask = 0; + uint32 mix = 0xffffffff; + int 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 == NULL))) + insertmix = True; + break; + case 8: /* Bicolour */ + colour1 = cvalx(&input, Bpp); + case 3: /* Colour */ + colour2 = cvalx(&input, Bpp); + break; + case 6: /* SetMix/Mix */ + case 7: /* SetMix/FillOrMix */ + mix = cvalx(&input, Bpp); + 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 False; + + x = 0; + height--; + + prevline = line; + line = output + height * width * Bpp; + } + + switch (opcode) + { + case 0: /* Fill */ + if (insertmix) + { + if (prevline == NULL) + setli(line, x, mix, Bpp); + else + setli(line, x, + getli(prevline, x, Bpp) ^ mix, Bpp); + + insertmix = False; + count--; + x++; + } + + if (prevline == NULL) + { + REPEAT(setli(line, x, 0, Bpp))} + else + { + REPEAT(setli + (line, x, getli(prevline, x, Bpp), Bpp)); + } + break; + + case 1: /* Mix */ + if (prevline == NULL) + { + REPEAT(setli(line, x, mix, Bpp)); + } + else + { + REPEAT(setli + (line, x, getli(prevline, x, Bpp) ^ mix, + Bpp)); + } + break; + + case 2: /* Fill or Mix */ + if (prevline == NULL) + { + REPEAT(MASK_UPDATE(); + if (mask & mixmask) setli(line, x, mix, Bpp); + else + setli(line, x, 0, Bpp);); + } + else + { + REPEAT(MASK_UPDATE(); + if (mask & mixmask) + setli(line, x, getli(prevline, x, Bpp) ^ mix, + Bpp); + else + setli(line, x, getli(prevline, x, Bpp), + Bpp);); + } + break; + + case 3: /* Colour */ + REPEAT(setli(line, x, colour2, Bpp)); + break; + + case 4: /* Copy */ + REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp)); + break; + + case 8: /* Bicolour */ + REPEAT(if (bicolour) + { + setli(line, x, colour2, Bpp); bicolour = False;} + else + { + setli(line, x, colour1, Bpp); bicolour = True; + count++;} + ); + break; + + case 0xd: /* White */ + REPEAT(setli(line, x, 0xffffffff, Bpp)); + break; + + case 0xe: /* Black */ + REPEAT(setli(line, x, 0, Bpp)); + break; + + default: + unimpl("bitmap opcode 0x%x\n", opcode); + return False; + } + } + } + + return True; +} diff --git a/noncore/net/opierdesktop/cache.cpp b/noncore/net/opierdesktop/cache.cpp new file mode 100644 index 0000000..42ab135 --- a/dev/null +++ b/noncore/net/opierdesktop/cache.cpp @@ -0,0 +1,235 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Cache routines + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0])) + + +/* BITMAP CACHE */ +static HBITMAP bmpcache[3][600]; + +/* Retrieve a bitmap from the cache */ +HBITMAP +cache_get_bitmap(uint8 cache_id, uint16 cache_idx) +{ + HBITMAP bitmap; + + if ((cache_id < NUM_ELEMENTS(bmpcache)) && (cache_idx < NUM_ELEMENTS(bmpcache[0]))) + { + bitmap = bmpcache[cache_id][cache_idx]; + if (bitmap != NULL) + return bitmap; + } + + error("get bitmap %d:%d\n", cache_id, cache_idx); + return NULL; +} + +/* Store a bitmap in the cache */ +void +cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap) +{ + HBITMAP old; + + if ((cache_id < NUM_ELEMENTS(bmpcache)) && (cache_idx < NUM_ELEMENTS(bmpcache[0]))) + { + old = bmpcache[cache_id][cache_idx]; + if (old != NULL) + ui_destroy_bitmap(old); + + bmpcache[cache_id][cache_idx] = bitmap; + } + else + { + error("put bitmap %d:%d\n", cache_id, cache_idx); + } +} + + +/* FONT CACHE */ +static FONTGLYPH fontcache[12][256]; + +/* Retrieve a glyph from the font cache */ +FONTGLYPH * +cache_get_font(uint8 font, uint16 character) +{ + FONTGLYPH *glyph; + + if ((font < NUM_ELEMENTS(fontcache)) && (character < NUM_ELEMENTS(fontcache[0]))) + { + glyph = &fontcache[font][character]; + if (glyph->pixmap != NULL) + return glyph; + } + + error("get font %d:%d\n", font, character); + return NULL; +} + +/* Store a glyph in the font cache */ +void +cache_put_font(uint8 font, uint16 character, uint16 offset, + uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap) +{ + FONTGLYPH *glyph; + + if ((font < NUM_ELEMENTS(fontcache)) && (character < NUM_ELEMENTS(fontcache[0]))) + { + glyph = &fontcache[font][character]; + if (glyph->pixmap != NULL) + ui_destroy_glyph(glyph->pixmap); + + glyph->offset = offset; + glyph->baseline = baseline; + glyph->width = width; + glyph->height = height; + glyph->pixmap = pixmap; + } + else + { + error("put font %d:%d\n", font, character); + } +} + + +/* TEXT CACHE */ +static DATABLOB textcache[256]; + +/* Retrieve a text item from the cache */ +DATABLOB * +cache_get_text(uint8 cache_id) +{ + DATABLOB *text; + + if (cache_id < NUM_ELEMENTS(textcache)) + { + text = &textcache[cache_id]; + if (text->data != NULL) + return text; + } + + error("get text %d\n", cache_id); + return NULL; +} + +/* Store a text item in the cache */ +void +cache_put_text(uint8 cache_id, void *data, int length) +{ + DATABLOB *text; + + if (cache_id < NUM_ELEMENTS(textcache)) + { + text = &textcache[cache_id]; + if (text->data != NULL) + xfree(text->data); + + text->data = xmalloc(length); + text->size = length; + memcpy(text->data, data, length); + } + else + { + error("put text %d\n", cache_id); + } +} + + +/* DESKTOP CACHE */ +static uint8 deskcache[0x38400]; + +/* Retrieve desktop data from the cache */ +uint8 * +cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel) +{ + int length = cx * cy * bytes_per_pixel; + + if ((offset + length) <= sizeof(deskcache)) + { + return &deskcache[offset]; + } + + error("get desktop %d:%d\n", offset, length); + return NULL; +} + +/* Store desktop data in the cache */ +void +cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data) +{ + int length = cx * cy * bytes_per_pixel; + + if ((offset + length) <= sizeof(deskcache)) + { + cx *= bytes_per_pixel; + while (cy--) + { + memcpy(&deskcache[offset], data, cx); + data += scanline; + offset += cx; + } + } + else + { + error("put desktop %d:%d\n", offset, length); + } +} + + +/* CURSOR CACHE */ +static HCURSOR cursorcache[0x20]; + +/* Retrieve cursor from cache */ +HCURSOR +cache_get_cursor(uint16 cache_idx) +{ + HCURSOR cursor; + + if (cache_idx < NUM_ELEMENTS(cursorcache)) + { + cursor = cursorcache[cache_idx]; + if (cursor != NULL) + return cursor; + } + + error("get cursor %d\n", cache_idx); + return NULL; +} + +/* Store cursor in cache */ +void +cache_put_cursor(uint16 cache_idx, HCURSOR cursor) +{ + HCURSOR old; + + if (cache_idx < NUM_ELEMENTS(cursorcache)) + { + old = cursorcache[cache_idx]; + if (old != NULL) + ui_destroy_cursor(old); + + cursorcache[cache_idx] = cursor; + } + else + { + error("put cursor %d\n", cache_idx); + } +} diff --git a/noncore/net/opierdesktop/constants.h b/noncore/net/opierdesktop/constants.h new file mode 100644 index 0000000..6dfbf93 --- a/dev/null +++ b/noncore/net/opierdesktop/constants.h @@ -0,0 +1,259 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Miscellaneous protocol constants + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +/* TCP port for Remote Desktop Protocol */ +#define TCP_PORT_RDP 3389 + +/* ISO PDU codes */ +enum ISO_PDU_CODE +{ + ISO_PDU_CR = 0xE0, /* Connection Request */ + ISO_PDU_CC = 0xD0, /* Connection Confirm */ + ISO_PDU_DR = 0x80, /* Disconnect Request */ + ISO_PDU_DT = 0xF0, /* Data */ + ISO_PDU_ER = 0x70 /* Error */ +}; + +/* MCS PDU codes */ +enum MCS_PDU_TYPE +{ + MCS_EDRQ = 1, /* Erect Domain Request */ + MCS_DPUM = 8, /* Disconnect Provider Ultimatum */ + MCS_AURQ = 10, /* Attach User Request */ + MCS_AUCF = 11, /* Attach User Confirm */ + MCS_CJRQ = 14, /* Channel Join Request */ + MCS_CJCF = 15, /* Channel Join Confirm */ + MCS_SDRQ = 25, /* Send Data Request */ + MCS_SDIN = 26 /* Send Data Indication */ +}; + +#define MCS_CONNECT_INITIAL 0x7f65 +#define MCS_CONNECT_RESPONSE 0x7f66 + +#define BER_TAG_BOOLEAN 1 +#define BER_TAG_INTEGER 2 +#define BER_TAG_OCTET_STRING 4 +#define BER_TAG_RESULT 10 +#define MCS_TAG_DOMAIN_PARAMS 0x30 + +#define MCS_GLOBAL_CHANNEL 1003 + +/* RDP secure transport constants */ +#define SEC_RANDOM_SIZE 32 +#define SEC_MODULUS_SIZE 64 +#define SEC_PADDING_SIZE 8 +#define SEC_EXPONENT_SIZE 4 + +#define SEC_CLIENT_RANDOM 0x0001 +#define SEC_ENCRYPT 0x0008 +#define SEC_LOGON_INFO 0x0040 +#define SEC_LICENCE_NEG 0x0080 + +#define SEC_TAG_SRV_INFO 0x0c01 +#define SEC_TAG_SRV_CRYPT 0x0c02 +#define SEC_TAG_SRV_3 0x0c03 + +#define SEC_TAG_CLI_INFO 0xc001 +#define SEC_TAG_CLI_CRYPT 0xc002 + +#define SEC_TAG_PUBKEY 0x0006 +#define SEC_TAG_KEYSIG 0x0008 + +#define SEC_RSA_MAGIC 0x31415352 /* RSA1 */ + +/* RDP licensing constants */ +#define LICENCE_TOKEN_SIZE 10 +#define LICENCE_HWID_SIZE 20 +#define LICENCE_SIGNATURE_SIZE 16 + +#define LICENCE_TAG_DEMAND 0x0201 +#define LICENCE_TAG_AUTHREQ 0x0202 +#define LICENCE_TAG_ISSUE 0x0203 +#define LICENCE_TAG_REISSUE 0x0204 +#define LICENCE_TAG_PRESENT 0x0212 +#define LICENCE_TAG_REQUEST 0x0213 +#define LICENCE_TAG_AUTHRESP 0x0215 +#define LICENCE_TAG_RESULT 0x02ff + +#define LICENCE_TAG_USER 0x000f +#define LICENCE_TAG_HOST 0x0010 + +/* RDP PDU codes */ +enum RDP_PDU_TYPE +{ + RDP_PDU_DEMAND_ACTIVE = 1, + RDP_PDU_CONFIRM_ACTIVE = 3, + RDP_PDU_DEACTIVATE = 6, + RDP_PDU_DATA = 7 +}; + +enum RDP_DATA_PDU_TYPE +{ + RDP_DATA_PDU_UPDATE = 2, + RDP_DATA_PDU_CONTROL = 20, + RDP_DATA_PDU_POINTER = 27, + RDP_DATA_PDU_INPUT = 28, + RDP_DATA_PDU_SYNCHRONISE = 31, + RDP_DATA_PDU_BELL = 34, + RDP_DATA_PDU_LOGON = 38, + RDP_DATA_PDU_FONT2 = 39 +}; + +enum RDP_CONTROL_PDU_TYPE +{ + RDP_CTL_REQUEST_CONTROL = 1, + RDP_CTL_GRANT_CONTROL = 2, + RDP_CTL_DETACH = 3, + RDP_CTL_COOPERATE = 4 +}; + +enum RDP_UPDATE_PDU_TYPE +{ + RDP_UPDATE_ORDERS = 0, + RDP_UPDATE_BITMAP = 1, + RDP_UPDATE_PALETTE = 2, + RDP_UPDATE_SYNCHRONIZE = 3 +}; + +enum RDP_POINTER_PDU_TYPE +{ + RDP_POINTER_MOVE = 3, + RDP_POINTER_COLOR = 6, + RDP_POINTER_CACHED = 7 +}; + +enum RDP_INPUT_DEVICE +{ + RDP_INPUT_SYNCHRONIZE = 0, + RDP_INPUT_CODEPOINT = 1, + RDP_INPUT_VIRTKEY = 2, + RDP_INPUT_SCANCODE = 4, + RDP_INPUT_MOUSE = 0x8001 +}; + +/* Device flags */ +#define KBD_FLAG_RIGHT 0x0001 +#define KBD_FLAG_EXT 0x0100 +#define KBD_FLAG_QUIET 0x1000 +#define KBD_FLAG_DOWN 0x4000 +#define KBD_FLAG_UP 0x8000 + +/* These are for synchronization; not for keystrokes */ +#define KBD_FLAG_SCROLL 0x0001 +#define KBD_FLAG_NUMLOCK 0x0002 +#define KBD_FLAG_CAPITAL 0x0004 + +/* See T.128 */ +#define RDP_KEYPRESS 0 +#define RDP_KEYRELEASE (KBD_FLAG_DOWN | KBD_FLAG_UP) + +#define MOUSE_FLAG_MOVE 0x0800 +#define MOUSE_FLAG_BUTTON1 0x1000 +#define MOUSE_FLAG_BUTTON2 0x2000 +#define MOUSE_FLAG_BUTTON3 0x4000 +#define MOUSE_FLAG_BUTTON4 0x0280 +#define MOUSE_FLAG_BUTTON5 0x0380 +#define MOUSE_FLAG_DOWN 0x8000 + +/* Raster operation masks */ +#define ROP2_S(rop3) (rop3 & 0xf) +#define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)) + +#define ROP2_COPY 0xc +#define ROP2_XOR 0x6 +#define ROP2_AND 0x8 +#define ROP2_NXOR 0x9 +#define ROP2_OR 0xe + +#define MIX_TRANSPARENT 0 +#define MIX_OPAQUE 1 + +#define TEXT2_VERTICAL 0x04 +#define TEXT2_IMPLICIT_X 0x20 + +/* RDP capabilities */ +#define RDP_CAPSET_GENERAL 1 +#define RDP_CAPLEN_GENERAL 0x18 +#define OS_MAJOR_TYPE_UNIX 4 +#define OS_MINOR_TYPE_XSERVER 7 + +#define RDP_CAPSET_BITMAP 2 +#define RDP_CAPLEN_BITMAP 0x1C + +#define RDP_CAPSET_ORDER 3 +#define RDP_CAPLEN_ORDER 0x58 +#define ORDER_CAP_NEGOTIATE 2 +#define ORDER_CAP_NOSUPPORT 4 + +#define RDP_CAPSET_BMPCACHE 4 +#define RDP_CAPLEN_BMPCACHE 0x28 + +#define RDP_CAPSET_CONTROL 5 +#define RDP_CAPLEN_CONTROL 0x0C + +#define RDP_CAPSET_ACTIVATE 7 +#define RDP_CAPLEN_ACTIVATE 0x0C + +#define RDP_CAPSET_POINTER 8 +#define RDP_CAPLEN_POINTER 0x08 + +#define RDP_CAPSET_SHARE 9 +#define RDP_CAPLEN_SHARE 0x08 + +#define RDP_CAPSET_COLCACHE 10 +#define RDP_CAPLEN_COLCACHE 0x08 + +#define RDP_CAPSET_UNKNOWN 13 +#define RDP_CAPLEN_UNKNOWN 0x9C + +#define RDP_SOURCE "MSTSC" + +/* Logon flags */ +#define RDP_LOGON_NORMAL 0x33 +#define RDP_LOGON_AUTO 0x8 + +/* Keymap flags */ +#define MapRightShiftMask (1<<0) +#define MapLeftShiftMask (1<<1) +#define MapShiftMask (MapRightShiftMask | MapLeftShiftMask) + +#define MapRightAltMask (1<<2) +#define MapLeftAltMask (1<<3) +#define MapAltGrMask MapRightAltMask + +#define MapRightCtrlMask (1<<4) +#define MapLeftCtrlMask (1<<5) +#define MapCtrlMask (MapRightCtrlMask | MapLeftCtrlMask) + +#define MapRightWinMask (1<<6) +#define MapLeftWinMask (1<<7) +#define MapWinMask (MapRightWinMask | MapLeftWinMask) + +#define MapNumLockMask (1<<8) +#define MapCapsLockMask (1<<9) + +#define MapLocalStateMask (1<<10) + +#define MapInhibitMask (1<<11) + +#define MASK_ADD_BITS(var, mask) (var |= mask) +#define MASK_REMOVE_BITS(var, mask) (var &= ~mask) +#define MASK_HAS_BITS(var, mask) ((var & mask)>0) +#define MASK_CHANGE_BIT(var, mask, active) (var = ((var & ~mask) | (active ? mask : 0))) diff --git a/noncore/net/opierdesktop/iso.cpp b/noncore/net/opierdesktop/iso.cpp new file mode 100644 index 0000000..0fa1a17 --- a/dev/null +++ b/noncore/net/opierdesktop/iso.cpp @@ -0,0 +1,170 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - ISO layer + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +/* Send a self-contained ISO PDU */ +static void +iso_send_msg(uint8 code) +{ + STREAM s; + + s = tcp_init(11); + + out_uint8(s, 3); /* version */ + out_uint8(s, 0); /* reserved */ + out_uint16_be(s, 11); /* length */ + + out_uint8(s, 6); /* hdrlen */ + out_uint8(s, code); + out_uint16(s, 0); /* dst_ref */ + out_uint16(s, 0); /* src_ref */ + out_uint8(s, 0); /* class */ + + s_mark_end(s); + tcp_send(s); +} + +/* Receive a message on the ISO layer, return code */ +static STREAM +iso_recv_msg(uint8 * code) +{ + STREAM s; + uint16 length; + uint8 version; + + s = tcp_recv(4); + if (s == NULL) + { + return NULL; + } + + in_uint8(s, version); + if (version != 3) + { + error("TPKT v%d\n", version); + return NULL; + } + + in_uint8s(s, 1); /* pad */ + in_uint16_be(s, length); + + s = tcp_recv(length - 4); + if (s == NULL) + return NULL; + + in_uint8s(s, 1); /* hdrlen */ + in_uint8(s, *code); + + if (*code == ISO_PDU_DT) + { + in_uint8s(s, 1); /* eot */ + return s; + } + + in_uint8s(s, 5); /* dst_ref, src_ref, class */ + return s; +} + +/* Initialise ISO transport data packet */ +STREAM +iso_init(int length) +{ + STREAM s; + + s = tcp_init(length + 7); + s_push_layer(s, iso_hdr, 7); + + return s; +} + +/* Send an ISO data PDU */ +void +iso_send(STREAM s) +{ + uint16 length; + + s_pop_layer(s, iso_hdr); + length = s->end - s->p; + + out_uint8(s, 3); /* version */ + out_uint8(s, 0); /* reserved */ + out_uint16_be(s, length); + + out_uint8(s, 2); /* hdrlen */ + out_uint8(s, ISO_PDU_DT); /* code */ + out_uint8(s, 0x80); /* eot */ + + tcp_send(s); +} + +/* Receive ISO transport data packet */ +STREAM +iso_recv(void) +{ + STREAM s; + uint8 code; + + s = iso_recv_msg(&code); + if (s == NULL) + return NULL; + + if (code != ISO_PDU_DT) + { + error("expected DT, got 0x%x\n", code); + return NULL; + } + + return s; +} + +/* Establish a connection up to the ISO layer */ +BOOL +iso_connect(char *server) +{ + uint8 code; + + if (!tcp_connect(server)) + return False; + + iso_send_msg(ISO_PDU_CR); + + if (iso_recv_msg(&code) == NULL) + { + return False; + } + + if (code != ISO_PDU_CC) + { + error("expected CC, got 0x%x\n", code); + tcp_disconnect(); + return False; + } + + return True; +} + +/* Disconnect from the ISO layer */ +void +iso_disconnect(void) +{ + iso_send_msg(ISO_PDU_DR); + tcp_disconnect(); +} diff --git a/noncore/net/opierdesktop/licence.cpp b/noncore/net/opierdesktop/licence.cpp new file mode 100644 index 0000000..4e5bc38 --- a/dev/null +++ b/noncore/net/opierdesktop/licence.cpp @@ -0,0 +1,314 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP licensing negotiation + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +#ifdef WITH_OPENSSL +#include <openssl/rc4.h> +#else +#include "crypto/rc4.h" +#endif + +extern char username[16]; +extern char hostname[16]; + +static uint8 licence_key[16]; +static uint8 licence_sign_key[16]; + +BOOL licence_issued = False; + +/* Generate a session key and RC4 keys, given client and server randoms */ +static void +licence_generate_keys(uint8 * client_key, uint8 * server_key, uint8 * client_rsa) +{ + uint8 session_key[48]; + uint8 temp_hash[48]; + + /* Generate session key - two rounds of sec_hash_48 */ + sec_hash_48(temp_hash, client_rsa, client_key, server_key, 65); + sec_hash_48(session_key, temp_hash, server_key, client_key, 65); + + /* Store first 16 bytes of session key, for generating signatures */ + memcpy(licence_sign_key, session_key, 16); + + /* Generate RC4 key */ + sec_hash_16(licence_key, &session_key[16], client_key, server_key); +} + +static void +licence_generate_hwid(uint8 * hwid) +{ + buf_out_uint32(hwid, 2); + strncpy((char *) (hwid + 4), hostname, LICENCE_HWID_SIZE - 4); +} + +/* Present an existing licence to the server */ +static void +licence_present(uint8 * client_random, uint8 * rsa_data, + uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) +{ + uint32 sec_flags = SEC_LICENCE_NEG; + uint16 length = + 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; + STREAM s; + + s = sec_init(sec_flags, length + 4); + + out_uint16_le(s, LICENCE_TAG_PRESENT); + out_uint16_le(s, length); + + out_uint32_le(s, 1); + out_uint16(s, 0); + out_uint16_le(s, 0x0201); + + out_uint8p(s, client_random, SEC_RANDOM_SIZE); + out_uint16(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); + sec_send(s, sec_flags); +} + +/* Send a licence request packet */ +static void +licence_send_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) +{ + uint32 sec_flags = SEC_LICENCE_NEG; + uint16 userlen = strlen(user) + 1; + uint16 hostlen = strlen(host) + 1; + uint16 length = 128 + userlen + hostlen; + STREAM s; + + s = sec_init(sec_flags, length + 2); + + out_uint16_le(s, LICENCE_TAG_REQUEST); + out_uint16_le(s, length); + + out_uint32_le(s, 1); + out_uint16(s, 0); + out_uint16_le(s, 0xff01); + + out_uint8p(s, client_random, SEC_RANDOM_SIZE); + out_uint16(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(s, LICENCE_TAG_USER); + out_uint16(s, userlen); + out_uint8p(s, user, userlen); + + out_uint16(s, LICENCE_TAG_HOST); + out_uint16(s, hostlen); + out_uint8p(s, host, hostlen); + + s_mark_end(s); + sec_send(s, sec_flags); +} + +/* Process a licence demand packet */ +static void +licence_process_demand(STREAM s) +{ + uint8 null_data[SEC_MODULUS_SIZE]; + uint8 *server_random; + uint8 signature[LICENCE_SIGNATURE_SIZE]; + uint8 hwid[LICENCE_HWID_SIZE]; + uint8 *licence_data; + int licence_size; + RC4_KEY 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. */ + memset(null_data, 0, sizeof(null_data)); + licence_generate_keys(null_data, server_random, null_data); + + licence_size = load_licence(&licence_data); + if (licence_size != -1) + { + /* Generate a signature for the HWID buffer */ + licence_generate_hwid(hwid); + sec_sign(signature, 16, licence_sign_key, 16, hwid, sizeof(hwid)); + + /* Now encrypt the HWID */ + RC4_set_key(&crypt_key, 16, licence_key); + RC4(&crypt_key, sizeof(hwid), hwid, hwid); + + licence_present(null_data, null_data, licence_data, licence_size, hwid, signature); + xfree(licence_data); + return; + } + + licence_send_request(null_data, null_data, username, hostname); +} + +/* Send an authentication response packet */ +static void +licence_send_authresp(uint8 * token, uint8 * crypt_hwid, uint8 * signature) +{ + uint32 sec_flags = SEC_LICENCE_NEG; + uint16 length = 58; + STREAM s; + + s = sec_init(sec_flags, length + 2); + + out_uint16_le(s, LICENCE_TAG_AUTHRESP); + 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); + sec_send(s, sec_flags); +} + +/* Parse an authentication request packet */ +static BOOL +licence_parse_authreq(STREAM s, uint8 ** token, uint8 ** signature) +{ + uint16 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 False; + } + + in_uint8p(s, *token, tokenlen); + in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); + + return s_check_end(s); +} + +/* Process an authentication request packet */ +static void +licence_process_authreq(STREAM s) +{ + uint8 *in_token, *in_sig; + uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE]; + uint8 hwid[LICENCE_HWID_SIZE], crypt_hwid[LICENCE_HWID_SIZE]; + uint8 sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; + uint8 out_sig[LICENCE_SIGNATURE_SIZE]; + RC4_KEY crypt_key; + + /* Parse incoming packet and save the encrypted token */ + licence_parse_authreq(s, &in_token, &in_sig); + memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); + + /* Decrypt the token. It should read TEST in Unicode. */ + RC4_set_key(&crypt_key, 16, licence_key); + RC4(&crypt_key, LICENCE_TOKEN_SIZE, in_token, decrypt_token); + + /* Generate a signature for a buffer of token and HWID */ + licence_generate_hwid(hwid); + memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); + memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); + sec_sign(out_sig, 16, licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer)); + + /* Now encrypt the HWID */ + RC4_set_key(&crypt_key, 16, licence_key); + RC4(&crypt_key, LICENCE_HWID_SIZE, hwid, crypt_hwid); + + licence_send_authresp(out_token, crypt_hwid, out_sig); +} + +/* Process an licence issue packet */ +static void +licence_process_issue(STREAM s) +{ + RC4_KEY crypt_key; + uint32 length; + uint16 check; + + in_uint8s(s, 2); /* 3d 45 - unknown */ + in_uint16_le(s, length); + if (!s_check_rem(s, length)) + return; + + RC4_set_key(&crypt_key, 16, licence_key); + RC4(&crypt_key, length, s->p, s->p); + + in_uint16(s, check); + if (check != 0) + return; + + licence_issued = True; + save_licence(s->p, length - 2); +} + +/* Process a licence packet */ +void +licence_process(STREAM s) +{ + uint16 tag; + + in_uint16_le(s, tag); + in_uint8s(s, 2); /* length */ + + switch (tag) + { + case LICENCE_TAG_DEMAND: + licence_process_demand(s); + break; + + case LICENCE_TAG_AUTHREQ: + licence_process_authreq(s); + break; + + case LICENCE_TAG_ISSUE: + licence_process_issue(s); + break; + + case LICENCE_TAG_REISSUE: + break; + + case LICENCE_TAG_RESULT: + break; + + default: + unimpl("licence tag 0x%x\n", tag); + } +} diff --git a/noncore/net/opierdesktop/mcs.cpp b/noncore/net/opierdesktop/mcs.cpp new file mode 100644 index 0000000..8877d62 --- a/dev/null +++ b/noncore/net/opierdesktop/mcs.cpp @@ -0,0 +1,394 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - Multipoint Communications Service + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +uint16 mcs_userid; + +/* Parse an ASN.1 BER header */ +static BOOL +ber_parse_header(STREAM s, int tagval, unsigned int *length) +{ + int tag, len; + + if (tagval > 0xff) + { + in_uint16_be(s, tag); + } + else + { + in_uint8(s, tag)} + + if (tag != tagval) + { + error("expected tag %d, got %d\n", tagval, tag); + return False; + } + + in_uint8(s, len); + + if (len & 0x80) + { + len &= ~0x80; + *length = 0; + while (len--) + next_be(s, *length); + } + else + *length = len; + + return s_check(s); +} + +/* Output an ASN.1 BER header */ +static void +ber_out_header(STREAM s, int tagval, int length) +{ + if (tagval > 0xff) + { + out_uint16_be(s, tagval); + } + else + { + out_uint8(s, tagval); + } + + if (length >= 0x80) + { + out_uint8(s, 0x82); + out_uint16_be(s, length); + } + else + out_uint8(s, length); +} + +/* Output an ASN.1 BER integer */ +static void +ber_out_integer(STREAM s, int value) +{ + ber_out_header(s, BER_TAG_INTEGER, 2); + out_uint16_be(s, value); +} + +/* Output a DOMAIN_PARAMS structure (ASN.1 BER) */ +static void +mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize) +{ + ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32); + ber_out_integer(s, max_channels); + ber_out_integer(s, max_users); + ber_out_integer(s, max_tokens); + ber_out_integer(s, 1); /* num_priorities */ + ber_out_integer(s, 0); /* min_throughput */ + ber_out_integer(s, 1); /* max_height */ + ber_out_integer(s, max_pdusize); + ber_out_integer(s, 2); /* ver_protocol */ +} + +/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */ +static BOOL +mcs_parse_domain_params(STREAM s) +{ + unsigned int length; + + ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length); + in_uint8s(s, length); + + return s_check(s); +} + +/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */ +static void +mcs_send_connect_initial(STREAM mcs_data) +{ + int datalen = mcs_data->end - mcs_data->data; + int length = 7 + 3 * 34 + 4 + datalen; + STREAM s; + + s = iso_init(length + 5); + + ber_out_header(s, MCS_CONNECT_INITIAL, length); + ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* calling domain */ + ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* called domain */ + + ber_out_header(s, BER_TAG_BOOLEAN, 1); + out_uint8(s, 0xff); /* upward flag */ + + mcs_out_domain_params(s, 2, 2, 0, 0xffff); /* target params */ + mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */ + mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ + + ber_out_header(s, BER_TAG_OCTET_STRING, datalen); + out_uint8p(s, mcs_data->data, datalen); + + s_mark_end(s); + iso_send(s); +} + +/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ +static BOOL +mcs_recv_connect_response(STREAM mcs_data) +{ + uint8 result; + unsigned int length; + STREAM s; + + s = iso_recv(); + if (s == NULL) + return False; + + ber_parse_header(s, MCS_CONNECT_RESPONSE, &length); + + ber_parse_header(s, BER_TAG_RESULT, &length); + in_uint8(s, result); + if (result != 0) + { + error("MCS connect: %d\n", result); + return False; + } + + ber_parse_header(s, BER_TAG_INTEGER, &length); + in_uint8s(s, length); /* connect id */ + mcs_parse_domain_params(s); + + ber_parse_header(s, BER_TAG_OCTET_STRING, &length); + if (length > mcs_data->size) + { + error("MCS data length %d\n", length); + length = mcs_data->size; + } + + in_uint8a(s, mcs_data->data, length); + mcs_data->p = mcs_data->data; + mcs_data->end = mcs_data->data + length; + + return s_check_end(s); +} + +/* Send an EDrq message (ASN.1 PER) */ +static void +mcs_send_edrq(void) +{ + STREAM s; + + s = iso_init(5); + + out_uint8(s, (MCS_EDRQ << 2)); + out_uint16_be(s, 1); /* height */ + out_uint16_be(s, 1); /* interval */ + + s_mark_end(s); + iso_send(s); +} + +/* Send an AUrq message (ASN.1 PER) */ +static void +mcs_send_aurq(void) +{ + STREAM s; + + s = iso_init(1); + + out_uint8(s, (MCS_AURQ << 2)); + + s_mark_end(s); + iso_send(s); +} + +/* Expect a AUcf message (ASN.1 PER) */ +static BOOL +mcs_recv_aucf(uint16 * mcs_userid) +{ + uint8 opcode, result; + STREAM s; + + s = iso_recv(); + if (s == NULL) + return False; + + in_uint8(s, opcode); + if ((opcode >> 2) != MCS_AUCF) + { + error("expected AUcf, got %d\n", opcode); + return False; + } + + in_uint8(s, result); + if (result != 0) + { + error("AUrq: %d\n", result); + return False; + } + + if (opcode & 2) + in_uint16_be(s, *mcs_userid); + + return s_check_end(s); +} + +/* Send a CJrq message (ASN.1 PER) */ +static void +mcs_send_cjrq(uint16 chanid) +{ + STREAM s; + + s = iso_init(5); + + out_uint8(s, (MCS_CJRQ << 2)); + out_uint16_be(s, mcs_userid); + out_uint16_be(s, chanid); + + s_mark_end(s); + iso_send(s); +} + +/* Expect a CJcf message (ASN.1 PER) */ +static BOOL +mcs_recv_cjcf(void) +{ + uint8 opcode, result; + STREAM s; + + s = iso_recv(); + if (s == NULL) + return False; + + in_uint8(s, opcode); + if ((opcode >> 2) != MCS_CJCF) + { + error("expected CJcf, got %d\n", opcode); + return False; + } + + in_uint8(s, result); + if (result != 0) + { + error("CJrq: %d\n", result); + return False; + } + + in_uint8s(s, 4); /* mcs_userid, req_chanid */ + if (opcode & 2) + in_uint8s(s, 2); /* join_chanid */ + + return s_check_end(s); +} + +/* Initialise an MCS transport data packet */ +STREAM +mcs_init(int length) +{ + STREAM s; + + s = iso_init(length + 8); + s_push_layer(s, mcs_hdr, 8); + + return s; +} + +/* Send an MCS transport data packet */ +void +mcs_send(STREAM s) +{ + uint16 length; + + s_pop_layer(s, mcs_hdr); + length = s->end - s->p - 8; + length |= 0x8000; + + out_uint8(s, (MCS_SDRQ << 2)); + out_uint16_be(s, mcs_userid); + out_uint16_be(s, MCS_GLOBAL_CHANNEL); + out_uint8(s, 0x70); /* flags */ + out_uint16_be(s, length); + + iso_send(s); +} + +/* Receive an MCS transport data packet */ +STREAM +mcs_recv(void) +{ + uint8 opcode, appid, length; + STREAM s; + + s = iso_recv(); + if (s == NULL) + return NULL; + + in_uint8(s, opcode); + appid = opcode >> 2; + if (appid != MCS_SDIN) + { + if (appid != MCS_DPUM) + { + error("expected data, got %d\n", opcode); + } + return NULL; + } + + in_uint8s(s, 5); /* userid, chanid, flags */ + in_uint8(s, length); + if (length & 0x80) + in_uint8s(s, 1); /* second byte of length */ + + return s; +} + +/* Establish a connection up to the MCS layer */ +BOOL +mcs_connect(char *server, STREAM mcs_data) +{ + if (!iso_connect(server)) + { + return False; + } + + mcs_send_connect_initial(mcs_data); + if (!mcs_recv_connect_response(mcs_data)) + goto error; + + mcs_send_edrq(); + + mcs_send_aurq(); + if (!mcs_recv_aucf(&mcs_userid)) + goto error; + + mcs_send_cjrq(mcs_userid + 1001); + if (!mcs_recv_cjcf()) + goto error; + + mcs_send_cjrq(MCS_GLOBAL_CHANNEL); + if (!mcs_recv_cjcf()) + goto error; + + return True; + + error: + iso_disconnect(); + return False; +} + +/* Disconnect from the MCS layer */ +void +mcs_disconnect(void) +{ + iso_disconnect(); +} diff --git a/noncore/net/opierdesktop/opie-rdesktop.control b/noncore/net/opierdesktop/opie-rdesktop.control new file mode 100644 index 0000000..3fe3705 --- a/dev/null +++ b/noncore/net/opierdesktop/opie-rdesktop.control @@ -0,0 +1,9 @@ +Package: opie-rdesktop +Files: bin/ordesktop pics/opierdesktop apps/Applications/opierdesktop.desktop +Priority: optional +Section: opie/applications +Maintainer: Michael 'Mickey' Lauer <mickeyl@handhelds.org> +Architecture: arm +Version: 1.2.0-$SUB_VERSION +Depends: task-opie-minimal +Description: Remote Desktop Protocol (RDP) Client diff --git a/noncore/net/opierdesktop/opierdesktop.pro b/noncore/net/opierdesktop/opierdesktop.pro new file mode 100644 index 0000000..7704855 --- a/dev/null +++ b/noncore/net/opierdesktop/opierdesktop.pro @@ -0,0 +1,26 @@ +TEMPLATE = app +DESTDIR = $(OPIEDIR)/bin +CONFIG = qt warn_on debug + +HEADERS += constants.h orders.h parse.h proto.h qtwin.h rdesktop.h types.h +SOURCES += bitmap.cpp \ + cache.cpp \ + iso.cpp \ + licence.cpp \ + mcs.cpp \ + orders.cpp \ + qtwin.cpp \ + rdesktop.cpp \ + rdp.cpp \ + secure.cpp \ + tcp.cpp + +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lqpe -lm -lcrypto +INTERFACES = +TARGET = ordesktop +QMAKE_CXXFLAGS += -DSHARP=1 -DWITH_OPENSSL=1 + +include ( $(OPIEDIR)/include.pro ) + diff --git a/noncore/net/opierdesktop/orders.cpp b/noncore/net/opierdesktop/orders.cpp new file mode 100644 index 0000000..194b043 --- a/dev/null +++ b/noncore/net/opierdesktop/orders.cpp @@ -0,0 +1,940 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP order processing + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" +#include "orders.h" + +extern uint8 *next_packet; +static RDP_ORDER_STATE order_state; + +/* Read field indicating which parameters are present */ +static void +rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size) +{ + uint8 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 +rdp_in_coord(STREAM s, sint16 * coord, BOOL delta) +{ + sint8 change; + + if (delta) + { + in_uint8(s, change); + *coord += change; + } + else + { + in_uint16_le(s, *coord); + } +} + +/* Read a colour entry */ +static void +rdp_in_colour(STREAM s, uint32 * colour) +{ + uint32 i; + in_uint8(s, i); + *colour = i; + in_uint8(s, i); + *colour |= i << 8; + in_uint8(s, i); + *colour |= i << 16; +} + +/* Parse bounds information */ +static BOOL +rdp_parse_bounds(STREAM s, BOUNDS * bounds) +{ + uint8 present; + + in_uint8(s, present); + + if (present & 1) + rdp_in_coord(s, &bounds->left, False); + else if (present & 16) + rdp_in_coord(s, &bounds->left, True); + + if (present & 2) + rdp_in_coord(s, &bounds->top, False); + else if (present & 32) + rdp_in_coord(s, &bounds->top, True); + + if (present & 4) + rdp_in_coord(s, &bounds->right, False); + else if (present & 64) + rdp_in_coord(s, &bounds->right, True); + + if (present & 8) + rdp_in_coord(s, &bounds->bottom, False); + else if (present & 128) + rdp_in_coord(s, &bounds->bottom, True); + + return s_check(s); +} + +/* Parse a pen */ +static BOOL +rdp_parse_pen(STREAM s, PEN * pen, uint32 present) +{ + if (present & 1) + in_uint8(s, pen->style); + + if (present & 2) + in_uint8(s, pen->width); + + if (present & 4) + rdp_in_colour(s, &pen->colour); + + return s_check(s); +} + +/* Parse a brush */ +static BOOL +rdp_parse_brush(STREAM s, BRUSH * brush, uint32 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); + + return s_check(s); +} + +/* Process a destination blt order */ +static void +process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta) +{ + if (present & 0x01) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x02) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x04) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x08) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x10) + in_uint8(s, os->opcode); + + DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n", + os->opcode, os->x, os->y, os->cx, os->cy)); + + ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy); +} + +/* Process a pattern blt order */ +static void +process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta) +{ + if (present & 0x0001) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x0002) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x0004) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x0008) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x0010) + in_uint8(s, os->opcode); + + if (present & 0x0020) + rdp_in_colour(s, &os->bgcolour); + + if (present & 0x0040) + rdp_in_colour(s, &os->fgcolour); + + rdp_parse_brush(s, &os->brush, present >> 7); + + DEBUG(("PATBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x, + os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour)); + + ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy, + &os->brush, os->bgcolour, os->fgcolour); +} + +/* Process a screen blt order */ +static void +process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta) +{ + if (present & 0x0001) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x0002) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x0004) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x0008) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x0010) + in_uint8(s, os->opcode); + + if (present & 0x0020) + rdp_in_coord(s, &os->srcx, delta); + + if (present & 0x0040) + rdp_in_coord(s, &os->srcy, delta); + + DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n", + os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy)); + + ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy); +} + +/* Process a line order */ +static void +process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta) +{ + if (present & 0x0001) + in_uint16_le(s, os->mixmode); + + if (present & 0x0002) + rdp_in_coord(s, &os->startx, delta); + + if (present & 0x0004) + rdp_in_coord(s, &os->starty, delta); + + if (present & 0x0008) + rdp_in_coord(s, &os->endx, delta); + + if (present & 0x0010) + rdp_in_coord(s, &os->endy, delta); + + if (present & 0x0020) + rdp_in_colour(s, &os->bgcolour); + + if (present & 0x0040) + in_uint8(s, os->opcode); + + rdp_parse_pen(s, &os->pen, present >> 7); + + DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dx=%d,fg=0x%x)\n", + os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour)); + + if (os->opcode < 0x01 || os->opcode > 0x10) + { + error("bad ROP2 0x%x\n", os->opcode); + return; + } + + ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen); +} + +/* Process an opaque rectangle order */ +static void +process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta) +{ + uint32 i; + if (present & 0x01) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x02) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x04) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x08) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x10) + { + in_uint8(s, i); + os->colour = (os->colour & 0xffffff00) | i; + } + + if (present & 0x20) + { + in_uint8(s, i); + os->colour = (os->colour & 0xffff00ff) | (i << 8); + } + + if (present & 0x40) + { + in_uint8(s, i); + os->colour = (os->colour & 0xff00ffff) | (i << 16); + } + + DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour)); + + ui_rect(os->x, os->y, os->cx, os->cy, os->colour); +} + +/* Process a desktop save order */ +static void +process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta) +{ + int width, height; + + if (present & 0x01) + in_uint32_le(s, os->offset); + + if (present & 0x02) + rdp_in_coord(s, &os->left, delta); + + if (present & 0x04) + rdp_in_coord(s, &os->top, delta); + + if (present & 0x08) + rdp_in_coord(s, &os->right, delta); + + if (present & 0x10) + rdp_in_coord(s, &os->bottom, delta); + + if (present & 0x20) + in_uint8(s, os->action); + + DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n", + os->left, os->top, os->right, os->bottom, os->offset, os->action)); + + width = os->right - os->left + 1; + height = os->bottom - os->top + 1; + + if (os->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 +process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta) +{ + HBITMAP bitmap; + + if (present & 0x0001) + { + in_uint8(s, os->cache_id); + in_uint8(s, os->colour_table); + } + + if (present & 0x0002) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x0004) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x0008) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x0010) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x0020) + in_uint8(s, os->opcode); + + if (present & 0x0040) + rdp_in_coord(s, &os->srcx, delta); + + if (present & 0x0080) + rdp_in_coord(s, &os->srcy, delta); + + if (present & 0x0100) + in_uint16_le(s, os->cache_idx); + + DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n", + os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx)); + + bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); + if (bitmap == NULL) + return; + + ui_memblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy); +} + +/* Process a 3-way blt order */ +static void +process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta) +{ + HBITMAP bitmap; + + if (present & 0x000001) + { + in_uint8(s, os->cache_id); + in_uint8(s, os->colour_table); + } + + if (present & 0x000002) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x000004) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x000008) + rdp_in_coord(s, &os->cx, delta); + + if (present & 0x000010) + rdp_in_coord(s, &os->cy, delta); + + if (present & 0x000020) + in_uint8(s, os->opcode); + + if (present & 0x000040) + rdp_in_coord(s, &os->srcx, delta); + + if (present & 0x000080) + rdp_in_coord(s, &os->srcy, delta); + + if (present & 0x000100) + rdp_in_colour(s, &os->bgcolour); + + if (present & 0x000200) + rdp_in_colour(s, &os->fgcolour); + + rdp_parse_brush(s, &os->brush, present >> 10); + + if (present & 0x008000) + in_uint16_le(s, os->cache_idx); + + if (present & 0x010000) + in_uint16_le(s, os->unknown); + + DEBUG(("TRIBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d,bs=%d,bg=0x%x,fg=0x%x)\n", + os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx, + os->brush.style, os->bgcolour, os->fgcolour)); + + bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); + if (bitmap == NULL) + return; + + ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy, + bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour); +} + +/* Parse a delta co-ordinate in polyline order form */ +static int +parse_delta(uint8 * buffer, int *offset) +{ + int value = buffer[(*offset)++]; + int two_byte = value & 0x80; + + if (value & 0x40) /* sign bit */ + value |= ~0x3f; + else + value &= 0x3f; + + if (two_byte) + value = (value << 8) | buffer[(*offset)++]; + + return value; +} + +/* Process a polyline order */ +static void +process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta) +{ + int index, line, data; + int x, y, xfrom, yfrom; + uint8 flags = 0; + PEN pen; + uint8 opcode; + + if (present & 0x01) + rdp_in_coord(s, &os->x, delta); + + if (present & 0x02) + rdp_in_coord(s, &os->y, delta); + + if (present & 0x04) + in_uint8(s, os->opcode); + + if (present & 0x10) + rdp_in_colour(s, &os->fgcolour); + + if (present & 0x20) + in_uint8(s, os->lines); + + if (present & 0x40) + { + in_uint8(s, os->datasize); + in_uint8a(s, os->data, os->datasize); + } + + DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n", + os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize)); + + DEBUG(("Data: ")); + + for (index = 0; index < os->datasize; index++) + DEBUG(("%02x ", os->data[index])); + + DEBUG(("\n")); + + if (os->opcode < 0x01 || os->opcode > 0x10) + { + error("bad ROP2 0x%x\n", os->opcode); + return; + } + + opcode = os->opcode - 1; + x = os->x; + y = os->y; + pen.style = pen.width = 0; + pen.colour = os->fgcolour; + + index = 0; + data = ((os->lines - 1) / 4) + 1; + for (line = 0; (line < os->lines) && (data < os->datasize); line++) + { + xfrom = x; + yfrom = y; + + if (line % 4 == 0) + flags = os->data[index++]; + + if ((flags & 0xc0) == 0) + flags |= 0xc0; /* none = both */ + + if (flags & 0x40) + x += parse_delta(os->data, &data); + + if (flags & 0x80) + y += parse_delta(os->data, &data); + + ui_line(opcode, xfrom, yfrom, x, y, &pen); + + flags <<= 2; + } +} + +/* Process a text order */ +static void +process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta) +{ + int i; + + if (present & 0x000001) + in_uint8(s, os->font); + + if (present & 0x000002) + in_uint8(s, os->flags); + + if (present & 0x000004) + in_uint8(s, os->unknown); + + if (present & 0x000008) + in_uint8(s, os->mixmode); + + if (present & 0x000010) + rdp_in_colour(s, &os->fgcolour); + + if (present & 0x000020) + rdp_in_colour(s, &os->bgcolour); + + if (present & 0x000040) + in_uint16_le(s, os->clipleft); + + if (present & 0x000080) + in_uint16_le(s, os->cliptop); + + if (present & 0x000100) + in_uint16_le(s, os->clipright); + + if (present & 0x000200) + in_uint16_le(s, os->clipbottom); + + if (present & 0x000400) + in_uint16_le(s, os->boxleft); + + if (present & 0x000800) + in_uint16_le(s, os->boxtop); + + if (present & 0x001000) + in_uint16_le(s, os->boxright); + + if (present & 0x002000) + in_uint16_le(s, os->boxbottom); + + if (present & 0x004000) /* fix for connecting to a server that */ + in_uint8s(s, 10); /* was disconnected with mstsc.exe */ + /* 0x008000, 0x020000, and 0x040000 are present too ??? */ + + if (present & 0x080000) + in_uint16_le(s, os->x); + + if (present & 0x100000) + in_uint16_le(s, os->y); + + if (present & 0x200000) + { + in_uint8(s, os->length); + in_uint8a(s, os->text, os->length); + } + + DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,bb=%d,br=%d,fg=0x%x,bg=0x%x,font=%d,fl=0x%x,mix=%d,unk=0x%x,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->fgcolour, os->bgcolour, os->font, os->flags, os->mixmode, os->unknown, os->length)); + + DEBUG(("Text: ")); + + for (i = 0; i < os->length; i++) + DEBUG(("%02x ", os->text[i])); + + DEBUG(("\n")); + + ui_draw_text(os->font, os->flags, os->mixmode, os->x, os->y, + os->clipleft, os->cliptop, + os->clipright - os->clipleft, + os->clipbottom - os->cliptop, + os->boxleft, os->boxtop, + os->boxright - os->boxleft, + os->boxbottom - os->boxtop, os->bgcolour, os->fgcolour, os->text, os->length); +} + +/* Process a raw bitmap cache order */ +static void +process_raw_bmpcache(STREAM s) +{ + HBITMAP bitmap; + uint16 cache_idx, bufsize; + uint8 cache_id, width, height, bpp, Bpp; + uint8 *data, *inverted; + int y; + + in_uint8(s, cache_id); + in_uint8s(s, 1); /* pad */ + 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); + + DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); + inverted = (uint8*)xmalloc(width * height * Bpp); + for (y = 0; y < height; y++) + { + memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)], + width * Bpp); + } + + bitmap = ui_create_bitmap(width, height, inverted); + xfree(inverted); + cache_put_bitmap(cache_id, cache_idx, bitmap); +} + +/* Process a bitmap cache order */ +static void +process_bmpcache(STREAM s) +{ + HBITMAP bitmap; + uint16 cache_idx, size; + uint8 cache_id, width, height, bpp, Bpp; + uint8 *data, *bmpdata; + + in_uint8(s, cache_id); + in_uint8s(s, 1); /* pad */ + in_uint8(s, width); + in_uint8(s, height); + in_uint8(s, bpp); + Bpp = (bpp + 7) / 8; + in_uint8s(s, 2); /* bufsize */ + in_uint16_le(s, cache_idx); + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, size); + in_uint8s(s, 4); /* row_size, final_size */ + in_uint8p(s, data, size); + DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); + bmpdata = (uint8*)xmalloc(width * height * Bpp); + if (bitmap_decompress(bmpdata, width, height, data, size, Bpp)) + { + bitmap = ui_create_bitmap(width, height, bmpdata); + cache_put_bitmap(cache_id, cache_idx, bitmap); + } + xfree(bmpdata); +} + +/* Process a colourmap cache order */ +static void +process_colcache(STREAM s) +{ + COLOURENTRY *entry; + COLOURMAP map; + HCOLOURMAP hmap; + uint8 cache_id; + int i; + in_uint8(s, cache_id); + in_uint16_le(s, map.ncolours); + + map.colours = (COLOURENTRY*)xmalloc(3 * map.ncolours); + + for (i = 0; i < map.ncolours; i++) + { + entry = &map.colours[i]; + in_uint8(s, entry->blue); + in_uint8(s, entry->green); + in_uint8(s, entry->red); + in_uint8s(s, 1); /* pad */ + } + + DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours)); + + hmap = ui_create_colourmap(&map); + ui_set_colourmap(hmap); + + xfree(map.colours); +} + +/* Process a font cache order */ +static void +process_fontcache(STREAM s) +{ + HGLYPH bitmap; + uint8 font, nglyphs; + uint16 character, offset, baseline, width, height; + int i, datasize; + uint8 *data; + + in_uint8(s, font); + in_uint8(s, nglyphs); + + DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, 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); + + bitmap = ui_create_glyph(width, height, data); + cache_put_font(font, character, offset, baseline, width, height, bitmap); + } +} + +/* Process a secondary order */ +static void +process_secondary_order(STREAM s) +{ + uint16 length; + uint8 type; + uint8 *next_order; + + in_uint16_le(s, length); + in_uint8s(s, 2); /* flags */ + in_uint8(s, type); + + next_order = s->p + length + 7; + + switch (type) + { + case RDP_ORDER_RAW_BMPCACHE: + process_raw_bmpcache(s); + break; + + case RDP_ORDER_COLCACHE: + process_colcache(s); + break; + + case RDP_ORDER_BMPCACHE: + process_bmpcache(s); + break; + + case RDP_ORDER_FONTCACHE: + process_fontcache(s); + break; + + default: + unimpl("secondary order %d\n", type); + } + + s->p = next_order; +} + +/* Process an order PDU */ +void +process_orders(STREAM s) +{ + RDP_ORDER_STATE *os = &order_state; + uint32 present; + uint16 num_orders; + uint8 order_flags; + int size, processed = 0; + BOOL delta; + + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, num_orders); + in_uint8s(s, 2); /* pad */ + + while (processed < num_orders) + { + in_uint8(s, order_flags); + + if (!(order_flags & RDP_ORDER_STANDARD)) + { + error("order parsing failed\n"); + break; + } + + if (order_flags & RDP_ORDER_SECONDARY) + { + process_secondary_order(s); + } + else + { + if (order_flags & RDP_ORDER_CHANGE) + { + in_uint8(s, os->order_type); + } + + switch (os->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; + } + + rdp_in_present(s, &present, order_flags, size); + + if (order_flags & RDP_ORDER_BOUNDS) + { + if (!(order_flags & RDP_ORDER_LASTBOUNDS)) + rdp_parse_bounds(s, &os->bounds); + + ui_set_clip(os->bounds.left, + os->bounds.top, + os->bounds.right - + os->bounds.left + 1, + os->bounds.bottom - os->bounds.top + 1); + } + + delta = order_flags & RDP_ORDER_DELTA; + + switch (os->order_type) + { + case RDP_ORDER_DESTBLT: + process_destblt(s, &os->destblt, present, delta); + break; + + case RDP_ORDER_PATBLT: + process_patblt(s, &os->patblt, present, delta); + break; + + case RDP_ORDER_SCREENBLT: + process_screenblt(s, &os->screenblt, present, delta); + break; + + case RDP_ORDER_LINE: + process_line(s, &os->line, present, delta); + break; + + case RDP_ORDER_RECT: + process_rect(s, &os->rect, present, delta); + break; + + case RDP_ORDER_DESKSAVE: + process_desksave(s, &os->desksave, present, delta); + break; + + case RDP_ORDER_MEMBLT: + process_memblt(s, &os->memblt, present, delta); + break; + + case RDP_ORDER_TRIBLT: + process_triblt(s, &os->triblt, present, delta); + break; + + case RDP_ORDER_POLYLINE: + process_polyline(s, &os->polyline, present, delta); + break; + + case RDP_ORDER_TEXT2: + process_text2(s, &os->text2, present, delta); + break; + + default: + unimpl("order %d\n", os->order_type); + return; + } + + if (order_flags & RDP_ORDER_BOUNDS) + ui_reset_clip(); + } + + processed++; + } + + if (s->p != next_packet) + error("%d bytes remaining\n", (int) (next_packet - s->p)); +} + +/* Reset order state */ +void +reset_order_state(void) +{ + memset(&order_state, 0, sizeof(order_state)); + order_state.order_type = RDP_ORDER_PATBLT; +} diff --git a/noncore/net/opierdesktop/orders.h b/noncore/net/opierdesktop/orders.h new file mode 100644 index 0000000..be862c6 --- a/dev/null +++ b/noncore/net/opierdesktop/orders.h @@ -0,0 +1,286 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP order processing + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#define RDP_ORDER_STANDARD 0x01 +#define RDP_ORDER_SECONDARY 0x02 +#define RDP_ORDER_BOUNDS 0x04 +#define RDP_ORDER_CHANGE 0x08 +#define RDP_ORDER_DELTA 0x10 +#define RDP_ORDER_LASTBOUNDS 0x20 +#define RDP_ORDER_SMALL 0x40 +#define RDP_ORDER_TINY 0x80 + +enum RDP_ORDER_TYPE +{ + RDP_ORDER_DESTBLT = 0, + RDP_ORDER_PATBLT = 1, + RDP_ORDER_SCREENBLT = 2, + RDP_ORDER_LINE = 9, + RDP_ORDER_RECT = 10, + RDP_ORDER_DESKSAVE = 11, + RDP_ORDER_MEMBLT = 13, + RDP_ORDER_TRIBLT = 14, + RDP_ORDER_POLYLINE = 22, + RDP_ORDER_TEXT2 = 27 +}; + +enum RDP_SECONDARY_ORDER_TYPE +{ + RDP_ORDER_RAW_BMPCACHE = 0, + RDP_ORDER_COLCACHE = 1, + RDP_ORDER_BMPCACHE = 2, + RDP_ORDER_FONTCACHE = 3 +}; + +typedef struct _DESTBLT_ORDER +{ + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint8 opcode; + +} +DESTBLT_ORDER; + +typedef struct _PATBLT_ORDER +{ + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint8 opcode; + uint32 bgcolour; + uint32 fgcolour; + BRUSH brush; + +} +PATBLT_ORDER; + +typedef struct _SCREENBLT_ORDER +{ + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint8 opcode; + sint16 srcx; + sint16 srcy; + +} +SCREENBLT_ORDER; + +typedef struct _LINE_ORDER +{ + uint16 mixmode; + sint16 startx; + sint16 starty; + sint16 endx; + sint16 endy; + uint32 bgcolour; + uint8 opcode; + PEN pen; + +} +LINE_ORDER; + +typedef struct _RECT_ORDER +{ + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint32 colour; + +} +RECT_ORDER; + +typedef struct _DESKSAVE_ORDER +{ + uint32 offset; + sint16 left; + sint16 top; + sint16 right; + sint16 bottom; + uint8 action; + +} +DESKSAVE_ORDER; + +typedef struct _TRIBLT_ORDER +{ + uint8 colour_table; + uint8 cache_id; + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint8 opcode; + sint16 srcx; + sint16 srcy; + uint32 bgcolour; + uint32 fgcolour; + BRUSH brush; + uint16 cache_idx; + uint16 unknown; + +} +TRIBLT_ORDER; + +typedef struct _MEMBLT_ORDER +{ + uint8 colour_table; + uint8 cache_id; + sint16 x; + sint16 y; + sint16 cx; + sint16 cy; + uint8 opcode; + sint16 srcx; + sint16 srcy; + uint16 cache_idx; + +} +MEMBLT_ORDER; + +#define MAX_DATA 256 + +typedef struct _POLYLINE_ORDER +{ + sint16 x; + sint16 y; + uint8 opcode; + uint32 fgcolour; + uint8 lines; + uint8 datasize; + uint8 data[MAX_DATA]; + +} +POLYLINE_ORDER; + +#define MAX_TEXT 256 + +typedef struct _TEXT2_ORDER +{ + uint8 font; + uint8 flags; + uint8 mixmode; + uint8 unknown; + uint32 fgcolour; + uint32 bgcolour; + sint16 clipleft; + sint16 cliptop; + sint16 clipright; + sint16 clipbottom; + sint16 boxleft; + sint16 boxtop; + sint16 boxright; + sint16 boxbottom; + sint16 x; + sint16 y; + uint8 length; + uint8 text[MAX_TEXT]; + +} +TEXT2_ORDER; + +typedef struct _RDP_ORDER_STATE +{ + uint8 order_type; + BOUNDS bounds; + + DESTBLT_ORDER destblt; + PATBLT_ORDER patblt; + SCREENBLT_ORDER screenblt; + LINE_ORDER line; + RECT_ORDER rect; + DESKSAVE_ORDER desksave; + MEMBLT_ORDER memblt; + TRIBLT_ORDER triblt; + POLYLINE_ORDER polyline; + TEXT2_ORDER text2; + +} +RDP_ORDER_STATE; + +typedef struct _RDP_RAW_BMPCACHE_ORDER +{ + uint8 cache_id; + uint8 pad1; + uint8 width; + uint8 height; + uint8 bpp; + uint16 bufsize; + uint16 cache_idx; + uint8 *data; + +} +RDP_RAW_BMPCACHE_ORDER; + +typedef struct _RDP_BMPCACHE_ORDER +{ + uint8 cache_id; + uint8 pad1; + uint8 width; + uint8 height; + uint8 bpp; + uint16 bufsize; + uint16 cache_idx; + uint16 pad2; + uint16 size; + uint16 row_size; + uint16 final_size; + uint8 *data; + +} +RDP_BMPCACHE_ORDER; + +#define MAX_GLYPH 32 + +typedef struct _RDP_FONT_GLYPH +{ + uint16 character; + uint16 unknown; + uint16 baseline; + uint16 width; + uint16 height; + uint8 data[MAX_GLYPH]; + +} +RDP_FONT_GLYPH; + +#define MAX_GLYPHS 256 + +typedef struct _RDP_FONTCACHE_ORDER +{ + uint8 font; + uint8 nglyphs; + RDP_FONT_GLYPH glyphs[MAX_GLYPHS]; + +} +RDP_FONTCACHE_ORDER; + +typedef struct _RDP_COLCACHE_ORDER +{ + uint8 cache_id; + COLOURMAP map; + +} +RDP_COLCACHE_ORDER; diff --git a/noncore/net/opierdesktop/parse.h b/noncore/net/opierdesktop/parse.h new file mode 100644 index 0000000..f54c05f --- a/dev/null +++ b/noncore/net/opierdesktop/parse.h @@ -0,0 +1,108 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Parsing primitives + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +/* Parser state */ +typedef struct stream +{ + unsigned char *p; + unsigned char *end; + unsigned char *data; + unsigned int size; +// unsigned char *next_packet; + + + /* Offsets of various headers */ + unsigned char *iso_hdr; + unsigned char *mcs_hdr; + unsigned char *sec_hdr; + unsigned char *rdp_hdr; + +} + *STREAM; + +#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; } +#define s_pop_layer(s,h) (s)->p = (s)->h; +#define s_mark_end(s) (s)->end = (s)->p; +#define s_check(s) ((s)->p <= (s)->end) +#define s_check_rem(s,n) ((s)->p + n <= (s)->end) +#define s_check_end(s) ((s)->p == (s)->end) + +#if defined(L_ENDIAN) && !defined(NEED_ALIGN) +#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } +#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } +#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } +#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } + +#else +#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; } +#define in_uint32_le(s,v) { in_uint16_le(s,v) \ + v += *((s)->p++) << 16; v += *((s)->p++) << 24; } +#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; } +#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); } +#endif + +#if defined(B_ENDIAN) && !defined(NEED_ALIGN) +#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } +#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } +#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } +#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } + +#define B_ENDIAN_PREFERRED +#define in_uint16(s,v) in_uint16_be(s,v) +#define in_uint32(s,v) in_uint32_be(s,v) +#define out_uint16(s,v) out_uint16_be(s,v) +#define out_uint32(s,v) out_uint32_be(s,v) + +#else +#define next_be(s,v) v = ((v) << 8) + *((s)->p++); +#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); } +#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); } +#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; } +#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); } +#endif + +#ifndef B_ENDIAN_PREFERRED +#define in_uint16(s,v) in_uint16_le(s,v) +#define in_uint32(s,v) in_uint32_le(s,v) +#define out_uint16(s,v) out_uint16_le(s,v) +#define out_uint32(s,v) out_uint32_le(s,v) +#endif + +#define in_uint8(s,v) v = *((s)->p++); +#define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; } +#define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; } +#define in_uint8s(s,n) (s)->p += n; +#define out_uint8(s,v) *((s)->p++) = v; +#define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; } +#define out_uint8a(s,v,n) out_uint8p(s,v,n); +#define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; } + +#if defined(B_ENDIAN) + +#endif +#if defined(B_ENDIAN_PREFERRED) + +#endif +#if defined(NEED_ALIGN) + +#endif +#if defined(L_ENDIAN) + +#endif diff --git a/noncore/net/opierdesktop/proto.h b/noncore/net/opierdesktop/proto.h new file mode 100644 index 0000000..6bc5b13 --- a/dev/null +++ b/noncore/net/opierdesktop/proto.h @@ -0,0 +1,121 @@ +/* bitmap.c */ +BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, + int Bpp); +/* cache.c */ +HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx); +void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap); +FONTGLYPH *cache_get_font(uint8 font, uint16 character); +void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, + uint16 height, HGLYPH pixmap); +DATABLOB *cache_get_text(uint8 cache_id); +void cache_put_text(uint8 cache_id, void *data, int length); +uint8 *cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel); +void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, + uint8 * data); +HCURSOR cache_get_cursor(uint16 cache_idx); +void cache_put_cursor(uint16 cache_idx, HCURSOR cursor); +/* ewmhints.c */ +int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height); +/* iso.c */ +STREAM iso_init(int length); +void iso_send(STREAM s); +STREAM iso_recv(void); +BOOL iso_connect(char *server); +void iso_disconnect(void); +/* licence.c */ +void licence_process(STREAM s); +/* mcs.c */ +STREAM mcs_init(int length); +void mcs_send(STREAM s); +STREAM mcs_recv(void); +BOOL mcs_connect(char *server, STREAM mcs_data); +void mcs_disconnect(void); +/* orders.c */ +void process_orders(STREAM s); +void reset_order_state(void); +/* rdesktop.c */ +int main(int argc, char *argv[]); +void generate_random(uint8 * random); +void *xmalloc(int size); +void *xrealloc(void *oldmem, int size); +void xfree(void *mem); +void error(char *format, ...); +void warning(char *format, ...); +void unimpl(char *format, ...); +void hexdump(unsigned char *p, unsigned int len); +int load_licence(unsigned char **data); +void save_licence(unsigned char *data, int length); +/* rdp.c */ +void rdp_out_unistr(STREAM s, char *string, int len); +void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, + uint16 param2); +BOOL rdp_main_loop(void); +BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, + char *directory); +void rdp_disconnect(void); +/* secure.c */ +void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt); +void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2); +void buf_out_uint32(uint8 * buffer, uint32 value); +void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, + int datalen); +STREAM sec_init(uint32 flags, int maxlen); +void sec_send(STREAM s, uint32 flags); +STREAM sec_recv(void); +BOOL sec_connect(char *server); +void sec_disconnect(void); +/* tcp.c */ +STREAM tcp_init(unsigned int maxlen); +void tcp_send(STREAM s); +STREAM tcp_recv(unsigned int length); +BOOL tcp_connect(char *server); +void tcp_disconnect(void); +/* xkeymap.c */ +void xkeymap_init(void); +BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed); +key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state); +uint16 xkeymap_translate_button(unsigned int button); +char *get_ksname(uint32 keysym); +void ensure_remote_modifiers(uint32 ev_time, key_translation tr); +void reset_modifier_keys(unsigned int state); +void rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode); +/* xwin.c */ +BOOL get_key_state(unsigned int state, uint32 keysym); +BOOL ui_init(void); +void ui_deinit(void); +BOOL ui_create_window(void); +void ui_destroy_window(void); +void xwin_toggle_fullscreen(void); +int ui_select(int rdp_socket); +void ui_move_pointer(int x, int y); +HBITMAP ui_create_bitmap(int width, int height, uint8 * data); +void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data); +void ui_destroy_bitmap(HBITMAP bmp); +HGLYPH ui_create_glyph(int width, int height, uint8 * data); +void ui_destroy_glyph(HGLYPH glyph); +HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask, + uint8 * xormask); +void ui_set_cursor(HCURSOR cursor); +void ui_destroy_cursor(HCURSOR cursor); +HCOLOURMAP ui_create_colourmap(COLOURMAP * colours); +void ui_destroy_colourmap(HCOLOURMAP map); +void ui_set_colourmap(HCOLOURMAP map); +void ui_begin_update(void); +void ui_end_update(void); +void ui_set_clip(int x, int y, int cx, int cy); +void ui_reset_clip(void); +void ui_bell(void); +void ui_destblt(uint8 opcode, int x, int y, int cx, int cy); +void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, + int fgcolour); +void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy); +void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy); +void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, + BRUSH * brush, int bgcolour, int fgcolour); +void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen); +void ui_rect(int x, int y, int cx, int cy, int colour); +void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int clipx, int clipy, + int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, + int fgcolour, uint8 * text, uint8 length); +void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy); +void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy); diff --git a/noncore/net/opierdesktop/qtwin.cpp b/noncore/net/opierdesktop/qtwin.cpp new file mode 100644 index 0000000..d2a5ef1 --- a/dev/null +++ b/noncore/net/opierdesktop/qtwin.cpp @@ -0,0 +1,1725 @@ +/* + rdesktop: A Remote Desktop Protocol client. + User interface services - X Window System + Copyright (C) Matthew Chapman 1999-2002 + qt.cpp by Jay Sorg + + 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. +*/ + +#include "rdesktop.h" +#ifdef SHARP +#include <qpe/qpeapplication.h> +#else +#include <qapplication.h> +#endif +#include <qmainwindow.h> +#include <qwidget.h> +#include <qpainter.h> +#include <qimage.h> +#include <qsocketnotifier.h> +#include <qscrollview.h> +#include <qmessagebox.h> +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qfile.h> +#include <qcheckbox.h> +#include <qpopupmenu.h> +#include "qtwin.h" +#include <stdlib.h> + +uint32 flags; +char server[64] = ""; +char domain[16] = ""; +char password[16] = ""; +char shell[128] = ""; +char directory[32] = ""; + +extern int g_width; +extern int g_height; +extern int server_bpp; +extern BOOL fullscreen; +extern char username[]; +int global_sock; + +QSocketNotifier* SocketNotifier; +#ifdef SHARP +QPEApplication* App; +#else +QApplication* App; +#endif +QMyMainWindow* MW; +QMyScrollView* SV; +struct QColorMap +{ + uint32 RGBColors[256]; + int NumColors; +}; +QColorMap* CM; +uint8* BS; +int clipx; +int clipy; +int clipcx; +int clipcy; + +struct bitmap +{ + int w; + int h; + uint8* data; +}; + +BOOL owncolmap = False; + +//***************************************************************************** +void CleanString(QString* Item) +{ + int i; + + i = Item->length() - 1; + while (i >= 0) + { + if (Item->at(i) == 10 || Item->at(i) == 13) + Item->remove(i, 1); + i--; + } +} + +//***************************************************************************** +QMyDialog::QMyDialog(QWidget* parent) : QDialog(parent, "Settings", true) +{ + int i, j; + char* home; + char Text[256]; + QString Line; + QString ItemName; + QString ItemValue; + + // resize dialog + resize(230, 270); + // main list box + ListBox = new QListBox(this); + ListBox->move(10, 10); + ListBox->resize(200, 100); + connect(ListBox, SIGNAL(selectionChanged()), this, SLOT(ListBoxChanged())); + connect(ListBox, SIGNAL(selected(int)), this, SLOT(ListBoxSelected(int))); + // server + Label1 = new QLabel(this); + Label1->setText("Server Desc"); + Label1->move(10, 120); + Label1->resize(100, 20); + ServerNameEdit = new QLineEdit(this); + ServerNameEdit->move(75, 120); + ServerNameEdit->resize(100, 20); + // username + Label2 = new QLabel(this); + Label2->setText("User Name"); + Label2->move(10, 150); + Label2->resize(100, 20); + UserNameEdit = new QLineEdit(this); + UserNameEdit->move(75, 150); + UserNameEdit->resize(100, 20); + // ip + Label3 = new QLabel(this); + Label3->setText("Server IP"); + Label3->move(10, 180); + Label3->resize(100, 20); + IPEdit = new QLineEdit(this); + IPEdit->move(75, 180); + IPEdit->resize(100, 20); + // width and height + WidthHeightBox = new QComboBox(this); + WidthHeightBox->move(10, 210); + WidthHeightBox->resize(100, 20); + WidthHeightBox->insertItem("240x320"); + WidthHeightBox->insertItem("640x480"); + WidthHeightBox->insertItem("800x600"); + connect(WidthHeightBox, SIGNAL(activated(int)), this, SLOT(ComboChanged(int))); + WidthHeightBox->setCurrentItem(1); + WidthEdit = new QLineEdit(this); + WidthEdit->move(110, 210); + WidthEdit->resize(30, 20); + WidthEdit->setText("800"); + HeightEdit = new QLineEdit(this); + HeightEdit->move(140, 210); + HeightEdit->resize(30, 20); + HeightEdit->setText("600"); + // add to list button + AddButton = new QPushButton(this); + AddButton->move(180, 120); + AddButton->resize(50, 20); + AddButton->setText("Add"); + connect(AddButton, SIGNAL(clicked()), this, SLOT(AddClicked())); + // change list item button + EditButton = new QPushButton(this); + EditButton->move(180, 140); + EditButton->resize(50, 20); + EditButton->setText("Edit"); + connect(EditButton, SIGNAL(clicked()), this, SLOT(EditClicked())); + // save to file button + SaveButton = new QPushButton(this); + SaveButton->move(180, 160); + SaveButton->resize(50, 20); + SaveButton->setText("Save"); + connect(SaveButton, SIGNAL(clicked()), this, SLOT(SaveClicked())); + // remove an item button + RemoveButton = new QPushButton(this); + RemoveButton->move(180, 180); + RemoveButton->resize(50, 20); + RemoveButton->setText("Remove"); + connect(RemoveButton, SIGNAL(clicked()), this, SLOT(RemoveClicked())); + // full screen check box + FullScreenCheckBox = new QCheckBox(this, "Full Screen"); + FullScreenCheckBox->setText("Full Screen"); + FullScreenCheckBox->move(10, 230); + // ok button + OKButton = new QPushButton(this); + OKButton->setText("OK"); + OKButton->move(100, 240); + OKButton->resize(50, 20); + connect(OKButton, SIGNAL(clicked()), this, SLOT(OKClicked())); + // cancel button + CancelButton = new QPushButton(this); + CancelButton->setText("Cancel"); + CancelButton->move(160, 240); + CancelButton->resize(50, 20); + connect(CancelButton, SIGNAL(clicked()), this, SLOT(CancelClicked())); + + for (i = 0; i < 10; i++) + { + ConnectionList[i] = new QMyConnectionItem; + ConnectionList[i]->ServerName = ""; + ConnectionList[i]->UserName = ""; + ConnectionList[i]->ServerIP = ""; + ConnectionList[i]->Width = 0; + ConnectionList[i]->Height = 0; + ConnectionList[i]->FullScreen = 0; + } + home = getenv("HOME"); + if (home != NULL) + { + sprintf(Text, "%s/rdesktop.ini", home); + QFile* File = new QFile(Text); + if (File->open(IO_ReadOnly)) + { + i = -1; + while (!File->atEnd()) + { + File->readLine(Line, 255); + j = Line.find("="); + if (j > 0) + { + ItemName = Line.mid(0, j); + CleanString(&ItemName); + ItemValue = Line.mid(j + 1); + CleanString(&ItemValue); + if (ItemName == "Server") + { + i++; + ConnectionList[i]->ServerName = ItemValue; + ListBox->insertItem(ItemValue); + } + else if (ItemName == "UserName") + ConnectionList[i]->UserName = ItemValue; + else if (ItemName == "Width") + ConnectionList[i]->Width = ItemValue.toInt(); + else if (ItemName == "Height") + ConnectionList[i]->Height = ItemValue.toInt(); + else if (ItemName == "IP") + ConnectionList[i]->ServerIP = ItemValue; + else if (ItemName == "FullScreen") + ConnectionList[i]->FullScreen = (ItemValue != "0"); + } + } + } + delete File; + } +} + +//***************************************************************************** +QMyDialog::~QMyDialog() +{ + QMyConnectionItem* Item; + int i; + + for (i = 0; i < 10; i++) + { + Item = ConnectionList[i]; + delete Item; + } +} + +//***************************************************************************** +void QMyDialog::ComboChanged(int index) +{ + if (index == 0) + { + WidthEdit->setText("240"); + HeightEdit->setText("320"); + } + if (index == 1) + { + WidthEdit->setText("640"); + HeightEdit->setText("480"); + } + else if (index == 2) + { + WidthEdit->setText("800"); + HeightEdit->setText("600"); + } +} + +//***************************************************************************** +void QMyDialog::OKClicked() +{ + ServerName = ServerNameEdit->text(); + UserName = UserNameEdit->text(); + Width = WidthEdit->text().toInt(); + Height = HeightEdit->text().toInt(); + ServerIP = IPEdit->text(); + FullScreen = FullScreenCheckBox->isChecked(); + done(1); +} + +//***************************************************************************** +void QMyDialog::CancelClicked() +{ + done(0); +} + +//***************************************************************************** +void QMyDialog::AddClicked() +{ + int i; + QMyConnectionItem* Item; + + i = ListBox->count(); + if (i < 10) + { + ListBox->insertItem(ServerNameEdit->text()); + Item = ConnectionList[i]; + Item->ServerName = ServerNameEdit->text(); + Item->UserName = UserNameEdit->text(); + Item->Width = WidthEdit->text().toInt(); + Item->Height = HeightEdit->text().toInt(); + Item->ServerIP = IPEdit->text(); + Item->FullScreen = FullScreenCheckBox->isChecked(); + } +} + +//***************************************************************************** +void QMyDialog::EditClicked() +{ + int i; + QMyConnectionItem* Item; + + i = ListBox->currentItem(); + if (i >= 0) + { + Item = ConnectionList[i]; + Item->ServerName = ServerNameEdit->text(); + Item->UserName = UserNameEdit->text(); + Item->Width = WidthEdit->text().toInt(); + Item->Height = HeightEdit->text().toInt(); + Item->ServerIP = IPEdit->text(); + Item->FullScreen = FullScreenCheckBox->isChecked(); + ListBox->changeItem(ServerNameEdit->text(), i); + } +} + +//***************************************************************************** +void WriteString(QFile* File, QString* Line) +{ + File->writeBlock((const char*)(*Line), Line->length()); +} + +//***************************************************************************** +void QMyDialog::SaveClicked() +{ + int i, j; + QMyConnectionItem* Item; + QString Line; + char* home; + char Text[256]; + QFile* File; + + home = getenv("HOME"); + if (home != NULL) + { + sprintf(Text, "%s/rdesktop.ini", home); + File = new QFile(Text); + if (File->open(IO_Truncate | IO_ReadWrite)) + { + i = ListBox->count(); + for (j = 0; j < i; j++) + { + Item = ConnectionList[j]; + Line = "Server="; + Line += Item->ServerName; + Line += (char)10; + WriteString(File, &Line); + Line = "UserName="; + Line += Item->UserName; + Line += (char)10; + WriteString(File, &Line); + Line = "Width="; + sprintf(Text, "%d", Item->Width); + Line += Text; + Line += (char)10; + WriteString(File, &Line); + Line = "Height="; + sprintf(Text, "%d", Item->Height); + Line += Text; + Line += (char)10; + WriteString(File, &Line); + Line = "IP="; + Line += Item->ServerIP; + Line += (char)10; + WriteString(File, &Line); + Line = "FullScreen="; + if (Item->FullScreen) + Line += "1"; + else + Line += "0"; + Line += (char)10; + WriteString(File, &Line); + } + } + File->flush(); + File->close(); + delete File; + } +} + +//***************************************************************************** +void QMyDialog::RemoveClicked() +{ + int i, j, c; + QMyConnectionItem* Item1; + QMyConnectionItem* Item2; + + i = ListBox->currentItem(); + if (i >= 0) + { + c = ListBox->count(); + for (j = i; j < c - 1; j++) + { + Item1 = ConnectionList[i]; + Item2 = ConnectionList[i + 1]; + Item1->ServerName = Item2->ServerName; + Item1->UserName = Item2->UserName; + Item1->Width = Item2->Width; + Item1->Height = Item2->Height; + Item1->ServerIP = Item2->ServerIP; + Item1->FullScreen = Item2->FullScreen; + } + ListBox->removeItem(i); + } +} + +//***************************************************************************** +void QMyDialog::ListBoxChanged() +{ + int i; + QMyConnectionItem* Item; + char Text[100]; + + i = ListBox->currentItem(); + if (i >= 0 && i < 10) + { + Item = ConnectionList[i]; + ServerNameEdit->setText(Item->ServerName); + UserNameEdit->setText(Item->UserName); + sprintf(Text, "%d", Item->Width); + WidthEdit->setText(Text); + sprintf(Text, "%d", Item->Height); + HeightEdit->setText(Text); + IPEdit->setText(Item->ServerIP); + FullScreenCheckBox->setChecked(Item->FullScreen != 0); + } +} + +//***************************************************************************** +void QMyDialog::ListBoxSelected(int /*index*/) +{ +} + +//***************************************************************************** +void GetScanCode(QKeyEvent* e, int* ScanCode, int* code) +{ + int key; + int mod; + int ascii; + + key = e->key(); + mod = e->state(); + ascii = e->ascii(); + + *ScanCode = 0; + *code = mod; // 8 shift, 16 control, 32 alt + + switch (key) + { + case 4096: // esc + case 4097: // tab + case 4099: // backspace + case 4100: // enter + case 4101: // enter + case 4103: // delete + ascii = 0; + } + + if (ascii == 0) + { + switch (key) + { + case 4096: *ScanCode = 0x01; break; // esc + case 4097: *ScanCode = 0x0f; break; // tab + case 4099: *ScanCode = 0x0e; break; // backspace + case 4100: *ScanCode = 0x1c; break; // enter + case 4101: *ScanCode = 0x1c; break; // enter + case 4112: *ScanCode = 0xc7; break; // home + case 4113: *ScanCode = 0xcf; break; // end + case 4102: *ScanCode = 0xd2; break; // insert + case 4103: *ScanCode = 0xd3; break; // delete + case 4118: *ScanCode = 0xc9; break; // page up + case 4119: *ScanCode = 0xd1; break; // page down + case 4117: *ScanCode = 0xd0; break; // down arrow + case 4115: *ScanCode = 0xc8; break; // up arrow + case 4114: *ScanCode = 0xcb; break; // left arrow + case 4116: *ScanCode = 0xcd; break; // right arrow + case 4128: *ScanCode = 0x2a; break; // shift + case 4131: *ScanCode = 0x38; break; // alt + case 4129: *ScanCode = 0x1d; break; // ctrl + } + if (*ScanCode != 0) + return; + } + + switch (ascii) + { + // first row + case 'q': *ScanCode = 0x10; break; + case 'Q': *ScanCode = 0x10; *code |= 8; break; + case '1': *ScanCode = 0x02; break; + case 'w': *ScanCode = 0x11; break; + case 'W': *ScanCode = 0x11; *code |= 8; break; + case '2': *ScanCode = 0x03; break; + case 'e': *ScanCode = 0x12; break; + case 'E': *ScanCode = 0x12; *code |= 8; break; + case '3': *ScanCode = 0x04; break; + case 'r': *ScanCode = 0x13; break; + case 'R': *ScanCode = 0x13; *code |= 8; break; + case '4': *ScanCode = 0x05; break; + case 't': *ScanCode = 0x14; break; + case 'T': *ScanCode = 0x14; *code |= 8; break; + case '5': *ScanCode = 0x06; break; + case 'y': *ScanCode = 0x15; break; + case 'Y': *ScanCode = 0x15; *code |= 8; break; + case '6': *ScanCode = 0x07; break; + case 'u': *ScanCode = 0x16; break; + case 'U': *ScanCode = 0x16; *code |= 8; break; + case '7': *ScanCode = 0x08; break; + case 'i': *ScanCode = 0x17; break; + case 'I': *ScanCode = 0x17; *code |= 8; break; + case '8': *ScanCode = 0x09; break; + case 'o': *ScanCode = 0x18; break; + case 'O': *ScanCode = 0x18; *code |= 8; break; + case '9': *ScanCode = 0x0a; break; + case 'p': *ScanCode = 0x19; break; + case 'P': *ScanCode = 0x19; *code |= 8; break; + case '0': *ScanCode = 0x0b; break; + // second row + case 'a': *ScanCode = 0x1e; break; + case 'A': *ScanCode = 0x1e; *code |= 8; break; + case '!': *ScanCode = 0x02; *code |= 8; break; + case 's': *ScanCode = 0x1f; break; + case 'S': *ScanCode = 0x1f; *code |= 8; break; + case '@': *ScanCode = 0x03; *code |= 8; break; + case 'd': *ScanCode = 0x20; break; + case 'D': *ScanCode = 0x20; *code |= 8; break; + case '#': *ScanCode = 0x04; *code |= 8; break; + case 'f': *ScanCode = 0x21; break; + case 'F': *ScanCode = 0x21; *code |= 8; break; + case '$': *ScanCode = 0x05; *code |= 8; break; + case 'g': *ScanCode = 0x22; break; + case 'G': *ScanCode = 0x22; *code |= 8; break; + case '%': *ScanCode = 0x06; *code |= 8; break; + case 'h': *ScanCode = 0x23; break; + case 'H': *ScanCode = 0x23; *code |= 8; break; + case '_': *ScanCode = 0x0c; *code |= 8; break; + case 'j': *ScanCode = 0x24; break; + case 'J': *ScanCode = 0x24; *code |= 8; break; + case '&': *ScanCode = 0x08; *code |= 8; break; + case 'k': *ScanCode = 0x25; break; + case 'K': *ScanCode = 0x25; *code |= 8; break; + case '*': *ScanCode = 0x09; *code |= 8; break; + case 'l': *ScanCode = 0x26; break; + case 'L': *ScanCode = 0x26; *code |= 8; break; + case '(': *ScanCode = 0x0a; *code |= 8; break; +// case 8: *ScanCode = 0x0e; break; // backspace + // third row + case 'z': *ScanCode = 0x2c; break; + case 'Z': *ScanCode = 0x2c; *code |= 8; break; + case 'x': *ScanCode = 0x2d; break; + case 'X': *ScanCode = 0x2d; *code |= 8; break; + case 'c': *ScanCode = 0x2e; break; + case 'C': *ScanCode = 0x2e; *code |= 8; break; + case 'v': *ScanCode = 0x2f; break; + case 'V': *ScanCode = 0x2f; *code |= 8; break; + case 'b': *ScanCode = 0x30; break; + case 'B': *ScanCode = 0x30; *code |= 8; break; + case '-': *ScanCode = 0x0c; break; + case 'n': *ScanCode = 0x31; break; + case 'N': *ScanCode = 0x31; *code |= 8; break; + case '+': *ScanCode = 0x0d; *code |= 8; break; + case 'm': *ScanCode = 0x32; break; + case 'M': *ScanCode = 0x32; *code |= 8; break; + case '=': *ScanCode = 0x0d; break; + case ',': *ScanCode = 0x33; break; + case ';': *ScanCode = 0x27; break; + case ')': *ScanCode = 0x0b; *code |= 8; break; + // fourth row +// case 9: *ScanCode = 0x0f; break; // tab + case '/': *ScanCode = 0x35; break; + case '?': *ScanCode = 0x35; *code |= 8; break; + case ' ': *ScanCode = 0x39; break; + case '\'': *ScanCode = 0x28; break; + case '"': *ScanCode = 0x28; *code |= 8; break; + case '~': *ScanCode = 0x29; *code |= 8; break; + case '.': *ScanCode = 0x34; break; + case ':': *ScanCode = 0x27; *code |= 8; break; + case '<': *ScanCode = 0x33; *code |= 8; break; +// case 13: *ScanCode = 0x1c; break; // enter + case '>': *ScanCode = 0x34; *code |= 8; break; + // others +// case 27: *ScanCode = 0x01; break; // esc + case '`': *ScanCode = 0x29; break; + case '^': *ScanCode = 0x07; *code |= 8; break; + case '[': *ScanCode = 0x1a; break; + case '{': *ScanCode = 0x1a; *code |= 8; break; + case ']': *ScanCode = 0x1b; break; + case '}': *ScanCode = 0x1b; *code |= 8; break; + case '\\': *ScanCode = 0x2b; break; + case '|': *ScanCode = 0x2b; *code |= 8; break; + // ctrl keys + case 1: *ScanCode = 0x1e; *code |= 16; break; // a + case 2: *ScanCode = 0x30; *code |= 16; break; // b + } + + if (*ScanCode == 0 && key < 3000) + printf("unknown key %d mod %d ascii %d\n", key, mod, ascii); + +} + +//***************************************************************************** +QMyScrollView::QMyScrollView() : QScrollView() +{ +} + +//***************************************************************************** +QMyScrollView::~QMyScrollView() +{ +} + +//***************************************************************************** +void QMyScrollView::keyPressEvent(QKeyEvent* e) +{ + int ScanCode, code; + GetScanCode(e, &ScanCode, &code); + if (ScanCode != 0) + { + if (code & 8) // send shift + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x2a, 0); + if (code & 16) // send control + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); + if (code & 32) // send alt + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x38, 0); + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, ScanCode, 0); + e->accept(); + } +} + +//***************************************************************************** +void QMyScrollView::keyReleaseEvent(QKeyEvent* e) +{ + int ScanCode, code; + GetScanCode(e, &ScanCode, &code); + if (ScanCode != 0) + { + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, ScanCode, 0); + if (code & 8) // send shift + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0); + if (code & 16) // send control + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); + if (code & 32) // send alt + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0); + e->accept(); + } +} + +//***************************************************************************** +void QMyScrollView::showEvent(QShowEvent* e) +{ + QScrollView::showEvent(e); +} + +//***************************************************************************** +void QMyScrollView::show() +{ + QScrollView::show(); +} + +//***************************************************************************** +void QMyScrollView::polish() +{ + QScrollView::polish(); +} + +//***************************************************************************** +void QMyScrollView::timerEvent(QTimerEvent* e) +{ + QScrollView::timerEvent(e); + killTimer(timer_id); + QMyDialog* d; + QWidget* Desktop; + int dw; + int dh; + + d = new QMyDialog(this); + if (d->exec() == 1) // ok clicked + { + flags = RDP_LOGON_NORMAL; + g_width = d->Width; + g_height = d->Height; + fullscreen = d->FullScreen; + sprintf(server, "%s", (const char*)d->ServerIP); + sprintf(username, "%s", (const char*)d->UserName); + if (!rdp_connect(server, flags, domain, password, shell, directory)) + { + delete d; + SV->close(); + return; + } + BS = (uint8*)xmalloc(g_width * g_height); + memset(BS, 0, g_width * g_height); + clipx = 0; + clipy = 0; + clipcx = g_width; + clipcy = g_height; + CM = (QColorMap*)xmalloc(sizeof(struct QColorMap)); + memset(CM, 0, sizeof(struct QColorMap)); + CM->NumColors = 256; + MW = new QMyMainWindow(); + MW->resize(g_width, g_height); + MW->show(); + SV->addChild(MW); + MW->setMouseTracking(true); + SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW); + MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived())); + if (fullscreen) + { + Desktop = App->desktop(); + dw = Desktop->width(); + dh = Desktop->height(); + if (dw == g_width && dh == g_height) + MW->resize(g_width - 4, g_height - 4); + SV->showFullScreen(); + } + delete d; + } + else // cancel clicked + { + delete d; + SV->close(); + } +} + +//***************************************************************************** +QMyMainWindow::QMyMainWindow() : QWidget(SV->viewport()) +{ + PopupMenu = new QPopupMenu(this); + PopupMenu->insertItem("Right click", 1, 0); + PopupMenu->insertItem("Toggle fullscreen", 2, 1); + PopupMenu->insertItem("Reset keyboard", 3, 2); + PopupMenu->insertItem("Double click", 4, 3); + connect(PopupMenu, SIGNAL(activated(int)), this, SLOT(MemuClicked(int))); +} + +//***************************************************************************** +QMyMainWindow::~QMyMainWindow() +{ + delete PopupMenu; +} + +//***************************************************************************** +void QMyMainWindow::timerEvent(QTimerEvent* e) +{ + QWidget::timerEvent(e); + if (e->timerId() == timer_id) + { + // send mouse up + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my); + // if in fullscreen, take it out or the menu won't work + if (fullscreen) + { + fullscreen = 0; + SV->showNormal(); + SV->showMaximized(); + } + else + PopupMenu->popup(mapToGlobal(QPoint(mx, my))); + } + killTimer(timer_id); +} + +//***************************************************************************** +void QMyMainWindow::MemuClicked(int MenuID) +{ + QWidget* Desktop; + int dw; + int dh; + + if (MenuID == 1) // right click + { + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, mx, my); + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, mx, my); + } + else if (MenuID == 2) // toggle full screen + { + fullscreen = ~fullscreen; + if (fullscreen) + { + Desktop = App->desktop(); + dw = Desktop->width(); + dh = Desktop->height(); + if (dw == g_width && dh == g_height) + MW->resize(g_width - 4, g_height - 4); + SV->showFullScreen(); + } + else + { + SV->showNormal(); + SV->showMaximized(); + MW->resize(g_width, g_height); + } + } + else if (MenuID == 3) // reset keyboard + { + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0); // shift + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); // control + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0); // alt + } + else if (MenuID == 4) // double click + { + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, mx, my); + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my); + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, mx, my); + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my); + } +} + +//***************************************************************************** +void QMyMainWindow::mouseMoveEvent(QMouseEvent* e) +{ + int x; + int y; + + x = e->x(); + y = e->y(); + + if (timer_id) + { + x = x - mx; + y = y - my; + if (x < -10 || x > 10 || y < -10 || y > 10) + { + killTimer(timer_id); + timer_id = 0; + } + } + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, e->x(), e->y()); +} + +//***************************************************************************** +void QMyMainWindow::mousePressEvent(QMouseEvent* e) +{ + timer_id = startTimer(1000); + mx = e->x(); + my = e->y(); + if (e->button() == LeftButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, e->x(), e->y()); + else if (e->button() == RightButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, e->x(), e->y()); + else if (e->button() == MidButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, e->x(), e->y()); +} + +//***************************************************************************** +void QMyMainWindow::mouseReleaseEvent(QMouseEvent* e) +{ + killTimer(timer_id); + timer_id = 0; + if (e->button() == LeftButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, e->x(), e->y()); + else if (e->button() == RightButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, e->x(), e->y()); + else if (e->button() == MidButton) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, e->x(), e->y()); +} + +//***************************************************************************** +void QMyMainWindow::wheelEvent(QWheelEvent* e) +{ + if (e->delta() > 0) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, e->x(), e->y()); + else if (e->delta() < 0) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, e->x(), e->y()); +} + +#define NOT(x) (255-(x)) + +//***************************************************************************** +uint8 rop(int rop, uint8 src, uint8 dst) +{ + switch (rop) + { + case 0x0: return 0; + case 0x1: return NOT (src | dst); + case 0x2: return NOT (src) & dst; + case 0x3: return NOT (src); + case 0x4: return src & NOT (dst); + case 0x5: return NOT (dst); + case 0x6: return src ^ dst; + case 0x7: return NOT (src & dst); + case 0x8: return src & dst; + case 0x9: return NOT (src) ^ dst; + case 0xa: return dst; + case 0xb: return NOT (src) | dst; + case 0xc: return src; + case 0xd: return src | NOT (dst); + case 0xe: return src | dst; + case 0xf: return NOT (0); + } + return dst; +} + +//***************************************************************************** +uint8 get_pixel(int x, int y) +{ + if (x >= 0 && x < g_width && y >= 0 && y < g_height) + return BS[y * g_width + x]; + else + return 0; +} + +//***************************************************************************** +void set_pixel(int x, int y, uint8 pixel, int op = 0xc) +{ + if (x >= clipx && x < (clipx + clipcx) && y >= clipy && y < (clipy + clipcy)) + if (x >= 0 && x < g_width && y >= 0 && y < g_height) + if (op == 0xc) + BS[y * g_width + x] = pixel; + else + BS[y * g_width + x] = rop(op, pixel, BS[y * g_width + x]); +} + +//****************************************************************************** +// adjust coordinates for cliping rect +bool WarpCoords(int* x, int* y, int* cx, int* cy, int* srcx, int* srcy) +{ + int dx, dy; + QRect InRect(*x, *y, *cx, *cy); + QRect OutRect; + QRect CRect(clipx, clipy, clipcx, clipcy); + OutRect = InRect.intersect(CRect); + if (OutRect.isEmpty()) + return false; + dx = OutRect.x() - InRect.x(); + dy = OutRect.y() - InRect.y(); + *x = OutRect.x(); + *y = OutRect.y(); + *cx = OutRect.width(); + *cy = OutRect.height(); + if (srcx != NULL) + *srcx = *srcx + dx; + if (srcy != NULL) + *srcy = *srcy + dy; + return true; +} + +//***************************************************************************** +void QMyMainWindow::paintEvent(QPaintEvent* pe) +{ + QImage* Image; + QPainter* Painter; + QRect Rect; + int i, j, w, h, l, t; + uint8* data; + + if (!testWFlags(WRepaintNoErase)) + setWFlags(WRepaintNoErase); + if (CM != NULL) + { + Rect = pe->rect(); + l = Rect.left(); + t = Rect.top(); + w = Rect.width(); + h = Rect.height(); + if (w > 0 && h > 0 && CM->NumColors > 0) + { + data = (uint8*)xmalloc(w * h); + for (i = 0; i < h; i++) + for (j = 0; j < w; j++) + data[i * w + j] = get_pixel(l + j, t + i); + Image = new QImage(data, w, h, 8,(QRgb*)CM->RGBColors, CM->NumColors, QImage::IgnoreEndian); + Painter = new QPainter(this); + Painter->drawImage(l, t, *Image, 0, 0, w, h); + xfree(data); + delete Painter; + delete Image; + } + } +} + +//***************************************************************************** +void QMyMainWindow::closeEvent(QCloseEvent* e) +{ + e->accept(); +} + +//***************************************************************************** +void QMyMainWindow::dataReceived() +{ + if (rdp_main_loop()) + return; + else + SV->close(); +} + +//***************************************************************************** +void redraw(int x, int y, int cx, int cy) +{ + if (WarpCoords(&x, &y, &cx, &cy, NULL, NULL)) + { + MW->update(x, y, cx, cy); + } +} + +/* +BOOL ui_init(void) +{ + QWidget* d; + + CM = NULL; + BS = NULL; +#ifdef SHARP + App = new QPEApplication(g_argc, g_argv); +#else + App = new QApplication(g_argc, g_argv, QApplication::GuiServer); +#endif + if (fullscreen) + { + d = QApplication::desktop(); + width = d->width(); // returns screen width + height = d->height(); // returns screen height + } + return True; +} +*/ + +/* +void ui_deinit(void) +{ + delete App; +} +*/ + +/* +BOOL ui_create_window(void) +{ + MW = new QMyMainWindow(); + MW->resize(width, height); + SV = new QMyScrollView(); + SV->resize(width + 4, height + 4); + App->setMainWidget(SV); + SV->addChild(MW); + MW->setMouseTracking(true); + SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW); + MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived())); + if (fullscreen) + SV->showFullScreen(); + else + SV->showMaximized(); + BS = (uint8*)xmalloc(width * height); + memset(BS, 0, width * height); + clipx = 0; + clipy = 0; + clipcx = width; + clipcy = height; + CM = (QColorMap*)xmalloc(sizeof(struct QColorMap)); + memset(CM, 0, sizeof(struct QColorMap)); + SV->timer_id = SV->startTimer(1000); + return True; +} +*/ + +/* +void ui_destroy_window(void) +{ + delete MW; + delete SV; + xfree(BS); + xfree(CM); +} +*/ + +//***************************************************************************** +/* Returns 0 after user quit, 1 otherwise */ +int ui_select(int rdp_socket) +{ + global_sock = rdp_socket; + return 1; +} + +//***************************************************************************** +void ui_move_pointer(int /*x*/, int /*y*/) +{ +} + +//***************************************************************************** +HBITMAP ui_create_bitmap(int width, int height, uint8 * data) +{ + struct bitmap* the_bitmap; + uint8* bitmap_data; + int i, j; + +// printf("width %d height %d times %d\n", width, height, width * height); + bitmap_data = (uint8*)xmalloc(width * height); + the_bitmap = (struct bitmap*)xmalloc(sizeof(struct bitmap)); + the_bitmap->w = width; + the_bitmap->h = height; + the_bitmap->data = bitmap_data; + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + bitmap_data[i * width + j] = data[i * width + j]; + return the_bitmap; +} + +//***************************************************************************** +void ui_paint_bitmap(int x, int y, int cx, int cy, int width, + int height, uint8 * data) +{ + int i, j; + + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + if (i < height) + if (j < width) + set_pixel(x + j, y + i, data[i * width + j]); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +void ui_destroy_bitmap(HBITMAP bmp) +{ + struct bitmap* the_bitmap; + + the_bitmap = (struct bitmap*)bmp; + if (the_bitmap != NULL) + { + if (the_bitmap->data != NULL) + xfree(the_bitmap->data); + xfree(the_bitmap); + } +} + +//***************************************************************************** +bool is_pixel_on(uint8* data, int x, int y, int width, int bpp) +{ + int start, shift; + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + return (data[start] & (0x80 >> shift)) != 0; + } + else if (bpp == 8) + return data[y * width + x] != 0; + else + return false; +} + +//***************************************************************************** +void set_pixel_on(uint8* data, int x, int y, int width, int bpp, uint8 pixel) +{ + if (bpp == 8) + data[y * width + x] = pixel; +} + +//***************************************************************************** +HGLYPH ui_create_glyph(int width, int height, uint8 * data) +{ + int i, j; + uint8* glyph_data; + struct bitmap* the_glyph; + + glyph_data = (uint8*)xmalloc(width * height); + the_glyph = (struct bitmap*)xmalloc(sizeof(struct bitmap)); + the_glyph->w = width; + the_glyph->h = height; + the_glyph->data = glyph_data; + memset(glyph_data, 0, width * height); + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + if (is_pixel_on(data, j, i, width, 1)) + set_pixel_on(glyph_data, j, i, width, 8, 255); + return the_glyph; +} + +//***************************************************************************** +void ui_destroy_glyph(HGLYPH glyph) +{ + struct bitmap* the_glyph; + + the_glyph = (struct bitmap*)glyph; + if (the_glyph != NULL) + { + if (the_glyph->data != NULL) + xfree(the_glyph->data); + xfree(the_glyph); + } +} + +//***************************************************************************** +HCURSOR ui_create_cursor(unsigned int /*x*/, unsigned int /*y*/, + int /*width*/, int /*height*/, uint8 * /*andmask*/, + uint8 * /*xormask*/) +{ + return (void*)1; +} + +//***************************************************************************** +void ui_set_cursor(HCURSOR /*cursor*/) +{ +} + +//***************************************************************************** +void ui_destroy_cursor(HCURSOR /*cursor*/) +{ +} + +//***************************************************************************** +HCOLOURMAP ui_create_colourmap(COLOURMAP * colours) +{ + int i; + int x; + uint8 r, g, b; + i = 0; + while (i < colours->ncolours && i < 256) + { + r = colours->colours[i].red; + g = colours->colours[i].green; + b = colours->colours[i].blue; + x = (r << 16) | (g << 8) | b; + CM->RGBColors[i] = x; + i++; + } + CM->NumColors = colours->ncolours; + return CM; +} + +//***************************************************************************** +void ui_destroy_colourmap(HCOLOURMAP /*map*/) +{ +} + +//***************************************************************************** +void ui_set_colourmap(HCOLOURMAP /*map*/) +{ +} + +//***************************************************************************** +void ui_begin_update(void) +{ +} + +//***************************************************************************** +void ui_end_update(void) +{ +} + +//***************************************************************************** +void ui_set_clip(int x, int y, int cx, int cy) +{ + clipx = x; + clipy = y; + clipcx = cx; + clipcy = cy; +} + +//***************************************************************************** +void ui_reset_clip(void) +{ + clipx = 0; + clipy = 0; + clipcx = g_width; + clipcy = g_height; +} + +//***************************************************************************** +void ui_bell(void) +{ + App->beep(); +} + +//***************************************************************************** +void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) +{ + int i, j; + + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, get_pixel(x + j, y + i), opcode); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +// does not repaint +void fill_rect(int x, int y, int cx, int cy, int colour, int opcode = 0xc) +{ + int i, j; + + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, colour, opcode); +} + +//***************************************************************************** +void ui_rect(int x, int y, int cx, int cy, int colour) +{ + fill_rect(x, y, cx, cy, colour); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, + BRUSH * brush, int bgcolour, int fgcolour) +{ + int i, j; + uint8 ipattern[8]; + + switch (brush->style) + { + case 0: + fill_rect(x, y, cx, cy, fgcolour, opcode); + break; + case 3: + for (i = 0; i < 8; i++) + ipattern[i] = ~brush->pattern[7 - i]; + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8, + (y + i + brush->yorigin) % 8, 8, 1)) + set_pixel(x + j, y + i, fgcolour, opcode); + else + set_pixel(x + j, y + i, bgcolour, opcode); + break; + } + redraw(x, y, cx, cy); +} + +//***************************************************************************** +void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, + int srcx, int srcy) +{ + int i, j; + uint8* temp; + + temp = (uint8*)xmalloc(cx * cy); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + temp[i * cx + j] = get_pixel(srcx + j, srcy + i); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, temp[i * cx + j], opcode); + xfree(temp); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, + HBITMAP src, int srcx, int srcy) +{ + int i, j; + struct bitmap* the_bitmap; + + the_bitmap = (struct bitmap*)src; + if (the_bitmap == NULL) + return; + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + if ((i + srcy) < the_bitmap->h && (j + srcx) < the_bitmap->w) + set_pixel(x + j, y + i, the_bitmap->data[(i + srcy) * the_bitmap->w + (j + srcx)], opcode); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +// not used +void ui_triblt(uint8 /*opcode*/, int /*x*/, int /*y*/, int /*cx*/, int /*cy*/, + HBITMAP /*src*/, int /*srcx*/, int /*srcy*/, BRUSH * /*brush*/, + int /*bgcolour*/, int /*fgcolour*/) +{ +} + +//***************************************************************************** +// Bresenham's line drawing algorithm +void ui_line(uint8 opcode, int startx, int starty, int endx, + int endy, PEN * pen) +{ + int dx, dy, incx, incy, dpr, dpru, p, left, top, right, bottom; + + if (startx > endx) + { + dx = startx - endx; + incx = -1; + left = endx; + right = startx; + } + else + { + dx = endx - startx; + incx = 1; + left = startx; + right = endx; + } + if (starty > endy) + { + dy = starty - endy; + incy = -1; + top = endy; + bottom = starty; + } + else + { + dy = endy - starty; + incy = 1; + top = starty; + bottom = endy; + } + if (dx >= dy) + { + dpr = dy << 1; + dpru = dpr - (dx << 1); + p = dpr - dx; + for (; dx >= 0; dx--) + { + set_pixel(startx, starty, pen->colour, opcode); + if (p > 0) + { + startx += incx; + starty += incy; + p += dpru; + } + else + { + startx += incx; + p += dpr; + } + } + } + else + { + dpr = dx << 1; + dpru = dpr - (dy << 1); + p = dpr - dy; + for (; dy >= 0; dy--) + { + set_pixel(startx, starty, pen->colour, opcode); + if (p > 0) + { + startx += incx; + starty += incy; + p += dpru; + } + else + { + starty += incy; + p += dpr; + } + } + } + redraw(left, top, (right - left) + 1, (bottom - top) + 1); +} + +//***************************************************************************** +void draw_glyph (int x, int y, HGLYPH glyph, int fgcolour) +{ + struct bitmap* the_glyph; + int i, j; + + the_glyph = (struct bitmap*)glyph; + if (the_glyph == NULL) + return; + for (i = 0; i < the_glyph->h; i++) + for (j = 0; j < the_glyph->w; j++) + if (is_pixel_on(the_glyph->data, j, i, the_glyph->w, 8)) + set_pixel(x + j, y + i, fgcolour); +} + +#define DO_GLYPH(ttext,idx) \ +{\ + glyph = cache_get_font (font, ttext[idx]);\ + if (!(flags & TEXT2_IMPLICIT_X))\ + {\ + xyoffset = ttext[++idx];\ + if ((xyoffset & 0x80))\ + {\ + if (flags & TEXT2_VERTICAL) \ + y += ttext[idx+1] | (ttext[idx+2] << 8);\ + else\ + x += ttext[idx+1] | (ttext[idx+2] << 8);\ + idx += 2;\ + }\ + else\ + {\ + if (flags & TEXT2_VERTICAL) \ + y += xyoffset;\ + else\ + x += xyoffset;\ + }\ + }\ + if (glyph != NULL)\ + {\ + draw_glyph (x + glyph->offset, y + glyph->baseline, glyph->pixmap, fgcolour);\ + if (flags & TEXT2_IMPLICIT_X)\ + x += glyph->width;\ + }\ +} + +//***************************************************************************** +void ui_draw_text(uint8 font, uint8 flags, int mixmode, + int x, int y, int clipx, int clipy, + int clipcx, int clipcy, int boxx, + int boxy, int boxcx, int boxcy, int bgcolour, + int fgcolour, uint8 * text, uint8 length) +{ + FONTGLYPH *glyph; + int i, j, xyoffset; + DATABLOB *entry; + + if (boxcx > 1) + fill_rect(boxx, boxy, boxcx, boxcy, bgcolour); + else if (mixmode == MIX_OPAQUE) + fill_rect(clipx, clipy, clipcx, clipcy, bgcolour); + + /* Paint text, character by character */ + for (i = 0; i < length;) + { + switch (text[i]) + { + case 0xff: + if (i + 2 < length) + cache_put_text(text[i + 1], text, text[i + 2]); + else + { + error("this shouldn't be happening\n"); + exit(1); + } + /* this will move pointer from start to first character after FF command */ + length -= i + 3; + text = &(text[i + 3]); + i = 0; + break; + + case 0xfe: + entry = cache_get_text(text[i + 1]); + if (entry != NULL) + { + if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X))) + { + if (flags & TEXT2_VERTICAL) + y += text[i + 2]; + else + x += text[i + 2]; + } + for (j = 0; j < entry->size; j++) + DO_GLYPH(((uint8 *) (entry->data)), j); + } + if (i + 2 < length) + i += 3; + else + i += 2; + length -= i; + /* this will move pointer from start to first character after FE command */ + text = &(text[i]); + i = 0; + break; + + default: + DO_GLYPH(text, i); + i++; + break; + } + } + if (boxcx > 1) + redraw(boxx, boxy, boxcx, boxcy); + else + redraw(clipx, clipy, clipcx, clipcy); +} + +//***************************************************************************** +void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) +{ + uint8* data; + int i, j; + + data = (uint8*)xmalloc(cx * cy); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + data[i * cx + j] = get_pixel(x + j, y + i); + cache_put_desktop(offset, cx, cy, cx, 1, data); + xfree(data); +} + +//***************************************************************************** +void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) +{ + uint8* data; + int i, j; + + data = cache_get_desktop(offset, cx, cy, 1); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, data[i * cx + j]); + redraw(x, y, cx, cy); +} + +//***************************************************************************** +int main(int argc, char** argv) +{ + CM = NULL; + BS = NULL; +#ifdef SHARP + App = new QPEApplication(argc, argv); +#else + App = new QApplication(argc, argv, QApplication::GuiServer); +#endif + SV = new QMyScrollView(); + App->setMainWidget(SV); + SV->showMaximized(); + SV->timer_id = SV->startTimer(1000); + App->exec(); + delete SV; + delete App; + if (CM != NULL) + xfree(CM); + if (BS !=NULL) + xfree(BS); + return 0; +} + +/* + MW = new QMyMainWindow(); + MW->resize(width, height); + SV->resize(width + 4, height + 4); + App->setMainWidget(SV); + SV->addChild(MW); + MW->setMouseTracking(true); + SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW); + MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived())); + if (fullscreen) + SV->showFullScreen(); + else + SV->showMaximized(); + BS = (uint8*)xmalloc(width * height); + memset(BS, 0, width * height); + clipx = 0; + clipy = 0; + clipcx = width; + clipcy = height; + CM = (QColorMap*)xmalloc(sizeof(struct QColorMap)); + memset(CM, 0, sizeof(struct QColorMap)); + SV->timer_id = SV->startTimer(1000); + return True; + + + + + +int main(int argc, char ** argv) +{ + uint32 flags; + int i, total_params; + char server[64] = "192.168.0.164"; + char domain[16] = ""; + char password[16] = ""; + char shell[128] = ""; + char directory[32] = ""; + char* p; + QString param, s1, s2, s3; + + flags = RDP_LOGON_NORMAL; + + g_argc = argc; + g_argv = argv; + + if (!ui_init()) + return 1; + + total_params = App->argc(); + + for (i = 1; (i + 1) < total_params; i = i + 2) + { + s1 = App->argv()[i]; + s2 = App->argv()[i + 1]; + if (s1 == "-g") + { + width = strtol((const char*)s2, &p, 10); + if (*p == 'x') + height = strtol(p + 1, NULL, 10); + } + else if (s1 = "-u") + strcpy(username, (const char*)s2); + } + if (i < total_params) + strcpy(server, App->argv()[i]); + +// printf("server %s width %d height %d\n", server, width, height); + + if (width == 0 || height == 0) + { + ui_deinit(); + return 1; + } + + if (!rdp_connect(server, flags, domain, password, shell, directory)) + { + ui_deinit(); + return 1; + } + if (ui_create_window()) + { + ui_main_loop(); + ui_destroy_window(); + } + rdp_disconnect(); + ui_deinit(); +} +*/ diff --git a/noncore/net/opierdesktop/qtwin.h b/noncore/net/opierdesktop/qtwin.h new file mode 100644 index 0000000..38ad190 --- a/dev/null +++ b/noncore/net/opierdesktop/qtwin.h @@ -0,0 +1,105 @@ + +#include <qwidget.h> +#include <qscrollview.h> +#include <qdialog.h> +#include <qlistbox.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qpopupmenu.h> + +class QMyConnectionItem +{ + public: + QString ServerName; + QString UserName; + QString ServerIP; + int Width; + int Height; + int FullScreen; +}; + +class QMyDialog: public QDialog +{ + Q_OBJECT + public: + QMyDialog(QWidget*); + ~QMyDialog(); + public: + QListBox* ListBox; + QPushButton* OKButton; + QPushButton* CancelButton; + QLabel* Label1; + QLineEdit* ServerNameEdit; + QLabel* Label2; + QLineEdit* UserNameEdit; + QLabel* Label3; + QLineEdit* IPEdit; + QLineEdit* WidthEdit; + QLineEdit* HeightEdit; + QComboBox* WidthHeightBox; + QPushButton* AddButton; + QPushButton* EditButton; + QPushButton* SaveButton; + QPushButton* RemoveButton; + QCheckBox* FullScreenCheckBox; + public slots: + void ComboChanged(int); + void OKClicked(); + void CancelClicked(); + void AddClicked(); + void EditClicked(); + void SaveClicked(); + void RemoveClicked(); + void ListBoxChanged(); + void ListBoxSelected(int); + public: + QString ServerName; + QString UserName; + QString ServerIP; + int Width; + int Height; + int FullScreen; + QMyConnectionItem* ConnectionList[10]; +}; + +class QMyScrollView: public QScrollView +{ + Q_OBJECT + public: + QMyScrollView(); + ~QMyScrollView(); + void keyPressEvent(QKeyEvent*); + void keyReleaseEvent(QKeyEvent*); + void showEvent(QShowEvent*); + void show(); + void polish(); + void timerEvent(QTimerEvent*); + public: + int timer_id; +}; + +class QMyMainWindow: public QWidget +{ + Q_OBJECT + public: + QMyMainWindow(); + ~QMyMainWindow(); + void paintEvent(QPaintEvent*); + void mouseMoveEvent(QMouseEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + void closeEvent(QCloseEvent*); + void timerEvent(QTimerEvent*); + public slots: + void dataReceived(); + void MemuClicked(int); + public: + QPopupMenu* PopupMenu; + int timer_id; + int mx; + int my; +}; + diff --git a/noncore/net/opierdesktop/rdesktop.cpp b/noncore/net/opierdesktop/rdesktop.cpp new file mode 100644 index 0000000..1a9a087 --- a/dev/null +++ b/noncore/net/opierdesktop/rdesktop.cpp @@ -0,0 +1,313 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Entrypoint and utility functions + Copyright (C) Matthew Chapman 1999-2003 + + 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. +*/ + +//#include <stdarg.h> /* va_list va_start va_end */ +#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */ +#include <fcntl.h> /* open */ +#include <pwd.h> /* getpwuid */ +//#include <termios.h> /* tcgetattr tcsetattr */ +#include <sys/stat.h> /* stat */ +#include <sys/time.h> /* gettimeofday */ +#include <sys/times.h> /* times */ +#include <errno.h> +#include "rdesktop.h" + +#ifdef EGD_SOCKET +#include <sys/socket.h> /* socket connect */ +#include <sys/un.h> /* sockaddr_un */ +#endif + +//#ifdef WITH_OPENSSL +#include <openssl/md5.h> +//#else +//#include "crypto/md5.h" +//#endif + +/*extern "C" */void ui_main_loop(void); + +int g_argc; +char ** g_argv; + +char title[32] = ""; +char username[16] = "j"; +char hostname[16] = "sharp"; +char keymapname[16]; +int keylayout = 0x409; /* Defaults to US keyboard layout */ +int g_width = 800; /* If width or height are reset to zero, the geometry will + be fetched from _NET_WORKAREA */ +int g_height = 600; +int tcp_port_rdp = TCP_PORT_RDP; +int server_bpp = 8; +int win_button_size = 0; /* If zero, disable single app mode */ +BOOL bitmap_compression = True; +BOOL sendmotion = True; +BOOL orders = True; +BOOL encryption = True; +BOOL desktop_save = True; +BOOL fullscreen = False; +BOOL grab_keyboard = True; +BOOL hide_decorations = False; +extern BOOL owncolmap; + +/* report an unimplemented protocol feature */ +void +unimpl(char *format, ...) +{ +} + +/* malloc; exit if out of memory */ +void * +xmalloc(int size) +{ + void *mem = malloc(size); + if (mem == NULL) + { + error("xmalloc %d\n", size); + exit(1); + } + return mem; +} + +/* realloc; exit if out of memory */ +void * +xrealloc(void *oldmem, int size) +{ + void *mem = realloc(oldmem, size); + if (mem == NULL) + { + error("xrealloc %d\n", size); + exit(1); + } + return mem; +} + +/* free */ +void +xfree(void *mem) +{ + free(mem); +} + +/* report an error */ +void +error(char *format, ...) +{ +} + +/* report a warning */ +void +warning(char *format, ...) +{ +} + +/* Generate a 32-byte random for the secure transport code. */ +void +generate_random(uint8 * random) +{ + struct stat st; + struct tms tmsbuf; + MD5_CTX md5; + uint32 *r; + int fd, n; + + /* If we have a kernel random device, try that first */ + if (((fd = open("/dev/urandom", O_RDONLY)) != -1) + || ((fd = open("/dev/random", O_RDONLY)) != -1)) + { + n = read(fd, random, 32); + close(fd); + if (n == 32) + return; + } + /* Otherwise use whatever entropy we can gather - ideas welcome. */ + r = (uint32 *) random; + r[0] = (getpid()) | (getppid() << 16); + r[1] = (getuid()) | (getgid() << 16); + r[2] = times(&tmsbuf); /* system uptime (clocks) */ + gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */ + stat("/tmp", &st); + r[5] = st.st_atime; + r[6] = st.st_mtime; + r[7] = st.st_ctime; + + /* Hash both halves with MD5 to obscure possible patterns */ + MD5_Init(&md5); + MD5_Update(&md5, random, 16); + MD5_Final(random, &md5); + MD5_Update(&md5, random + 16, 16); + MD5_Final(random + 16, &md5); +} + +int +load_licence(unsigned char **data) +{ + char *path; + char *home; + struct stat st; + int fd; + + home = getenv("HOME"); + if (home == NULL) + return -1; + + path = (char*)xmalloc(strlen(home) + strlen(hostname) + 20); + sprintf(path, "%s/.rdesktop/licence.%s", home, hostname); + + fd = open(path, O_RDONLY); + if (fd == -1) + return -1; + + if (fstat(fd, &st)) + return -1; + + *data = (unsigned char*)xmalloc(st.st_size); + return read(fd, *data, st.st_size); +} + +void +save_licence(unsigned char *data, int length) +{ + char *fpath; /* file path for licence */ + char *fname, *fnamewrk; /* file name for licence .inkl path. */ + char *home; + uint32 y; + struct flock fnfl; + int fnfd, fnwrkfd, i, wlen; + struct stream s, *s_ptr; + uint32 len; + + /* Construct a stream, so that we can use macros to extract the + * licence. + */ + s_ptr = &s; + s_ptr->p = data; + /* Skip first two bytes */ + in_uint16(s_ptr, len); + + /* Skip three strings */ + for (i = 0; i < 3; i++) + { + in_uint32(s_ptr, len); + s_ptr->p += len; + /* Make sure that we won't be past the end of data after + * reading the next length value + */ + if ((s_ptr->p) + 4 > data + length) + { + printf("Error in parsing licence key.\n"); + printf("Strings %d end value %x > supplied length (%x)\n", i, + (unsigned int) s_ptr->p, (unsigned int) data + length); + return; + } + } + in_uint32(s_ptr, len); + if (s_ptr->p + len > data + length) + { + printf("Error in parsing licence key.\n"); + printf("End of licence %x > supplied length (%x)\n", + (unsigned int) s_ptr->p + len, (unsigned int) data + length); + return; + } + + home = getenv("HOME"); + if (home == NULL) + return; + + /* set and create the directory -- if it doesn't exist. */ + fpath = (char*)xmalloc(strlen(home) + 11); + STRNCPY(fpath, home, strlen(home) + 1); + + sprintf(fpath, "%s/.rdesktop", fpath); + if (mkdir(fpath, 0700) == -1 && errno != EEXIST) + { + perror("mkdir"); + exit(1); + } + + /* set the real licence filename, and put a write lock on it. */ + fname = (char*)xmalloc(strlen(fpath) + strlen(hostname) + 10); + sprintf(fname, "%s/licence.%s", fpath, hostname); + fnfd = open(fname, O_RDONLY); + if (fnfd != -1) + { + fnfl.l_type = F_WRLCK; + fnfl.l_whence = SEEK_SET; + fnfl.l_start = 0; + fnfl.l_len = 1; + fcntl(fnfd, F_SETLK, &fnfl); + } + + /* create a temporary licence file */ + fnamewrk = (char*)xmalloc(strlen(fname) + 12); + for (y = 0;; y++) + { + sprintf(fnamewrk, "%s.%lu", fname, (long unsigned int) y); + fnwrkfd = open(fnamewrk, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fnwrkfd == -1) + { + if (errno == EINTR || errno == EEXIST) + continue; + perror("create"); + exit(1); + } + break; + } + /* write to the licence file */ + for (y = 0; y < len;) + { + do + { + wlen = write(fnwrkfd, s_ptr->p + y, len - y); + } + while (wlen == -1 && errno == EINTR); + if (wlen < 1) + { + perror("write"); + unlink(fnamewrk); + exit(1); + } + y += wlen; + } + + /* close the file and rename it to fname */ + if (close(fnwrkfd) == -1) + { + perror("close"); + unlink(fnamewrk); + exit(1); + } + if (rename(fnamewrk, fname) == -1) + { + perror("rename"); + unlink(fnamewrk); + exit(1); + } + /* close the file lock on fname */ + if (fnfd != -1) + { + fnfl.l_type = F_UNLCK; + fnfl.l_whence = SEEK_SET; + fnfl.l_start = 0; + fnfl.l_len = 1; + fcntl(fnfd, F_SETLK, &fnfl); + close(fnfd); + } + +} diff --git a/noncore/net/opierdesktop/rdesktop.h b/noncore/net/opierdesktop/rdesktop.h new file mode 100644 index 0000000..0fca123 --- a/dev/null +++ b/noncore/net/opierdesktop/rdesktop.h @@ -0,0 +1,66 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Master include file + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +//#define __LITTLE_ENDIAN 1234 +//#define __BIG_ENDIAN 4321 +//#define __BYTE_ORDER __BIG_ENDIAN + +//#if __BYTE_ORDER == __LITTLE_ENDIAN +#define L_ENDIAN +#define NEED_ALIGN +//#error le +//#elif __BYTE_ORDER == __BIG_ENDIAN +//#define B_ENDIAN +//#error be +//#else +//#error Unknown endianness. Edit rdesktop.h. +//#endif + + +//#define B_ENDIAN +//#define B_ENDIAN_PREFERRED + +#define VERSION "1.2.0" + +#ifdef WITH_DEBUG +#define DEBUG(args) printf args; +#else +#define DEBUG(args) +#endif + +#ifdef WITH_DEBUG_KBD +#define DEBUG_KBD(args) printf args; +#else +#define DEBUG_KBD(args) +#endif + +#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } + +#include "constants.h" +#include "types.h" +#include "parse.h" + +#ifndef MAKE_PROTO +#include "proto.h" +#endif diff --git a/noncore/net/opierdesktop/rdp.cpp b/noncore/net/opierdesktop/rdp.cpp new file mode 100644 index 0000000..bab8568 --- a/dev/null +++ b/noncore/net/opierdesktop/rdp.cpp @@ -0,0 +1,748 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - RDP layer + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +extern uint16 mcs_userid; +extern char username[16]; +extern BOOL bitmap_compression; +extern BOOL orders; +extern BOOL encryption; +extern BOOL desktop_save; + +uint8 *next_packet; +uint32 rdp_shareid; + +/* Initialise an RDP packet */ +static STREAM +rdp_init(int maxlen) +{ + STREAM s; + + s = sec_init(encryption ? SEC_ENCRYPT : 0, maxlen + 6); + s_push_layer(s, rdp_hdr, 6); + + return s; +} + +/* Send an RDP packet */ +static void +rdp_send(STREAM s, uint8 pdu_type) +{ + uint16 length; + + s_pop_layer(s, rdp_hdr); + length = s->end - s->p; + + out_uint16_le(s, length); + out_uint16_le(s, (pdu_type | 0x10)); /* Version 1 */ + out_uint16_le(s, (mcs_userid + 1001)); + + sec_send(s, encryption ? SEC_ENCRYPT : 0); +} + +/* Receive an RDP packet */ +STREAM +rdp_recv(uint8 * type) +{ + static STREAM rdp_s; + uint16 length, pdu_type; + + if ((rdp_s == NULL) || (next_packet >= rdp_s->end)) + { + rdp_s = sec_recv(); + if (rdp_s == NULL) + return NULL; + + next_packet = rdp_s->p; + } + else + { + rdp_s->p = next_packet; + } + + in_uint16_le(rdp_s, length); + /* 32k packets are really 8, keepalive fix */ + if (length == 0x8000) + { + next_packet += 8; + *type = 0; + return rdp_s; + } + in_uint16_le(rdp_s, pdu_type); + in_uint8s(rdp_s, 2); /* userid */ + *type = pdu_type & 0xf; + +#if WITH_DEBUG + DEBUG(("RDP packet (type %x):\n", *type)); + hexdump(next_packet, length); +#endif /* */ + + next_packet += length; + return rdp_s; +} + +/* Initialise an RDP data packet */ +static STREAM +rdp_init_data(int maxlen) +{ + STREAM s; + + s = sec_init(encryption ? SEC_ENCRYPT : 0, maxlen + 18); + s_push_layer(s, rdp_hdr, 18); + + return s; +} + +/* Send an RDP data packet */ +static void +rdp_send_data(STREAM s, uint8 data_pdu_type) +{ + uint16 length; + + s_pop_layer(s, rdp_hdr); + length = s->end - s->p; + + out_uint16_le(s, length); + out_uint16_le(s, (RDP_PDU_DATA | 0x10)); + out_uint16_le(s, (mcs_userid + 1001)); + + out_uint32_le(s, rdp_shareid); + out_uint8(s, 0); /* pad */ + out_uint8(s, 1); /* streamid */ + out_uint16_le(s, (length - 14)); + out_uint8(s, data_pdu_type); + out_uint8(s, 0); /* compress_type */ + out_uint16(s, 0); /* compress_len */ + + sec_send(s, encryption ? SEC_ENCRYPT : 0); +} + +/* Output a string in Unicode */ +void +rdp_out_unistr(STREAM s, char *string, int len) +{ + int i = 0, j = 0; + + len += 2; + + while (i < len) + { + s->p[i++] = string[j++]; + s->p[i++] = 0; + } + + s->p += len; +} + +/* Parse a logon info packet */ +static void +rdp_send_logon_info(uint32 flags, char *domain, char *user, + char *password, char *program, char *directory) +{ + int len_domain = 2 * strlen(domain); + int len_user = 2 * strlen(user); + int len_password = 2 * strlen(password); + int len_program = 2 * strlen(program); + int len_directory = 2 * strlen(directory); + uint32 sec_flags = encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; + STREAM s; + + s = sec_init(sec_flags, 18 + len_domain + len_user + len_password + + len_program + len_directory + 10); + + out_uint32(s, 0); + out_uint32_le(s, flags); + out_uint16_le(s, len_domain); + out_uint16_le(s, len_user); + out_uint16_le(s, len_password); + out_uint16_le(s, len_program); + out_uint16_le(s, len_directory); + rdp_out_unistr(s, domain, len_domain); + rdp_out_unistr(s, user, len_user); + rdp_out_unistr(s, password, len_password); + rdp_out_unistr(s, program, len_program); + rdp_out_unistr(s, directory, len_directory); + + s_mark_end(s); + sec_send(s, sec_flags); +} + +/* Send a control PDU */ +static void +rdp_send_control(uint16 action) +{ + STREAM s; + + s = rdp_init_data(8); + + out_uint16_le(s, action); + out_uint16(s, 0); /* userid */ + out_uint32(s, 0); /* control id */ + + s_mark_end(s); + rdp_send_data(s, RDP_DATA_PDU_CONTROL); +} + +/* Send a synchronisation PDU */ +static void +rdp_send_synchronise(void) +{ + STREAM s; + + s = rdp_init_data(4); + + out_uint16_le(s, 1); /* type */ + out_uint16_le(s, 1002); + + s_mark_end(s); + rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE); +} + +/* Send a single input event */ +void +rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2) +{ + STREAM s; + + s = rdp_init_data(16); + + out_uint16_le(s, 1); /* number of events */ + out_uint16(s, 0); /* pad */ + + 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); + rdp_send_data(s, RDP_DATA_PDU_INPUT); +} + +/* Send an (empty) font information PDU */ +static void +rdp_send_fonts(uint16 seq) +{ + STREAM s; + + s = rdp_init_data(8); + + out_uint16(s, 0); /* number of fonts */ + out_uint16_le(s, 0x3e); /* unknown */ + out_uint16_le(s, seq); /* unknown */ + out_uint16_le(s, 0x32); /* entry size */ + + s_mark_end(s); + rdp_send_data(s, RDP_DATA_PDU_FONT2); +} + +/* Output general capability set */ +static void +rdp_out_general_caps(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(s, 0); /* Pad */ + out_uint16(s, 0); /* Compression types */ + out_uint16(s, 0); /* Pad */ + out_uint16(s, 0); /* Update capability */ + out_uint16(s, 0); /* Remote unshare capability */ + out_uint16(s, 0); /* Compression level */ + out_uint16(s, 0); /* Pad */ +} + +/* Output bitmap capability set */ +static void +rdp_out_bitmap_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_BITMAP); + out_uint16_le(s, RDP_CAPLEN_BITMAP); + + out_uint16_le(s, 8); /* 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(s, 0); /* Pad */ + out_uint16(s, 0); /* Allow resize */ + out_uint16_le(s, bitmap_compression ? 1 : 0); /* Support compression */ + out_uint16(s, 0); /* Unknown */ + out_uint16_le(s, 1); /* Unknown */ + out_uint16(s, 0); /* Pad */ +} + +/* Output order capability set */ +static void +rdp_out_order_caps(STREAM s) +{ + uint8 order_caps[32]; + + + 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] = 1; /* required for memblt? */ + order_caps[8] = 1; /* line */ + order_caps[9] = 1; /* line */ + order_caps[10] = 1; /* rect */ + order_caps[11] = (desktop_save == False ? 0 : 1); /* desksave */ + order_caps[13] = 1; /* memblt */ + order_caps[14] = 1; /* triblt */ + order_caps[22] = 1; /* polyline */ + 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(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, desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ +// out_uint32_le(s, 0); // desktop cache set to 0 + out_uint32(s, 0); /* Unknown */ + out_uint32_le(s, 0x4e4); /* Unknown */ +} + +/* Output bitmap cache capability set */ +static void +rdp_out_bmpcache_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_BMPCACHE); + out_uint16_le(s, RDP_CAPLEN_BMPCACHE); + + out_uint8s(s, 24); /* unused */ + out_uint16_le(s, 0x258); /* entries */ + out_uint16_le(s, 0x100); /* max cell size */ + out_uint16_le(s, 0x12c); /* entries */ + out_uint16_le(s, 0x400); /* max cell size */ + out_uint16_le(s, 0x106); /* entries */ + out_uint16_le(s, 0x1000); /* max cell size */ +} + +/* Output control capability set */ +static void +rdp_out_control_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_CONTROL); + out_uint16_le(s, RDP_CAPLEN_CONTROL); + + out_uint16(s, 0); /* Control capabilities */ + out_uint16(s, 0); /* Remote detach */ + out_uint16_le(s, 2); /* Control interest */ + out_uint16_le(s, 2); /* Detach interest */ +} + +/* Output activation capability set */ +static void +rdp_out_activate_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_ACTIVATE); + out_uint16_le(s, RDP_CAPLEN_ACTIVATE); + + out_uint16(s, 0); /* Help key */ + out_uint16(s, 0); /* Help index key */ + out_uint16(s, 0); /* Extended help key */ + out_uint16(s, 0); /* Window activate */ +} + +/* Output pointer capability set */ +static void +rdp_out_pointer_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_POINTER); + + out_uint16(s, 0); /* Colour pointer */ + out_uint16_le(s, 20); /* Cache size */ +} + +/* Output share capability set */ +static void +rdp_out_share_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_SHARE); + out_uint16_le(s, RDP_CAPLEN_SHARE); + + out_uint16(s, 0); /* userid */ + out_uint16(s, 0); /* pad */ +} + +/* Output colour cache capability set */ +static void +rdp_out_colcache_caps(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(s, 0); /* pad */ +} + +static uint8 canned_caps[] = { + 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, + 0x0C, 0x00, 0x08, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x34, 0x00, 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 set */ +static void +rdp_out_unknown_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_UNKNOWN); + out_uint16_le(s, 0x58); + + out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN - 4); +} + +/* Send a confirm active PDU */ +static void +rdp_send_confirm_active(void) +{ + STREAM s; + uint16 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 + RDP_CAPLEN_UNKNOWN + 4 /* w2k fix, why? */ ; + + s = rdp_init(14 + caplen + sizeof(RDP_SOURCE)); + + out_uint32_le(s, rdp_shareid); + 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_out_general_caps(s); + rdp_out_bitmap_caps(s); + rdp_out_order_caps(s); + rdp_out_bmpcache_caps(s); + rdp_out_colcache_caps(s); + rdp_out_activate_caps(s); + rdp_out_control_caps(s); + rdp_out_pointer_caps(s); + rdp_out_share_caps(s); + rdp_out_unknown_caps(s); + + s_mark_end(s); + rdp_send(s, RDP_PDU_CONFIRM_ACTIVE); +} + +/* Respond to a demand active PDU */ +void +process_demand_active(STREAM s) +{ + uint8 type; + + in_uint32_le(s, rdp_shareid); + + DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", rdp_shareid)); + + rdp_send_confirm_active(); + rdp_send_synchronise(); + rdp_send_control(RDP_CTL_COOPERATE); + rdp_send_control(RDP_CTL_REQUEST_CONTROL); + rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */ + rdp_recv(&type); /* RDP_CTL_COOPERATE */ + rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */ + rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0); + rdp_send_fonts(1); + rdp_send_fonts(2); + rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 */ + reset_order_state(); +} + +/* Process a pointer PDU */ +static void +process_pointer_pdu(STREAM s) +{ + uint16 message_type; + uint16 x, y, width, height, cache_idx, masklen, datalen; + uint8 *mask, *data; + HCURSOR cursor; + + 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); + if (s_check(s)) + ui_move_pointer(x, y); + break; + + case RDP_POINTER_COLOR: + in_uint16_le(s, cache_idx); + in_uint16_le(s, x); + in_uint16_le(s, y); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_uint16_le(s, masklen); + in_uint16_le(s, datalen); + in_uint8p(s, data, datalen); + in_uint8p(s, mask, masklen); + cursor = ui_create_cursor(x, y, width, height, mask, data); + ui_set_cursor(cursor); + cache_put_cursor(cache_idx, cursor); + break; + + case RDP_POINTER_CACHED: + in_uint16_le(s, cache_idx); + ui_set_cursor(cache_get_cursor(cache_idx)); + break; + + default: + DEBUG(("Pointer message 0x%x\n", message_type)); + } +} + +/* Process bitmap updates */ +static void +process_bitmap_updates(STREAM s) +{ + uint16 num_updates; + uint16 left, top, right, bottom, width, height; + uint16 cx, cy, bpp, Bpp, compress, bufsize, size; + uint8 *data, *bmpdata; + int i; + + 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; + + DEBUG(("UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,cmp=%d)\n", + left, top, right, bottom, width, height, compress)); + + if (!compress) + { + int y; + bmpdata = (uint8*)xmalloc(width * height * Bpp); + for (y = 0; y < height; y++) + { + in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)], + width * Bpp); + } + ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); + xfree(bmpdata); + continue; + } + + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, size); + in_uint8s(s, 4); /* line_size, final_size */ + in_uint8p(s, data, size); + bmpdata = (uint8*)xmalloc(width * height * Bpp); + if (bitmap_decompress(bmpdata, width, height, data, size, Bpp)) + { + ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); + } + xfree(bmpdata); + } +} + +/* Process a palette update */ +static void +process_palette(STREAM s) +{ + COLOURENTRY *entry; + COLOURMAP map; + HCOLOURMAP hmap; + int i; + uint8 data[1536]; + + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, map.ncolours); + in_uint8s(s, 2); /* pad */ + + map.colours = (COLOURENTRY*)data; + + for (i = 0; i < map.ncolours; i++) + { + entry = &map.colours[i]; + in_uint8(s, entry->red); + in_uint8(s, entry->green); + in_uint8(s, entry->blue); + } + hmap = ui_create_colourmap(&map); + ui_set_colourmap(hmap); +} + +/* Process an update PDU */ +static void +process_update_pdu(STREAM s) +{ + uint16 update_type; + + in_uint16_le(s, update_type); + ui_begin_update(); + switch (update_type) + { + case RDP_UPDATE_ORDERS: + process_orders(s); + break; + + case RDP_UPDATE_BITMAP: + process_bitmap_updates(s); + break; + + case RDP_UPDATE_PALETTE: + process_palette(s); + break; + + case RDP_UPDATE_SYNCHRONIZE: + break; + + default: + unimpl("update %d\n", update_type); + } + ui_end_update(); +} + +/* Process data PDU */ +void +process_data_pdu(STREAM s) +{ + uint8 data_pdu_type; + + in_uint8s(s, 8); /* shareid, pad, streamid, length */ + in_uint8(s, data_pdu_type); + in_uint8s(s, 3); /* compress_type, compress_len */ + + switch (data_pdu_type) + { + case RDP_DATA_PDU_UPDATE: + process_update_pdu(s); + break; + + case RDP_DATA_PDU_POINTER: + process_pointer_pdu(s); + break; + + case RDP_DATA_PDU_BELL: + ui_bell(); + break; + + case RDP_DATA_PDU_LOGON: + /* User logged on */ + break; + + default: + unimpl("data PDU %d\n", data_pdu_type); + } +} + +/* Process incoming packets */ +BOOL +rdp_main_loop(void) +{ + uint8 type; + STREAM s; + BOOL cont = True; + while (cont) + { + s = rdp_recv(&type); + if (s == NULL) + return False; + switch (type) + { + case RDP_PDU_DEMAND_ACTIVE: + process_demand_active(s); + break; + case RDP_PDU_DEACTIVATE: + break; + case RDP_PDU_DATA: + process_data_pdu(s); + break; + case 0: + break; + default: + unimpl("PDU %d\n", type); + } + cont = next_packet < s->end; + } + return True; +} + +/* Establish a connection up to the RDP layer */ +BOOL +rdp_connect(char *server, uint32 flags, char *domain, char *password, + char *command, char *directory) +{ + if (!sec_connect(server)) + return False; + + rdp_send_logon_info(flags, domain, username, password, command, directory); + return True; +} + +/* Disconnect from the RDP layer */ +void +rdp_disconnect(void) +{ + sec_disconnect(); +} diff --git a/noncore/net/opierdesktop/secure.cpp b/noncore/net/opierdesktop/secure.cpp new file mode 100644 index 0000000..5e50f8d --- a/dev/null +++ b/noncore/net/opierdesktop/secure.cpp @@ -0,0 +1,658 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - RDP encryption and licensing + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include "rdesktop.h" + +//#ifdef WITH_OPENSSL +#include <openssl/rc4.h> +#include <openssl/md5.h> +#include <openssl/sha.h> +#include <openssl/bn.h> +//#else +//#include "crypto/rc4.h" +//#include "crypto/md5.h" +//#include "crypto/sha.h" +//#include "crypto/bn.h" +//#endif + +extern char hostname[16]; +extern int g_width; +extern int g_height; +extern int keylayout; +extern BOOL encryption; +extern BOOL licence_issued; +extern int server_bpp; + +static int rc4_key_len; +static RC4_KEY rc4_decrypt_key; +static RC4_KEY rc4_encrypt_key; + +static uint8 sec_sign_key[16]; +static uint8 sec_decrypt_key[16]; +static uint8 sec_encrypt_key[16]; +static uint8 sec_decrypt_update_key[16]; +static uint8 sec_encrypt_update_key[16]; +static uint8 sec_crypted_random[SEC_MODULUS_SIZE]; + +/* + * General purpose 48-byte transformation, using two 32-byte salts (generally, + * a client and server salt) and a global salt value used for padding. + * Both SHA1 and MD5 algorithms are used. + */ +void +sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) +{ + uint8 shasig[20]; + uint8 pad[4]; + SHA_CTX sha; + MD5_CTX md5; + int i; + + for (i = 0; i < 3; i++) + { + memset(pad, salt + i, i + 1); + + SHA1_Init(&sha); + SHA1_Update(&sha, pad, i + 1); + SHA1_Update(&sha, in, 48); + SHA1_Update(&sha, salt1, 32); + SHA1_Update(&sha, salt2, 32); + SHA1_Final(shasig, &sha); + + MD5_Init(&md5); + MD5_Update(&md5, in, 48); + MD5_Update(&md5, shasig, 20); + MD5_Final(&out[i * 16], &md5); + } +} + +/* + * Weaker 16-byte transformation, also using two 32-byte salts, but + * only using a single round of MD5. + */ +void +sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) +{ + MD5_CTX md5; + + MD5_Init(&md5); + MD5_Update(&md5, in, 16); + MD5_Update(&md5, salt1, 32); + MD5_Update(&md5, salt2, 32); + MD5_Final(out, &md5); +} + +/* Reduce key entropy from 64 to 40 bits */ +static void +sec_make_40bit(uint8 * key) +{ + key[0] = 0xd1; + key[1] = 0x26; + key[2] = 0x9e; +} + +/* Generate a session key and RC4 keys, given client and server randoms */ +static void +sec_generate_keys(uint8 * client_key, uint8 * server_key, int rc4_key_size) +{ + uint8 session_key[48]; + uint8 temp_hash[48]; + uint8 input[48]; + + /* Construct input data to hash */ + memcpy(input, client_key, 24); + memcpy(input + 24, server_key, 24); + + /* Generate session key - two rounds of sec_hash_48 */ + sec_hash_48(temp_hash, input, client_key, server_key, 65); + sec_hash_48(session_key, temp_hash, client_key, server_key, 88); + + /* Store first 16 bytes of session key, for generating signatures */ + memcpy(sec_sign_key, session_key, 16); + + /* Generate RC4 keys */ + sec_hash_16(sec_decrypt_key, &session_key[16], client_key, server_key); + sec_hash_16(sec_encrypt_key, &session_key[32], client_key, server_key); + + if (rc4_key_size == 1) + { + DEBUG(("40-bit encryption enabled\n")); + sec_make_40bit(sec_sign_key); + sec_make_40bit(sec_decrypt_key); + sec_make_40bit(sec_encrypt_key); + rc4_key_len = 8; + } + else + { + DEBUG(("128-bit encryption enabled\n")); + rc4_key_len = 16; + } + + /* Save initial RC4 keys as update keys */ + memcpy(sec_decrypt_update_key, sec_decrypt_key, 16); + memcpy(sec_encrypt_update_key, sec_encrypt_key, 16); + + /* Initialise RC4 state arrays */ + RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key); + RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key); +} + +static uint8 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 uint8 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 +}; + +/* Output a uint32 into a buffer (little-endian) */ +void +buf_out_uint32(uint8 * buffer, uint32 value) +{ + buffer[0] = (value) & 0xff; + buffer[1] = (value >> 8) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[3] = (value >> 24) & 0xff; +} + +/* Generate a signature hash, using a combination of SHA1 and MD5 */ +void +sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen) +{ + uint8 shasig[20]; + uint8 md5sig[16]; + uint8 lenhdr[4]; + SHA_CTX sha; + MD5_CTX md5; + + buf_out_uint32(lenhdr, datalen); + + SHA1_Init(&sha); + SHA1_Update(&sha, session_key, keylen); + SHA1_Update(&sha, pad_54, 40); + SHA1_Update(&sha, lenhdr, 4); + SHA1_Update(&sha, data, datalen); + SHA1_Final(shasig, &sha); + + MD5_Init(&md5); + MD5_Update(&md5, session_key, keylen); + MD5_Update(&md5, pad_92, 48); + MD5_Update(&md5, shasig, 20); + MD5_Final(md5sig, &md5); + + memcpy(signature, md5sig, siglen); +} + +/* Update an encryption key - similar to the signing process */ +static void +sec_update(uint8 * key, uint8 * update_key) +{ + uint8 shasig[20]; + SHA_CTX sha; + MD5_CTX md5; + RC4_KEY update; + + SHA1_Init(&sha); + SHA1_Update(&sha, update_key, rc4_key_len); + SHA1_Update(&sha, pad_54, 40); + SHA1_Update(&sha, key, rc4_key_len); + SHA1_Final(shasig, &sha); + + MD5_Init(&md5); + MD5_Update(&md5, update_key, rc4_key_len); + MD5_Update(&md5, pad_92, 48); + MD5_Update(&md5, shasig, 20); + MD5_Final(key, &md5); + + RC4_set_key(&update, rc4_key_len, key); + RC4(&update, rc4_key_len, key, key); + + if (rc4_key_len == 8) + sec_make_40bit(key); +} + +/* Encrypt data using RC4 */ +static void +sec_encrypt(uint8 * data, int length) +{ + static int use_count; + + if (use_count == 4096) + { + sec_update(sec_encrypt_key, sec_encrypt_update_key); + RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key); + use_count = 0; + } + + RC4(&rc4_encrypt_key, length, data, data); + use_count++; +} + +/* Decrypt data using RC4 */ +static void +sec_decrypt(uint8 * data, int length) +{ + static int use_count; + + if (use_count == 4096) + { + sec_update(sec_decrypt_key, sec_decrypt_update_key); + RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key); + use_count = 0; + } + + RC4(&rc4_decrypt_key, length, data, data); + use_count++; +} + +static void +reverse(uint8 * p, int len) +{ + int i, j; + uint8 temp; + + for (i = 0, j = len - 1; i < j; i++, j--) + { + temp = p[i]; + p[i] = p[j]; + p[j] = temp; + } +} + +/* Perform an RSA public key encryption operation */ +static void +sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint8 * modulus, uint8 * exponent) +{ + BN_CTX *ctx; + BIGNUM mod, exp, x, y; + uint8 inr[SEC_MODULUS_SIZE]; + int outlen; + + reverse(modulus, SEC_MODULUS_SIZE); + reverse(exponent, SEC_EXPONENT_SIZE); + memcpy(inr, in, len); + reverse(inr, len); + + ctx = BN_CTX_new(); + BN_init(&mod); + BN_init(&exp); + BN_init(&x); + BN_init(&y); + + BN_bin2bn(modulus, SEC_MODULUS_SIZE, &mod); + BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp); + BN_bin2bn(inr, len, &x); + BN_mod_exp(&y, &x, &exp, &mod, ctx); + outlen = BN_bn2bin(&y, out); + reverse(out, outlen); + if (outlen < SEC_MODULUS_SIZE) + memset(out + outlen, 0, SEC_MODULUS_SIZE - outlen); + + BN_free(&y); + BN_clear_free(&x); + BN_free(&exp); + BN_free(&mod); + BN_CTX_free(ctx); +} + +/* Initialise secure transport packet */ +STREAM +sec_init(uint32 flags, int maxlen) +{ + int hdrlen; + STREAM s; + + if (!licence_issued) + hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; + else + hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; + s = mcs_init(maxlen + hdrlen); + s_push_layer(s, sec_hdr, hdrlen); + + return s; +} + +/* Transmit secure transport packet */ +void +sec_send(STREAM s, uint32 flags) +{ + int datalen; + + s_pop_layer(s, sec_hdr); + if (!licence_issued || (flags & SEC_ENCRYPT)) + out_uint32_le(s, flags); + + if (flags & SEC_ENCRYPT) + { + flags &= ~SEC_ENCRYPT; + datalen = s->end - s->p - 8; + +#if WITH_DEBUG + DEBUG(("Sending encrypted packet:\n")); + hexdump(s->p + 8, datalen); +#endif + + sec_sign(s->p, 8, sec_sign_key, rc4_key_len, s->p + 8, datalen); + sec_encrypt(s->p + 8, datalen); + } + + mcs_send(s); +} + +/* Transfer the client random to the server */ +static void +sec_establish_key(void) +{ + uint32 length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE; + uint32 flags = SEC_CLIENT_RANDOM; + STREAM s; + + s = sec_init(flags, 76); + + out_uint32_le(s, length); + out_uint8p(s, sec_crypted_random, SEC_MODULUS_SIZE); + out_uint8s(s, SEC_PADDING_SIZE); + + s_mark_end(s); + sec_send(s, flags); +} + +/* Output connect initial data blob */ +static void +sec_out_mcs_data(STREAM s) +{ + int hostlen = 2 * strlen(hostname); + + if (hostlen > 30) + hostlen = 30; + + out_uint16_be(s, 5); /* unknown */ + out_uint16_be(s, 0x14); + out_uint8(s, 0x7c); + out_uint16_be(s, 1); + + out_uint16_be(s, (158 | 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); /* "Duca" ?! */ + out_uint16_be(s, (144 | 0x8000)); /* remaining length */ + + /* Client information */ + out_uint16_le(s, SEC_TAG_CLI_INFO); + out_uint16_le(s, 136); /* length */ + out_uint16_le(s, 1); + out_uint16_le(s, 8); + out_uint16_le(s, g_width); + out_uint16_le(s, g_height); + out_uint16_le(s, 0xca01); + out_uint16_le(s, 0xaa03); + out_uint32_le(s, keylayout); + out_uint32_le(s, 419); /* client build? we are 419 compatible :-) */ + + /* Unicode name of client, padded to 32 bytes */ + rdp_out_unistr(s, hostname, hostlen); + out_uint8s(s, 30 - hostlen); + + out_uint32_le(s, 4); + out_uint32(s, 0); + out_uint32_le(s, 12); + out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ + + switch (server_bpp) + { + case 8: + out_uint16_le(s, 0xca01); + break; + case 15: + out_uint16_le(s, 0xca02); + break; + case 16: + out_uint16_le(s, 0xca03); + break; + case 24: + out_uint16_le(s, 0xca04); + break; + } + out_uint16(s, 0); + + /* Client encryption settings */ + out_uint16_le(s, SEC_TAG_CLI_CRYPT); + out_uint16_le(s, 8); /* length */ + out_uint32_le(s, encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */ + s_mark_end(s); +} + +/* Parse a public key structure */ +static BOOL +sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent) +{ + uint32 magic, modulus_len; + + in_uint32_le(s, magic); + if (magic != SEC_RSA_MAGIC) + { + error("RSA magic 0x%x\n", magic); + return False; + } + + in_uint32_le(s, modulus_len); + if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE) + { + error("modulus len 0x%x\n", modulus_len); + return False; + } + + in_uint8s(s, 8); /* modulus_bits, unknown */ + in_uint8p(s, *exponent, SEC_EXPONENT_SIZE); + in_uint8p(s, *modulus, SEC_MODULUS_SIZE); + in_uint8s(s, SEC_PADDING_SIZE); + + return s_check(s); +} + +/* Parse a crypto information structure */ +static BOOL +sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, + uint8 ** server_random, uint8 ** modulus, uint8 ** exponent) +{ + uint32 crypt_level, random_len, rsa_info_len; + uint16 tag, length; + uint8 *next_tag, *end; + + in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ + in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */ + if (crypt_level == 0) /* no encryptation */ + return False; + in_uint32_le(s, random_len); + in_uint32_le(s, rsa_info_len); + + if (random_len != SEC_RANDOM_SIZE) + { + error("random len %d\n", random_len); + return False; + } + + in_uint8p(s, *server_random, random_len); + + /* RSA info */ + end = s->p + rsa_info_len; + if (end > s->end) + return False; + + in_uint8s(s, 12); /* unknown */ + + while (s->p < end) + { + in_uint16_le(s, tag); + in_uint16_le(s, length); + + next_tag = s->p + length; + + switch (tag) + { + case SEC_TAG_PUBKEY: + if (!sec_parse_public_key(s, modulus, exponent)) + return False; + + break; + + case SEC_TAG_KEYSIG: + /* Is this a Microsoft key that we just got? */ + /* Care factor: zero! */ + break; + + default: + unimpl("crypt tag 0x%x\n", tag); + } + + s->p = next_tag; + } + + return s_check_end(s); +} + +/* Process crypto information blob */ +static void +sec_process_crypt_info(STREAM s) +{ + uint8 *server_random, *modulus, *exponent; + uint8 client_random[SEC_RANDOM_SIZE]; + uint32 rc4_key_size; + + if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent)) + return; + + /* Generate a client random, and hence determine encryption keys */ + generate_random(client_random); + sec_rsa_encrypt(sec_crypted_random, client_random, SEC_RANDOM_SIZE, modulus, exponent); + sec_generate_keys(client_random, server_random, rc4_key_size); +} + +/* Process connect response data blob */ +static void +sec_process_mcs_data(STREAM s) +{ + uint16 tag, length; + uint8 *next_tag; + uint8 len; + + in_uint8s(s, 21); /* header */ + 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); + + if (length <= 4) + return; + + next_tag = s->p + length - 4; + + switch (tag) + { + case SEC_TAG_SRV_INFO: + case SEC_TAG_SRV_3: + break; + + case SEC_TAG_SRV_CRYPT: + sec_process_crypt_info(s); + break; + + default: + unimpl("response tag 0x%x\n", tag); + } + + s->p = next_tag; + } +} + +/* Receive secure transport packet */ +STREAM +sec_recv(void) +{ + uint32 sec_flags; + STREAM s; + + while ((s = mcs_recv()) != NULL) + { + if (encryption || !licence_issued) + { + in_uint32_le(s, sec_flags); + + if (sec_flags & SEC_LICENCE_NEG) + { + licence_process(s); + continue; + } + + if (sec_flags & SEC_ENCRYPT) + { + in_uint8s(s, 8); /* signature */ + sec_decrypt(s->p, s->end - s->p); + } + } + + return s; + } + + return NULL; +} + +/* Establish a secure connection */ +BOOL +sec_connect(char *server) +{ + struct stream mcs_data; + + /* We exchange some RDP data during the MCS-Connect */ + mcs_data.size = 512; + mcs_data.p = mcs_data.data = (unsigned char*)xmalloc(mcs_data.size); + sec_out_mcs_data(&mcs_data); + + if (!mcs_connect(server, &mcs_data)) + return False; + + sec_process_mcs_data(&mcs_data); + if (encryption) + sec_establish_key(); + xfree(mcs_data.data); + return True; +} + +/* Disconnect a connection */ +void +sec_disconnect(void) +{ + mcs_disconnect(); +} diff --git a/noncore/net/opierdesktop/tcp.cpp b/noncore/net/opierdesktop/tcp.cpp new file mode 100644 index 0000000..0a2ca3e --- a/dev/null +++ b/noncore/net/opierdesktop/tcp.cpp @@ -0,0 +1,181 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - TCP layer + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +#include <unistd.h> /* select read write close */ +#include <sys/socket.h> /* socket connect setsockopt */ +#include <sys/time.h> /* timeval */ +#include <netdb.h> /* gethostbyname */ +#include <netinet/in.h> /* sockaddr_in */ +#include <netinet/tcp.h> /* TCP_NODELAY */ +#include <arpa/inet.h> /* inet_addr */ +#include <fcntl.h> +#include <errno.h> /* errno */ +#include "rdesktop.h" + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif + +static int sock; +static struct stream in; +static struct stream out; +extern int tcp_port_rdp; + +/* Initialise TCP transport data packet */ +STREAM +tcp_init(unsigned int maxlen) +{ + if (maxlen > out.size) + { + out.data = (unsigned char*)xrealloc(out.data, maxlen); + out.size = maxlen; + } + + out.p = out.data; + out.end = out.data + out.size; + return &out; +} + +/* Send TCP transport data packet */ +void +tcp_send(STREAM s) +{ + int length = s->end - s->data; + int sent, total = 0; + + while (total < length) + { + sent = send(sock, s->data + total, length - total, 0); + if (sent == -1 && errno == EWOULDBLOCK) + { + usleep(1000); + } + else if (sent <= 0) + { + error("send: %s\n", strerror(errno)); + return; + } + else + total += sent; + } +} + +/* Receive a message on the TCP layer */ +STREAM +tcp_recv(unsigned int length) +{ + int rcvd = 0; + + if (length > in.size) + { + in.data = (unsigned char*)xrealloc(in.data, length); + in.size = length; + } + + in.end = in.p = in.data; + + while (length > 0) + { + if (!ui_select(sock)) + /* User quit */ + return NULL; + + rcvd = recv(sock, in.end, length, 0); + if (rcvd == -1 && errno == EWOULDBLOCK) + { + usleep(1000); + } + else if (rcvd == -1) + { + error("recv: %s\n", strerror(errno)); + return NULL; + } + else if (rcvd == 0) + return NULL; + else + { + in.end += rcvd; + length -= rcvd; + } + } + + return ∈ +} + +/* Establish a connection on the TCP layer */ +BOOL +tcp_connect(char *server) +{ + struct hostent *nslookup; + struct sockaddr_in servaddr; + int l_true = 1; + + if ((nslookup = gethostbyname(server)) != NULL) + { + memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr)); + } + else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE) + { + error("%s: unable to resolve host\n", server); + return False; + } + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error("socket: %s\n", strerror(errno)); + return False; + } + + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(tcp_port_rdp); + + if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) + { + error("connect: %s\n", strerror(errno)); + close(sock); + return False; + } + + /* set non blocking */ + { + int op; + op = fcntl(sock, F_GETFL); + op |= O_NONBLOCK; + fcntl(sock, F_SETFL, op); + } + +// fcntl(sock, O_NONBLOCK); + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &l_true, sizeof(l_true)); + + in.size = 4096; + in.data = (unsigned char*)xmalloc(in.size); + + out.size = 4096; + out.data = (unsigned char*)xmalloc(out.size); + + return True; +} + +/* Disconnect on the TCP layer */ +void +tcp_disconnect(void) +{ + close(sock); +} diff --git a/noncore/net/opierdesktop/types.h b/noncore/net/opierdesktop/types.h new file mode 100644 index 0000000..4cb59e6 --- a/dev/null +++ b/noncore/net/opierdesktop/types.h @@ -0,0 +1,110 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Common data types + Copyright (C) Matthew Chapman 1999-2002 + + 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. +*/ + +typedef int BOOL; + +#ifndef True +#define True (1) +#define False (0) +#endif + +typedef unsigned char uint8; +typedef signed char sint8; +typedef unsigned short uint16; +typedef signed short sint16; +typedef unsigned int uint32; +typedef signed int sint32; + +typedef void *HBITMAP; +typedef void *HGLYPH; +typedef void *HCOLOURMAP; +typedef void *HCURSOR; + +typedef struct _COLOURENTRY +{ + uint8 red; + uint8 green; + uint8 blue; + +} +COLOURENTRY; + +typedef struct _COLOURMAP +{ + uint16 ncolours; + COLOURENTRY *colours; + +} +COLOURMAP; + +typedef struct _BOUNDS +{ + sint16 left; + sint16 top; + sint16 right; + sint16 bottom; + +} +BOUNDS; + +typedef struct _PEN +{ + uint8 style; + uint8 width; + uint32 colour; + +} +PEN; + +typedef struct _BRUSH +{ + uint8 xorigin; + uint8 yorigin; + uint8 style; + uint8 pattern[8]; + +} +BRUSH; + +typedef struct _FONTGLYPH +{ + sint16 offset; + sint16 baseline; + uint16 width; + uint16 height; + HBITMAP pixmap; + +} +FONTGLYPH; + +typedef struct _DATABLOB +{ + void *data; + int size; + +} +DATABLOB; + +typedef struct _key_translation +{ + uint8 scancode; + uint16 modifiers; +} +key_translation; |