Major commit of work from laptop - done in various free moments.

Implemented encryption layer and some basic licensing negotiation.
Reorganised code somewhat. While this is not quite as clean, it is
a lot faster - our parser speed was becoming a bottle-neck.


git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@9 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Matt Chapman 2000-08-15 10:23:24 +00:00
parent e11a571f14
commit cd9b5a8761
28 changed files with 3944 additions and 4300 deletions

33
ANNOUNCE Normal file
View File

@ -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 <matthewc@cse.unsw.edu.au>
rdesktop Author

View File

@ -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 *~

View File

@ -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)
{

131
cache.c
View File

@ -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);
}
}

View File

@ -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 <server>\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;
}

208
constants.h Normal file
View File

@ -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"

225
iso.c
View File

@ -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();
}

54
iso.h
View File

@ -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;

240
licence.c Normal file
View File

@ -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);
}
}

859
mcs.c
View File

@ -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;
}

120
mcs.h
View File

@ -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

70
misc.c
View File

@ -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);
}

853
orders.c Normal file
View File

@ -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));
}

254
orders.h Normal file
View File

@ -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;

126
parse.c
View File

@ -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;
}

93
parse.h
View File

@ -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; }

569
process.c
View File

@ -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);
}
}

269
proto.h
View File

@ -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);

236
rdesktop.c Normal file
View File

@ -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 <stdlib.h> /* malloc realloc free */
#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
#include <fcntl.h> /* open */
#include <getopt.h> /* getopt */
#include <pwd.h> /* getpwuid */
#include <sys/stat.h> /* stat */
#include <sys/time.h> /* gettimeofday */
#include <sys/times.h> /* 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;
}
}

View File

@ -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 <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#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"

1991
rdp.c

File diff suppressed because it is too large Load Diff

575
rdp.h
View File

@ -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;

589
secure.c Normal file
View File

@ -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();
}

189
tcp.c
View File

@ -18,15 +18,102 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include <unistd.h> /* select read write close */
#include <sys/socket.h> /* socket connect setsockopt */
#include <sys/time.h> /* timeval */
#include <netdb.h> /* gethostbyname */
#include <netinet/tcp.h> /* TCP_NODELAY */
#include <arpa/inet.h> /* inet_aton */
#include <errno.h> /* 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 &in;
}
/* 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);
}

22
tcp.h
View File

@ -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

View File

@ -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;

330
xwin.c
View File

@ -18,55 +18,73 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include <X11/Xlib.h>
#include <time.h>
#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);
}

40
xwin.h
View File

@ -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 <X11/Xlib.h>
#include <X11/Xutil.h>
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;