diff --git a/ANNOUNCE b/ANNOUNCE new file mode 100644 index 0000000..4f3d251 --- /dev/null +++ b/ANNOUNCE @@ -0,0 +1,33 @@ +=============================== +ANNOUNCING rdesktop 0.9.0alpha1 +=============================== + +rdesktop is an open source client for Windows NT Terminal Server, +capable of natively speaking its Remote Desktop Protocol. No server +extensions are required. + +0.9.0alpha1 is a milestone release including experimental support for +much of the protocol. It is NOT a stable, production-quality release. +Users should be prepared to submit bug reports and, ideally, patches. + +The current X-Windows driver is rather limited - an Xlib guru's +assistance would be appreciated. In particular, this version requires +the X display to support windows of 8-bit depth, which in most cases +means running X in 8-bit mode. Keyboard mapping may also be problematic. + +The -l option will disable licence negotiation, which is probably +what you want during testing. + +Tested platforms include Linux, Solaris and IRIX, but it is should be +fairly straight-forward to port to other platforms and even windowing +systems. + +rdesktop is released under the GNU Public License. + +See http://www.cse.unsw.edu.au/~matthewc/rdesktop/ for more information +and download instructions. Please send feedback to me. + +Cheers, + +Matt Chapman +rdesktop Author diff --git a/Makefile b/Makefile index 3c0bb89..888c591 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,24 @@ ############################################## # rdesktop: A Remote Desktop Protocol client # -# Linux Makefile # +# Basic Makefile # # Copyright (C) Matthew Chapman 1999-2000 # ############################################## -CC = gcc -CFLAGS = -g -Wall -DDUMP -LIBS = -L/usr/X11R6/lib -lX11 -OBJECTS = client.o parse.o tcp.o iso.o mcs.o rdp.o process.o bitmap.o cache.o xwin.o misc.o +# Uncomment to enable debugging +# DEBUG = -g -DRDP_DEBUG -rdesktop: $(OBJECTS) - @$(CC) $(CFLAGS) -o rdesktop $(LIBS) $(OBJECTS) +CC = gcc +CFLAGS = -O2 -Wall $(DEBUG) +LIBS = -L/usr/X11R6/lib -lX11 + +RDPOBJ = rdesktop.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o xwin.o +CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/arith.o + +rdesktop: $(RDPOBJ) $(CRYPTOBJ) + @$(CC) $(CFLAGS) -o rdesktop $(LIBS) $(RDPOBJ) $(CRYPTOBJ) proto: - @cproto -D MAKE_PROTO -o proto.h *.c + @cproto -DMAKE_PROTO -o proto.h *.c clean: - rm -f *.o + rm -f *.o crypto/*.o *~ diff --git a/bitmap.c b/bitmap.c index 1a558a1..811cedb 100644 --- a/bitmap.c +++ b/bitmap.c @@ -18,7 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "rdesktop.h" #define CVAL(p) (*(p++)) #define SVAL(p) ((*((p++) + 1) << 8) | CVAL(p)) @@ -30,11 +30,11 @@ BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size) { unsigned char *end = input + size; - unsigned char *prevline, *line = NULL; + unsigned char *prevline = NULL, *line = NULL; int opcode, count, offset, isfillormix, x = width; int lastopcode = -1, insertmix = False; - uint8 code, colour1, colour2, mask, mixmask; - uint8 mix = 0xff; + uint8 code, colour1 = 0, colour2 = 0; + uint8 mixmask, mask = 0, mix = 0xff; while (input < end) { diff --git a/cache.c b/cache.c index 787da07..8b1692f 100644 --- a/cache.c +++ b/cache.c @@ -18,70 +18,84 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "rdesktop.h" -HBITMAP cache_get_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx) +#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(conn->bmpcache)) - && (cache_idx < NUM_ELEMENTS(conn->bmpcache[0]))) + if ((cache_id < NUM_ELEMENTS(bmpcache)) + && (cache_idx < NUM_ELEMENTS(bmpcache[0]))) { - bitmap = conn->bmpcache[cache_id][cache_idx]; + bitmap = bmpcache[cache_id][cache_idx]; if (bitmap != NULL) return bitmap; } - ERROR("Bitmap %d:%d not found\n", cache_id, cache_idx); + ERROR("get bitmap %d:%d\n", cache_id, cache_idx); return NULL; } -void cache_put_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx, HBITMAP bitmap) +/* 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(conn->bmpcache)) - && (cache_idx < NUM_ELEMENTS(conn->bmpcache[0]))) + if ((cache_id < NUM_ELEMENTS(bmpcache)) + && (cache_idx < NUM_ELEMENTS(bmpcache[0]))) { - old = conn->bmpcache[cache_id][cache_idx]; + old = bmpcache[cache_id][cache_idx]; if (old != NULL) - ui_destroy_bitmap(conn->wnd, old); + ui_destroy_bitmap(old); - conn->bmpcache[cache_id][cache_idx] = bitmap; + bmpcache[cache_id][cache_idx] = bitmap; } else { - ERROR("Bitmap %d:%d past end of cache\n", cache_id, cache_idx); + ERROR("put bitmap %d:%d\n", cache_id, cache_idx); } } -FONT_GLYPH *cache_get_font(HCONN conn, uint8 font, uint16 character) -{ - FONT_GLYPH *glyph; - if ((font < NUM_ELEMENTS(conn->fontcache)) - && (character < NUM_ELEMENTS(conn->fontcache[0]))) +/* 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 = &conn->fontcache[font][character]; + glyph = &fontcache[font][character]; if (glyph->pixmap != NULL) return glyph; } - ERROR("Font %d character %d not found\n", font, character); + ERROR("get font %d:%d\n", font, character); return NULL; } -void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline, +/* Store a glyph in the font cache */ +void cache_put_font(uint8 font, uint32 character, uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap) { - FONT_GLYPH *glyph; + FONTGLYPH *glyph; - if ((font < NUM_ELEMENTS(conn->fontcache)) - && (character < NUM_ELEMENTS(conn->fontcache[0]))) + if ((font < NUM_ELEMENTS(fontcache)) + && (character < NUM_ELEMENTS(fontcache[0]))) { - glyph = &conn->fontcache[font][character]; + glyph = &fontcache[font][character]; if (glyph->pixmap != NULL) - ui_destroy_glyph(conn->wnd, glyph->pixmap); + ui_destroy_glyph(glyph->pixmap); glyph->baseline = baseline; glyph->width = width; @@ -90,42 +104,77 @@ void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline, } else { - ERROR("Font %d character %d past end of cache\n", - font, character); + ERROR("put font %d:%d\n", font, character); } } -BLOB *cache_get_text(HCONN conn, uint8 cache_id) -{ - BLOB *text; - if (cache_id < NUM_ELEMENTS(conn->textcache)) +/* 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 = &conn->textcache[cache_id]; + text = &textcache[cache_id]; if (text->data != NULL) return text; } - ERROR("Text cache id %d not found\n", cache_id); + ERROR("get text %d\n", cache_id); return NULL; } -void cache_put_text(HCONN conn, uint8 cache_id, void *data, int length) +/* Store a text item in the cache */ +void cache_put_text(uint8 cache_id, void *data, int length) { - BLOB *text; + DATABLOB *text; - if (cache_id < NUM_ELEMENTS(conn->textcache)) + if (cache_id < NUM_ELEMENTS(textcache)) { - text = &conn->textcache[cache_id]; + text = &textcache[cache_id]; if (text->data != NULL) - free(text->data); + xfree(text->data); - text->data = malloc(length); + text->data = xmalloc(length); text->size = length; memcpy(text->data, data, length); } else { - ERROR("Text cache id %d past end of cache\n", cache_id); + 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, uint32 length) +{ + 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, uint32 length, uint8 *data) +{ + if ((offset + length) <= sizeof(deskcache)) + { + memcpy(&deskcache[offset], data, length); + } + else + { + ERROR("put desktop %d:%d\n", offset, length); + } +} + diff --git a/client.c b/client.c deleted file mode 100644 index 54c295e..0000000 --- a/client.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Entrypoint and utility functions - Copyright (C) Matthew Chapman 1999-2000 - - 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 "includes.h" - -int main(int argc, char *argv[]) -{ - HCONN conn; - int width = 640; - int height = 480; - - fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); - fprintf(stderr, "Version 0.9.0-prealpha. Copyright (C) 1999-2000 Matt Chapman.\n\n"); - - if (argc < 2) - { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - if ((conn = rdp_connect(argv[1], width, height)) == NULL) - return 1; - - fprintf(stderr, "Connection successful.\n"); - - conn->wnd = ui_create_window(conn, width, height); - rdp_main_loop(conn); - - ui_destroy_window(conn->wnd); - rdp_disconnect(conn); - - return 0; -} diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..7724a85 --- /dev/null +++ b/constants.h @@ -0,0 +1,208 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Miscellaneous protocol constants + Copyright (C) Matthew Chapman 1999-2000 + + 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_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 +}; + +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_QUIET 0x1000 +#define KBD_FLAG_DOWN 0x4000 +#define KBD_FLAG_UP 0x8000 + +#define MOUSE_FLAG_MOVE 0x0800 +#define MOUSE_FLAG_BUTTON1 0x1000 +#define MOUSE_FLAG_BUTTON2 0x2000 +#define MOUSE_FLAG_BUTTON3 0x4000 +#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_OR 0xe + +#define MIX_TRANSPARENT 0 +#define MIX_OPAQUE 1 + +#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" diff --git a/iso.c b/iso.c index 72ff979..c94e4c0 100644 --- a/iso.c +++ b/iso.c @@ -18,157 +18,136 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "rdesktop.h" -/* Establish a connection up to the ISO layer */ -HCONN iso_connect(char *server) +/* Send a self-contained ISO PDU */ +static void iso_send_msg(uint8 code) { - HCONN conn; - uint8 code; + STREAM s; - if ((conn = tcp_connect(server)) == NULL) - return NULL; + s = tcp_init(11); - iso_send_msg(conn, ISO_PDU_CR); + out_uint8(s, 3); /* version */ + out_uint8(s, 0); /* reserved */ + out_uint16_be(s, 11); /* length */ - if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_CC)) - { - ERROR("ISO error, expected CC\n"); - tcp_disconnect(conn); - return NULL; - } + 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 */ - return conn; -} - -/* Disconnect from the ISO layer */ -void iso_disconnect(HCONN conn) -{ - iso_send_msg(conn, ISO_PDU_DR); - tcp_disconnect(conn); -} - -/* Send self-contained ISO message identified by code */ -BOOL iso_send_msg(HCONN conn, uint8 code) -{ - TPKT tpkt; - TPDU tpdu; - - iso_make_tpkt(&tpkt, 11); - iso_io_tpkt(&conn->out, &tpkt); - iso_make_tpdu(&tpdu, code); - iso_io_tpdu(&conn->out, &tpdu); - MARK_END(conn->out); - return tcp_send(conn); + s_mark_end(s); + tcp_send(s); } /* Receive a message on the ISO layer, return code */ -BOOL iso_recv_msg(HCONN conn, uint8 *code) +static STREAM iso_recv_msg(uint8 *code) { - TPDU tpdu; - TPKT tpkt; - BOOL res; + STREAM s; + uint16 length; + uint8 version; - res = tcp_recv(conn, 4); - res = res ? iso_io_tpkt(&conn->in, &tpkt) : False; - res = res ? tcp_recv(conn, tpkt.length - 4) : False; - res = res ? iso_io_tpdu(&conn->in, &tpdu) : False; + s = tcp_recv(4); + if (s == NULL) + return False; - *code = tpdu.code; - return res; + in_uint8(s, version); + if (version != 3) + { + ERROR("TPKT v%d\n", version); + return False; + } + + in_uint8s(s, 1); /* pad */ + in_uint16_be(s, length); + + s = tcp_recv(length - 4); + if (s == NULL) + return False; + + 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 */ -void iso_init(struct connection *conn) +STREAM iso_init(int length) { - PUSH_LAYER(conn->out, iso_offset, 7); + 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 */ -BOOL iso_recv(HCONN conn) +STREAM iso_recv() +{ + STREAM s; + uint8 code; + + s = iso_recv_msg(&code); + if ((s == NULL) || (code != ISO_PDU_DT)) + { + ERROR("expected DT, got %d\n", code); + return False; + } + + return s; +} + +/* Establish a connection up to the ISO layer */ +BOOL iso_connect(char *server) { uint8 code; - if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_DT)) + if (!tcp_connect(server)) + return False; + + iso_send_msg(ISO_PDU_CR); + + if ((iso_recv_msg(&code) == NULL) || (code != ISO_PDU_CC)) { - ERROR("ISO error, expected DT\n"); + ERROR("expected CC, got %d\n", code); + tcp_disconnect(); return False; } return True; } -/* Receive ISO transport data packet */ -BOOL iso_send(HCONN conn) +/* Disconnect from the ISO layer */ +void iso_disconnect() { - TPKT tpkt; - TPDU tpdu; - - POP_LAYER(conn->out, iso_offset); - iso_make_tpkt(&tpkt, conn->out.end); - iso_io_tpkt(&conn->out, &tpkt); - iso_make_tpdu(&tpdu, ISO_PDU_DT); - iso_io_tpdu(&conn->out, &tpdu); - return tcp_send(conn); -} - -/* Initialise a TPKT structure */ -void iso_make_tpkt(TPKT *tpkt, int length) -{ - tpkt->version = 3; - tpkt->reserved = 0; - tpkt->length = length; -} - -/* Marshall/demarshall a TPKT structure */ -BOOL iso_io_tpkt(STREAM s, TPKT *tpkt) -{ - if (!prs_io_uint8(s, &tpkt->version)) - return False; - - if (tpkt->version != 3) - { - ERROR("Wrong TPKT version %d\n", tpkt->version); - return False; - } - - if (!prs_io_uint8 (s, &tpkt->reserved)) - return False; - - if (!msb_io_uint16(s, &tpkt->length)) - return False; - - return True; -} - -/* Initialise a TPDU structure */ -void iso_make_tpdu(TPDU *tpdu, uint8 code) -{ - tpdu->hlen = (code == ISO_PDU_DT) ? 2 : 6; - tpdu->code = code; - tpdu->dst_ref = tpdu->src_ref = 0; - tpdu->class = 0; - tpdu->eot = 0x80; -} - -/* Marshall/demarshall a TPDU structure */ -BOOL iso_io_tpdu(STREAM s, TPDU *tpdu) -{ - BOOL res = True; - - res = res ? prs_io_uint8 (s, &tpdu->hlen) : False; - res = res ? prs_io_uint8 (s, &tpdu->code) : False; - - if (tpdu->code == ISO_PDU_DT) - { - res = res ? prs_io_uint8(s, &tpdu->eot) : False; - } - else - { - res = res ? msb_io_uint16(s, &tpdu->dst_ref) : False; - res = res ? msb_io_uint16(s, &tpdu->src_ref) : False; - res = res ? prs_io_uint8 (s, &tpdu->class ) : False; - } - - return res; + iso_send_msg(ISO_PDU_DR); + tcp_disconnect(); } diff --git a/iso.h b/iso.h deleted file mode 100644 index 4695ae6..0000000 --- a/iso.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Protocol services - ISO layer - Copyright (C) Matthew Chapman 1999-2000 - - 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. -*/ - -/* 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 */ -}; - -/* ISO transport encapsulation over TCP (RFC2126) */ -typedef struct _TPKT -{ - uint8 version; - uint8 reserved; - uint16 length; - -} TPKT; - -/* ISO transport protocol PDU (RFC905) */ -typedef struct _TPDU -{ - uint8 hlen; - uint8 code; - - /* CR, CC, DR PDUs */ - uint16 dst_ref; - uint16 src_ref; - uint8 class; - - /* DT PDU */ - uint8 eot; - -} TPDU; diff --git a/licence.c b/licence.c new file mode 100644 index 0000000..ee8761a --- /dev/null +++ b/licence.c @@ -0,0 +1,240 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP licensing negotiation + Copyright (C) Matthew Chapman 1999-2000 + + 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 "crypto/rc4.h" + +extern char username[16]; +extern char hostname[16]; +extern BOOL licence; + +static uint8 licence_key[16]; +static uint8 licence_sign_key[16]; + +/* Generate a session key and RC4 keys, given client and server randoms */ +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); +} + +/* 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 = 120 + 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_uint32_le(s, 0xff010000); + + 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; + + /* 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); + + /* Send a certificate request back to the server */ + 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); + + /* Construct HWID */ + buf_out_uint32(hwid, 2); + strncpy(hwid + 4, hostname, LICENCE_HWID_SIZE - 4); + + /* Generate a signature for a buffer of token and HWID */ + memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); + memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); + sec_sign(out_sig, licence_sign_key, 16, + sealed_buffer, sizeof(sealed_buffer)); + + /* Deliberately break signature if licencing disabled */ + if (!licence) + memset(out_sig, 0, sizeof(out_sig)); + + /* 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; + + /* We should save the licence here */ + STATUS("Server issued licence.\n"); +} + +/* 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_RESULT: + break; + + default: + NOTIMP("licence tag 0x%x\n", tag); + } +} diff --git a/mcs.c b/mcs.c index d6ee215..1731d52 100644 --- a/mcs.c +++ b/mcs.c @@ -18,567 +18,358 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "rdesktop.h" -/* Establish a connection up to the MCS layer */ -HCONN mcs_connect(char *server) +uint16 mcs_userid; + +/* Parse an ASN.1 BER header */ +static BOOL ber_parse_header(STREAM s, int tagval, int *length) { - HCONN conn; - MCS_CONNECT_RESPONSE mcr; - MCS_AUCF aucf; + int tag, len; - if ((conn = iso_connect(server)) == NULL) - return NULL; - - mcs_send_connect_initial(conn); - if (!iso_recv(conn) || !mcs_io_connect_response(&conn->in, &mcr)) + if (tagval > 0xff) { - ERROR("MCS error, expected Connect-Response\n"); - iso_disconnect(conn); - return NULL; + in_uint16_be(s, tag); + } + else + { + in_uint8(s, tag) } - if (mcr.result != 0) + if (tag != tagval) { - ERROR("MCS-Connect-Initial failed, result %d\n", mcr.result); - iso_disconnect(conn); - return NULL; + ERROR("expected tag %d, got %d\n", tagval, tag); + return False; } - mcs_send_edrq(conn); + in_uint8(s, len); - mcs_send_aurq(conn); - if (!iso_recv(conn) || !mcs_io_aucf(&conn->in, &aucf)) + if (len & 0x80) { - ERROR("MCS error, expected AUcf\n"); - mcs_disconnect(conn); - return NULL; + len &= ~0x80; + *length = 0; + while (len--) + next_be(s, *length); } + else *length = len; - if (aucf.result != 0) - { - ERROR("AUrq failed, result %d\n", mcr.result); - mcs_disconnect(conn); - return NULL; - } - - conn->mcs_userid = aucf.userid; - - if (!mcs_join_channel(conn, aucf.userid + 1001) - || !mcs_join_channel(conn, MCS_GLOBAL_CHANNEL)) - { - mcs_disconnect(conn); - return NULL; - } - - return conn; + return s_check(s); } -BOOL mcs_join_channel(HCONN conn, uint16 chanid) +/* Output an ASN.1 BER header */ +static void ber_out_header(STREAM s, int tagval, int length) { - MCS_CJCF cjcf; - - mcs_send_cjrq(conn, chanid); - if (!iso_recv(conn) || !mcs_io_cjcf(&conn->in, &cjcf)) + if (tagval > 0xff) { - ERROR("MCS error, expected CJcf\n"); + 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) +{ + 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; + 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; } - if (cjcf.result != 0) + 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("CJrq failed, result %d\n", cjcf.result); + WARN("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() +{ + 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() +{ + 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() +{ + 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() +{ + 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(HCONN conn) +void mcs_disconnect() { - /* Not complete */ - iso_disconnect(conn); + iso_disconnect(); } - -/* Send a Connect-Initial message */ -void mcs_send_connect_initial(HCONN conn) -{ - MCS_CONNECT_INITIAL mci; - - iso_init(conn); - mcs_make_connect_initial(&mci); - mcs_io_connect_initial(&conn->out, &mci); - MARK_END(conn->out); - iso_send(conn); -} - -/* Send a EDrq message */ -void mcs_send_edrq(HCONN conn) -{ - MCS_EDRQ edrq; - - iso_init(conn); - edrq.height = edrq.interval = 1; - mcs_io_edrq(&conn->out, &edrq); - MARK_END(conn->out); - iso_send(conn); -} - -/* Send a AUrq message */ -void mcs_send_aurq(HCONN conn) -{ - MCS_AURQ aurq; - - iso_init(conn); - mcs_io_aurq(&conn->out, &aurq); - MARK_END(conn->out); - iso_send(conn); -} - -/* Send a CJrq message */ -void mcs_send_cjrq(HCONN conn, uint16 chanid) -{ - MCS_CJRQ cjrq; - - iso_init(conn); - cjrq.userid = conn->mcs_userid; - cjrq.chanid = chanid; - mcs_io_cjrq(&conn->out, &cjrq); - MARK_END(conn->out); - iso_send(conn); -} - -/* Initialise MCS transport data packet */ -void mcs_init_data(HCONN conn) -{ - iso_init(conn); - PUSH_LAYER(conn->out, mcs_offset, 8); -} - -/* Transmit MCS transport data packet */ -void mcs_send_data(HCONN conn, uint16 chanid, BOOL request) -{ - MCS_DATA dt; - - POP_LAYER(conn->out, mcs_offset); - dt.userid = conn->mcs_userid; - dt.chanid = chanid; - dt.flags = 0x70; - dt.length = conn->out.end - conn->out.offset - 8; - mcs_io_data(&conn->out, &dt, request); - iso_send(conn); -} - -/* Receive a message on the MCS layer */ -BOOL mcs_recv(HCONN conn, BOOL request) -{ - MCS_DATA data; - - if (!iso_recv(conn) || !mcs_io_data(&conn->in, &data, request)) - return False; - - conn->in.rdp_offset = conn->in.offset; - return True; -} - -/* Initialise a DOMAIN_PARAMS structure */ -void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels, - uint16 max_users, uint16 max_tokens, uint16 max_pdusize) -{ - dp->max_channels = max_channels; - dp->max_users = max_users; - dp->max_tokens = max_tokens; - dp->num_priorities = 1; - dp->min_throughput = 0; - dp->max_height = 1; - dp->max_pdusize = max_pdusize; - dp->ver_protocol = 2; -} - -/* RDP-specific 'user data'. Let's just get this right for now - to be - decoded later. */ -char precanned_connect_userdata[] = { - 0x00,0x05,0x00,0x14,0x7c,0x00,0x01,0x80,0x9e,0x00,0x08,0x00,0x10,0x00, - 0x01,0xc0,0x00,0x44,0x75,0x63,0x61,0x80,0x90,0x01,0xc0,0x88,0x00,0x01, - 0x00,0x08,0x00,0x80,0x02,0xe0,0x01,0x01,0xca,0x03,0xaa,0x09,0x04,0x00, - 0x00,0xa3,0x01,0x00,0x00,0x52,0x00,0x45,0x00,0x53,0x00,0x31,0x00,0x2d, - 0x00,0x4e,0x00,0x45,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x01,0xca,0x00,0x00,0x02,0xc0,0x08,0x00, - /* encryption disabled */ 0x00,0x00,0x00,0x00 }; - -char precanned_connect_userdata_e[] = { -0x00, -0x05,0x00,0x14,0x7c,0x00,0x01,0x80,0x9e,0x00,0x08,0x00,0x10,0x00,0x01,0xc0,0x00, -0x44,0x75,0x63,0x61,0x80,0x90,0x01,0xc0,0x88,0x00,0x01,0x00,0x08,0x00,0x80,0x02, -0xe0,0x01,0x01,0xca,0x03,0xaa,0x09,0x04,0x00,0x00,0xa3,0x01,0x00,0x00,0x57,0x00, -0x49,0x00,0x4e,0x00,0x39,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x01,0xca,0x00,0x00,0x02,0xc0, -0x08,0x00,0x01,0x00,0x00,0x00 -}; - -char domain_data[] = {0x01}; - -/* Initialise a MCS_CONNECT_INITIAL structure */ -void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci) -{ - mci->calling_domain.length = 1; - mci->calling_domain.data = domain_data; - - mci->called_domain.length = 1; - mci->called_domain.data = domain_data; - - mci->upward_flag = 0xff; - - mcs_make_domain_params(&mci->target_params, 2, 2, 0, 0xffff); - mcs_make_domain_params(&mci->minimum_params, 1, 1, 1, 0x420); - mcs_make_domain_params(&mci->maximum_params, 0xffff, 0xfc17, 0xffff, - 0xffff); - - mci->user_data.length = sizeof(precanned_connect_userdata); - mci->user_data.data = precanned_connect_userdata; - - mci->length = 2*2 + 3 + 3*34 + 4 + mci->user_data.length; -} - -/* Marshall/demarshall an ASN.1 BER header */ -BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length) -{ - uint16 word_tag; - uint8 byte_tag; - uint16 word_len; - uint8 byte_len; - uint8 byte_int; - int tag; - BOOL res; - - /* Read/write tag */ - if (islong) - { - word_tag = tagval; - res = msb_io_uint16(s, &word_tag); - tag = word_tag; - } - else - { - byte_tag = tagval; - res = prs_io_uint8(s, &byte_tag); - tag = byte_tag; - } - - if (!res || (tag != tagval)) - { - ERROR("Invalid ASN.1 tag\n"); - return False; - } - - /* Read/write length */ - if (s->marshall) - { - if (*length >= 0x80) - { - byte_len = 0x82; - word_len = (uint16)*length; - res = prs_io_uint8(s, &byte_len); - res = res ? msb_io_uint16(s, &word_len) : False; - } - else - { - byte_len = (uint8)*length; - res = prs_io_uint8(s, &byte_len); - } - } - else - { - if (!prs_io_uint8(s, &byte_len)) - return False; - - if (byte_len & 0x80) - { - byte_len &= ~0x80; - *length = 0; - while (byte_len--) - { - if (!prs_io_uint8(s, &byte_int)) - return False; - - *length <<= 8; - *length += byte_int; - } - } - else *length = byte_len; - } - - return res; -} - -/* Marshall/demarshall an octet string (ASN.1 BER) */ -BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os) -{ - if (!ber_io_header(s, False, 4, &os->length)) - return False; - - if (os->length > s->end - s->offset) - return False; - - if (s->marshall) - { - memcpy(s->data + s->offset, os->data, os->length); - } - else - { - os->data = malloc(os->length); - memcpy(os->data, s->data + s->offset, os->length); - } - - s->offset += os->length; - return True; -} - -/* Marshall/demarshall an integer (ASN.1 BER) */ -BOOL ber_io_integer(STREAM s, uint16 *word_int) -{ - int length = 2; - uint8 byte_int; - BOOL res; - - if (!ber_io_header(s, False, 2, &length)) - return False; - - if (s->marshall) - { - res = msb_io_uint16(s, word_int); - } - else - { - *word_int = 0; - while (length--) - { - if (!prs_io_uint8(s, &byte_int)) - return False; - - *word_int <<= 8; - *word_int += byte_int; - } - } - - return res; -} - -/* Marshall/demarshall a simple uint8 type (ASN.1 BER) */ -BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval) -{ - int length = 1; - - if (!ber_io_header(s, False, tagval, &length)) - return False; - - if (length != 1) - { - ERROR("Wrong length for simple type\n"); - return False; - } - - return prs_io_uint8(s, i); -} - -/* Marshall/demarshall a DOMAIN_PARAMS structure (ASN.1 BER) */ -BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp) -{ - int length = 32; - BOOL res; - - res = ber_io_header(s, False, 0x30, &length); - res = res ? ber_io_integer(s, &dp->max_channels ) : False; - res = res ? ber_io_integer(s, &dp->max_users ) : False; - res = res ? ber_io_integer(s, &dp->max_tokens ) : False; - res = res ? ber_io_integer(s, &dp->num_priorities) : False; - res = res ? ber_io_integer(s, &dp->min_throughput) : False; - res = res ? ber_io_integer(s, &dp->max_height ) : False; - res = res ? ber_io_integer(s, &dp->max_pdusize ) : False; - res = res ? ber_io_integer(s, &dp->ver_protocol ) : False; - - return res; -} - -/* Marshall/demarshall a MCS_CONNECT_INITIAL structure (ASN.1 BER) */ -BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci) -{ - BOOL res; - - res = ber_io_header(s, True, 0x7f65, &mci->length); - res = res ? ber_io_octet_string (s, &mci->calling_domain) : False; - res = res ? ber_io_octet_string (s, &mci->called_domain ) : False; - res = res ? ber_io_uint8 (s, &mci->upward_flag, 1) : False; - res = res ? mcs_io_domain_params(s, &mci->target_params ) : False; - res = res ? mcs_io_domain_params(s, &mci->minimum_params) : False; - res = res ? mcs_io_domain_params(s, &mci->maximum_params) : False; - res = res ? ber_io_octet_string (s, &mci->user_data ) : False; - - return res; -} - -/* Marshall/demarshall a MCS_CONNECT_RESPONSE structure (ASN.1 BER) */ -BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr) -{ - BOOL res; - - res = ber_io_header(s, True, 0x7f66, &mcr->length); - res = res ? ber_io_uint8 (s, &mcr->result, 10 ) : False; - res = res ? ber_io_integer (s, &mcr->connect_id ) : False; - res = res ? mcs_io_domain_params(s, &mcr->domain_params) : False; - res = res ? ber_io_octet_string (s, &mcr->user_data ) : False; - - return res; -} - -/* Marshall/demarshall an EDrq structure (ASN.1 PER) */ -BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq) -{ - uint8 opcode = (1) << 2; - uint8 pkt_opcode = opcode; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if (pkt_opcode != opcode) - { - ERROR("Expected EDrq, received %x\n", pkt_opcode); - return False; - } - - res = res ? msb_io_uint16(s, &edrq->height ) : False; - res = res ? msb_io_uint16(s, &edrq->interval) : False; - - return res; -} - -/* Marshall/demarshall an AUrq structure (ASN.1 PER) */ -BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq) -{ - uint8 opcode = (10) << 2; - uint8 pkt_opcode = opcode; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if (pkt_opcode != opcode) - { - ERROR("Expected AUrq, received %x\n", pkt_opcode); - return False; - } - - return res; -} - -/* Marshall/demarshall an AUcf structure (ASN.1 PER) */ -BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf) -{ - uint8 opcode = (11) << 2; - uint8 pkt_opcode = opcode | 2; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if ((pkt_opcode & 0xfc) != opcode) - { - ERROR("Expected AUcf, received %x\n", pkt_opcode); - return False; - } - - res = res ? prs_io_uint8 (s, &aucf->result) : False; - if (pkt_opcode & 2) - res = res ? msb_io_uint16(s, &aucf->userid) : False; - - return res; -} - -/* Marshall/demarshall an CJrq structure (ASN.1 PER) */ -BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq) -{ - uint8 opcode = (14) << 2; - uint8 pkt_opcode = opcode; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if (pkt_opcode != opcode) - { - ERROR("Expected CJrq, received %x\n", pkt_opcode); - return False; - } - - res = res ? msb_io_uint16(s, &cjrq->userid) : False; - res = res ? msb_io_uint16(s, &cjrq->chanid) : False; - - return res; -} - -/* Marshall/demarshall an CJcf structure (ASN.1 PER) */ -BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf) -{ - uint8 opcode = (15) << 2; - uint8 pkt_opcode = opcode | 2; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if ((pkt_opcode & 0xfc) != opcode) - { - ERROR("Expected CJcf, received %x\n", pkt_opcode); - return False; - } - - res = res ? prs_io_uint8 (s, &cjcf->result) : False; - res = res ? msb_io_uint16(s, &cjcf->userid) : False; - res = res ? msb_io_uint16(s, &cjcf->req_chanid) : False; - if (pkt_opcode & 2) - res = res ? msb_io_uint16(s, &cjcf->join_chanid) : False; - - return res; -} - -/* Marshall/demarshall an SDrq or SDin packet (ASN.1 PER) */ -BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request) -{ - uint8 opcode = (request ? 25 : 26) << 2; - uint8 pkt_opcode = opcode; - uint8 byte1, byte2; - BOOL res; - - res = prs_io_uint8(s, &pkt_opcode); - if (pkt_opcode != opcode) - { - ERROR("Expected MCS data, received %x\n", pkt_opcode); - return False; - } - - res = res ? msb_io_uint16(s, &dt->userid) : False; - res = res ? msb_io_uint16(s, &dt->chanid) : False; - res = res ? prs_io_uint8 (s, &dt->flags ) : False; - - if (s->marshall) - { - dt->length |= 0x8000; - res = res ? msb_io_uint16(s, &dt->length) : False; - } - else - { - res = res ? prs_io_uint8(s, &byte1) : False; - if (byte1 & 0x80) - { - res = res ? prs_io_uint8(s, &byte2) : False; - dt->length = ((byte1 & ~0x80) << 8) + byte2; - } - else dt->length = byte1; - } - - return res; -} - diff --git a/mcs.h b/mcs.h deleted file mode 100644 index ef18a5d..0000000 --- a/mcs.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Protocol services - Multipoint Communications Service - Copyright (C) Matthew Chapman 1999-2000 - - 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. -*/ - -/* An ASN.1 octet string */ -typedef struct _OCTET_STRING -{ - int length; - unsigned char *data; - -} OCTET_STRING; - -/* MCS domain parameters */ -typedef struct _DOMAIN_PARAMS -{ - uint16 max_channels; - uint16 max_users; - uint16 max_tokens; - uint16 num_priorities; - uint16 min_throughput; - uint16 max_height; - uint16 max_pdusize; - uint16 ver_protocol; - -} DOMAIN_PARAMS; - -/* MCS-CONNECT-INITIAL request */ -typedef struct _MCS_CONNECT_INITIAL -{ - int length; - - OCTET_STRING calling_domain; - OCTET_STRING called_domain; - uint8 upward_flag; - DOMAIN_PARAMS target_params; - DOMAIN_PARAMS minimum_params; - DOMAIN_PARAMS maximum_params; - OCTET_STRING user_data; - -} MCS_CONNECT_INITIAL; - -/* MCS-CONNECT-RESPONSE */ -typedef struct _MCS_CONNECT_RESPONSE -{ - int length; - - uint8 result; - uint16 connect_id; - DOMAIN_PARAMS domain_params; - OCTET_STRING user_data; - -} MCS_CONNECT_RESPONSE; - -/* EDrq - Erect Domain Request */ -typedef struct _MCS_EDRQ -{ - uint16 height; - uint16 interval; - -} MCS_EDRQ; - -/* AUrq - Attach User Request */ -typedef struct _MCS_AURQ -{ - -} MCS_AURQ; - -/* AUcf - Attach User Confirm */ -typedef struct _MCS_AUCF -{ - uint8 result; - uint16 userid; - -} MCS_AUCF; - -/* CJrq - Channel Join Request */ -typedef struct _MCS_CJRQ -{ - uint16 userid; - uint16 chanid; - -} MCS_CJRQ; - -/* CJcf - Channel Join Confirm */ -typedef struct _MCS_CJCF -{ - uint8 result; - uint16 userid; - uint16 req_chanid; - uint16 join_chanid; - -} MCS_CJCF; - -/* SDrq/SDin - Send Data */ -typedef struct _MCS_DATA -{ - uint16 userid; - uint16 chanid; - uint8 flags; - uint16 length; - -} MCS_DATA; - -#define MCS_GLOBAL_CHANNEL 1003 diff --git a/misc.c b/misc.c deleted file mode 100644 index 059eea0..0000000 --- a/misc.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Entrypoint and utility functions - Copyright (C) Matthew Chapman 1999-2000 - - 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 "includes.h" - -void *xmalloc(int size) -{ - void *mem = malloc(size); - if (mem == NULL) - { - fprintf(stderr, "xmalloc: Out of memory.\n"); - exit(1); - } - return mem; -} - -void *xrealloc(void *oldmem, int size) -{ - void *mem = realloc(oldmem, size); - if (mem == NULL) - { - fprintf(stderr, "xrealloc: Out of memory.\n"); - exit(1); - } - return mem; -} - -void dump_data(unsigned char *p, int len) -{ - unsigned char *line = p; - int i, j; - - fprintf(stderr, "0000 "); - - for (i = 0; i < len; i++) - { - if ((i & 15) == 0) - { - if (i != 0) - { - for (j = 0; j < 16; j++) - fputc(isprint(line[j]) ? line[j] : '.', - stderr); - line = p + i; - fprintf(stderr, "\n%04x ", line-p); - } - } - - fprintf(stderr, "%02X ", p[i]); - } - - fputc('\n', stderr); -} diff --git a/orders.c b/orders.c new file mode 100644 index 0000000..923dfe3 --- /dev/null +++ b/orders.c @@ -0,0 +1,853 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP order processing + Copyright (C) Matthew Chapman 1999-2000 + + 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 unsigned char *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, uint16 *coord, BOOL delta) +{ + uint8 change; + + if (delta) + { + in_uint8(s, change); + *coord += (char)change; + } + else + { + in_uint16_le(s, *coord); + } +} + +/* Read a colour entry */ +static void rdp_in_colour(STREAM s, uint8 *colour) +{ + in_uint8(s, *colour); + s->p += 2; +} + +/* 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) +{ + 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->colour); + + 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); +} + +/* Process a text order */ +static void process_text2(STREAM s, TEXT2_ORDER *os, uint32 present, BOOL delta) +{ + DATABLOB *entry; + 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 & 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"); + + /* Process special cache strings */ + if ((os->length == 2) && (os->text[0] == 0xfe)) + { + entry = cache_get_text(os->text[1]); + + if (entry == NULL) + return; + + memcpy(os->text, entry->data, entry->size); + os->length = entry->size; + } + else if ((os->length >= 3) && (os->text[os->length-3] == 0xff)) + { + os->length -= 3; + cache_put_text(os->text[os->length+1], os->text, os->length); + } + + ui_draw_text(os->font, os->flags, os->mixmode, + os->x, os->y, 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; + uint8 *data; + + in_uint8(s, cache_id); + in_uint8s(s, 1); /* pad */ + in_uint8(s, width); + in_uint8(s, height); + in_uint8(s, bpp); + 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); + + bitmap = ui_create_bitmap(width, height, data); + 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; + 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); + 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 = xmalloc(width * height); + + if (bitmap_decompress(bmpdata, width, height, data, size)) + { + 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 = 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, baseline, width, height; + uint8 *data, *rev_data, in, out; + int i, j, datasize; + + 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_uint8s(s, 2); /* unknown */ + 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); + + /* Need to reverse bit order */ + rev_data = xmalloc(datasize); + + for (j = 0; j < datasize; j++) + { + in = data[j]; + out = 0; + if (in & 1) out |= 128; + if (in & 2) out |= 64; + if (in & 4) out |= 32; + if (in & 8) out |= 16; + if (in & 16) out |= 8; + if (in & 32) out |= 4; + if (in & 64) out |= 2; + if (in & 128) out |= 1; + rev_data[j] = out; + } + + bitmap = ui_create_glyph(width, height, rev_data); + xfree(rev_data); + + cache_put_font(font, character, 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: + NOTIMP("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_TEXT2: + process_text2(s, &os->text2, + present, delta); + break; + + default: + NOTIMP("order %d\n", os->order_type); + return; + } + + if (order_flags & RDP_ORDER_BOUNDS) + ui_reset_clip(); + } + + processed++; + } + + if (s->p != next_packet) + WARN("%d bytes remaining\n", next_packet - s->p); +} + +/* Reset order state */ +void reset_order_state() +{ + memset(&order_state, 0, sizeof(order_state)); +} + diff --git a/orders.h b/orders.h new file mode 100644 index 0000000..0cea268 --- /dev/null +++ b/orders.h @@ -0,0 +1,254 @@ +/* + rdesktop: A Remote Desktop Protocol client. + RDP order processing + Copyright (C) Matthew Chapman 1999-2000 + + 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_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 +{ + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 opcode; + +} DESTBLT_ORDER; + +typedef struct _PATBLT_ORDER +{ + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 opcode; + uint8 bgcolour; + uint8 fgcolour; + BRUSH brush; + +} PATBLT_ORDER; + +typedef struct _SCREENBLT_ORDER +{ + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 opcode; + uint16 srcx; + uint16 srcy; + +} SCREENBLT_ORDER; + +typedef struct _LINE_ORDER +{ + uint16 mixmode; + uint16 startx; + uint16 starty; + uint16 endx; + uint16 endy; + uint8 bgcolour; + uint8 opcode; + PEN pen; + +} LINE_ORDER; + +typedef struct _RECT_ORDER +{ + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 colour; + +} RECT_ORDER; + +typedef struct _DESKSAVE_ORDER +{ + uint32 offset; + uint16 left; + uint16 top; + uint16 right; + uint16 bottom; + uint8 action; + +} DESKSAVE_ORDER; + +typedef struct _TRIBLT_ORDER +{ + uint8 colour_table; + uint8 cache_id; + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 opcode; + uint16 srcx; + uint16 srcy; + uint8 bgcolour; + uint8 fgcolour; + BRUSH brush; + uint16 cache_idx; + uint16 unknown; + +} TRIBLT_ORDER; + +typedef struct _MEMBLT_ORDER +{ + uint8 colour_table; + uint8 cache_id; + uint16 x; + uint16 y; + uint16 cx; + uint16 cy; + uint8 opcode; + uint16 srcx; + uint16 srcy; + uint16 cache_idx; + +} MEMBLT_ORDER; + +#define MAX_TEXT 256 + +typedef struct _TEXT2_ORDER +{ + uint8 font; + uint8 flags; + uint8 mixmode; + uint8 unknown; + uint8 fgcolour; + uint8 bgcolour; + uint16 clipleft; + uint16 cliptop; + uint16 clipright; + uint16 clipbottom; + uint16 boxleft; + uint16 boxtop; + uint16 boxright; + uint16 boxbottom; + uint16 x; + uint16 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; + 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/parse.c b/parse.c deleted file mode 100644 index c0bf5e4..0000000 --- a/parse.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Protocol services - parsing layer - Copyright (C) Matthew Chapman 1999-2000 - - 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 "includes.h" - -/* Parse a 8-bit integer */ -BOOL prs_io_uint8(STREAM s, uint8 *i) -{ - if (s->offset + 1 > s->end) - { - ERROR("Parse past end of buffer\n"); - return False; - } - - if (s->marshall) - s->data[s->offset] = *i; - else - *i = s->data[s->offset]; - - s->offset++; - return True; -} - -/* Parse a sequence of 8-bit integers */ -BOOL prs_io_uint8s(STREAM s, uint8 *p, unsigned int length) -{ - if (s->offset + length > s->end) - { - ERROR("Parse past end of buffer\n"); - return False; - } - - if (s->marshall) - memcpy(s->data + s->offset, p, length); - else - memcpy(p, s->data + s->offset, length); - - s->offset += length; - return True; -} - -/* Parse a 16-bit integer, most significant bytes first */ -BOOL msb_io_uint16(STREAM s, uint16 *i) -{ - int offset = s->offset; - - if (offset + 2 > s->end) - { - ERROR("Parse past end of buffer\n"); - return False; - } - - if (s->marshall) { - s->data[offset] = (uint8)(*i >> 8); - s->data[offset+1] = (uint8)(*i); - } else { - *i = (s->data[offset] << 8) + (s->data[offset+1]); - } - - s->offset+=2; - return True; -} - -/* Parse a 16-bit integer, least significant bytes first */ -BOOL lsb_io_uint16(STREAM s, uint16 *i) -{ - int offset = s->offset; - - if (offset + 2 > s->end) - { - ERROR("Parse past end of buffer\n"); - return False; - } - - if (s->marshall) { - s->data[offset] = (uint8)(*i); - s->data[offset+1] = (uint8)(*i >> 8); - } else { - *i = (s->data[offset]) + (s->data[offset+1] << 8); - } - - s->offset += 2; - return True; -} - -/* Parse a 32-bit integer, least significant bytes first */ -BOOL lsb_io_uint32(STREAM s, uint32 *i) -{ - int offset = s->offset; - - if (offset + 4 > s->end) - { - ERROR("Parse past end of buffer\n"); - return False; - } - - if (s->marshall) { - s->data[offset] = (uint8)(*i); - s->data[offset+1] = (uint8)(*i >> 8); - s->data[offset+2] = (uint8)(*i >> 16); - s->data[offset+3] = (uint8)(*i >> 24); - } else { - *i = (s->data[offset]) + (s->data[offset+1] << 8) - + (s->data[offset+2] << 16) + (s->data[offset+3] << 24); - } - - s->offset += 4; - return True; -} diff --git a/parse.h b/parse.h index 7b40288..3596677 100644 --- a/parse.h +++ b/parse.h @@ -1,6 +1,6 @@ /* rdesktop: A Remote Desktop Protocol client. - Protocol services - parsing layer + Parsing primitives Copyright (C) Matthew Chapman 1999-2000 This program is free software; you can redistribute it and/or modify @@ -21,47 +21,72 @@ /* Parser state */ typedef struct stream { - /* Parsing layer */ + unsigned char *p; + unsigned char *end; unsigned char *data; unsigned int size; - unsigned int offset; - unsigned int end; - BOOL marshall; - BOOL error; - /* Other layers */ - int iso_offset; - int mcs_offset; - int rdp_offset; + /* Offsets of various headers */ + unsigned char *iso_hdr; + unsigned char *mcs_hdr; + unsigned char *sec_hdr; + unsigned char *rdp_hdr; } *STREAM; -/* Connection state */ -typedef struct connection -{ - /* User interface */ - HWINDOW wnd; - HBITMAP bmpcache[3][600]; - FONT_GLYPH fontcache[12][256]; - BLOB textcache[256]; - uint8 deskcache[0x38400]; +#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) - /* Parsing layer */ - struct stream in; - struct stream out; +#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; } - /* TCP layer */ - int tcp_socket; +#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 - /* MCS layer */ - uint16 mcs_userid; +#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; } -} *HCONN; +#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,b) -#define STREAM_INIT(s,m) { s.data = xmalloc(2048); s.end = s.size = 2048; s.offset = 0; s.marshall = m; s.error = False; } -#define STREAM_SIZE(s,l) { if (l > s.size) { s.data = xrealloc(s.data,l); s.end = s.size = l; } } -#define REMAINING(s) ( s->end - s->offset ) -#define PUSH_LAYER(s,v,l) { s.v = s.offset; s.offset += l; } -#define POP_LAYER(s,v) { s.offset = s.v; } -#define MARK_END(s) { s.end = s.offset; } -#define PRS_ERROR(s) (!(s)->error) +#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; } diff --git a/process.c b/process.c deleted file mode 100644 index 92ccf39..0000000 --- a/process.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - RDP message processing - Copyright (C) Matthew Chapman 1999-2000 - - 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 "includes.h" - -/* Process incoming packets */ -void rdp_main_loop(HCONN conn) -{ - RDP_DATA_HEADER hdr; - RDP_ORDER_STATE os; - uint8 type; - - memset(&os, 0, sizeof(os)); - - while (rdp_recv_pdu(conn, &type)) - { - switch (type) - { - case RDP_PDU_DEMAND_ACTIVE: - process_demand_active(conn); - memset(&os, 0, sizeof(os)); - break; - - case RDP_PDU_DEACTIVATE: - break; - - case RDP_PDU_DATA: - rdp_io_data_header(&conn->in, &hdr); - - switch (hdr.data_pdu_type) - { - case RDP_DATA_PDU_UPDATE: - process_update_pdu(conn, &os); - break; - - case RDP_DATA_PDU_POINTER: - process_pointer_pdu(conn); - break; - - default: - NOTIMP("data PDU 0x%x\n", - hdr.data_pdu_type); - } - break; - - default: - NOTIMP("PDU 0x%x\n", type); - } - } -} - -/* Respond to a demand active PDU */ -void process_demand_active(HCONN conn) -{ - RDP_ACTIVE_PDU active; - uint8 type; - - if (!rdp_io_active_pdu(&conn->in, &active, RDP_PDU_DEMAND_ACTIVE)) - return; - - DEBUG("DEMAND_ACTIVE(id=0x%x)\n", active.shareid); - - rdp_send_confirm_active(conn, active.shareid, 640, 480); - rdp_send_synchronize(conn); - rdp_send_control(conn, RDP_CTL_COOPERATE); - rdp_send_control(conn, RDP_CTL_REQUEST_CONTROL); - rdp_recv_pdu(conn, &type); // RDP_PDU_SYNCHRONIZE - rdp_recv_pdu(conn, &type); // RDP_CTL_COOPERATE - rdp_recv_pdu(conn, &type); // RDP_CTL_GRANT_CONTROL - rdp_send_input(conn, RDP_INPUT_SYNCHRONIZE, 0, 0, 0); - rdp_send_fonts(conn, 1); - rdp_send_fonts(conn, 2); - rdp_recv_pdu(conn, &type); // RDP_PDU_UNKNOWN 0x28 -} - -/* Process a pointer PDU */ -void process_pointer_pdu(HCONN conn) -{ - RDP_POINTER_PDU pp; - - if (!rdp_io_pointer_pdu(&conn->in, &pp)) - return; - - switch (pp.message) - { - case RDP_POINTER_MOVE: - ui_move_pointer(conn->wnd, pp.x, pp.y); - break; - - default: - NOTIMP("pointer message 0x%x\n", pp.message); - } -} - -/* Process an update PDU */ -void process_update_pdu(HCONN conn, RDP_ORDER_STATE *os) -{ - RDP_UPDATE_PDU update; - - if (!rdp_io_update_pdu(&conn->in, &update)) - return; - - switch (update.update_type) - { - case RDP_UPDATE_ORDERS: - process_orders(conn, os); - break; - - case RDP_UPDATE_PALETTE: - case RDP_UPDATE_SYNCHRONIZE: - break; - - default: - NOTIMP("update 0x%x\n", update.update_type); - } - -} - - -/* UPDATE PDUs */ - -/* Process an order */ -void process_orders(HCONN conn, RDP_ORDER_STATE *os) -{ - RDP_SECONDARY_ORDER rso; - uint32 present, num_orders; - uint8 order_flags; - int size, processed = 0; - BOOL delta; - - lsb_io_uint32(&conn->in, &num_orders); - num_orders &= 0xffff; /* second word padding */ - - while (processed < num_orders) - { - if (!prs_io_uint8(&conn->in, &order_flags)) - break; - - if (!(order_flags & RDP_ORDER_STANDARD)) - { - ERROR("Order parsing failed\n"); - return; - } - - if (order_flags & RDP_ORDER_SECONDARY) - { - if (!rdp_io_secondary_order(&conn->in, &rso)) - break; - - switch (rso.type) - { - case RDP_ORDER_RAW_BMPCACHE: - process_raw_bmpcache(conn); - break; - - case RDP_ORDER_COLCACHE: - process_colcache(conn); - break; - - case RDP_ORDER_BMPCACHE: - process_bmpcache(conn); - break; - - case RDP_ORDER_FONTCACHE: - process_fontcache(conn); - break; - - default: - NOTIMP("secondary order %d\n", - rso.type); - conn->in.offset += rso.length + 7; - } - } - else - { - if (order_flags & RDP_ORDER_CHANGE) - { - prs_io_uint8(&conn->in, &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_io_present(&conn->in, &present, order_flags, size); - - if (order_flags & RDP_ORDER_BOUNDS) - { - if (!(order_flags & RDP_ORDER_LASTBOUNDS)) - rdp_io_bounds(&conn->in, &os->bounds); - - ui_set_clip(conn->wnd, 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(conn, &os->destblt, - present, delta); - break; - - case RDP_ORDER_PATBLT: - process_patblt(conn, &os->patblt, - present, delta); - break; - - case RDP_ORDER_SCREENBLT: - process_screenblt(conn, &os->screenblt, - present, delta); - break; - - case RDP_ORDER_LINE: - process_line(conn, &os->line, - present, delta); - break; - - case RDP_ORDER_RECT: - process_rect(conn, &os->rect, - present, delta); - break; - - case RDP_ORDER_DESKSAVE: - process_desksave(conn, &os->desksave, - present, delta); - break; - - case RDP_ORDER_MEMBLT: - process_memblt(conn, &os->memblt, - present, delta); - break; - - case RDP_ORDER_TRIBLT: - process_triblt(conn, &os->triblt, - present, delta); - break; - - case RDP_ORDER_TEXT2: - process_text2(conn, &os->text2, - present, delta); - break; - - default: - NOTIMP("order %d\n", os->order_type); - return; - } - - if (order_flags & RDP_ORDER_BOUNDS) - ui_reset_clip(conn->wnd); - } - - processed++; - } - - if (conn->in.offset != conn->in.rdp_offset) - WARN("Order data remaining\n"); -} - - -/* PRIMARY ORDERS */ - -/* Process a destination blt order */ -void process_destblt(HCONN conn, DESTBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (!rdp_io_destblt_order(&conn->in, os, present, delta)) - return; - - 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(conn->wnd, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy); -} - -/* Process a pattern blt order */ -void process_patblt(HCONN conn, PATBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (!rdp_io_patblt_order(&conn->in, os, present, delta)) - return; - - 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(conn->wnd, ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy, - &os->brush, os->bgcolour, os->fgcolour); -} - -/* Process a screen blt order */ -void process_screenblt(HCONN conn, SCREENBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (!rdp_io_screenblt_order(&conn->in, os, present, delta)) - return; - - 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(conn->wnd, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, - os->srcx, os->srcy); -} - -/* Process a line order */ -void process_line(HCONN conn, LINE_ORDER *os, uint32 present, BOOL delta) -{ - if (!rdp_io_line_order(&conn->in, os, present, delta)) - return; - - 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 opcode 0x%x\n", os->opcode); - return; - } - - ui_line(conn->wnd, os->opcode-1, os->startx, os->starty, - os->endx, os->endy, &os->pen); -} - -/* Process an opaque rectangle order */ -void process_rect(HCONN conn, RECT_ORDER *os, uint32 present, BOOL delta) -{ - if (!rdp_io_rect_order(&conn->in, os, present, delta)) - return; - - 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(conn->wnd, os->x, os->y, os->cx, os->cy, os->colour); -} - -/* Process a desktop save order */ -void process_desksave(HCONN conn, DESKSAVE_ORDER *os, uint32 present, BOOL delta) -{ - int width, height; - uint8 *data; - - if (!rdp_io_desksave_order(&conn->in, os, present, delta)) - return; - - 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); - - data = conn->deskcache + os->offset; - width = os->right - os->left + 1; - height = os->bottom - os->top + 1; - - if (os->action == 0) - { - ui_desktop_save(conn->wnd, data, os->left, os->top, - width, height); - } - else - { - ui_desktop_restore(conn->wnd, data, os->left, os->top, - width, height); - } -} - -/* Process a memory blt order */ -void process_memblt(HCONN conn, MEMBLT_ORDER *os, uint32 present, BOOL delta) -{ - HBITMAP bitmap; - - if (!rdp_io_memblt_order(&conn->in, os, present, delta)) - return; - - 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(conn, os->cache_id, os->cache_idx); - if (bitmap == NULL) - return; - - ui_memblt(conn->wnd, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, - bitmap, os->srcx, os->srcy); -} - -/* Process a 3-way blt order */ -void process_triblt(HCONN conn, TRIBLT_ORDER *os, uint32 present, BOOL delta) -{ - HBITMAP bitmap; - - if (!rdp_io_triblt_order(&conn->in, os, present, delta)) - return; - - 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(conn, os->cache_id, os->cache_idx); - if (bitmap == NULL) - return; - - ui_triblt(conn->wnd, os->opcode, os->x, os->y, os->cx, os->cy, - bitmap, os->srcx, os->srcy, - &os->brush, os->bgcolour, os->fgcolour); -} - -/* Process a text order */ -void process_text2(HCONN conn, TEXT2_ORDER *os, uint32 present, BOOL delta) -{ - BLOB *entry; - int i; - - if (!rdp_io_text2_order(&conn->in, os, present, delta)) - return; - - 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); - - fprintf(stderr, "Text: "); - - for (i = 0; i < os->length; i++) - fprintf(stderr, "%02x ", os->text[i]); - - fprintf(stderr, "\n"); - - /* Process special cache strings */ - if ((os->length == 2) && (os->text[0] == 0xfe)) - { - entry = cache_get_text(conn, os->text[1]); - - if (entry == NULL) - return; - - memcpy(os->text, entry->data, entry->size); - os->length = entry->size; - } - else if ((os->length >= 3) && (os->text[os->length-3] == 0xff)) - { - os->length -= 3; - cache_put_text(conn, os->text[os->length+1], - os->text, os->length); - } - - ui_draw_text(conn->wnd, os->font, os->flags, os->mixmode, - os->x, os->y, os->boxleft, os->boxtop, - os->boxright - os->boxleft, - os->boxbottom - os->boxtop, - os->bgcolour, os->fgcolour, os->text, os->length); -} - - -/* SECONDARY ORDERS */ - -/* Process a raw bitmap cache order */ -void process_raw_bmpcache(HCONN conn) -{ - RDP_RAW_BMPCACHE_ORDER order; - HBITMAP bitmap; - - if (!rdp_io_raw_bmpcache_order(&conn->in, &order)) - return; - - DEBUG("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", - order.width, order.height, order.cache_id, order.cache_idx); - - bitmap = ui_create_bitmap(conn->wnd, order.width, order.height, - order.data); - cache_put_bitmap(conn, order.cache_id, order.cache_idx, bitmap); -} - -/* Process a bitmap cache order */ -void process_bmpcache(HCONN conn) -{ - RDP_BMPCACHE_ORDER order; - HBITMAP bitmap; - char *bmpdata; - - if (!rdp_io_bmpcache_order(&conn->in, &order)) - return; - - DEBUG("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", - order.width, order.height, order.cache_id, order.cache_idx); - - bmpdata = malloc(order.width * order.height); - - if (bitmap_decompress(bmpdata, order.width, order.height, - order.data, order.size)) - { - bitmap = ui_create_bitmap(conn->wnd, order.width, order.height, - bmpdata); - cache_put_bitmap(conn, order.cache_id, order.cache_idx, bitmap); - } - - free(bmpdata); -} - -/* Process a colourmap cache order */ -void process_colcache(HCONN conn) -{ - RDP_COLCACHE_ORDER order; - HCOLOURMAP map; - - if (!rdp_io_colcache_order(&conn->in, &order)) - return; - - DEBUG("COLCACHE(id=%d,n=%d)\n", order.cache_id, order.map.ncolours); - - map = ui_create_colourmap(conn->wnd, &order.map); - ui_set_colourmap(conn->wnd, map); -} - -/* Process a font cache order */ -void process_fontcache(HCONN conn) -{ - RDP_FONTCACHE_ORDER order; - RDP_FONT_GLYPH *glyph; - HGLYPH bitmap; - int i; - - if (!rdp_io_fontcache_order(&conn->in, &order)) - return; - - DEBUG("FONTCACHE(font=%d,n=%d)\n", order.font, order.nglyphs); - - for (i = 0; i < order.nglyphs; i++) - { - glyph = &order.glyphs[i]; - - bitmap = ui_create_glyph(conn->wnd, glyph->width, - glyph->height, glyph->data); - - cache_put_font(conn, order.font, glyph->character, - glyph->baseline, glyph->width, glyph->height, - bitmap); - } -} diff --git a/proto.h b/proto.h index a9dcdfa..d13eea3 100644 --- a/proto.h +++ b/proto.h @@ -1,184 +1,95 @@ -/* bitmap.c */ -BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size); -/* cache.c */ -HBITMAP cache_get_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx); -void cache_put_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx, HBITMAP bitmap); -FONT_GLYPH *cache_get_font(HCONN conn, uint8 font, uint16 character); -void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap); -BLOB *cache_get_text(HCONN conn, uint8 cache_id); -void cache_put_text(HCONN conn, uint8 cache_id, void *data, int length); -/* client.c */ +/* rdesktop.c */ int main(int argc, char *argv[]); -/* iso.c */ -HCONN iso_connect(char *server); -void iso_disconnect(HCONN conn); -BOOL iso_send_msg(HCONN conn, uint8 code); -BOOL iso_recv_msg(HCONN conn, uint8 *code); -void iso_init(struct connection *conn); -BOOL iso_recv(HCONN conn); -BOOL iso_send(HCONN conn); -void iso_make_tpkt(TPKT *tpkt, int length); -BOOL iso_io_tpkt(STREAM s, TPKT *tpkt); -void iso_make_tpdu(TPDU *tpdu, uint8 code); -BOOL iso_io_tpdu(STREAM s, TPDU *tpdu); -/* mcs.c */ -HCONN mcs_connect(char *server); -BOOL mcs_join_channel(HCONN conn, uint16 chanid); -void mcs_disconnect(HCONN conn); -void mcs_send_connect_initial(HCONN conn); -void mcs_send_edrq(HCONN conn); -void mcs_send_aurq(HCONN conn); -void mcs_send_cjrq(HCONN conn, uint16 chanid); -void mcs_init_data(HCONN conn); -void mcs_send_data(HCONN conn, uint16 chanid, BOOL request); -BOOL mcs_recv(HCONN conn, BOOL request); -void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels, uint16 max_users, uint16 max_tokens, uint16 max_pdusize); -void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci); -BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length); -BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os); -BOOL ber_io_integer(STREAM s, uint16 *word_int); -BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval); -BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp); -BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci); -BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr); -BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq); -BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq); -BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf); -BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq); -BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf); -BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request); -/* misc.c */ +void generate_random(uint8 *random); void *xmalloc(int size); void *xrealloc(void *oldmem, int size); -void dump_data(unsigned char *p, int len); -/* parse.c */ -BOOL prs_io_uint8(STREAM s, uint8 *i); -BOOL prs_io_uint8s(STREAM s, uint8 *p, unsigned int length); -BOOL msb_io_uint16(STREAM s, uint16 *i); -BOOL lsb_io_uint16(STREAM s, uint16 *i); -BOOL lsb_io_uint32(STREAM s, uint32 *i); -/* process.c */ -void rdp_main_loop(HCONN conn); -void process_demand_active(HCONN conn); -void process_pointer_pdu(HCONN conn); -void process_update_pdu(HCONN conn, RDP_ORDER_STATE *os); -void process_orders(HCONN conn, RDP_ORDER_STATE *os); -void process_destblt(HCONN conn, DESTBLT_ORDER *os, uint32 present, BOOL delta); -void process_patblt(HCONN conn, PATBLT_ORDER *os, uint32 present, BOOL delta); -void process_screenblt(HCONN conn, SCREENBLT_ORDER *os, uint32 present, BOOL delta); -void process_line(HCONN conn, LINE_ORDER *os, uint32 present, BOOL delta); -void process_rect(HCONN conn, RECT_ORDER *os, uint32 present, BOOL delta); -void process_desksave(HCONN conn, DESKSAVE_ORDER *os, uint32 present, BOOL delta); -void process_memblt(HCONN conn, MEMBLT_ORDER *os, uint32 present, BOOL delta); -void process_triblt(HCONN conn, TRIBLT_ORDER *os, uint32 present, BOOL delta); -void process_text2(HCONN conn, TEXT2_ORDER *os, uint32 present, BOOL delta); -void process_raw_bmpcache(HCONN conn); -void process_bmpcache(HCONN conn); -void process_colcache(HCONN conn); -void process_fontcache(HCONN conn); -/* rdp.c */ -HCONN rdp_connect(char *server, int width, int height); -void rdp_establish_key(HCONN conn); -void rdp_establish_key_e1(HCONN conn); -void rdp_establish_key_e2(HCONN conn); -void rdp_send_cert(HCONN conn); -void rdp_init(HCONN conn); -void rdp_send(HCONN conn, uint16 pdu_type); -void rdp_init_data(HCONN conn); -void rdp_send_data(HCONN conn, uint16 data_pdu_type); -void rdp_send_confirm_active(HCONN conn, uint32 shareid, int width, int height); -void rdp_send_synchronize(HCONN conn); -void rdp_send_control(HCONN conn, uint16 action); -void rdp_send_fonts(HCONN conn, uint16 seqno); -void rdp_send_input(HCONN conn, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2); -BOOL rdp_recv_pdu(HCONN conn, uint8 *type); -void rdp_disconnect(HCONN conn); -void rdp_make_header(RDP_HEADER *hdr, uint16 length, uint16 pdu_type, uint16 userid); -BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr); -void rdp_make_data_header(RDP_DATA_HEADER *hdr, uint32 shareid, uint16 length, uint16 data_pdu_type); -BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr); -BOOL rdp_io_present(STREAM s, uint32 *present, uint8 flags, int size); -BOOL rdp_io_coord(STREAM s, uint16 *coord, BOOL delta); -BOOL rdp_io_colour(STREAM s, uint8 *colour); -BOOL rdp_io_colourmap(STREAM s, COLOURMAP *colours); -BOOL rdp_io_bounds(STREAM s, BOUNDS *bounds); -BOOL rdp_io_pen(STREAM s, PEN *pen, uint32 present); -BOOL rdp_io_brush(STREAM s, BRUSH *brush, uint32 present); -void rdp_make_active_pdu(RDP_ACTIVE_PDU *pdu, uint32 shareid, uint16 userid, int width, int height); -BOOL rdp_io_active_pdu(STREAM s, RDP_ACTIVE_PDU *pdu, int pdutype); -void rdp_make_control_pdu(RDP_CONTROL_PDU *pdu, uint16 action); -BOOL rdp_io_control_pdu(STREAM s, RDP_CONTROL_PDU *pdu); -void rdp_make_synchronise_pdu(RDP_SYNCHRONISE_PDU *pdu, uint16 userid); -BOOL rdp_io_synchronise_pdu(STREAM s, RDP_SYNCHRONISE_PDU *pdu); -BOOL rdp_io_input_event(STREAM s, RDP_INPUT_EVENT *evt); -void rdp_make_input_pdu(RDP_INPUT_PDU *pdu, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2); -BOOL rdp_io_input_pdu(STREAM s, RDP_INPUT_PDU *pdu); -void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno); -BOOL rdp_io_font_info(STREAM s, RDP_FONT_INFO *font); -BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu); -BOOL rdp_io_pointer_pdu(STREAM s, RDP_POINTER_PDU *ptr); -BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu); -BOOL rdp_io_destblt_order(STREAM s, DESTBLT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_patblt_order(STREAM s, PATBLT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_screenblt_order(STREAM s, SCREENBLT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_line_order(STREAM s, LINE_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_rect_order(STREAM s, RECT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_desksave_order(STREAM s, DESKSAVE_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_memblt_order(STREAM s, MEMBLT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_triblt_order(STREAM s, TRIBLT_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_text2_order(STREAM s, TEXT2_ORDER *os, uint32 present, BOOL delta); -BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso); -BOOL rdp_io_raw_bmpcache_order(STREAM s, RDP_RAW_BMPCACHE_ORDER *rbo); -BOOL rdp_io_bmpcache_order(STREAM s, RDP_BMPCACHE_ORDER *rbo); -BOOL rdp_io_colcache_order(STREAM s, RDP_COLCACHE_ORDER *colours); -BOOL rdp_io_fontcache_order(STREAM s, RDP_FONTCACHE_ORDER *font); -void rdp_make_general_caps(RDP_GENERAL_CAPS *caps); -BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps); -void rdp_make_bitmap_caps(RDP_BITMAP_CAPS *caps, int width, int height); -BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps); -void rdp_make_order_caps(RDP_ORDER_CAPS *caps); -BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps); -void rdp_make_bmpcache_caps(RDP_BMPCACHE_CAPS *caps); -BOOL rdp_io_bmpcache_info(STREAM s, RDP_BMPCACHE_INFO *info); -BOOL rdp_io_bmpcache_caps(STREAM s, RDP_BMPCACHE_CAPS *caps); -void rdp_make_control_caps(RDP_CONTROL_CAPS *caps); -BOOL rdp_io_control_caps(STREAM s, RDP_CONTROL_CAPS *caps); -void rdp_make_activate_caps(RDP_ACTIVATE_CAPS *caps); -BOOL rdp_io_activate_caps(STREAM s, RDP_ACTIVATE_CAPS *caps); -void rdp_make_pointer_caps(RDP_POINTER_CAPS *caps); -BOOL rdp_io_pointer_caps(STREAM s, RDP_POINTER_CAPS *caps); -void rdp_make_share_caps(RDP_SHARE_CAPS *caps, uint16 userid); -BOOL rdp_io_share_caps(STREAM s, RDP_SHARE_CAPS *caps); -void rdp_make_colcache_caps(RDP_COLCACHE_CAPS *caps); -BOOL rdp_io_colcache_caps(STREAM s, RDP_COLCACHE_CAPS *caps); -BOOL rdp_io_unknown_caps(STREAM s, void *caps); +void xfree(void *mem); +void hexdump(unsigned char *p, unsigned int len); + /* tcp.c */ -HCONN tcp_connect(char *server); -void tcp_disconnect(HCONN conn); -BOOL tcp_send(HCONN conn); -BOOL tcp_recv(HCONN conn, int length); +STREAM tcp_init(int maxlen); +void tcp_send(STREAM s); +STREAM tcp_recv(int length); +BOOL tcp_connect(char *server); +void tcp_disconnect(void); + +/* 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); + +/* 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); + +/* 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, uint8 *session_key, int length, 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); + +/* licence.c */ +void licence_generate_keys(uint8 *client_key, uint8 *server_key, uint8 *client_rsa); +void licence_process(STREAM s); + +/* 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); +void rdp_main_loop(void); +BOOL rdp_connect(char *server); +void rdp_disconnect(void); + +/* orders.c */ +void process_orders(STREAM s); +void reset_order_state(void); + +/* bitmap.c */ +BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size); + +/* 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, uint32 character, 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, uint32 length); +void cache_put_desktop(uint32 offset, uint32 length, uint8 *data); + /* xwin.c */ -HWINDOW ui_create_window(HCONN conn, int width, int height); -void ui_destroy_window(HWINDOW wnd); -void ui_process_events(HWINDOW wnd, HCONN conn); -void ui_move_pointer(HWINDOW wnd, int x, int y); -HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data); -void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp); -HGLYPH ui_create_glyph(HWINDOW wnd, int width, int height, uint8 *data); -void ui_destroy_glyph(HWINDOW wnd, HGLYPH glyph); -HCOLOURMAP ui_create_colourmap(HWINDOW wnd, COLOURMAP *colours); -void ui_destroy_colourmap(HWINDOW wnd, HCOLOURMAP map); -void ui_set_colourmap(HWINDOW wnd, HCOLOURMAP map); -void ui_set_clip(HWINDOW wnd, int x, int y, int cx, int cy); -void ui_reset_clip(HWINDOW wnd); -void ui_destblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy); -void ui_patblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, BRUSH *brush, int bgcolour, int fgcolour); -void ui_screenblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy); -void ui_memblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy); -void ui_triblt(HWINDOW wnd, 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(HWINDOW wnd, uint8 opcode, int startx, int starty, int endx, int endy, PEN *pen); -void ui_rect(HWINDOW wnd, int x, int y, int cx, int cy, int colour); -void ui_draw_glyph(HWINDOW wnd, int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour); -void ui_draw_text(HWINDOW wnd, uint8 font, uint8 flags, int mixmode, int x, int y, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, int fgcolour, uint8 *text, uint8 length); -void ui_desktop_save(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy); -void ui_desktop_restore(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy); +BOOL ui_create_window(char *title); +void ui_destroy_window(void); +void ui_process_events(void); +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); +HCOLOURMAP ui_create_colourmap(COLOURMAP *colours); +void ui_destroy_colourmap(HCOLOURMAP map); +void ui_set_colourmap(HCOLOURMAP map); +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_glyph(int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour); +void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, 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/rdesktop.c b/rdesktop.c new file mode 100644 index 0000000..1e6ed36 --- /dev/null +++ b/rdesktop.c @@ -0,0 +1,236 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Entrypoint and utility functions + Copyright (C) Matthew Chapman 1999-2000 + + 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 /* malloc realloc free */ +#include /* read close getuid getgid getpid getppid gethostname */ +#include /* open */ +#include /* getopt */ +#include /* getpwuid */ +#include /* stat */ +#include /* gettimeofday */ +#include /* times */ +#include "rdesktop.h" + +char username[16]; +char hostname[16]; +int width = 800; +int height = 600; +int keylayout = 0x409; +BOOL motion = False; +BOOL orders = True; +BOOL licence = True; + +/* Display usage information */ +static void usage(char *program) +{ + STATUS("Usage: %s [options] server\n", program); + STATUS(" -u: user name\n"); + STATUS(" -n: client hostname\n"); + STATUS(" -w: desktop width\n"); + STATUS(" -h: desktop height\n"); + STATUS(" -k: keyboard layout (hex)\n"); + STATUS(" -m: send motion events\n"); + STATUS(" -b: force bitmap updates\n"); + STATUS(" -l: do not request licence\n\n"); +} + +/* Client program */ +int main(int argc, char *argv[]) +{ + struct passwd *pw; + char *server; + char title[32]; + int c; + + STATUS("rdesktop: A Remote Desktop Protocol client.\n"); + STATUS("Version "VERSION". Copyright (C) 1999-2000 Matt Chapman.\n\n"); + + while ((c = getopt(argc, argv, "u:n:w:h:k:mbl?")) != -1) + { + switch (c) + { + case 'u': + strncpy(username, optarg, sizeof(username)); + break; + + case 'n': + strncpy(hostname, optarg, sizeof(hostname)); + break; + + case 'w': + width = strtol(optarg, NULL, 10); + break; + + case 'h': + height = strtol(optarg, NULL, 10); + break; + + case 'k': + keylayout = strtol(optarg, NULL, 16); + break; + + case 'm': + motion = True; + break; + + case 'b': + orders = False; + break; + + case 'l': + licence = False; + break; + + case '?': + default: + usage(argv[0]); + return 1; + } + } + + if (argc - optind < 1) + { + usage(argv[0]); + return 1; + } + + server = argv[optind]; + + if (username[0] == 0) + { + pw = getpwuid(getuid()); + if ((pw == NULL) || (pw->pw_name == NULL)) + { + STATUS("Could not determine user name.\n"); + return 1; + } + + strncpy(username, pw->pw_name, sizeof(username)); + } + + if (hostname[0] == 0) + { + if (gethostname(hostname, sizeof(hostname)) == -1) + { + STATUS("Could not determine host name.\n"); + return 1; + } + } + + if (!rdp_connect(server)) + return 1; + + STATUS("Connection successful.\n"); + + snprintf(title, sizeof(title), "rdesktop - %s", server); + if (ui_create_window(title)) + { + rdp_main_loop(); + ui_destroy_window(); + } + + rdp_disconnect(); + return 0; +} + +/* Generate a 32-byte random for the secure transport code. */ +void generate_random(uint8 *random) +{ + struct stat st; + uint32 *r = (uint32 *)random; + int fd; + + /* If we have a kernel random device, use it. */ + if ((fd = open("/dev/urandom", O_RDONLY)) != -1) + { + read(fd, random, 32); + close(fd); + return; + } + + /* Otherwise use whatever entropy we can gather - ideas welcome. */ + r[0] = (getpid()) | (getppid() << 16); + r[1] = (getuid()) | (getgid() << 16); + r[2] = times(NULL); /* 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; +} + +/* 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); +} + +/* Produce a hex dump */ +void hexdump(unsigned char *p, unsigned int len) +{ + unsigned char *line = p; + unsigned int thisline, offset = 0; + int i; + + while (offset < len) + { + STATUS("%04x ", offset); + thisline = len - offset; + if (thisline > 16) + thisline = 16; + + for (i = 0; i < thisline; i++) + STATUS("%02x ", line[i]) + + for (; i < 16; i++) + STATUS(" "); + + for (i = 0; i < thisline; i++) + STATUS("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + + STATUS("\n"); + offset += thisline; + line += thisline; + } +} diff --git a/includes.h b/rdesktop.h similarity index 64% rename from includes.h rename to rdesktop.h index f2862d6..c7254fd 100644 --- a/includes.h +++ b/rdesktop.h @@ -1,6 +1,6 @@ /* rdesktop: A Remote Desktop Protocol client. - Global include file + Master include file Copyright (C) Matthew Chapman 1999-2000 This program is free software; you can redistribute it and/or modify @@ -18,37 +18,25 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#define VERSION "0.9.0-alpha1" -#if 0 -#define False (0) -#define True (1) +#define STATUS(args...) fprintf(stderr, args); +#define ERROR(args...) fprintf(stderr, "ERROR: "args); +#define WARN(args...) fprintf(stderr, "WARNING: "args); +#define NOTIMP(args...) fprintf(stderr, "NOTIMP: "args); + +#ifdef RDP_DEBUG +#define DEBUG(args...) fprintf(stderr, args); +#else +#define DEBUG(args...) #endif -typedef int BOOL; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; - -#include "xwin.h" -#include "misc.h" +#include "constants.h" +#include "types.h" #include "parse.h" -#include "tcp.h" -#include "iso.h" -#include "mcs.h" -#include "rdp.h" #ifndef MAKE_PROTO #include "proto.h" diff --git a/rdp.c b/rdp.c index c3cd942..4b609c8 100644 --- a/rdp.c +++ b/rdp.c @@ -18,1561 +18,356 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "rdesktop.h" -/* Establish a connection up to the RDP layer */ -HCONN rdp_connect(char *server, int width, int height) +extern uint16 mcs_userid; +extern char username[16]; +extern BOOL orders; + +unsigned char *next_packet; +uint32 rdp_shareid; + +/* Initialise an RDP packet */ +static STREAM rdp_init(int maxlen) { - HCONN conn; + STREAM s; - if ((conn = mcs_connect(server)) == NULL) - return NULL; - - rdp_establish_key(conn); - mcs_recv(conn, False); /* Server's licensing certificate */ - rdp_send_cert(conn); - mcs_recv(conn, False); - mcs_recv(conn, False); - - return conn; + s = sec_init(SEC_ENCRYPT, maxlen + 6); + s_push_layer(s, rdp_hdr, 6); + return s; } -/* Work this out later. This is useless anyway when encryption is off. */ -uint8 precanned_key_packet[] = { - 0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x86, - 0xf7,0x99,0xef,0x60,0xc4,0x49,0x52,0xd0,0xd8,0xea,0xb5,0x4f,0x58,0x19, - 0x52,0x2a,0x93,0x83,0x57,0x4f,0x4e,0x04,0xde,0x96,0x51,0xab,0x13,0x20, - 0xd8,0xe5,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -uint8 precanned_key_packet_e1[] = { -0x01,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7c,0xbd,0x8b,0x8f,0x16,0x2b,0xa1,0x00, -0xc6,0xfb,0x8a,0x39,0xf5,0x33,0xed,0x36,0x14,0x55,0x17,0x8c,0x3a,0xde,0x5e,0xdf, -0xcb,0x41,0x4c,0xc7,0x89,0x7d,0xe3,0xe9,0x34,0x08,0xda,0xdc,0x08,0x77,0x98,0xda, -0x65,0xae,0x27,0x74,0xf1,0x79,0xd0,0x28,0x54,0x64,0x86,0x7f,0x02,0xe0,0x71,0x51, -0x56,0x4e,0xca,0x72,0x94,0x62,0x49,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -uint8 precanned_key_packet_e2[] = { -0x48,0x00,0x00,0x00,0x8a,0xe4,0x9f,0x8a,0xd5,0x04,0x02,0xfd,0x09,0x1f,0xff,0x53, -0xe0,0xb2,0x72,0x8b,0x19,0xba,0x22,0xe4,0x2a,0x7b,0xeb,0x79,0xa8,0x83,0x31,0x6f, -0x5c,0xcc,0x37,0x9c,0xe8,0x73,0x64,0x64,0xd3,0xab,0xaa,0x9f,0xbe,0x49,0x27,0xfc, -0x95,0xf3,0x6e,0xf8,0xb1,0x01,0x7c,0xba,0xa9,0xc5,0x35,0x9c,0x8f,0x74,0x3a,0x9f, -0xd4,0x26,0x4d,0x39,0x90,0xbe,0xf4,0xfb,0x72,0x9e,0x54,0x18 -}; - -/* Create an RC4 key and transfer it to the server */ -void rdp_establish_key(HCONN conn) +/* Send an RDP packet */ +static void rdp_send(STREAM s, uint8 pdu_type) { - mcs_init_data(conn); - memcpy(conn->out.data + conn->out.offset, precanned_key_packet, - sizeof(precanned_key_packet)); - conn->out.offset += sizeof(precanned_key_packet); - MARK_END(conn->out); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); + 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, SEC_ENCRYPT); } -/* Create an RC4 key and transfer it to the server */ -void rdp_establish_key_e1(HCONN conn) +/* Receive an RDP packet */ +static STREAM rdp_recv(uint8 *type) { - mcs_init_data(conn); - memcpy(conn->out.data + conn->out.offset, precanned_key_packet_e1, - sizeof(precanned_key_packet_e1)); - conn->out.offset += sizeof(precanned_key_packet_e1); - MARK_END(conn->out); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); -} + static STREAM rdp_s; + uint16 length, pdu_type; -/* Create an RC4 key and transfer it to the server */ -void rdp_establish_key_e2(HCONN conn) -{ - mcs_init_data(conn); - memcpy(conn->out.data + conn->out.offset, precanned_key_packet_e2, - sizeof(precanned_key_packet_e2)); - conn->out.offset += sizeof(precanned_key_packet_e2); - MARK_END(conn->out); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); -} - -/* Horrible horrible certificate stuff. Work out later. */ -uint8 precanned_cert_packet[] = { // 4c8 -0x80,0x00,0x00,0x00,0x12,0x02,0xb4,0x04,0x01,0x00,0x00, -0x00,0x00,0x00,0x01,0x02,0x9d,0xa3,0x7a,0x93,0x34,0x7b,0x28,0x37,0x24,0xa0,0x1f, -0x61,0x26,0xfd,0x96,0x3a,0x92,0x83,0xf3,0xe9,0x6a,0x2e,0x81,0x7c,0x2c,0xe4,0x72,// -0x01,0x18,0xe9,0xa1,0x0f,0x00,0x00,0x48,0x00,0x84,0x23,0x90,0xe6,0xd3,0xf8,0x20, -0xdb,0xa8,0x1b,0xb2,0xd0,0x78,0x2c,0x35,0xde,0xe3,0x0e,0x63,0x40,0xca,0xac,0x71, -0xc9,0x17,0x49,0x05,0x25,0xeb,0x9b,0xd0,0xa6,0x5c,0x90,0x3e,0x9d,0x4b,0x27,0x01, -0x79,0x1c,0x22,0xfb,0x3c,0x2c,0xb9,0x9f,0xf5,0x21,0xf3,0xee,0xd5,0x4d,0x47,0x1c, -0x85,0xbe,0x83,0x93,0xe8,0xed,0x8c,0x5c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x01,0x00,0x10,0x04,0x30,0x82,0x04,0x0c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, -0x0d,0x01,0x07,0x02,0xa0,0x82,0x03,0xfd,0x30,0x82,0x03,0xf9,0x02,0x01,0x01,0x31, -0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x82, -0x03,0xe1,0x30,0x82,0x01,0x77,0x30,0x82,0x01,0x25,0xa0,0x03,0x02,0x01,0x02,0x02, -0x08,0x01,0xbf,0x06,0x84,0x9d,0xdb,0x2d,0xe0,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, -0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x30,0x38,0x31,0x36,0x30,0x11,0x06,0x03, -0x55,0x04,0x03,0x1e,0x0a,0x00,0x4e,0x00,0x54,0x00,0x54,0x00,0x53,0x00,0x45,0x30, -0x21,0x06,0x03,0x55,0x04,0x07,0x1e,0x1a,0x00,0x4d,0x00,0x69,0x00,0x63,0x00,0x72, -0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x6f, -0x00,0x6d,0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x39,0x32,0x34,0x31,0x32,0x30,0x32, -0x30,0x34,0x5a,0x17,0x0d,0x34,0x39,0x30,0x39,0x32,0x34,0x31,0x32,0x30,0x32,0x30, -0x34,0x5a,0x30,0x38,0x31,0x36,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x1e,0x0a,0x00, -0x4e,0x00,0x54,0x00,0x54,0x00,0x53,0x00,0x45,0x30,0x21,0x06,0x03,0x55,0x04,0x07, -0x1e,0x1a,0x00,0x4d,0x00,0x69,0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f, -0x00,0x66,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x30,0x5c,0x30,0x0d, -0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x4b,0x00, -0x30,0x48,0x02,0x41,0x00,0x91,0xb2,0x16,0x1c,0xae,0x4f,0x7f,0x7c,0xaf,0x57,0x2b, -0x23,0x4c,0x0c,0x25,0x3c,0x4f,0x66,0x9d,0x25,0xc3,0x4f,0x29,0xee,0x8b,0xda,0x4e, -0x95,0xe7,0x3b,0xaa,0xc0,0xa7,0xba,0xaf,0x99,0x8c,0x47,0x24,0x8b,0x09,0x77,0xbc, -0x2c,0xf4,0xe7,0x1a,0x07,0x58,0x7b,0x11,0x37,0x2a,0xa8,0x90,0xc3,0x50,0x92,0x80, -0x15,0xc5,0xda,0x51,0x8b,0x02,0x03,0x01,0x00,0x01,0xa3,0x13,0x30,0x11,0x30,0x0f, -0x06,0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30, -0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x41,0x00,0x14,0x04,0x67, -0x28,0xc8,0xd3,0x1f,0x13,0x14,0x2e,0x2c,0x93,0x09,0x25,0xbb,0xbe,0x86,0x6a,0xd3, -0x47,0x6f,0x44,0x16,0x7b,0x94,0x8c,0xb2,0xa2,0xd5,0xf7,0x4f,0xb1,0x8f,0x7f,0xde, -0x0b,0x88,0x34,0x4a,0x1d,0xdc,0xa1,0xfd,0x26,0xbd,0x43,0xbb,0x38,0xf1,0x87,0x34, -0xbb,0xe9,0x3b,0xfa,0x7f,0x1e,0xff,0xe1,0x10,0x7e,0xee,0x6e,0xd8,0x30,0x82,0x02, -0x62,0x30,0x82,0x02,0x10,0xa0,0x03,0x02,0x01,0x02,0x02,0x05,0x01,0x00,0x00,0x00, -0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x38,0x31,0x36, -0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x1e,0x0a,0x00,0x4e,0x00,0x54,0x00,0x54,0x00, -0x53,0x00,0x45,0x30,0x21,0x06,0x03,0x55,0x04,0x07,0x1e,0x1a,0x00,0x4d,0x00,0x69, -0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x2e, -0x00,0x63,0x00,0x6f,0x00,0x6d,0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x39,0x32,0x34, -0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x34,0x39,0x30,0x39,0x32,0x34,0x30, -0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x79,0x31,0x77,0x30,0x17,0x06,0x03,0x55,0x04, -0x03,0x1e,0x10,0x00,0x52,0x00,0x45,0x00,0x53,0x00,0x37,0x00,0x2d,0x00,0x4e,0x00, -0x45,0x00,0x57,0x30,0x17,0x06,0x03,0x55,0x04,0x07,0x1e,0x10,0x00,0x7a,0x00,0x32, -0x00,0x32,0x00,0x33,0x00,0x32,0x00,0x32,0x00,0x30,0x00,0x33,0x30,0x43,0x06,0x03, -0x55,0x04,0x05,0x1e,0x3c,0x00,0x31,0x00,0x42,0x00,0x63,0x00,0x4b,0x00,0x65,0x00, -0x57,0x00,0x50,0x00,0x6c,0x00,0x37,0x00,0x58,0x00,0x47,0x00,0x61,0x00,0x73,0x00, -0x38,0x00,0x4a,0x00,0x79,0x00,0x50,0x00,0x34,0x00,0x30,0x00,0x7a,0x00,0x49,0x00, -0x6d,0x00,0x6e,0x00,0x6f,0x00,0x51,0x00,0x5a,0x00,0x59,0x00,0x3d,0x00,0x0d,0x00, -0x0a,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, -0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0x91,0xb2,0x16,0x1c,0xae,0x4f, -0x7f,0x7c,0xaf,0x57,0x2b,0x23,0x4c,0x0c,0x25,0x3c,0x4f,0x66,0x9d,0x25,0xc3,0x4f, -0x29,0xee,0x8b,0xda,0x4e,0x95,0xe7,0x3b,0xaa,0xc0,0xa7,0xba,0xaf,0x99,0x8c,0x47, -0x24,0x8b,0x09,0x77,0xbc,0x2c,0xf4,0xe7,0x1a,0x07,0x58,0x7b,0x11,0x37,0x2a,0xa8, -0x90,0xc3,0x50,0x92,0x80,0x15,0xc5,0xda,0x51,0x8b,0x02,0x03,0x01,0x00,0x01,0xa3, -0x81,0xc3,0x30,0x81,0xc0,0x30,0x14,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0x82,0x37, -0x12,0x04,0x01,0x01,0xff,0x04,0x04,0x01,0x00,0x01,0x00,0x30,0x3c,0x06,0x09,0x2b, -0x06,0x01,0x04,0x01,0x82,0x37,0x12,0x02,0x01,0x01,0xff,0x04,0x2c,0x4d,0x00,0x69, -0x00,0x63,0x00,0x72,0x00,0x6f,0x00,0x73,0x00,0x6f,0x00,0x66,0x00,0x74,0x00,0x20, -0x00,0x43,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x61,0x00,0x74, -0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x30,0x4c,0x06,0x09,0x2b,0x06,0x01, -0x04,0x01,0x82,0x37,0x12,0x05,0x01,0x01,0xff,0x04,0x3c,0x00,0x10,0x00,0x00,0x01, -0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x18,0x00,0x18,0x00,0x30, -0x00,0x01,0x00,0x32,0x00,0x33,0x00,0x36,0x00,0x2d,0x00,0x34,0x00,0x2e,0x00,0x30, -0x00,0x30,0x00,0x2d,0x00,0x45,0x00,0x58,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x1c,0x06,0x03,0x55,0x1d,0x23,0x01,0x01, -0xff,0x04,0x12,0x30,0x10,0xa1,0x07,0x81,0x05,0x4e,0x54,0x54,0x53,0x45,0x82,0x05, -0x01,0x00,0x00,0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, -0x03,0x41,0x00,0x7b,0x1d,0xfd,0x24,0xea,0xf2,0xe8,0x17,0xdd,0x88,0x7e,0xfd,0xee, -0x28,0x61,0x7a,0x02,0xc3,0x73,0xcf,0x32,0x0f,0x7c,0x66,0x87,0x31,0xa7,0xbe,0x1b, -0x31,0xe2,0x20,0xa5,0x76,0x91,0x68,0x97,0x53,0x9e,0x80,0xcd,0x2b,0xd0,0x8e,0x8b, -0x7f,0x89,0x1b,0x62,0xa8,0xf8,0xee,0x5e,0x56,0xbd,0x9c,0x6b,0x80,0x06,0x54,0xd3, -0xf0,0xbf,0xb2,0x31,0x00,0x01,0x00,0x14,0x00,0xc7,0x32,0xf2,0x5b,0x98,0x0e,0x04, -0x49,0xa0,0x27,0x7e,0xf5,0xf6,0x0f,0xda,0x08,0x1d,0xe9,0x79,0xd1,0x31,0xc6,0x50, -0x90,0x4a,0xd3,0x1f,0x1d,0xf0,0x65,0x0d,0xb6,0x1f,0xaf,0xc9,0x1d -}; - -/* Send license certificate and related data to the server */ -void rdp_send_cert(HCONN conn) -{ - mcs_init_data(conn); - prs_io_uint8s(&conn->out, precanned_cert_packet, sizeof(precanned_cert_packet)); - MARK_END(conn->out); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); -} - -/* Initialise RDP transport packet */ -void rdp_init(HCONN conn) -{ - mcs_init_data(conn); - PUSH_LAYER(conn->out, rdp_offset, 6); -} - -/* Transmit RDP transport packet */ -void rdp_send(HCONN conn, uint16 pdu_type) -{ - RDP_HEADER hdr; - int length; - - POP_LAYER(conn->out, rdp_offset); - length = conn->out.end - conn->out.offset; - rdp_make_header(&hdr, length, pdu_type, conn->mcs_userid); - rdp_io_header(&conn->out, &hdr); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); -} - -/* Initialise RDP transport data packet */ -void rdp_init_data(HCONN conn) -{ - mcs_init_data(conn); - PUSH_LAYER(conn->out, rdp_offset, 18); -} - -/* Transmit RDP transport data packet */ -void rdp_send_data(HCONN conn, uint16 data_pdu_type) -{ - RDP_HEADER hdr; - RDP_DATA_HEADER datahdr; - int length = conn->out.end - conn->out.offset; - - POP_LAYER(conn->out, rdp_offset); - length = conn->out.end - conn->out.offset; - rdp_make_header(&hdr, length, RDP_PDU_DATA, conn->mcs_userid); - rdp_io_header(&conn->out, &hdr); - rdp_make_data_header(&datahdr, 0x103ea, length, data_pdu_type); - rdp_io_data_header(&conn->out, &datahdr); - mcs_send_data(conn, MCS_GLOBAL_CHANNEL, True); -} - -void rdp_send_confirm_active(HCONN conn, uint32 shareid, int width, int height) -{ - RDP_ACTIVE_PDU active; - - rdp_init(conn); - rdp_make_active_pdu(&active, shareid, conn->mcs_userid, width, height); - rdp_io_active_pdu(&conn->out, &active, RDP_PDU_CONFIRM_ACTIVE); - MARK_END(conn->out); - rdp_send(conn, RDP_PDU_CONFIRM_ACTIVE); -} - -void rdp_send_synchronize(HCONN conn) -{ - RDP_SYNCHRONISE_PDU sync; - - rdp_init_data(conn); - rdp_make_synchronise_pdu(&sync, 1002); - rdp_io_synchronise_pdu(&conn->out, &sync); - MARK_END(conn->out); - rdp_send_data(conn, RDP_DATA_PDU_SYNCHRONIZE); -} - -void rdp_send_control(HCONN conn, uint16 action) -{ - RDP_CONTROL_PDU control; - - rdp_init_data(conn); - rdp_make_control_pdu(&control, action); - rdp_io_control_pdu(&conn->out, &control); - MARK_END(conn->out); - rdp_send_data(conn, RDP_DATA_PDU_CONTROL); -} - -void rdp_send_fonts(HCONN conn, uint16 seqno) -{ - RDP_FONT_PDU fonts; - - rdp_init_data(conn); - rdp_make_font_pdu(&fonts, seqno); - rdp_io_font_pdu(&conn->out, &fonts); - MARK_END(conn->out); - rdp_send_data(conn, RDP_DATA_PDU_FONT2); -} - -void rdp_send_input(HCONN conn, uint16 message_type, uint16 device_flags, - uint16 param1, uint16 param2) -{ - RDP_INPUT_PDU input; - - rdp_init_data(conn); - rdp_make_input_pdu(&input, message_type, device_flags, param1, param2); - rdp_io_input_pdu(&conn->out, &input); - MARK_END(conn->out); - rdp_send_data(conn, RDP_DATA_PDU_INPUT); -} - -BOOL rdp_recv_pdu(HCONN conn, uint8 *type) -{ - RDP_HEADER hdr; - - conn->in.offset = conn->in.rdp_offset; - - if (conn->in.offset >= conn->in.end) + if ((rdp_s == NULL) || (next_packet >= rdp_s->end)) { - if (!mcs_recv(conn, False)) - return False; + rdp_s = sec_recv(); + if (rdp_s == NULL) + return NULL; + + next_packet = rdp_s->p; + } + else + { + rdp_s->p = next_packet; } - if (!rdp_io_header(&conn->in, &hdr)) - return False; + in_uint16_le(rdp_s, length); + in_uint16_le(rdp_s, pdu_type); + in_uint8s(rdp_s, 2); /* userid */ - conn->in.rdp_offset += hdr.length; - *type = hdr.pdu_type & 0xf; + next_packet += length; + *type = pdu_type & 0xf; -#if DUMP - fprintf(stderr, "RDP packet (type %x):\n", *type); - dump_data(conn->in.data+conn->in.offset, conn->in.rdp_offset-conn->in.offset); +#if RDP_DEBUG + DEBUG("RDP packet (type %x):\n", *type); + hexdump(rdp_s->p, length); #endif - return True; + return rdp_s; } -/* Disconnect from the RDP layer */ -void rdp_disconnect(HCONN conn) +/* Initialise an RDP data packet */ +static STREAM rdp_init_data(int maxlen) { - mcs_disconnect(conn); + STREAM s; + + s = sec_init(SEC_ENCRYPT, maxlen + 18); + s_push_layer(s, rdp_hdr, 18); + + return s; } -/* Construct an RDP header */ -void rdp_make_header(RDP_HEADER *hdr, uint16 length, uint16 pdu_type, - uint16 userid) +/* Send an RDP data packet */ +static void rdp_send_data(STREAM s, uint8 data_pdu_type) { - hdr->length = length; - hdr->pdu_type = pdu_type | 0x10; /* Version 1 */ - hdr->userid = userid + 1001; -} - -/* Parse an RDP header */ -BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr) -{ - BOOL res = True; - - res = res ? lsb_io_uint16(s, &hdr->length ) : False; - res = res ? lsb_io_uint16(s, &hdr->pdu_type) : False; - if ((hdr->pdu_type & 0xf) != RDP_PDU_DEACTIVATE) - res = res ? lsb_io_uint16(s, &hdr->userid ) : False; - - return res; -} - -/* Construct a data header */ -void rdp_make_data_header(RDP_DATA_HEADER *hdr, uint32 shareid, - uint16 length, uint16 data_pdu_type) -{ - hdr->shareid = shareid; - hdr->pad = 0; - hdr->streamid = 1; - hdr->length = length - 14; - hdr->data_pdu_type = data_pdu_type; - hdr->compress_type = 0; - hdr->compress_len = 0; -} - -/* Parse a data header */ -BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr) -{ - BOOL res = True; - - res = res ? lsb_io_uint32(s, &hdr->shareid ) : False; - res = res ? prs_io_uint8 (s, &hdr->pad ) : False; - res = res ? prs_io_uint8 (s, &hdr->streamid ) : False; - res = res ? lsb_io_uint16(s, &hdr->length ) : False; - res = res ? prs_io_uint8 (s, &hdr->data_pdu_type) : False; - res = res ? prs_io_uint8 (s, &hdr->compress_type) : False; - res = res ? lsb_io_uint16(s, &hdr->compress_len ) : False; - - return res; -} - -BOOL rdp_io_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) - return False; - - size -= 2; - } - - *present = 0; - for (i = 0; i < size; i++) - { - prs_io_uint8(s, &bits); - *present |= bits << (i * 8); - } - - return True; -} - -BOOL rdp_io_coord(STREAM s, uint16 *coord, BOOL delta) -{ - uint8 change; - BOOL res; - - if (delta) - { - res = prs_io_uint8(s, &change); - *coord += (char)change; - } - else - { - res = lsb_io_uint16(s, coord); - } - - return res; -} - -BOOL rdp_io_colour(STREAM s, uint8 *colour) -{ - BOOL res; - - res = prs_io_uint8(s, colour); - s->offset += 2; - - return res; -} - -BOOL rdp_io_colourmap(STREAM s, COLOURMAP *colours) -{ - int datasize; - - lsb_io_uint16(s, &colours->ncolours); - datasize = colours->ncolours * 3; - - if (datasize > sizeof(colours->colours)) - return False; - - memcpy(colours->colours, s->data + s->offset, datasize); - s->offset += datasize; - return True; -} - -BOOL rdp_io_bounds(STREAM s, BOUNDS *bounds) -{ - uint8 present; - - prs_io_uint8(s, &present); - - if (present & 1) - rdp_io_coord(s, &bounds->left, False); - else if (present & 16) - rdp_io_coord(s, &bounds->left, True); - - if (present & 2) - rdp_io_coord(s, &bounds->top, False); - else if (present & 32) - rdp_io_coord(s, &bounds->top, True); - - if (present & 4) - rdp_io_coord(s, &bounds->right, False); - else if (present & 64) - rdp_io_coord(s, &bounds->right, True); - - if (present & 8) - rdp_io_coord(s, &bounds->bottom, False); - else if (present & 128) - rdp_io_coord(s, &bounds->bottom, True); - - return True; -} - -BOOL rdp_io_pen(STREAM s, PEN *pen, uint32 present) -{ - BOOL res = True; - - if (present & 1) - res = res ? prs_io_uint8(s, &pen->style) : False; - - if (present & 2) - res = res ? prs_io_uint8(s, &pen->width) : False; - - if (present & 4) - res = res ? rdp_io_colour(s, &pen->colour) : False; - - return res; -} - -BOOL rdp_io_brush(STREAM s, BRUSH *brush, uint32 present) -{ - BOOL res = True; - - if (present & 1) - res = res ? prs_io_uint8(s, &brush->xorigin) : False; - - if (present & 2) - res = res ? prs_io_uint8(s, &brush->yorigin) : False; - - if (present & 4) - res = res ? prs_io_uint8(s, &brush->style) : False; - - if (present & 8) - res = res ? prs_io_uint8(s, &brush->pattern[0]) : False; - - if (present & 16) - res = res ? prs_io_uint8s(s, &brush->pattern[1], 7) : False; - - return res; -} - -/* Construct a confirm/demand active PDU */ -void rdp_make_active_pdu(RDP_ACTIVE_PDU *pdu, uint32 shareid, uint16 userid, - int width, int height) -{ - memset(pdu, 0, sizeof(*pdu)); - pdu->shareid = shareid; - pdu->userid = 1002; - pdu->source_len = sizeof(RDP_SOURCE); - memcpy(pdu->source, RDP_SOURCE, sizeof(RDP_SOURCE)); - - pdu->caps_len = 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; - pdu->num_caps = 0xD; - - rdp_make_general_caps (&pdu->general_caps ); - rdp_make_bitmap_caps (&pdu->bitmap_caps, width, height); - rdp_make_order_caps (&pdu->order_caps ); - rdp_make_bmpcache_caps(&pdu->bmpcache_caps); - rdp_make_control_caps (&pdu->control_caps ); - rdp_make_activate_caps(&pdu->activate_caps); - rdp_make_pointer_caps (&pdu->pointer_caps ); - rdp_make_share_caps (&pdu->share_caps, userid); - rdp_make_colcache_caps(&pdu->colcache_caps); -} - -/* Parse a confirm/demand active PDU */ -BOOL rdp_io_active_pdu(STREAM s, RDP_ACTIVE_PDU *pdu, int pdutype) -{ - uint16 capset; uint16 length; - BOOL res; - int i; - res = lsb_io_uint32(s, &pdu->shareid); + s_pop_layer(s, rdp_hdr); + length = s->end - s->p; - if (pdutype == RDP_PDU_CONFIRM_ACTIVE) - res = res ? lsb_io_uint16(s, &pdu->userid ) : False; + out_uint16_le(s, length); + out_uint16_le(s, (RDP_PDU_DATA | 0x10)); + out_uint16_le(s, (mcs_userid + 1001)); - res = res ? lsb_io_uint16(s, &pdu->source_len) : False; - res = res ? lsb_io_uint16(s, &pdu->caps_len ) : False; + out_uint32_le(s, rdp_shareid); + out_uint8(s, 0); /* pad */ + out_uint8(s, 1); /* streamid */ + out_uint16(s, (length - 14)); + out_uint8(s, data_pdu_type); + out_uint8(s, 0); /* compress_type */ + out_uint16(s, 0); /* compress_len */ - if (pdu->source_len > 48) + sec_send(s, SEC_ENCRYPT); +} + +/* 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) { - ERROR("RDP source descriptor too long\n"); - return False; + s->p[i++] = string[j++]; + s->p[i++] = 0; } - res = res ? prs_io_uint8s(s, pdu->source, pdu->source_len) : False; - res = res ? lsb_io_uint16(s, &pdu->num_caps ) : False; - res = res ? lsb_io_uint16(s, &pdu->pad ) : False; - - if (s->marshall) - { - capset = RDP_CAPSET_GENERAL; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_general_caps(s, &pdu->general_caps) : False; - - capset = RDP_CAPSET_BITMAP; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_bitmap_caps (s, &pdu->bitmap_caps ) : False; - - capset = RDP_CAPSET_ORDER; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_order_caps (s, &pdu->order_caps ) : False; - - capset = RDP_CAPSET_BMPCACHE; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_bmpcache_caps(s, &pdu->bmpcache_caps) : False; - - capset = RDP_CAPSET_COLCACHE; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_colcache_caps(s, &pdu->colcache_caps) : False; - - capset = RDP_CAPSET_ACTIVATE; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_activate_caps(s, &pdu->activate_caps) : False; - - capset = RDP_CAPSET_CONTROL; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_control_caps(s, &pdu->control_caps) : False; - - capset = RDP_CAPSET_POINTER; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_pointer_caps(s, &pdu->pointer_caps) : False; - - capset = RDP_CAPSET_SHARE; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_share_caps (s, &pdu->share_caps ) : False; - - capset = RDP_CAPSET_UNKNOWN; - res = res ? lsb_io_uint16(s, &capset) : False; - res = res ? rdp_io_unknown_caps(s, NULL) : False; - } - else - { - for (i = 0; i < pdu->num_caps; i++) - { - if (!res) - return False; - - if (!lsb_io_uint16(s, &capset)) - return False; - - switch (capset) - { - case RDP_CAPSET_GENERAL: - res = rdp_io_general_caps (s, &pdu->general_caps ); - break; - case RDP_CAPSET_BITMAP: - res = rdp_io_bitmap_caps (s, &pdu->bitmap_caps ); - break; - case RDP_CAPSET_ORDER: - res = rdp_io_order_caps (s, &pdu->order_caps ); - break; - case RDP_CAPSET_BMPCACHE: - res = rdp_io_bmpcache_caps(s, &pdu->bmpcache_caps); - break; - case RDP_CAPSET_CONTROL: - res = rdp_io_control_caps (s, &pdu->control_caps ); - break; - case RDP_CAPSET_ACTIVATE: - res = rdp_io_activate_caps(s, &pdu->activate_caps); - break; - case RDP_CAPSET_POINTER: - res = rdp_io_pointer_caps (s, &pdu->pointer_caps ); - break; - case RDP_CAPSET_SHARE: - res = rdp_io_share_caps (s, &pdu->share_caps ); - break; - case RDP_CAPSET_COLCACHE: - res = rdp_io_colcache_caps(s, &pdu->colcache_caps); - break; - default: - NOTIMP("capset 0x%x\n", capset); - - if (!lsb_io_uint16(s, &length)) - return False; - - s->offset += (length - 4); - } - } - } - - return res; + s->p += len; } -/* Construct a control PDU */ -void rdp_make_control_pdu(RDP_CONTROL_PDU *pdu, uint16 action) +/* Parse a logon info packet */ +static void rdp_send_logon_info(uint32 flags, char *domain, char *user, + char *password, char *program, char *directory) { - pdu->action = action; - pdu->userid = 0; - pdu->controlid = 0; + 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 = SEC_LOGON_INFO | SEC_ENCRYPT; + 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); } -/* Parse a control PDU */ -BOOL rdp_io_control_pdu(STREAM s, RDP_CONTROL_PDU *pdu) +/* Send a control PDU */ +static void rdp_send_control(uint16 action) { - BOOL res = True; + STREAM s; - res = res ? lsb_io_uint16(s, &pdu->action ) : False; - res = res ? lsb_io_uint16(s, &pdu->userid ) : False; - res = res ? lsb_io_uint32(s, &pdu->controlid) : False; + s = rdp_init_data(8); - return res; + 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); } -/* Construct a synchronisation PDU */ -void rdp_make_synchronise_pdu(RDP_SYNCHRONISE_PDU *pdu, uint16 userid) +/* Send a synchronisation PDU */ +static void rdp_send_synchronise() { - pdu->type = 1; - pdu->userid = userid; + 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); } -/* Parse a synchronisation PDU */ -BOOL rdp_io_synchronise_pdu(STREAM s, RDP_SYNCHRONISE_PDU *pdu) +/* Send a single input event */ +void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, + uint16 param1, uint16 param2) { - BOOL res = True; + STREAM s; - res = res ? lsb_io_uint16(s, &pdu->type ) : False; - res = res ? lsb_io_uint16(s, &pdu->userid) : False; + s = rdp_init_data(16); - return res; + 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); } -/* Parse a single input event */ -BOOL rdp_io_input_event(STREAM s, RDP_INPUT_EVENT *evt) +/* Send an (empty) font information PDU */ +static void rdp_send_fonts(uint16 seq) { - BOOL res = True; + STREAM s; - res = res ? lsb_io_uint32(s, &evt->event_time) : False; - res = res ? lsb_io_uint16(s, &evt->message_type) : False; - res = res ? lsb_io_uint16(s, &evt->device_flags) : False; + s = rdp_init_data(8); - if (!res) - return False; + 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 */ - switch (evt->message_type) - { - case RDP_INPUT_CODEPOINT: - case RDP_INPUT_VIRTKEY: - res = res ? lsb_io_uint16(s, &evt->param1) : False; - break; - case RDP_INPUT_SYNCHRONIZE: - case RDP_INPUT_SCANCODE: - case RDP_INPUT_MOUSE: - res = res ? lsb_io_uint16(s, &evt->param1) : False; - res = res ? lsb_io_uint16(s, &evt->param2) : False; - break; - default: - NOTIMP("input type %d\n", evt->message_type); - return False; - } - - return res; + s_mark_end(s); + rdp_send_data(s, RDP_DATA_PDU_FONT2); } -/* Construct an input PDU */ -void rdp_make_input_pdu(RDP_INPUT_PDU *pdu, uint16 message_type, - uint16 device_flags, uint16 param1, uint16 param2) +/* Output general capability set */ +static void rdp_out_general_caps(STREAM s) { - uint32 now = time(NULL); + out_uint16_le(s, RDP_CAPSET_GENERAL); + out_uint16_le(s, RDP_CAPLEN_GENERAL); - pdu->num_events = 1; - pdu->pad = 0; - - pdu->event[0].event_time = now; - pdu->event[0].message_type = message_type; - pdu->event[0].device_flags = device_flags; - pdu->event[0].param1 = param1; - pdu->event[0].param2 = param2; + 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 */ } -/* Parse an input PDU */ -BOOL rdp_io_input_pdu(STREAM s, RDP_INPUT_PDU *pdu) +/* Output bitmap capability set */ +static void rdp_out_bitmap_caps(STREAM s) { - BOOL res = True; - int i; + out_uint16_le(s, RDP_CAPSET_BITMAP); + out_uint16_le(s, RDP_CAPLEN_BITMAP); - res = res ? lsb_io_uint16(s, &pdu->num_events) : False; - res = res ? lsb_io_uint16(s, &pdu->pad ) : False; - - if (pdu->num_events > RDP_MAX_EVENTS) - { - ERROR("Too many events in one PDU\n"); - return False; - } - - for (i = 0; i < pdu->num_events; i++) - { - res = res ? rdp_io_input_event(s, &pdu->event[i]) : False; - } - - return res; + out_uint16_le(s, 8); /* Preferred BPP */ + out_uint16(s, 1); /* Receive 1 BPP */ + out_uint16(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, 1); /* Support compression */ + out_uint16(s, 0); /* Unknown */ + out_uint16_le(s, 1); /* Unknown */ + out_uint16(s, 0); /* Pad */ } -/* Construct a font information PDU */ -void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno) +/* Output order capability set */ +static void rdp_out_order_caps(STREAM s) { - pdu->num_fonts = 0; - pdu->unknown1 = 0x3e; - pdu->unknown2 = seqno; - pdu->entry_size = RDP_FONT_INFO_SIZE; + uint8 order_caps[32]; + + memset(order_caps, orders, 32); + + 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(s, 0x38400); /* Desktop cache size */ + out_uint32(s, 0); /* Unknown */ + out_uint32(s, 0x4e4); /* Unknown */ } -/* Parse a font information structure */ -BOOL rdp_io_font_info(STREAM s, RDP_FONT_INFO *font) +/* Output bitmap cache capability set */ +static void rdp_out_bmpcache_caps(STREAM s) { - BOOL res = True; + out_uint16_le(s, RDP_CAPSET_BMPCACHE); + out_uint16_le(s, RDP_CAPLEN_BMPCACHE); - res = res ? prs_io_uint8s(s, font->name, 32 ) : False; - res = res ? lsb_io_uint16(s, &font->flags ) : False; - res = res ? lsb_io_uint16(s, &font->width ) : False; - res = res ? lsb_io_uint16(s, &font->height ) : False; - res = res ? lsb_io_uint16(s, &font->xaspect ) : False; - res = res ? lsb_io_uint16(s, &font->yaspect ) : False; - res = res ? lsb_io_uint32(s, &font->signature) : False; - res = res ? lsb_io_uint16(s, &font->codepage ) : False; - res = res ? lsb_io_uint16(s, &font->ascent ) : False; - - return res; + 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 */ } -/* Parse a font information PDU */ -BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu) +/* Output control capability set */ +static void rdp_out_control_caps(STREAM s) { - BOOL res = True; - int i; + out_uint16_le(s, RDP_CAPSET_CONTROL); + out_uint16_le(s, RDP_CAPLEN_CONTROL); - res = res ? lsb_io_uint16(s, &pdu->num_fonts ) : False; - res = res ? lsb_io_uint16(s, &pdu->unknown1 ) : False; - res = res ? lsb_io_uint16(s, &pdu->unknown2 ) : False; - res = res ? lsb_io_uint16(s, &pdu->entry_size) : False; - - if (pdu->num_fonts > RDP_MAX_FONTS) - { - ERROR("Too many fonts in one PDU\n"); - return False; - } - - for (i = 0; i < pdu->num_fonts; i++) - { - res = res ? rdp_io_font_info(s, &pdu->font[i]) : False; - } - - return res; + 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 */ } -/* Parse a pointer PDU */ -BOOL rdp_io_pointer_pdu(STREAM s, RDP_POINTER_PDU *ptr) +/* Output activation capability set */ +static void rdp_out_activate_caps(STREAM s) { - BOOL res = True; + out_uint16_le(s, RDP_CAPSET_ACTIVATE); + out_uint16_le(s, RDP_CAPLEN_ACTIVATE); - res = res ? lsb_io_uint16(s, &ptr->message) : False; - res = res ? lsb_io_uint16(s, &ptr->pad ) : False; - - switch (ptr->message) - { - case RDP_POINTER_MOVE: - res = res ? lsb_io_uint16(s, &ptr->x ) : False; - res = res ? lsb_io_uint16(s, &ptr->y ) : False; - break; - } - - return res; + 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 */ } -/* Parse an update PDU */ -BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu) +/* Output pointer capability set */ +static void rdp_out_pointer_caps(STREAM s) { - BOOL res = True; + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_POINTER); - res = res ? lsb_io_uint16(s, &pdu->update_type) : False; - res = res ? lsb_io_uint16(s, &pdu->pad ) : False; - - return res; + out_uint16(s, 0); /* Colour pointer */ + out_uint16_le(s, 20); /* Cache size */ } - -/* PRIMARY ORDERS */ - -/* Parse an destination blt order */ -BOOL rdp_io_destblt_order(STREAM s, DESTBLT_ORDER *os, uint32 present, BOOL delta) +/* Output share capability set */ +static void rdp_out_share_caps(STREAM s) { - if (present & 0x01) - rdp_io_coord(s, &os->x, delta); + out_uint16_le(s, RDP_CAPSET_SHARE); + out_uint16_le(s, RDP_CAPLEN_SHARE); - if (present & 0x02) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x04) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x08) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x10) - prs_io_uint8(s, &os->opcode); - - return PRS_ERROR(s); + out_uint16(s, 0); /* userid */ + out_uint16(s, 0); /* pad */ } -/* Parse an pattern blt order */ -BOOL rdp_io_patblt_order(STREAM s, PATBLT_ORDER *os, uint32 present, BOOL delta) +/* Output colour cache capability set */ +static void rdp_out_colcache_caps(STREAM s) { - if (present & 0x0001) - rdp_io_coord(s, &os->x, delta); + out_uint16_le(s, RDP_CAPSET_COLCACHE); + out_uint16_le(s, RDP_CAPLEN_COLCACHE); - if (present & 0x0002) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x0004) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x0008) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x0010) - prs_io_uint8(s, &os->opcode); - - if (present & 0x0020) - rdp_io_colour(s, &os->bgcolour); - - if (present & 0x0040) - rdp_io_colour(s, &os->fgcolour); - - rdp_io_brush(s, &os->brush, present >> 7); - - return PRS_ERROR(s); + out_uint16_le(s, 6); /* cache size */ + out_uint16(s, 0); /* pad */ } -/* Parse an screen blt order */ -BOOL rdp_io_screenblt_order(STREAM s, SCREENBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x0001) - rdp_io_coord(s, &os->x, delta); - - if (present & 0x0002) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x0004) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x0008) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x0010) - prs_io_uint8(s, &os->opcode); - - if (present & 0x0020) - rdp_io_coord(s, &os->srcx, delta); - - if (present & 0x0040) - rdp_io_coord(s, &os->srcy, delta); - - return PRS_ERROR(s); -} - -/* Parse a line order */ -BOOL rdp_io_line_order(STREAM s, LINE_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x0001) - lsb_io_uint16(s, &os->mixmode); - - if (present & 0x0002) - rdp_io_coord(s, &os->startx, delta); - - if (present & 0x0004) - rdp_io_coord(s, &os->starty, delta); - - if (present & 0x0008) - rdp_io_coord(s, &os->endx, delta); - - if (present & 0x0010) - rdp_io_coord(s, &os->endy, delta); - - if (present & 0x0020) - rdp_io_colour(s, &os->bgcolour); - - if (present & 0x0040) - prs_io_uint8(s, &os->opcode); - - rdp_io_pen(s, &os->pen, present >> 7); - - return PRS_ERROR(s); -} - -/* Parse an opaque rectangle order */ -BOOL rdp_io_rect_order(STREAM s, RECT_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x01) - rdp_io_coord(s, &os->x, delta); - - if (present & 0x02) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x04) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x08) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x10) - prs_io_uint8(s, &os->colour); - - return PRS_ERROR(s); -} - -/* Parse a desktop save order */ -BOOL rdp_io_desksave_order(STREAM s, DESKSAVE_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x01) - lsb_io_uint32(s, &os->offset); - - if (present & 0x02) - rdp_io_coord(s, &os->left, delta); - - if (present & 0x04) - rdp_io_coord(s, &os->top, delta); - - if (present & 0x08) - rdp_io_coord(s, &os->right, delta); - - if (present & 0x10) - rdp_io_coord(s, &os->bottom, delta); - - if (present & 0x20) - prs_io_uint8(s, &os->action); - - return PRS_ERROR(s); -} - -/* Parse a memory blt order */ -BOOL rdp_io_memblt_order(STREAM s, MEMBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x0001) - { - prs_io_uint8(s, &os->cache_id); - prs_io_uint8(s, &os->colour_table); - } - - if (present & 0x0002) - rdp_io_coord(s, &os->x, delta); - - if (present & 0x0004) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x0008) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x0010) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x0020) - prs_io_uint8(s, &os->opcode); - - if (present & 0x0040) - rdp_io_coord(s, &os->srcx, delta); - - if (present & 0x0080) - rdp_io_coord(s, &os->srcy, delta); - - if (present & 0x0100) - lsb_io_uint16(s, &os->cache_idx); - - return PRS_ERROR(s); -} - -/* Parse a 3-way blt order */ -BOOL rdp_io_triblt_order(STREAM s, TRIBLT_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x000001) - { - prs_io_uint8(s, &os->cache_id); - prs_io_uint8(s, &os->colour_table); - } - - if (present & 0x000002) - rdp_io_coord(s, &os->x, delta); - - if (present & 0x000004) - rdp_io_coord(s, &os->y, delta); - - if (present & 0x000008) - rdp_io_coord(s, &os->cx, delta); - - if (present & 0x000010) - rdp_io_coord(s, &os->cy, delta); - - if (present & 0x000020) - prs_io_uint8(s, &os->opcode); - - if (present & 0x000040) - rdp_io_coord(s, &os->srcx, delta); - - if (present & 0x000080) - rdp_io_coord(s, &os->srcy, delta); - - if (present & 0x000100) - rdp_io_colour(s, &os->bgcolour); - - if (present & 0x000200) - rdp_io_colour(s, &os->fgcolour); - - rdp_io_brush(s, &os->brush, present >> 10); - - if (present & 0x008000) - lsb_io_uint16(s, &os->cache_idx); - - if (present & 0x010000) - lsb_io_uint16(s, &os->unknown); - - return PRS_ERROR(s); -} - -/* Parse a text order */ -BOOL rdp_io_text2_order(STREAM s, TEXT2_ORDER *os, uint32 present, BOOL delta) -{ - if (present & 0x000001) - prs_io_uint8(s, &os->font); - - if (present & 0x000002) - prs_io_uint8(s, &os->flags); - - if (present & 0x000004) - prs_io_uint8(s, &os->unknown); - - if (present & 0x000008) - prs_io_uint8(s, &os->mixmode); - - if (present & 0x000010) - rdp_io_colour(s, &os->fgcolour); - - if (present & 0x000020) - rdp_io_colour(s, &os->bgcolour); - - if (present & 0x000040) - lsb_io_uint16(s, &os->clipleft); - - if (present & 0x000080) - lsb_io_uint16(s, &os->cliptop); - - if (present & 0x000100) - lsb_io_uint16(s, &os->clipright); - - if (present & 0x000200) - lsb_io_uint16(s, &os->clipbottom); - - if (present & 0x000400) - lsb_io_uint16(s, &os->boxleft); - - if (present & 0x000800) - lsb_io_uint16(s, &os->boxtop); - - if (present & 0x001000) - lsb_io_uint16(s, &os->boxright); - - if (present & 0x002000) - lsb_io_uint16(s, &os->boxbottom); - - if (present & 0x080000) - lsb_io_uint16(s, &os->x); - - if (present & 0x100000) - lsb_io_uint16(s, &os->y); - - if (present & 0x200000) - { - prs_io_uint8(s, &os->length); - prs_io_uint8s(s, os->text, os->length); - } - - return PRS_ERROR(s); -} - - -/* SECONDARY ORDERS */ - -BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso) -{ - BOOL res = True; - - res = res ? lsb_io_uint16(s, &rso->length) : False; - res = res ? lsb_io_uint16(s, &rso->flags ) : False; - res = res ? prs_io_uint8 (s, &rso->type ) : False; - - return res; -} - -BOOL rdp_io_raw_bmpcache_order(STREAM s, RDP_RAW_BMPCACHE_ORDER *rbo) -{ - BOOL res = True; - - res = res ? prs_io_uint8 (s, &rbo->cache_id ) : False; - res = res ? prs_io_uint8 (s, &rbo->pad1 ) : False; - res = res ? prs_io_uint8 (s, &rbo->width ) : False; - res = res ? prs_io_uint8 (s, &rbo->height ) : False; - res = res ? prs_io_uint8 (s, &rbo->bpp ) : False; - res = res ? lsb_io_uint16(s, &rbo->bufsize ) : False; - res = res ? lsb_io_uint16(s, &rbo->cache_idx ) : False; - - rbo->data = s->data + s->offset; - s->offset += rbo->bufsize; - - return res; -} - -BOOL rdp_io_bmpcache_order(STREAM s, RDP_BMPCACHE_ORDER *rbo) -{ - BOOL res = True; - - res = res ? prs_io_uint8 (s, &rbo->cache_id ) : False; - res = res ? prs_io_uint8 (s, &rbo->pad1 ) : False; - res = res ? prs_io_uint8 (s, &rbo->width ) : False; - res = res ? prs_io_uint8 (s, &rbo->height ) : False; - res = res ? prs_io_uint8 (s, &rbo->bpp ) : False; - res = res ? lsb_io_uint16(s, &rbo->bufsize ) : False; - res = res ? lsb_io_uint16(s, &rbo->cache_idx ) : False; - res = res ? lsb_io_uint16(s, &rbo->pad2 ) : False; - res = res ? lsb_io_uint16(s, &rbo->size ) : False; - res = res ? lsb_io_uint16(s, &rbo->row_size ) : False; - res = res ? lsb_io_uint16(s, &rbo->final_size) : False; - - rbo->data = s->data + s->offset; - s->offset += rbo->size; - - return res; -} - -BOOL rdp_io_colcache_order(STREAM s, RDP_COLCACHE_ORDER *colours) -{ - COLOURENTRY *entry; - int i; - - prs_io_uint8(s, &colours->cache_id); - lsb_io_uint16(s, &colours->map.ncolours); - - for (i = 0; i < colours->map.ncolours; i++) - { - entry = &colours->map.colours[i]; - prs_io_uint8(s, &entry->blue); - prs_io_uint8(s, &entry->green); - prs_io_uint8(s, &entry->red); - s->offset++; - } - - return True; -} - -BOOL rdp_io_fontcache_order(STREAM s, RDP_FONTCACHE_ORDER *font) -{ - RDP_FONT_GLYPH *glyph; - BOOL res = True; - int i, j, datasize; - uint8 in, out; - - res = res ? prs_io_uint8(s, &font->font ) : False; - res = res ? prs_io_uint8(s, &font->nglyphs) : False; - - for (i = 0; i < font->nglyphs; i++) - { - glyph = &font->glyphs[i]; - res = res ? lsb_io_uint16(s, &glyph->character) : False; - res = res ? lsb_io_uint16(s, &glyph->unknown ) : False; - res = res ? lsb_io_uint16(s, &glyph->baseline ) : False; - res = res ? lsb_io_uint16(s, &glyph->width ) : False; - res = res ? lsb_io_uint16(s, &glyph->height ) : False; - - datasize = (glyph->height * ((glyph->width + 7) / 8) + 3) & ~3; - res = res ? prs_io_uint8s(s, glyph->data, datasize) : False; - for (j = 0; j < datasize; j++) - { - in = glyph->data[j]; - out = 0; - if (in & 1) out |= 128; - if (in & 2) out |= 64; - if (in & 4) out |= 32; - if (in & 8) out |= 16; - if (in & 16) out |= 8; - if (in & 32) out |= 4; - if (in & 64) out |= 2; - if (in & 128) out |= 1; - glyph->data[j] = out; - } - } - - return res; -} - - -/* CAPABILITIES */ - -/* Construct a general capability set */ -void rdp_make_general_caps(RDP_GENERAL_CAPS *caps) -{ - caps->os_major_type = 1; - caps->os_minor_type = 3; - caps->ver_protocol = 0x200; -} - -/* Parse general capability set */ -BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_GENERAL; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->os_major_type ) : False; - res = res ? lsb_io_uint16(s, &caps->os_minor_type ) : False; - res = res ? lsb_io_uint16(s, &caps->ver_protocol ) : False; - res = res ? lsb_io_uint16(s, &caps->pad1 ) : False; - res = res ? lsb_io_uint16(s, &caps->compress_types) : False; - res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; - res = res ? lsb_io_uint16(s, &caps->cap_update ) : False; - res = res ? lsb_io_uint16(s, &caps->remote_unshare) : False; - res = res ? lsb_io_uint16(s, &caps->compress_level) : False; - res = res ? lsb_io_uint16(s, &caps->pad3 ) : False; - - return res; -} - -/* Construct a bitmap capability set */ -void rdp_make_bitmap_caps(RDP_BITMAP_CAPS *caps, int width, int height) -{ - caps->preferred_bpp = 8; - caps->receive1bpp = 1; - caps->receive4bpp = 1; - caps->receive8bpp = 1; - caps->width = width; - caps->height = height; - caps->compression = 1; - caps->unknown2 = 1; -} - -/* Parse bitmap capability set */ -BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_BITMAP; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->preferred_bpp) : False; - res = res ? lsb_io_uint16(s, &caps->receive1bpp ) : False; - res = res ? lsb_io_uint16(s, &caps->receive4bpp ) : False; - res = res ? lsb_io_uint16(s, &caps->receive8bpp ) : False; - res = res ? lsb_io_uint16(s, &caps->width ) : False; - res = res ? lsb_io_uint16(s, &caps->height ) : False; - res = res ? lsb_io_uint16(s, &caps->pad1 ) : False; - res = res ? lsb_io_uint16(s, &caps->allow_resize ) : False; - res = res ? lsb_io_uint16(s, &caps->compression ) : False; - res = res ? lsb_io_uint16(s, &caps->unknown1 ) : False; - res = res ? lsb_io_uint16(s, &caps->unknown2 ) : False; - res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; - - return res; -} - -/* Construct an order capability set */ -void rdp_make_order_caps(RDP_ORDER_CAPS *caps) -{ - caps->xgranularity = 1; - caps->ygranularity = 20; - caps->max_order_level = 1; - caps->num_fonts = 0x147; - caps->cap_flags = 0x2A; - -// caps->cap_flags = ORDER_CAP_NEGOTIATE | ORDER_CAP_NOSUPPORT; - - caps->support[0] = caps->support[1] = caps->support[2] - = caps->support[3] = caps->support[4] = caps->support[5] - = caps->support[6] = caps->support[8] = caps->support[11] - = caps->support[12] = caps->support[22] = caps->support[28] - = caps->support[29] = caps->support[30] = 1; - caps->text_cap_flags = 0x6A1; - caps->desk_save_size = 0x38400; - caps->unknown2 = 0x4E4; -} - -/* Parse order capability set */ -BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_ORDER; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? prs_io_uint8s(s, caps->terminal_desc, 16) : False; - res = res ? lsb_io_uint32(s, &caps->pad1 ) : False; - res = res ? lsb_io_uint16(s, &caps->xgranularity ) : False; - res = res ? lsb_io_uint16(s, &caps->ygranularity ) : False; - res = res ? lsb_io_uint16(s, &caps->pad2 ) : False; - res = res ? lsb_io_uint16(s, &caps->max_order_level ) : False; - res = res ? lsb_io_uint16(s, &caps->num_fonts ) : False; - res = res ? lsb_io_uint16(s, &caps->cap_flags ) : False; - res = res ? prs_io_uint8s(s, caps->support , 32) : False; - res = res ? lsb_io_uint16(s, &caps->text_cap_flags ) : False; - res = res ? lsb_io_uint16(s, &caps->pad3 ) : False; - res = res ? lsb_io_uint32(s, &caps->pad4 ) : False; - res = res ? lsb_io_uint32(s, &caps->desk_save_size ) : False; - res = res ? lsb_io_uint32(s, &caps->unknown1 ) : False; - res = res ? lsb_io_uint32(s, &caps->unknown2 ) : False; - - return res; -} - -/* Construct a bitmap cache capability set */ -void rdp_make_bmpcache_caps(RDP_BMPCACHE_CAPS *caps) -{ - caps->caches[0].entries = 0x258; - caps->caches[0].max_cell_size = 0x100; - caps->caches[1].entries = 0x12c; - caps->caches[1].max_cell_size = 0x400; - caps->caches[2].entries = 0x106; - caps->caches[2].max_cell_size = 0x1000; -} - -/* Parse single bitmap cache information structure */ -BOOL rdp_io_bmpcache_info(STREAM s, RDP_BMPCACHE_INFO *info) -{ - if (!lsb_io_uint16(s, &info->entries )) - return False; - - if (!lsb_io_uint16(s, &info->max_cell_size)) - return False; - - return True; -} - -/* Parse bitmap cache capability set */ -BOOL rdp_io_bmpcache_caps(STREAM s, RDP_BMPCACHE_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_BMPCACHE; - uint16 pkt_length = length; - BOOL res; - int i; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - for (i = 0; i < 6; i++) - res = res ? lsb_io_uint32(s, &caps->unused[i]) : False; - - for (i = 0; i < 3; i++) - res = res ? rdp_io_bmpcache_info(s, &caps->caches[i]) : False; - - return res; -} - -/* Construct a control capability set */ -void rdp_make_control_caps(RDP_CONTROL_CAPS *caps) -{ - caps->control_interest = 2; - caps->detach_interest = 2; -} - -/* Parse control capability set */ -BOOL rdp_io_control_caps(STREAM s, RDP_CONTROL_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_CONTROL; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->control_caps ) : False; - res = res ? lsb_io_uint16(s, &caps->remote_detach ) : False; - res = res ? lsb_io_uint16(s, &caps->control_interest) : False; - res = res ? lsb_io_uint16(s, &caps->detach_interest ) : False; - - return res; -} - -/* Construct an activation capability set */ -void rdp_make_activate_caps(RDP_ACTIVATE_CAPS *caps) -{ -} - -/* Parse activation capability set */ -BOOL rdp_io_activate_caps(STREAM s, RDP_ACTIVATE_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_ACTIVATE; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->help_key ) : False; - res = res ? lsb_io_uint16(s, &caps->help_index_key ) : False; - res = res ? lsb_io_uint16(s, &caps->help_extended_key) : False; - res = res ? lsb_io_uint16(s, &caps->window_activate ) : False; - - return res; -} - -/* Construct a pointer capability set */ -void rdp_make_pointer_caps(RDP_POINTER_CAPS *caps) -{ - caps->colour_pointer = 0; - caps->cache_size = 20; -} - -/* Parse pointer capability set */ -BOOL rdp_io_pointer_caps(STREAM s, RDP_POINTER_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_POINTER; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->colour_pointer) : False; - res = res ? lsb_io_uint16(s, &caps->cache_size ) : False; - - return res; -} - -/* Construct a share capability set */ -void rdp_make_share_caps(RDP_SHARE_CAPS *caps, uint16 userid) -{ -} - -/* Parse share capability set */ -BOOL rdp_io_share_caps(STREAM s, RDP_SHARE_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_SHARE; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->userid) : False; - res = res ? lsb_io_uint16(s, &caps->pad ) : False; - - return res; -} - -/* Construct a colour cache capability set */ -void rdp_make_colcache_caps(RDP_COLCACHE_CAPS *caps) -{ - caps->cache_size = 6; -} - -/* Parse colour cache capability set */ -BOOL rdp_io_colcache_caps(STREAM s, RDP_COLCACHE_CAPS *caps) -{ - uint16 length = RDP_CAPLEN_COLCACHE; - uint16 pkt_length = length; - BOOL res; - - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) - { - ERROR("Unrecognised capabilities size\n"); - return False; - } - - res = res ? lsb_io_uint16(s, &caps->cache_size) : False; - res = res ? lsb_io_uint16(s, &caps->pad ) : False; - - return res; -} - -uint8 canned_caps[] = { +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, @@ -1585,21 +380,265 @@ uint8 canned_caps[] = { 0x00,0x00,0x01,0x40,0x00,0x00,0x08,0x00,0x01,0x00,0x01,0x02,0x00,0x00,0x00 }; -/* Insert canned capabilities */ -BOOL rdp_io_unknown_caps(STREAM s, void *caps) +/* Output unknown capability set */ +static void rdp_out_unknown_caps(STREAM s) { - uint16 length = 0x58; - uint16 pkt_length = length; - BOOL res; + out_uint16_le(s, RDP_CAPSET_UNKNOWN); + out_uint16_le(s, 0x58); + + out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN-4); +} - res = lsb_io_uint16(s, &pkt_length); - if (pkt_length != length) +/* Send a confirm active PDU */ +static void rdp_send_confirm_active() +{ + 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; + + 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 */ +static 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; + + in_uint16_le(s, message_type); + in_uint8s(s, 2); /* pad */ + + switch (message_type) { - ERROR("Unrecognised capabilities size\n"); - return False; + case RDP_POINTER_MOVE: + in_uint16_le(s, x); + in_uint16_le(s, y); + if (s_check(s)) + ui_move_pointer(x, y); + 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, compress, bufsize, size; + uint8 *data, *rawdata; + 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); + 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) + { + in_uint8p(s, data, bufsize); + ui_paint_bitmap(left, top, cx, cy, width, height, data); + return; + } + + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, size); + in_uint8s(s, 4); /* line_size, final_size */ + in_uint8p(s, data, size); + + rawdata = xmalloc(width * height); + if (bitmap_decompress(rawdata, width, height, data, size)) + { + ui_paint_bitmap(left, top, cx, cy, width, height, + rawdata); + } + + xfree(rawdata); + } +} + +/* Process a palette update */ +static void process_palette(STREAM s) +{ + HCOLOURMAP hmap; + COLOURMAP map; + + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, map.ncolours); + in_uint8s(s, 2); /* pad */ + in_uint8p(s, (uint8 *)map.colours, (map.ncolours * 3)); + + 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); + + 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: + NOTIMP("update %d\n", update_type); } - res = res ? prs_io_uint8s(s, canned_caps, RDP_CAPLEN_UNKNOWN-4) : False; - - return res; } + +/* Process data PDU */ +static 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: + NOTIMP("data PDU %d\n", data_pdu_type); + } +} + +/* Process incoming packets */ +void rdp_main_loop() +{ + uint8 type; + STREAM s; + + while ((s = rdp_recv(&type)) != NULL) + { + 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; + + default: + NOTIMP("PDU %d\n", type); + } + } +} + +/* Establish a connection up to the RDP layer */ +BOOL rdp_connect(char *server) +{ + if (!sec_connect(server)) + return False; + + rdp_send_logon_info(0x33, "", username, "", "", ""); + return True; +} + +/* Disconnect from the RDP layer */ +void rdp_disconnect() +{ + sec_disconnect(); +} + diff --git a/rdp.h b/rdp.h deleted file mode 100644 index 7e9ae30..0000000 --- a/rdp.h +++ /dev/null @@ -1,575 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Protocol services - RDP layer - Copyright (C) Matthew Chapman 1999-2000 - - 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. -*/ - -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_SYNCHRONIZE = 31, - RDP_DATA_PDU_FONT2 = 39 -}; - -typedef struct _RDP_HEADER -{ - uint16 length; - uint16 pdu_type; - uint16 userid; - -} RDP_HEADER; - -typedef struct _RDP_DATA_HEADER -{ - uint32 shareid; - uint8 pad; - uint8 streamid; - uint16 length; - uint8 data_pdu_type; - uint8 compress_type; - uint16 compress_len; - -} RDP_DATA_HEADER; - -#define RDP_CAPSET_GENERAL 1 -#define RDP_CAPLEN_GENERAL 0x18 -#define OS_MAJOR_TYPE_UNIX 4 -#define OS_MINOR_TYPE_XSERVER 7 - -typedef struct _RDP_GENERAL_CAPS -{ - uint16 os_major_type; - uint16 os_minor_type; - uint16 ver_protocol; - uint16 pad1; - uint16 compress_types; - uint16 pad2; - uint16 cap_update; - uint16 remote_unshare; - uint16 compress_level; - uint16 pad3; - -} RDP_GENERAL_CAPS; - -#define RDP_CAPSET_BITMAP 2 -#define RDP_CAPLEN_BITMAP 0x1C - -typedef struct _RDP_BITMAP_CAPS -{ - uint16 preferred_bpp; - uint16 receive1bpp; - uint16 receive4bpp; - uint16 receive8bpp; - uint16 width; - uint16 height; - uint16 pad1; - uint16 allow_resize; - uint16 compression; - uint16 unknown1; - uint16 unknown2; - uint16 pad2; - -} RDP_BITMAP_CAPS; - -#define RDP_CAPSET_ORDER 3 -#define RDP_CAPLEN_ORDER 0x58 -#define ORDER_CAP_NEGOTIATE 2 -#define ORDER_CAP_NOSUPPORT 4 - -typedef struct _RDP_ORDER_CAPS -{ - uint8 terminal_desc[16]; - uint32 pad1; - uint16 xgranularity; // 1 - uint16 ygranularity; // 20 - uint16 pad2; - uint16 max_order_level; - uint16 num_fonts; // 0x2C - uint16 cap_flags; // 0x22 - uint8 support[32]; - uint16 text_cap_flags; // 0x6A1 - uint16 pad3; - uint32 pad4; - uint32 desk_save_size; - uint32 unknown1; // 1 from server, 0 from client - uint32 unknown2; // 0x4E4 from client - -} RDP_ORDER_CAPS; - -#define RDP_CAPSET_BMPCACHE 4 -#define RDP_CAPLEN_BMPCACHE 0x28 - -typedef struct _RDP_BMPCACHE_INFO -{ - uint16 entries; - uint16 max_cell_size; - -} RDP_BMPCACHE_INFO; - -typedef struct _RDP_BMPCACHE_CAPS -{ - uint32 unused[6]; - RDP_BMPCACHE_INFO caches[3]; - -} RDP_BMPCACHE_CAPS; - -#define RDP_CAPSET_CONTROL 5 -#define RDP_CAPLEN_CONTROL 0x0C - -typedef struct _RDP_CONTROL_CAPS -{ - uint16 control_caps; - uint16 remote_detach; - uint16 control_interest; - uint16 detach_interest; - -} RDP_CONTROL_CAPS; - -#define RDP_CAPSET_ACTIVATE 7 -#define RDP_CAPLEN_ACTIVATE 0x0C - -typedef struct _RDP_ACTIVATE_CAPS -{ - uint16 help_key; - uint16 help_index_key; - uint16 help_extended_key; - uint16 window_activate; - -} RDP_ACTIVATE_CAPS; - -#define RDP_CAPSET_POINTER 8 -#define RDP_CAPLEN_POINTER 0x08 - -typedef struct _RDP_POINTER_CAPS -{ - uint16 colour_pointer; - uint16 cache_size; - -} RDP_POINTER_CAPS; - -#define RDP_CAPSET_SHARE 9 -#define RDP_CAPLEN_SHARE 0x08 - -typedef struct _RDP_SHARE_CAPS -{ - uint16 userid; - uint16 pad; - -} RDP_SHARE_CAPS; - -#define RDP_CAPSET_COLCACHE 10 -#define RDP_CAPLEN_COLCACHE 0x08 - -typedef struct _RDP_COLCACHE_CAPS -{ - uint16 cache_size; - uint16 pad; - -} RDP_COLCACHE_CAPS; - -#define RDP_CAPSET_UNKNOWN 13 -#define RDP_CAPLEN_UNKNOWN 0x9C - -#define RDP_SOURCE "MSTSC" - -typedef struct _RDP_ACTIVE_PDU -{ - uint32 shareid; - uint16 userid; // RDP_PDU_CONFIRM_ACTIVE only - uint16 source_len; - uint16 caps_len; - uint8 source[48]; - uint16 num_caps; - uint16 pad; - - RDP_GENERAL_CAPS general_caps; - RDP_BITMAP_CAPS bitmap_caps; - RDP_ORDER_CAPS order_caps; - RDP_BMPCACHE_CAPS bmpcache_caps; - RDP_ACTIVATE_CAPS activate_caps; - RDP_CONTROL_CAPS control_caps; - RDP_POINTER_CAPS pointer_caps; - RDP_SHARE_CAPS share_caps; - RDP_COLCACHE_CAPS colcache_caps; - -} RDP_ACTIVE_PDU; - -typedef struct _RDP_SYNCHRONISE_PDU -{ - uint16 type; // 1 - uint16 userid; - -} RDP_SYNCHRONISE_PDU; - -#define RDP_CTL_REQUEST_CONTROL 1 -#define RDP_CTL_GRANT_CONTROL 2 -#define RDP_CTL_DETACH 3 -#define RDP_CTL_COOPERATE 4 - -typedef struct _RDP_CONTROL_PDU -{ - uint16 action; // see above - uint16 userid; - uint32 controlid; - -} RDP_CONTROL_PDU; - -#define RDP_INPUT_SYNCHRONIZE 0 -#define RDP_INPUT_CODEPOINT 1 -#define RDP_INPUT_VIRTKEY 2 -#define RDP_INPUT_SCANCODE 4 -#define RDP_INPUT_MOUSE 0x8001 - -#define KBD_FLAG_RIGHT 0x0001 -#define KBD_FLAG_QUIET 0x1000 -#define KBD_FLAG_DOWN 0x4000 -#define KBD_FLAG_UP 0x8000 - -#define MOUSE_FLAG_MOVE 0x0800 -#define MOUSE_FLAG_BUTTON1 0x1000 -#define MOUSE_FLAG_BUTTON2 0x2000 -#define MOUSE_FLAG_BUTTON3 0x4000 -#define MOUSE_FLAG_DOWN 0x8000 - -#define RDP_MAX_EVENTS 50 - -typedef struct _RDP_INPUT_EVENT -{ - uint32 event_time; - uint16 message_type; - uint16 device_flags; - uint16 param1; - uint16 param2; - -} RDP_INPUT_EVENT; - -typedef struct _RDP_INPUT_PDU -{ - uint16 num_events; - uint16 pad; - RDP_INPUT_EVENT event[RDP_MAX_EVENTS]; - -} RDP_INPUT_PDU; - -#define RDP_FONT_INFO_SIZE 0x32 -#define RDP_MAX_FONTS 100 - -typedef struct _RDP_FONT_INFO -{ - uint8 name[32]; - uint16 flags; - uint16 width; - uint16 height; - uint16 xaspect; - uint16 yaspect; - uint32 signature; - uint16 codepage; - uint16 ascent; - -} RDP_FONT_INFO; - -typedef struct _RDP_FONT_PDU -{ - uint16 num_fonts; - uint16 unknown1; // 0x3e - uint16 unknown2; // series number? - uint16 entry_size; - RDP_FONT_INFO font[RDP_MAX_FONTS]; - -} RDP_FONT_PDU; - -#define RDP_UPDATE_ORDERS 0 -#define RDP_UPDATE_PALETTE 2 -#define RDP_UPDATE_SYNCHRONIZE 3 - -typedef struct _DESTBLT_ORDER -{ - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 opcode; - -} DESTBLT_ORDER; - -typedef struct _PATBLT_ORDER -{ - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 opcode; - uint8 bgcolour; - uint8 fgcolour; - BRUSH brush; - -} PATBLT_ORDER; - -typedef struct _SCREENBLT_ORDER -{ - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 opcode; - uint16 srcx; - uint16 srcy; - -} SCREENBLT_ORDER; - -typedef struct _LINE_ORDER -{ - uint16 mixmode; - uint16 startx; - uint16 starty; - uint16 endx; - uint16 endy; - uint8 bgcolour; - uint8 opcode; - PEN pen; - -} LINE_ORDER; - -typedef struct _RECT_ORDER -{ - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 colour; - -} RECT_ORDER; - -typedef struct _DESKSAVE_ORDER -{ - uint32 offset; - uint16 left; - uint16 top; - uint16 right; - uint16 bottom; - uint8 action; - -} DESKSAVE_ORDER; - -typedef struct _TRIBLT_ORDER -{ - uint8 colour_table; - uint8 cache_id; - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 opcode; - uint16 srcx; - uint16 srcy; - uint8 bgcolour; - uint8 fgcolour; - BRUSH brush; - uint16 cache_idx; - uint16 unknown; - -} TRIBLT_ORDER; - -typedef struct _MEMBLT_ORDER -{ - uint8 colour_table; - uint8 cache_id; - uint16 x; - uint16 y; - uint16 cx; - uint16 cy; - uint8 opcode; - uint16 srcx; - uint16 srcy; - uint16 cache_idx; - -} MEMBLT_ORDER; - -#define MAX_TEXT 256 - -#define MIX_TRANSPARENT 0 -#define MIX_OPAQUE 1 - -#define TEXT2_IMPLICIT_X 0x20 - -typedef struct _TEXT2_ORDER -{ - uint8 font; - uint8 flags; - uint8 mixmode; - uint8 unknown; - uint8 fgcolour; - uint8 bgcolour; - uint16 clipleft; - uint16 cliptop; - uint16 clipright; - uint16 clipbottom; - uint16 boxleft; - uint16 boxtop; - uint16 boxright; - uint16 boxbottom; - uint16 x; - uint16 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; - TEXT2_ORDER text2; - -} RDP_ORDER_STATE; - -typedef struct _RDP_UPDATE_PDU -{ - uint16 update_type; - uint16 pad; - -} RDP_UPDATE_PDU; - -#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_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 _RDP_SECONDARY_ORDER -{ - uint16 length; - uint16 flags; - uint8 type; - -} RDP_SECONDARY_ORDER; - -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; - -#define RDP_POINTER_MOVE 3 - -typedef struct _RDP_POINTER_PDU -{ - uint16 message; - uint16 pad; - uint16 x; - uint16 y; - -} RDP_POINTER_PDU; - diff --git a/secure.c b/secure.c new file mode 100644 index 0000000..a7dea10 --- /dev/null +++ b/secure.c @@ -0,0 +1,589 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Protocol services - RDP encryption and licensing + Copyright (C) Matthew Chapman 1999-2000 + + 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 "crypto/rc4.h" +#include "crypto/md5.h" +#include "crypto/sha.h" +#include "crypto/arith.h" + +extern char hostname[16]; +extern int width; +extern int height; +extern int keylayout; + +static int rc4_key_len; +static RC4_KEY rc4_decrypt_key; +static RC4_KEY rc4_encrypt_key; + +static uint8 sec_sign_key[8]; +static uint8 sec_decrypt_key[16]; +static uint8 sec_encrypt_key[16]; +static uint8 sec_decrypt_update_key[8]; +static uint8 sec_encrypt_update_key[8]; +static uint8 sec_crypted_random[64]; + +/* + * 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 8 bytes of session key, for generating signatures */ + memcpy(sec_sign_key, session_key, 8); + + /* 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; + } + + /* Store first 8 bytes of RC4 keys as update keys */ + memcpy(sec_decrypt_update_key, sec_decrypt_key, 8); + memcpy(sec_encrypt_update_key, sec_encrypt_key, 8); + + /* 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, uint8 *session_key, int length, + 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, length); + 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, length); + MD5_Update(&md5, pad_92, 48); + MD5_Update(&md5, shasig, 20); + MD5_Final(md5sig, &md5); + + memcpy(signature, md5sig, length); +} + +/* 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, 8); + SHA1_Update(&sha, pad_54, 40); + SHA1_Update(&sha, key, 8); + SHA1_Final(shasig, &sha); + + MD5_Init(&md5); + MD5_Update(&md5, update_key, 8); + 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++; +} + +/* Read in a NUMBER from a buffer */ +static void sec_read_number(NUMBER *num, uint8 *buffer, int len) +{ + INT *data = num->n_part; + int i, j; + + for (i = 0, j = 0; j < len; i++, j += 2) + data[i] = buffer[j] | (buffer[j+1] << 8); + + num->n_len = i; +} + +/* Write a NUMBER to a buffer */ +static void sec_write_number(NUMBER *num, uint8 *buffer, int len) +{ + INT *data = num->n_part; + int i, j; + + for (i = 0, j = 0; j < len; i++, j += 2) + { + buffer[j] = data[i] & 0xff; + buffer[j+1] = data[i] >> 8; + } +} + +/* Perform an RSA public key encryption operation */ +static void sec_rsa_encrypt(uint8 *out, uint8 *in, int len, + uint8 *modulus, uint8 *exponent) +{ + NUMBER data, key; + + /* Set modulus for arithmetic */ + sec_read_number(&key, modulus, SEC_MODULUS_SIZE); + m_init(&key, NULL); + + /* Exponentiate */ + sec_read_number(&data, in, len); + sec_read_number(&key, exponent, SEC_EXPONENT_SIZE); + m_exp(&data, &key, &data); + sec_write_number(&data, out, SEC_MODULUS_SIZE); +} + +/* Initialise secure transport packet */ +STREAM sec_init(uint32 flags, int maxlen) +{ + int hdrlen; + STREAM s; + + hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; + 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); + out_uint32_le(s, flags); + + if (flags & SEC_ENCRYPT) + { + flags &= ~SEC_ENCRYPT; + datalen = s->end - s->p - 8; + +#if RDP_DEBUG + DEBUG("Sending encrypted packet:\n"); + hexdump(s->p+8, datalen); +#endif + + sec_sign(s->p, sec_sign_key, 8, 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() +{ + 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); + + 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, width); + out_uint16_le(s, 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 */ + + out_uint16(s, 0xca01); + out_uint16(s, 0); + + /* Client encryption settings */ + out_uint16_le(s, SEC_TAG_CLI_CRYPT); + out_uint16(s, 8); /* length */ + out_uint32_le(s, 1); /* encryption enabled */ + 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 */ + 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: + NOTIMP("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; + + in_uint8s(s, 23); /* header */ + + 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: + NOTIMP("response tag 0x%x\n", tag); + } + + s->p = next_tag; + } +} + +/* Receive secure transport packet */ +STREAM sec_recv() +{ + uint32 sec_flags; + STREAM s; + + while ((s = mcs_recv()) != NULL) + { + 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 = xmalloc(mcs_data.size); + sec_out_mcs_data(&mcs_data); + + if (!mcs_connect(server, &mcs_data)) + return False; + + sec_process_mcs_data(&mcs_data); + sec_establish_key(); + return True; +} + +/* Disconnect a connection */ +void sec_disconnect() +{ + mcs_disconnect(); +} diff --git a/tcp.c b/tcp.c index 6d47743..94941bb 100644 --- a/tcp.c +++ b/tcp.c @@ -18,15 +18,102 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include /* select read write close */ +#include /* socket connect setsockopt */ +#include /* timeval */ +#include /* gethostbyname */ +#include /* TCP_NODELAY */ +#include /* inet_aton */ +#include /* errno */ +#include "rdesktop.h" + +static int sock; +static struct stream in; +static struct stream out; + +/* Initialise TCP transport data packet */ +STREAM tcp_init(int maxlen) +{ + if (maxlen > out.size) + { + out.data = 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 = write(sock, s->data + total, length - total); + + if (sent <= 0) + { + STATUS("write: %s\n", strerror(errno)); + return; + } + + total += sent; + } +} + +/* Receive a message on the TCP layer */ +STREAM tcp_recv(int length) +{ + int ret, rcvd = 0; + struct timeval tv; + fd_set rfds; + + if (length > in.size) + { + in.data = xrealloc(in.data, length); + in.size = length; + } + + in.end = in.p = in.data; + + while (length > 0) + { + ui_process_events(); + + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 100; + + ret = select(sock+1, &rfds, NULL, NULL, &tv); + + if (ret) + { + rcvd = read(sock, in.end, length); + + if (rcvd <= 0) + { + STATUS("read: %s\n", strerror(errno)); + return NULL; + } + + in.end += rcvd; + length -= rcvd; + } + } + + return ∈ +} /* Establish a connection on the TCP layer */ -HCONN tcp_connect(char *server) +BOOL tcp_connect(char *server) { struct hostent *nslookup; struct sockaddr_in servaddr; - struct connection *conn; - int sock; int true = 1; if ((nslookup = gethostbyname(server)) != NULL) @@ -35,14 +122,14 @@ HCONN tcp_connect(char *server) } else if (!inet_aton(server, &servaddr.sin_addr)) { - fprintf(stderr, "%s: unable to resolve host\n", server); - return NULL; + STATUS("%s: unable to resolve host\n", server); + return False; } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket: %s\n", strerror(errno)); - return NULL; + STATUS("socket: %s\n", strerror(errno)); + return False; } servaddr.sin_family = AF_INET; @@ -50,90 +137,24 @@ HCONN tcp_connect(char *server) if (connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) { - fprintf(stderr, "connect: %s\n", strerror(errno)); + STATUS("connect: %s\n", strerror(errno)); close(sock); - return NULL; + return False; } setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &true, sizeof(true)); - conn = xmalloc(sizeof(struct connection)); - STREAM_INIT(conn->in, False); - STREAM_INIT(conn->out, True); + in.size = 4096; + in.data = xmalloc(in.size); - conn->tcp_socket = sock; - return conn; + out.size = 4096; + out.data = xmalloc(out.size); + + return True; } /* Disconnect on the TCP layer */ -void tcp_disconnect(HCONN conn) +void tcp_disconnect() { - close(conn->tcp_socket); - free(conn); -} - -/* Send TCP transport data packet */ -BOOL tcp_send(HCONN conn) -{ - int length = conn->out.end; - int sent, total = 0; - - while (total < length) - { - sent = write(conn->tcp_socket, conn->out.data + total, - length - total); - - if (sent <= 0) - { - fprintf(stderr, "write: %s\n", strerror(errno)); - return False; - } - - total += sent; - } - - conn->out.offset = 0; - conn->out.end = conn->out.size; - return True; -} - -/* Receive a message on the TCP layer */ -BOOL tcp_recv(HCONN conn, int length) -{ - int ret, rcvd = 0; - struct timeval tv; - fd_set rfds; - - STREAM_SIZE(conn->in, length); - conn->in.end = conn->in.offset = 0; - - while (length > 0) - { - ui_process_events(conn->wnd, conn); - - FD_ZERO(&rfds); - FD_SET(conn->tcp_socket, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 100; - - ret = select(conn->tcp_socket+1, &rfds, NULL, NULL, &tv); - - if (ret) - { - rcvd = read(conn->tcp_socket, conn->in.data - + conn->in.end, length); - - if (rcvd <= 0) - { - fprintf(stderr, "read: %s\n", - strerror(errno)); - return False; - } - - conn->in.end += rcvd; - length -= rcvd; - } - } - - return True; + close(sock); } diff --git a/tcp.h b/tcp.h deleted file mode 100644 index b867765..0000000 --- a/tcp.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Protocol services - TCP layer - Copyright (C) Matthew Chapman 1999-2000 - - 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. -*/ - -/* Port number for Remote Desktop Protocol */ -#define TCP_PORT_RDP 3389 diff --git a/misc.h b/types.h similarity index 61% rename from misc.h rename to types.h index cfce5ba..7ee5642 100644 --- a/misc.h +++ b/types.h @@ -1,6 +1,6 @@ /* rdesktop: A Remote Desktop Protocol client. - Protocol services - RDP layer + Common data types Copyright (C) Matthew Chapman 1999-2000 This program is free software; you can redistribute it and/or modify @@ -18,38 +18,37 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0])) -#define DEBUG(args...) fprintf(stderr, args); -#define ERROR(args...) fprintf(stderr, "ERROR: "args); -#define WARN(args...) fprintf(stderr, "WARNING: "args); -#define NOTIMP(args...) fprintf(stderr, "NOT IMPLEMENTED: "args); +typedef int BOOL; -#define ROP2_S(rop3) (rop3 & 0xf) -#define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)) +#ifndef True +#define True (1) +#define False (0) +#endif -#define ROP2_COPY 0xc -#define ROP2_XOR 0x6 -#define ROP2_AND 0x8 -#define ROP2_OR 0xe +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; -#define MAX_COLOURS 256 +typedef void *HBITMAP; +typedef void *HGLYPH; +typedef void *HCOLOURMAP; -typedef struct _colourentry +typedef struct _COLOURENTRY { - uint8 blue; - uint8 green; uint8 red; + uint8 green; + uint8 blue; } COLOURENTRY; -typedef struct _colourmap +typedef struct _COLOURMAP { uint16 ncolours; - COLOURENTRY colours[MAX_COLOURS]; + COLOURENTRY *colours; } COLOURMAP; -typedef struct _bounds +typedef struct _BOUNDS { uint16 left; uint16 top; @@ -58,7 +57,7 @@ typedef struct _bounds } BOUNDS; -typedef struct _pen +typedef struct _PEN { uint8 style; uint8 width; @@ -66,7 +65,7 @@ typedef struct _pen } PEN; -typedef struct _brush +typedef struct _BRUSH { uint8 xorigin; uint8 yorigin; @@ -75,18 +74,18 @@ typedef struct _brush } BRUSH; -typedef struct _font_glyph +typedef struct _FONTGLYPH { uint16 baseline; uint16 width; uint16 height; HBITMAP pixmap; -} FONT_GLYPH; +} FONTGLYPH; -typedef struct _blob +typedef struct _DATABLOB { void *data; int size; -} BLOB; +} DATABLOB; diff --git a/xwin.c b/xwin.c index 8c12929..e54f349 100644 --- a/xwin.c +++ b/xwin.c @@ -18,55 +18,73 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include +#include +#include "rdesktop.h" -HWINDOW ui_create_window(HCONN conn, int width, int height) +extern int width; +extern int height; +extern BOOL motion; + +static Display *display; +static Window wnd; +static GC gc; +static Visual *visual; +static XIM IM; + +BOOL ui_create_window(char *title) { - struct window *wnd; + Screen *screen; XSetWindowAttributes attribs; - Display *display; - Visual *visual; - Window window; - int black; - GC gc; + unsigned long input_mask; + int i; display = XOpenDisplay(NULL); if (display == NULL) - return NULL; + return False; + + /* Check the screen supports 8-bit depth. */ + screen = DefaultScreenOfDisplay(display); + for (i = 0; i < screen->ndepths; i++) + if (screen->depths[i].depth == 8) + break; + + if (i >= screen->ndepths) + { + ERROR("8-bit depth required (in this version).\n"); + XCloseDisplay(display); + return False; + } visual = DefaultVisual(display, DefaultScreen(display)); - black = BlackPixel(display, DefaultScreen(display)); - attribs.background_pixel = black; + attribs.background_pixel = BlackPixel(display, DefaultScreen(display)); attribs.backing_store = Always; - window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, - width, height, 0, 8, InputOutput, visual, + wnd = XCreateWindow(display, DefaultRootWindow(display), + 0, 0, width, height, 0, 8, InputOutput, visual, CWBackingStore | CWBackPixel, &attribs); - XStoreName(display, window, "rdesktop"); - XMapWindow(display, window); - XSelectInput(display, window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - XSync(display, True); + XStoreName(display, wnd, title); + XMapWindow(display, wnd); - gc = XCreateGC(display, window, 0, NULL); + input_mask = KeyPressMask | KeyReleaseMask; + input_mask |= ButtonPressMask | ButtonReleaseMask; + if (motion) + input_mask |= PointerMotionMask; - wnd = xmalloc(sizeof(struct window)); - wnd->conn = conn; - wnd->width = width; - wnd->height = height; - wnd->display = display; - wnd->wnd = window; - wnd->gc = gc; - wnd->visual = visual; + XSelectInput(display, wnd, input_mask); + gc = XCreateGC(display, wnd, 0, NULL); - return wnd; + IM = XOpenIM(display, NULL, NULL, NULL); + return True; } -void ui_destroy_window(HWINDOW wnd) +void ui_destroy_window() { - XFreeGC(wnd->display, wnd->gc); - XDestroyWindow(wnd->display, wnd->wnd); - XCloseDisplay(wnd->display); + XCloseIM(IM); + XFreeGC(display, gc); + XDestroyWindow(display, wnd); + XCloseDisplay(display); } static uint8 xwin_translate_key(unsigned long key) @@ -108,17 +126,20 @@ static uint16 xwin_translate_mouse(unsigned long button) return 0; } -void ui_process_events(HWINDOW wnd, HCONN conn) +void ui_process_events() { XEvent event; uint8 scancode; uint16 button; + uint32 ev_time; - if (wnd == NULL) + if (display == NULL) return; - while (XCheckWindowEvent(wnd->display, wnd->wnd, 0xffffffff, &event)) + while (XCheckWindowEvent(display, wnd, 0xffffffff, &event)) { + ev_time = time(NULL); + switch (event.type) { case KeyPress: @@ -126,7 +147,7 @@ void ui_process_events(HWINDOW wnd, HCONN conn) if (scancode == 0) break; - rdp_send_input(conn, RDP_INPUT_SCANCODE, 0, + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, scancode, 0); break; @@ -135,7 +156,7 @@ void ui_process_events(HWINDOW wnd, HCONN conn) if (scancode == 0) break; - rdp_send_input(conn, RDP_INPUT_SCANCODE, + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, scancode, 0); break; @@ -146,7 +167,7 @@ void ui_process_events(HWINDOW wnd, HCONN conn) if (button == 0) break; - rdp_send_input(conn, RDP_INPUT_MOUSE, + rdp_send_input(ev_time, RDP_INPUT_MOUSE, button | MOUSE_FLAG_DOWN, event.xbutton.x, event.xbutton.y); @@ -157,42 +178,60 @@ void ui_process_events(HWINDOW wnd, HCONN conn) if (button == 0) break; - rdp_send_input(conn, RDP_INPUT_MOUSE, + rdp_send_input(ev_time, RDP_INPUT_MOUSE, button, event.xbutton.x, event.xbutton.y); + break; + + case MotionNotify: + rdp_send_input(ev_time, RDP_INPUT_MOUSE, + MOUSE_FLAG_MOVE, + event.xmotion.x, + event.xmotion.y); } } } -void ui_move_pointer(HWINDOW wnd, int x, int y) +void ui_move_pointer(int x, int y) { - XWarpPointer(wnd->display, wnd->wnd, wnd->wnd, 0, 0, 0, 0, x, y); + XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y); } -HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data) +HBITMAP ui_create_bitmap(int width, int height, uint8 *data) { XImage *image; Pixmap bitmap; - bitmap = XCreatePixmap(wnd->display, wnd->wnd, width, height, 8); + bitmap = XCreatePixmap(display, wnd, width, height, 8); - image = XCreateImage(wnd->display, wnd->visual, 8, ZPixmap, 0, + image = XCreateImage(display, visual, 8, ZPixmap, 0, data, width, height, 8, width); - XSetFunction(wnd->display, wnd->gc, GXcopy); - XPutImage(wnd->display, bitmap, wnd->gc, image, 0, 0, 0, 0, - width, height); + XSetFunction(display, gc, GXcopy); + XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height); XFree(image); return (HBITMAP)bitmap; } -void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp) +void ui_paint_bitmap(int x, int y, int cx, int cy, + int width, int height, uint8 *data) { - XFreePixmap(wnd->display, (Pixmap)bmp); + XImage *image; + + image = XCreateImage(display, visual, 8, ZPixmap, 0, + data, width, height, 8, width); + XSetFunction(display, gc, GXcopy); + XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy); + XFree(image); } -HGLYPH ui_create_glyph(HWINDOW wnd, int width, int height, uint8 *data) +void ui_destroy_bitmap(HBITMAP bmp) +{ + XFreePixmap(display, (Pixmap)bmp); +} + +HGLYPH ui_create_glyph(int width, int height, uint8 *data) { XImage *image; Pixmap bitmap; @@ -201,32 +240,32 @@ HGLYPH ui_create_glyph(HWINDOW wnd, int width, int height, uint8 *data) scanline = (width + 7) / 8; - bitmap = XCreatePixmap(wnd->display, wnd->wnd, width, height, 1); - gc = XCreateGC(wnd->display, bitmap, 0, NULL); + bitmap = XCreatePixmap(display, wnd, width, height, 1); + gc = XCreateGC(display, bitmap, 0, NULL); - image = XCreateImage(wnd->display, wnd->visual, 1, ZPixmap, 0, + image = XCreateImage(display, visual, 1, ZPixmap, 0, data, width, height, 8, scanline); - XSetFunction(wnd->display, wnd->gc, GXcopy); - XPutImage(wnd->display, bitmap, gc, image, 0, 0, 0, 0, width, height); + XSetFunction(display, gc, GXcopy); + XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height); XFree(image); - XFreeGC(wnd->display, gc); + XFreeGC(display, gc); return (HGLYPH)bitmap; } -void ui_destroy_glyph(HWINDOW wnd, HGLYPH glyph) +void ui_destroy_glyph(HGLYPH glyph) { - XFreePixmap(wnd->display, (Pixmap)glyph); + XFreePixmap(display, (Pixmap)glyph); } -HCOLOURMAP ui_create_colourmap(HWINDOW wnd, COLOURMAP *colours) +HCOLOURMAP ui_create_colourmap(COLOURMAP *colours) { COLOURENTRY *entry; XColor *xcolours, *xentry; Colormap map; int i, ncolours = colours->ncolours; - xcolours = malloc(sizeof(XColor) * ncolours); + xcolours = xmalloc(sizeof(XColor) * ncolours); for (i = 0; i < ncolours; i++) { entry = &colours->colours[i]; @@ -239,24 +278,24 @@ HCOLOURMAP ui_create_colourmap(HWINDOW wnd, COLOURMAP *colours) xentry->flags = DoRed | DoBlue | DoGreen; } - map = XCreateColormap(wnd->display, wnd->wnd, wnd->visual, AllocAll); - XStoreColors(wnd->display, map, xcolours, ncolours); + map = XCreateColormap(display, wnd, visual, AllocAll); + XStoreColors(display, map, xcolours, ncolours); - free(xcolours); + xfree(xcolours); return (HCOLOURMAP)map; } -void ui_destroy_colourmap(HWINDOW wnd, HCOLOURMAP map) +void ui_destroy_colourmap(HCOLOURMAP map) { - XFreeColormap(wnd->display, (Colormap)map); + XFreeColormap(display, (Colormap)map); } -void ui_set_colourmap(HWINDOW wnd, HCOLOURMAP map) +void ui_set_colourmap(HCOLOURMAP map) { - XSetWindowColormap(wnd->display, wnd->wnd, (Colormap)map); + XSetWindowColormap(display, wnd, (Colormap)map); } -void ui_set_clip(HWINDOW wnd, int x, int y, int cx, int cy) +void ui_set_clip(int x, int y, int cx, int cy) { XRectangle rect; @@ -264,18 +303,23 @@ void ui_set_clip(HWINDOW wnd, int x, int y, int cx, int cy) rect.y = y; rect.width = cx; rect.height = cy; - XSetClipRectangles(wnd->display, wnd->gc, 0, 0, &rect, 1, YXBanded); + XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded); } -void ui_reset_clip(HWINDOW wnd) +void ui_reset_clip() { XRectangle rect; rect.x = 0; rect.y = 0; - rect.width = wnd->width; - rect.height = wnd->height; - XSetClipRectangles(wnd->display, wnd->gc, 0, 0, &rect, 1, YXBanded); + rect.width = width; + rect.height = height; + XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded); +} + +void ui_bell() +{ + XBell(display, 0); } static int rop2_map[] = { @@ -297,173 +341,172 @@ static int rop2_map[] = { GXset /* 1 */ }; -static void xwin_set_function(HWINDOW wnd, uint8 rop2) +static void xwin_set_function(uint8 rop2) { - XSetFunction(wnd->display, wnd->gc, rop2_map[rop2]); + XSetFunction(display, gc, rop2_map[rop2]); } -void ui_destblt(HWINDOW wnd, uint8 opcode, +void ui_destblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy) { - xwin_set_function(wnd, opcode); + xwin_set_function(opcode); - XFillRectangle(wnd->display, wnd->wnd, wnd->gc, x, y, cx, cy); + XFillRectangle(display, wnd, gc, x, y, cx, cy); } -void ui_patblt(HWINDOW wnd, uint8 opcode, +void ui_patblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* brush */ BRUSH *brush, int bgcolour, int fgcolour) { - Display *dpy = wnd->display; - GC gc = wnd->gc; + Display *dpy = display; Pixmap fill; - xwin_set_function(wnd, opcode); + xwin_set_function(opcode); switch (brush->style) { case 0: /* Solid */ XSetForeground(dpy, gc, fgcolour); - XFillRectangle(dpy, wnd->wnd, gc, x, y, cx, cy); + XFillRectangle(dpy, wnd, gc, x, y, cx, cy); break; case 3: /* Pattern */ - fill = (Pixmap)ui_create_glyph(wnd, 8, 8, brush->pattern); + fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern); XSetForeground(dpy, gc, fgcolour); XSetBackground(dpy, gc, bgcolour); XSetFillStyle(dpy, gc, FillOpaqueStippled); XSetStipple(dpy, gc, fill); - XFillRectangle(dpy, wnd->wnd, gc, x, y, cx, cy); + XFillRectangle(dpy, wnd, gc, x, y, cx, cy); XSetFillStyle(dpy, gc, FillSolid); - ui_destroy_glyph(wnd, (HGLYPH)fill); + ui_destroy_glyph((HGLYPH)fill); break; default: - NOTIMP("brush style %d\n", brush->style); + NOTIMP("brush %d\n", brush->style); } } -void ui_screenblt(HWINDOW wnd, uint8 opcode, +void ui_screenblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ int srcx, int srcy) { - xwin_set_function(wnd, opcode); + xwin_set_function(opcode); - XCopyArea(wnd->display, wnd->wnd, wnd->wnd, wnd->gc, srcx, srcy, + XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y); } -void ui_memblt(HWINDOW wnd, uint8 opcode, +void ui_memblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ HBITMAP src, int srcx, int srcy) { - xwin_set_function(wnd, opcode); + xwin_set_function(opcode); - XCopyArea(wnd->display, (Pixmap)src, wnd->wnd, wnd->gc, srcx, srcy, + XCopyArea(display, (Pixmap)src, wnd, gc, srcx, srcy, cx, cy, x, y); } -void ui_triblt(HWINDOW wnd, uint8 opcode, +void ui_triblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ HBITMAP src, int srcx, int srcy, /* brush */ BRUSH *brush, int bgcolour, int fgcolour) { /* This is potentially difficult to do in general. Until someone - comes up with an efficient way of doing that I am using cases. */ + comes up with a more efficient way of doing it I am using cases. */ switch (opcode) { case 0xb8: /* PSDPxax */ - ui_patblt(wnd, ROP2_XOR, x, y, cx, cy, + ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); - ui_memblt(wnd, ROP2_AND, x, y, cx, cy, + ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy); - ui_patblt(wnd, ROP2_XOR, x, y, cx, cy, + ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); break; default: - NOTIMP("triblt opcode 0x%x\n", opcode); - ui_memblt(wnd, ROP2_COPY, x, y, cx, cy, + NOTIMP("triblt 0x%x\n", opcode); + ui_memblt(ROP2_COPY, x, y, cx, cy, brush, bgcolour, fgcolour); } } -void ui_line(HWINDOW wnd, uint8 opcode, +void ui_line(uint8 opcode, /* dest */ int startx, int starty, int endx, int endy, /* pen */ PEN *pen) { - xwin_set_function(wnd, opcode); + xwin_set_function(opcode); - XSetForeground(wnd->display, wnd->gc, pen->colour); - XDrawLine(wnd->display, wnd->wnd, wnd->gc, startx, starty, endx, endy); + XSetForeground(display, gc, pen->colour); + XDrawLine(display, wnd, gc, startx, starty, endx, endy); } -void ui_rect(HWINDOW wnd, +void ui_rect( /* dest */ int x, int y, int cx, int cy, /* brush */ int colour) { - xwin_set_function(wnd, ROP2_COPY); + xwin_set_function(ROP2_COPY); - XSetForeground(wnd->display, wnd->gc, colour); - XFillRectangle(wnd->display, wnd->wnd, wnd->gc, x, y, cx, cy); + XSetForeground(display, gc, colour); + XFillRectangle(display, wnd, gc, x, y, cx, cy); } -void ui_draw_glyph(HWINDOW wnd, int mixmode, +void ui_draw_glyph(int mixmode, /* dest */ int x, int y, int cx, int cy, /* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour) { Pixmap pixmap = (Pixmap)glyph; - xwin_set_function(wnd, ROP2_COPY); + xwin_set_function(ROP2_COPY); - XSetForeground(wnd->display, wnd->gc, fgcolour); + XSetForeground(display, gc, fgcolour); switch (mixmode) { case MIX_TRANSPARENT: - XSetStipple(wnd->display, wnd->gc, pixmap); - XSetFillStyle(wnd->display, wnd->gc, FillStippled); - XSetTSOrigin(wnd->display, wnd->gc, x, y); - XFillRectangle(wnd->display, wnd->wnd, wnd->gc, + XSetStipple(display, gc, pixmap); + XSetFillStyle(display, gc, FillStippled); + XSetTSOrigin(display, gc, x, y); + XFillRectangle(display, wnd, gc, x, y, cx, cy); - XSetFillStyle(wnd->display, wnd->gc, FillSolid); + XSetFillStyle(display, gc, FillSolid); break; case MIX_OPAQUE: - XSetBackground(wnd->display, wnd->gc, bgcolour); - XCopyPlane(wnd->display, pixmap, wnd->wnd, wnd->gc, + XSetBackground(display, gc, bgcolour); + XCopyPlane(display, pixmap, wnd, gc, srcx, srcy, cx, cy, x, y, 1); break; default: - NOTIMP("mix mode %d\n", mixmode); + NOTIMP("mix %d\n", mixmode); } } -void ui_draw_text(HWINDOW wnd, uint8 font, uint8 flags, int mixmode, int x, +void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, int fgcolour, uint8 *text, uint8 length) { - FONT_GLYPH *glyph; + FONTGLYPH *glyph; int i; if (boxcx > 1) { - ui_rect(wnd, boxx, boxy, boxcx, boxcy, bgcolour); + ui_rect(boxx, boxy, boxcx, boxcy, bgcolour); } /* Paint text, character by character */ for (i = 0; i < length; i++) { - glyph = cache_get_font(wnd->conn, font, text[i]); + glyph = cache_get_font(font, text[i]); if (glyph != NULL) { - ui_draw_glyph(wnd, mixmode, x, + ui_draw_glyph(mixmode, x, y + (short)glyph->baseline, glyph->width, glyph->height, glyph->pixmap, 0, 0, @@ -477,27 +520,34 @@ void ui_draw_text(HWINDOW wnd, uint8 font, uint8 flags, int mixmode, int x, } } -void ui_desktop_save(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy) +void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) { XImage *image; int scanline; scanline = (cx + 3) & ~3; - image = XGetImage(wnd->display, wnd->wnd, x, y, cx, cy, - 0xffffffff, ZPixmap); - memcpy(data, image->data, scanline*cy); - XDestroyImage(image); -} - -void ui_desktop_restore(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy) -{ - XImage *image; - int scanline; - - scanline = (cx + 3) & ~3; - image = XCreateImage(wnd->display, wnd->visual, 8, ZPixmap, 0, - data, cx, cy, 32, scanline); - XSetFunction(wnd->display, wnd->gc, GXcopy); - XPutImage(wnd->display, wnd->wnd, wnd->gc, image, 0, 0, x, y, cx, cy); + STATUS("XGetImage(%p,%x,%d,%d,%d,%d,%x,%d)\n", display, wnd, x, y, + cx, cy, 0xffffffff, ZPixmap); + image = XGetImage(display, wnd, x, y, cx, cy, 0xffffffff, ZPixmap); + cache_put_desktop(offset, scanline*cy, image->data); + XFree(image->data); + XFree(image); +} + +void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) +{ + XImage *image; + int scanline; + uint8 *data; + + scanline = (cx + 3) & ~3; + data = cache_get_desktop(offset, scanline*cy); + if (data == NULL) + return; + + image = XCreateImage(display, visual, 8, ZPixmap, 0, + data, cx, cy, 32, scanline); + XSetFunction(display, gc, GXcopy); + XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy); XFree(image); } diff --git a/xwin.h b/xwin.h deleted file mode 100644 index 7b276a1..0000000 --- a/xwin.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - User interface services - X-Windows - Copyright (C) Matthew Chapman 1999-2000 - - 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 -#include - -typedef struct window -{ - struct connection *conn; - int width; - int height; - - Display *display; - Window wnd; - GC gc; - Visual *visual; - -} *HWINDOW; - -typedef void *HBITMAP; -typedef void *HGLYPH; -typedef void *HCOLOURMAP; -