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:
parent
e11a571f14
commit
cd9b5a8761
33
ANNOUNCE
Normal file
33
ANNOUNCE
Normal 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
|
23
Makefile
23
Makefile
@ -1,19 +1,24 @@
|
||||
##############################################
|
||||
# rdesktop: A Remote Desktop Protocol client #
|
||||
# Linux Makefile #
|
||||
# Basic Makefile #
|
||||
# Copyright (C) Matthew Chapman 1999-2000 #
|
||||
##############################################
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -g -Wall -DDUMP
|
||||
LIBS = -L/usr/X11R6/lib -lX11
|
||||
OBJECTS = client.o parse.o tcp.o iso.o mcs.o rdp.o process.o bitmap.o cache.o xwin.o misc.o
|
||||
# Uncomment to enable debugging
|
||||
# DEBUG = -g -DRDP_DEBUG
|
||||
|
||||
rdesktop: $(OBJECTS)
|
||||
@$(CC) $(CFLAGS) -o rdesktop $(LIBS) $(OBJECTS)
|
||||
CC = gcc
|
||||
CFLAGS = -O2 -Wall $(DEBUG)
|
||||
LIBS = -L/usr/X11R6/lib -lX11
|
||||
|
||||
RDPOBJ = rdesktop.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o xwin.o
|
||||
CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/arith.o
|
||||
|
||||
rdesktop: $(RDPOBJ) $(CRYPTOBJ)
|
||||
@$(CC) $(CFLAGS) -o rdesktop $(LIBS) $(RDPOBJ) $(CRYPTOBJ)
|
||||
|
||||
proto:
|
||||
@cproto -D MAKE_PROTO -o proto.h *.c
|
||||
@cproto -DMAKE_PROTO -o proto.h *.c
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *.o crypto/*.o *~
|
||||
|
8
bitmap.c
8
bitmap.c
@ -18,7 +18,7 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "rdesktop.h"
|
||||
|
||||
#define CVAL(p) (*(p++))
|
||||
#define SVAL(p) ((*((p++) + 1) << 8) | CVAL(p))
|
||||
@ -30,11 +30,11 @@ BOOL bitmap_decompress(unsigned char *output, int width, int height,
|
||||
unsigned char *input, int size)
|
||||
{
|
||||
unsigned char *end = input + size;
|
||||
unsigned char *prevline, *line = NULL;
|
||||
unsigned char *prevline = NULL, *line = NULL;
|
||||
int opcode, count, offset, isfillormix, x = width;
|
||||
int lastopcode = -1, insertmix = False;
|
||||
uint8 code, colour1, colour2, mask, mixmask;
|
||||
uint8 mix = 0xff;
|
||||
uint8 code, colour1 = 0, colour2 = 0;
|
||||
uint8 mixmask, mask = 0, mix = 0xff;
|
||||
|
||||
while (input < end)
|
||||
{
|
||||
|
131
cache.c
131
cache.c
@ -18,70 +18,84 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "rdesktop.h"
|
||||
|
||||
HBITMAP cache_get_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx)
|
||||
#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
|
||||
/* BITMAP CACHE */
|
||||
static HBITMAP bmpcache[3][600];
|
||||
|
||||
/* Retrieve a bitmap from the cache */
|
||||
HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
|
||||
{
|
||||
HBITMAP bitmap;
|
||||
|
||||
if ((cache_id < NUM_ELEMENTS(conn->bmpcache))
|
||||
&& (cache_idx < NUM_ELEMENTS(conn->bmpcache[0])))
|
||||
if ((cache_id < NUM_ELEMENTS(bmpcache))
|
||||
&& (cache_idx < NUM_ELEMENTS(bmpcache[0])))
|
||||
{
|
||||
bitmap = conn->bmpcache[cache_id][cache_idx];
|
||||
bitmap = bmpcache[cache_id][cache_idx];
|
||||
if (bitmap != NULL)
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
ERROR("Bitmap %d:%d not found\n", cache_id, cache_idx);
|
||||
ERROR("get bitmap %d:%d\n", cache_id, cache_idx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cache_put_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
|
||||
/* Store a bitmap in the cache */
|
||||
void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
|
||||
{
|
||||
HBITMAP old;
|
||||
|
||||
if ((cache_id < NUM_ELEMENTS(conn->bmpcache))
|
||||
&& (cache_idx < NUM_ELEMENTS(conn->bmpcache[0])))
|
||||
if ((cache_id < NUM_ELEMENTS(bmpcache))
|
||||
&& (cache_idx < NUM_ELEMENTS(bmpcache[0])))
|
||||
{
|
||||
old = conn->bmpcache[cache_id][cache_idx];
|
||||
old = bmpcache[cache_id][cache_idx];
|
||||
if (old != NULL)
|
||||
ui_destroy_bitmap(conn->wnd, old);
|
||||
ui_destroy_bitmap(old);
|
||||
|
||||
conn->bmpcache[cache_id][cache_idx] = bitmap;
|
||||
bmpcache[cache_id][cache_idx] = bitmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("Bitmap %d:%d past end of cache\n", cache_id, cache_idx);
|
||||
ERROR("put bitmap %d:%d\n", cache_id, cache_idx);
|
||||
}
|
||||
}
|
||||
|
||||
FONT_GLYPH *cache_get_font(HCONN conn, uint8 font, uint16 character)
|
||||
{
|
||||
FONT_GLYPH *glyph;
|
||||
|
||||
if ((font < NUM_ELEMENTS(conn->fontcache))
|
||||
&& (character < NUM_ELEMENTS(conn->fontcache[0])))
|
||||
/* FONT CACHE */
|
||||
static FONTGLYPH fontcache[12][256];
|
||||
|
||||
/* Retrieve a glyph from the font cache */
|
||||
FONTGLYPH *cache_get_font(uint8 font, uint16 character)
|
||||
{
|
||||
FONTGLYPH *glyph;
|
||||
|
||||
if ((font < NUM_ELEMENTS(fontcache))
|
||||
&& (character < NUM_ELEMENTS(fontcache[0])))
|
||||
{
|
||||
glyph = &conn->fontcache[font][character];
|
||||
glyph = &fontcache[font][character];
|
||||
if (glyph->pixmap != NULL)
|
||||
return glyph;
|
||||
}
|
||||
|
||||
ERROR("Font %d character %d not found\n", font, character);
|
||||
ERROR("get font %d:%d\n", font, character);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline,
|
||||
/* Store a glyph in the font cache */
|
||||
void cache_put_font(uint8 font, uint32 character, uint16 baseline,
|
||||
uint16 width, uint16 height, HGLYPH pixmap)
|
||||
{
|
||||
FONT_GLYPH *glyph;
|
||||
FONTGLYPH *glyph;
|
||||
|
||||
if ((font < NUM_ELEMENTS(conn->fontcache))
|
||||
&& (character < NUM_ELEMENTS(conn->fontcache[0])))
|
||||
if ((font < NUM_ELEMENTS(fontcache))
|
||||
&& (character < NUM_ELEMENTS(fontcache[0])))
|
||||
{
|
||||
glyph = &conn->fontcache[font][character];
|
||||
glyph = &fontcache[font][character];
|
||||
if (glyph->pixmap != NULL)
|
||||
ui_destroy_glyph(conn->wnd, glyph->pixmap);
|
||||
ui_destroy_glyph(glyph->pixmap);
|
||||
|
||||
glyph->baseline = baseline;
|
||||
glyph->width = width;
|
||||
@ -90,42 +104,77 @@ void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline,
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("Font %d character %d past end of cache\n",
|
||||
font, character);
|
||||
ERROR("put font %d:%d\n", font, character);
|
||||
}
|
||||
}
|
||||
|
||||
BLOB *cache_get_text(HCONN conn, uint8 cache_id)
|
||||
{
|
||||
BLOB *text;
|
||||
|
||||
if (cache_id < NUM_ELEMENTS(conn->textcache))
|
||||
/* TEXT CACHE */
|
||||
static DATABLOB textcache[256];
|
||||
|
||||
/* Retrieve a text item from the cache */
|
||||
DATABLOB *cache_get_text(uint8 cache_id)
|
||||
{
|
||||
DATABLOB *text;
|
||||
|
||||
if (cache_id < NUM_ELEMENTS(textcache))
|
||||
{
|
||||
text = &conn->textcache[cache_id];
|
||||
text = &textcache[cache_id];
|
||||
if (text->data != NULL)
|
||||
return text;
|
||||
}
|
||||
|
||||
ERROR("Text cache id %d not found\n", cache_id);
|
||||
ERROR("get text %d\n", cache_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cache_put_text(HCONN conn, uint8 cache_id, void *data, int length)
|
||||
/* Store a text item in the cache */
|
||||
void cache_put_text(uint8 cache_id, void *data, int length)
|
||||
{
|
||||
BLOB *text;
|
||||
DATABLOB *text;
|
||||
|
||||
if (cache_id < NUM_ELEMENTS(conn->textcache))
|
||||
if (cache_id < NUM_ELEMENTS(textcache))
|
||||
{
|
||||
text = &conn->textcache[cache_id];
|
||||
text = &textcache[cache_id];
|
||||
if (text->data != NULL)
|
||||
free(text->data);
|
||||
xfree(text->data);
|
||||
|
||||
text->data = malloc(length);
|
||||
text->data = xmalloc(length);
|
||||
text->size = length;
|
||||
memcpy(text->data, data, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("Text cache id %d past end of cache\n", cache_id);
|
||||
ERROR("put text %d\n", cache_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* DESKTOP CACHE */
|
||||
static uint8 deskcache[0x38400];
|
||||
|
||||
/* Retrieve desktop data from the cache */
|
||||
uint8 *cache_get_desktop(uint32 offset, uint32 length)
|
||||
{
|
||||
if ((offset + length) <= sizeof(deskcache))
|
||||
{
|
||||
return &deskcache[offset];
|
||||
}
|
||||
|
||||
ERROR("get desktop %d:%d\n", offset, length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Store desktop data in the cache */
|
||||
void cache_put_desktop(uint32 offset, uint32 length, uint8 *data)
|
||||
{
|
||||
if ((offset + length) <= sizeof(deskcache))
|
||||
{
|
||||
memcpy(&deskcache[offset], data, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("put desktop %d:%d\n", offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
50
client.c
50
client.c
@ -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
208
constants.h
Normal 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
225
iso.c
@ -18,157 +18,136 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "rdesktop.h"
|
||||
|
||||
/* Establish a connection up to the ISO layer */
|
||||
HCONN iso_connect(char *server)
|
||||
/* Send a self-contained ISO PDU */
|
||||
static void iso_send_msg(uint8 code)
|
||||
{
|
||||
HCONN conn;
|
||||
uint8 code;
|
||||
STREAM s;
|
||||
|
||||
if ((conn = tcp_connect(server)) == NULL)
|
||||
return NULL;
|
||||
s = tcp_init(11);
|
||||
|
||||
iso_send_msg(conn, ISO_PDU_CR);
|
||||
out_uint8(s, 3); /* version */
|
||||
out_uint8(s, 0); /* reserved */
|
||||
out_uint16_be(s, 11); /* length */
|
||||
|
||||
if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_CC))
|
||||
{
|
||||
ERROR("ISO error, expected CC\n");
|
||||
tcp_disconnect(conn);
|
||||
return NULL;
|
||||
}
|
||||
out_uint8(s, 6); /* hdrlen */
|
||||
out_uint8(s, code);
|
||||
out_uint16(s, 0); /* dst_ref */
|
||||
out_uint16(s, 0); /* src_ref */
|
||||
out_uint8(s, 0); /* class */
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* Disconnect from the ISO layer */
|
||||
void iso_disconnect(HCONN conn)
|
||||
{
|
||||
iso_send_msg(conn, ISO_PDU_DR);
|
||||
tcp_disconnect(conn);
|
||||
}
|
||||
|
||||
/* Send self-contained ISO message identified by code */
|
||||
BOOL iso_send_msg(HCONN conn, uint8 code)
|
||||
{
|
||||
TPKT tpkt;
|
||||
TPDU tpdu;
|
||||
|
||||
iso_make_tpkt(&tpkt, 11);
|
||||
iso_io_tpkt(&conn->out, &tpkt);
|
||||
iso_make_tpdu(&tpdu, code);
|
||||
iso_io_tpdu(&conn->out, &tpdu);
|
||||
MARK_END(conn->out);
|
||||
return tcp_send(conn);
|
||||
s_mark_end(s);
|
||||
tcp_send(s);
|
||||
}
|
||||
|
||||
/* Receive a message on the ISO layer, return code */
|
||||
BOOL iso_recv_msg(HCONN conn, uint8 *code)
|
||||
static STREAM iso_recv_msg(uint8 *code)
|
||||
{
|
||||
TPDU tpdu;
|
||||
TPKT tpkt;
|
||||
BOOL res;
|
||||
STREAM s;
|
||||
uint16 length;
|
||||
uint8 version;
|
||||
|
||||
res = tcp_recv(conn, 4);
|
||||
res = res ? iso_io_tpkt(&conn->in, &tpkt) : False;
|
||||
res = res ? tcp_recv(conn, tpkt.length - 4) : False;
|
||||
res = res ? iso_io_tpdu(&conn->in, &tpdu) : False;
|
||||
s = tcp_recv(4);
|
||||
if (s == NULL)
|
||||
return False;
|
||||
|
||||
*code = tpdu.code;
|
||||
return res;
|
||||
in_uint8(s, version);
|
||||
if (version != 3)
|
||||
{
|
||||
ERROR("TPKT v%d\n", version);
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint8s(s, 1); /* pad */
|
||||
in_uint16_be(s, length);
|
||||
|
||||
s = tcp_recv(length - 4);
|
||||
if (s == NULL)
|
||||
return False;
|
||||
|
||||
in_uint8s(s, 1); /* hdrlen */
|
||||
in_uint8(s, *code);
|
||||
|
||||
if (*code == ISO_PDU_DT)
|
||||
{
|
||||
in_uint8s(s, 1); /* eot */
|
||||
return s;
|
||||
}
|
||||
|
||||
in_uint8s(s, 5); /* dst_ref, src_ref, class */
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Initialise ISO transport data packet */
|
||||
void iso_init(struct connection *conn)
|
||||
STREAM iso_init(int length)
|
||||
{
|
||||
PUSH_LAYER(conn->out, iso_offset, 7);
|
||||
STREAM s;
|
||||
|
||||
s = tcp_init(length + 7);
|
||||
s_push_layer(s, iso_hdr, 7);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Send an ISO data PDU */
|
||||
void iso_send(STREAM s)
|
||||
{
|
||||
uint16 length;
|
||||
|
||||
s_pop_layer(s, iso_hdr);
|
||||
length = s->end - s->p;
|
||||
|
||||
out_uint8(s, 3); /* version */
|
||||
out_uint8(s, 0); /* reserved */
|
||||
out_uint16_be(s, length);
|
||||
|
||||
out_uint8(s, 2); /* hdrlen */
|
||||
out_uint8(s, ISO_PDU_DT); /* code */
|
||||
out_uint8(s, 0x80); /* eot */
|
||||
|
||||
tcp_send(s);
|
||||
}
|
||||
|
||||
/* Receive ISO transport data packet */
|
||||
BOOL iso_recv(HCONN conn)
|
||||
STREAM iso_recv()
|
||||
{
|
||||
STREAM s;
|
||||
uint8 code;
|
||||
|
||||
s = iso_recv_msg(&code);
|
||||
if ((s == NULL) || (code != ISO_PDU_DT))
|
||||
{
|
||||
ERROR("expected DT, got %d\n", code);
|
||||
return False;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Establish a connection up to the ISO layer */
|
||||
BOOL iso_connect(char *server)
|
||||
{
|
||||
uint8 code;
|
||||
|
||||
if (!iso_recv_msg(conn, &code) || (code != ISO_PDU_DT))
|
||||
if (!tcp_connect(server))
|
||||
return False;
|
||||
|
||||
iso_send_msg(ISO_PDU_CR);
|
||||
|
||||
if ((iso_recv_msg(&code) == NULL) || (code != ISO_PDU_CC))
|
||||
{
|
||||
ERROR("ISO error, expected DT\n");
|
||||
ERROR("expected CC, got %d\n", code);
|
||||
tcp_disconnect();
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Receive ISO transport data packet */
|
||||
BOOL iso_send(HCONN conn)
|
||||
/* Disconnect from the ISO layer */
|
||||
void iso_disconnect()
|
||||
{
|
||||
TPKT tpkt;
|
||||
TPDU tpdu;
|
||||
|
||||
POP_LAYER(conn->out, iso_offset);
|
||||
iso_make_tpkt(&tpkt, conn->out.end);
|
||||
iso_io_tpkt(&conn->out, &tpkt);
|
||||
iso_make_tpdu(&tpdu, ISO_PDU_DT);
|
||||
iso_io_tpdu(&conn->out, &tpdu);
|
||||
return tcp_send(conn);
|
||||
}
|
||||
|
||||
/* Initialise a TPKT structure */
|
||||
void iso_make_tpkt(TPKT *tpkt, int length)
|
||||
{
|
||||
tpkt->version = 3;
|
||||
tpkt->reserved = 0;
|
||||
tpkt->length = length;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a TPKT structure */
|
||||
BOOL iso_io_tpkt(STREAM s, TPKT *tpkt)
|
||||
{
|
||||
if (!prs_io_uint8(s, &tpkt->version))
|
||||
return False;
|
||||
|
||||
if (tpkt->version != 3)
|
||||
{
|
||||
ERROR("Wrong TPKT version %d\n", tpkt->version);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!prs_io_uint8 (s, &tpkt->reserved))
|
||||
return False;
|
||||
|
||||
if (!msb_io_uint16(s, &tpkt->length))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Initialise a TPDU structure */
|
||||
void iso_make_tpdu(TPDU *tpdu, uint8 code)
|
||||
{
|
||||
tpdu->hlen = (code == ISO_PDU_DT) ? 2 : 6;
|
||||
tpdu->code = code;
|
||||
tpdu->dst_ref = tpdu->src_ref = 0;
|
||||
tpdu->class = 0;
|
||||
tpdu->eot = 0x80;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a TPDU structure */
|
||||
BOOL iso_io_tpdu(STREAM s, TPDU *tpdu)
|
||||
{
|
||||
BOOL res = True;
|
||||
|
||||
res = res ? prs_io_uint8 (s, &tpdu->hlen) : False;
|
||||
res = res ? prs_io_uint8 (s, &tpdu->code) : False;
|
||||
|
||||
if (tpdu->code == ISO_PDU_DT)
|
||||
{
|
||||
res = res ? prs_io_uint8(s, &tpdu->eot) : False;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = res ? msb_io_uint16(s, &tpdu->dst_ref) : False;
|
||||
res = res ? msb_io_uint16(s, &tpdu->src_ref) : False;
|
||||
res = res ? prs_io_uint8 (s, &tpdu->class ) : False;
|
||||
}
|
||||
|
||||
return res;
|
||||
iso_send_msg(ISO_PDU_DR);
|
||||
tcp_disconnect();
|
||||
}
|
||||
|
54
iso.h
54
iso.h
@ -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
240
licence.c
Normal 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
859
mcs.c
@ -18,567 +18,358 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "rdesktop.h"
|
||||
|
||||
/* Establish a connection up to the MCS layer */
|
||||
HCONN mcs_connect(char *server)
|
||||
uint16 mcs_userid;
|
||||
|
||||
/* Parse an ASN.1 BER header */
|
||||
static BOOL ber_parse_header(STREAM s, int tagval, int *length)
|
||||
{
|
||||
HCONN conn;
|
||||
MCS_CONNECT_RESPONSE mcr;
|
||||
MCS_AUCF aucf;
|
||||
int tag, len;
|
||||
|
||||
if ((conn = iso_connect(server)) == NULL)
|
||||
return NULL;
|
||||
|
||||
mcs_send_connect_initial(conn);
|
||||
if (!iso_recv(conn) || !mcs_io_connect_response(&conn->in, &mcr))
|
||||
if (tagval > 0xff)
|
||||
{
|
||||
ERROR("MCS error, expected Connect-Response\n");
|
||||
iso_disconnect(conn);
|
||||
return NULL;
|
||||
in_uint16_be(s, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
in_uint8(s, tag)
|
||||
}
|
||||
|
||||
if (mcr.result != 0)
|
||||
if (tag != tagval)
|
||||
{
|
||||
ERROR("MCS-Connect-Initial failed, result %d\n", mcr.result);
|
||||
iso_disconnect(conn);
|
||||
return NULL;
|
||||
ERROR("expected tag %d, got %d\n", tagval, tag);
|
||||
return False;
|
||||
}
|
||||
|
||||
mcs_send_edrq(conn);
|
||||
in_uint8(s, len);
|
||||
|
||||
mcs_send_aurq(conn);
|
||||
if (!iso_recv(conn) || !mcs_io_aucf(&conn->in, &aucf))
|
||||
if (len & 0x80)
|
||||
{
|
||||
ERROR("MCS error, expected AUcf\n");
|
||||
mcs_disconnect(conn);
|
||||
return NULL;
|
||||
len &= ~0x80;
|
||||
*length = 0;
|
||||
while (len--)
|
||||
next_be(s, *length);
|
||||
}
|
||||
else *length = len;
|
||||
|
||||
if (aucf.result != 0)
|
||||
{
|
||||
ERROR("AUrq failed, result %d\n", mcr.result);
|
||||
mcs_disconnect(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->mcs_userid = aucf.userid;
|
||||
|
||||
if (!mcs_join_channel(conn, aucf.userid + 1001)
|
||||
|| !mcs_join_channel(conn, MCS_GLOBAL_CHANNEL))
|
||||
{
|
||||
mcs_disconnect(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conn;
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
BOOL mcs_join_channel(HCONN conn, uint16 chanid)
|
||||
/* Output an ASN.1 BER header */
|
||||
static void ber_out_header(STREAM s, int tagval, int length)
|
||||
{
|
||||
MCS_CJCF cjcf;
|
||||
|
||||
mcs_send_cjrq(conn, chanid);
|
||||
if (!iso_recv(conn) || !mcs_io_cjcf(&conn->in, &cjcf))
|
||||
if (tagval > 0xff)
|
||||
{
|
||||
ERROR("MCS error, expected CJcf\n");
|
||||
out_uint16_be(s, tagval);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint8(s, tagval);
|
||||
}
|
||||
|
||||
if (length >= 0x80)
|
||||
{
|
||||
out_uint8(s, 0x82);
|
||||
out_uint16_be(s, length);
|
||||
}
|
||||
else out_uint8(s, length);
|
||||
}
|
||||
|
||||
/* Output an ASN.1 BER integer */
|
||||
static void ber_out_integer(STREAM s, int value)
|
||||
{
|
||||
ber_out_header(s, BER_TAG_INTEGER, 2);
|
||||
out_uint16_be(s, value);
|
||||
}
|
||||
|
||||
/* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
|
||||
static void mcs_out_domain_params(STREAM s, int max_channels, int max_users,
|
||||
int max_tokens, int max_pdusize)
|
||||
{
|
||||
ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32);
|
||||
ber_out_integer(s, max_channels);
|
||||
ber_out_integer(s, max_users);
|
||||
ber_out_integer(s, max_tokens);
|
||||
ber_out_integer(s, 1); /* num_priorities */
|
||||
ber_out_integer(s, 0); /* min_throughput */
|
||||
ber_out_integer(s, 1); /* max_height */
|
||||
ber_out_integer(s, max_pdusize);
|
||||
ber_out_integer(s, 2); /* ver_protocol */
|
||||
}
|
||||
|
||||
/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
|
||||
static BOOL mcs_parse_domain_params(STREAM s)
|
||||
{
|
||||
int length;
|
||||
|
||||
ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
|
||||
in_uint8s(s, length);
|
||||
|
||||
return s_check(s);
|
||||
}
|
||||
|
||||
/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
|
||||
static void mcs_send_connect_initial(STREAM mcs_data)
|
||||
{
|
||||
int datalen = mcs_data->end - mcs_data->data;
|
||||
int length = 7 + 3*34 + 4 + datalen;
|
||||
STREAM s;
|
||||
|
||||
s = iso_init(length + 5);
|
||||
|
||||
ber_out_header(s, MCS_CONNECT_INITIAL, length);
|
||||
ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* calling domain */
|
||||
ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* called domain */
|
||||
|
||||
ber_out_header(s, BER_TAG_BOOLEAN, 1);
|
||||
out_uint8(s, 0xff); /* upward flag */
|
||||
|
||||
mcs_out_domain_params(s, 2, 2, 0, 0xffff); /* target params */
|
||||
mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */
|
||||
mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */
|
||||
|
||||
ber_out_header(s, BER_TAG_OCTET_STRING, datalen);
|
||||
out_uint8p(s, mcs_data->data, datalen);
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
}
|
||||
|
||||
/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
|
||||
static BOOL mcs_recv_connect_response(STREAM mcs_data)
|
||||
{
|
||||
uint8 result;
|
||||
int length;
|
||||
STREAM s;
|
||||
|
||||
s = iso_recv();
|
||||
if (s == NULL)
|
||||
return False;
|
||||
|
||||
ber_parse_header(s, MCS_CONNECT_RESPONSE, &length);
|
||||
|
||||
ber_parse_header(s, BER_TAG_RESULT, &length);
|
||||
in_uint8(s, result);
|
||||
if (result != 0)
|
||||
{
|
||||
ERROR("MCS connect: %d\n", result);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cjcf.result != 0)
|
||||
ber_parse_header(s, BER_TAG_INTEGER, &length);
|
||||
in_uint8s(s, length); /* connect id */
|
||||
mcs_parse_domain_params(s);
|
||||
|
||||
ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
|
||||
if (length > mcs_data->size)
|
||||
{
|
||||
ERROR("CJrq failed, result %d\n", cjcf.result);
|
||||
WARN("MCS data length %d\n", length);
|
||||
length = mcs_data->size;
|
||||
}
|
||||
|
||||
in_uint8a(s, mcs_data->data, length);
|
||||
mcs_data->p = mcs_data->data;
|
||||
mcs_data->end = mcs_data->data + length;
|
||||
|
||||
return s_check_end(s);
|
||||
}
|
||||
|
||||
/* Send an EDrq message (ASN.1 PER) */
|
||||
static void mcs_send_edrq()
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = iso_init(5);
|
||||
|
||||
out_uint8(s, (MCS_EDRQ << 2));
|
||||
out_uint16_be(s, 1); /* height */
|
||||
out_uint16_be(s, 1); /* interval */
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
}
|
||||
|
||||
/* Send an AUrq message (ASN.1 PER) */
|
||||
static void mcs_send_aurq()
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = iso_init(1);
|
||||
|
||||
out_uint8(s, (MCS_AURQ << 2));
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
}
|
||||
|
||||
/* Expect a AUcf message (ASN.1 PER) */
|
||||
static BOOL mcs_recv_aucf(uint16 *mcs_userid)
|
||||
{
|
||||
uint8 opcode, result;
|
||||
STREAM s;
|
||||
|
||||
s = iso_recv();
|
||||
if (s == NULL)
|
||||
return False;
|
||||
|
||||
in_uint8(s, opcode);
|
||||
if ((opcode >> 2) != MCS_AUCF)
|
||||
{
|
||||
ERROR("expected AUcf, got %d\n", opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint8(s, result);
|
||||
if (result != 0)
|
||||
{
|
||||
ERROR("AUrq: %d\n", result);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (opcode & 2)
|
||||
in_uint16_be(s, *mcs_userid);
|
||||
|
||||
return s_check_end(s);
|
||||
}
|
||||
|
||||
/* Send a CJrq message (ASN.1 PER) */
|
||||
static void mcs_send_cjrq(uint16 chanid)
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = iso_init(5);
|
||||
|
||||
out_uint8(s, (MCS_CJRQ << 2));
|
||||
out_uint16_be(s, mcs_userid);
|
||||
out_uint16_be(s, chanid);
|
||||
|
||||
s_mark_end(s);
|
||||
iso_send(s);
|
||||
}
|
||||
|
||||
/* Expect a CJcf message (ASN.1 PER) */
|
||||
static BOOL mcs_recv_cjcf()
|
||||
{
|
||||
uint8 opcode, result;
|
||||
STREAM s;
|
||||
|
||||
s = iso_recv();
|
||||
if (s == NULL)
|
||||
return False;
|
||||
|
||||
in_uint8(s, opcode);
|
||||
if ((opcode >> 2) != MCS_CJCF)
|
||||
{
|
||||
ERROR("expected CJcf, got %d\n", opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint8(s, result);
|
||||
if (result != 0)
|
||||
{
|
||||
ERROR("CJrq: %d\n", result);
|
||||
return False;
|
||||
}
|
||||
|
||||
in_uint8s(s, 4); /* mcs_userid, req_chanid */
|
||||
if (opcode & 2)
|
||||
in_uint8s(s, 2); /* join_chanid */
|
||||
|
||||
return s_check_end(s);
|
||||
}
|
||||
|
||||
/* Initialise an MCS transport data packet */
|
||||
STREAM mcs_init(int length)
|
||||
{
|
||||
STREAM s;
|
||||
|
||||
s = iso_init(length + 8);
|
||||
s_push_layer(s, mcs_hdr, 8);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Send an MCS transport data packet */
|
||||
void mcs_send(STREAM s)
|
||||
{
|
||||
uint16 length;
|
||||
|
||||
s_pop_layer(s, mcs_hdr);
|
||||
length = s->end - s->p - 8;
|
||||
length |= 0x8000;
|
||||
|
||||
out_uint8(s, (MCS_SDRQ << 2));
|
||||
out_uint16_be(s, mcs_userid);
|
||||
out_uint16_be(s, MCS_GLOBAL_CHANNEL);
|
||||
out_uint8(s, 0x70); /* flags */
|
||||
out_uint16_be(s, length);
|
||||
|
||||
iso_send(s);
|
||||
}
|
||||
|
||||
/* Receive an MCS transport data packet */
|
||||
STREAM mcs_recv()
|
||||
{
|
||||
uint8 opcode, appid, length;
|
||||
STREAM s;
|
||||
|
||||
s = iso_recv();
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
in_uint8(s, opcode);
|
||||
appid = opcode >> 2;
|
||||
if (appid != MCS_SDIN)
|
||||
{
|
||||
if (appid != MCS_DPUM)
|
||||
{
|
||||
ERROR("expected data, got %d\n", opcode);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
in_uint8s(s, 5); /* userid, chanid, flags */
|
||||
in_uint8(s, length);
|
||||
if (length & 0x80)
|
||||
in_uint8s(s, 1); /* second byte of length */
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Establish a connection up to the MCS layer */
|
||||
BOOL mcs_connect(char *server, STREAM mcs_data)
|
||||
{
|
||||
if (!iso_connect(server))
|
||||
return False;
|
||||
|
||||
mcs_send_connect_initial(mcs_data);
|
||||
if (!mcs_recv_connect_response(mcs_data))
|
||||
goto error;
|
||||
|
||||
mcs_send_edrq();
|
||||
|
||||
mcs_send_aurq();
|
||||
if (!mcs_recv_aucf(&mcs_userid))
|
||||
goto error;
|
||||
|
||||
mcs_send_cjrq(mcs_userid + 1001);
|
||||
if (!mcs_recv_cjcf())
|
||||
goto error;
|
||||
|
||||
mcs_send_cjrq(MCS_GLOBAL_CHANNEL);
|
||||
if (!mcs_recv_cjcf())
|
||||
goto error;
|
||||
|
||||
return True;
|
||||
|
||||
error:
|
||||
iso_disconnect();
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Disconnect from the MCS layer */
|
||||
void mcs_disconnect(HCONN conn)
|
||||
void mcs_disconnect()
|
||||
{
|
||||
/* Not complete */
|
||||
iso_disconnect(conn);
|
||||
iso_disconnect();
|
||||
}
|
||||
|
||||
/* Send a Connect-Initial message */
|
||||
void mcs_send_connect_initial(HCONN conn)
|
||||
{
|
||||
MCS_CONNECT_INITIAL mci;
|
||||
|
||||
iso_init(conn);
|
||||
mcs_make_connect_initial(&mci);
|
||||
mcs_io_connect_initial(&conn->out, &mci);
|
||||
MARK_END(conn->out);
|
||||
iso_send(conn);
|
||||
}
|
||||
|
||||
/* Send a EDrq message */
|
||||
void mcs_send_edrq(HCONN conn)
|
||||
{
|
||||
MCS_EDRQ edrq;
|
||||
|
||||
iso_init(conn);
|
||||
edrq.height = edrq.interval = 1;
|
||||
mcs_io_edrq(&conn->out, &edrq);
|
||||
MARK_END(conn->out);
|
||||
iso_send(conn);
|
||||
}
|
||||
|
||||
/* Send a AUrq message */
|
||||
void mcs_send_aurq(HCONN conn)
|
||||
{
|
||||
MCS_AURQ aurq;
|
||||
|
||||
iso_init(conn);
|
||||
mcs_io_aurq(&conn->out, &aurq);
|
||||
MARK_END(conn->out);
|
||||
iso_send(conn);
|
||||
}
|
||||
|
||||
/* Send a CJrq message */
|
||||
void mcs_send_cjrq(HCONN conn, uint16 chanid)
|
||||
{
|
||||
MCS_CJRQ cjrq;
|
||||
|
||||
iso_init(conn);
|
||||
cjrq.userid = conn->mcs_userid;
|
||||
cjrq.chanid = chanid;
|
||||
mcs_io_cjrq(&conn->out, &cjrq);
|
||||
MARK_END(conn->out);
|
||||
iso_send(conn);
|
||||
}
|
||||
|
||||
/* Initialise MCS transport data packet */
|
||||
void mcs_init_data(HCONN conn)
|
||||
{
|
||||
iso_init(conn);
|
||||
PUSH_LAYER(conn->out, mcs_offset, 8);
|
||||
}
|
||||
|
||||
/* Transmit MCS transport data packet */
|
||||
void mcs_send_data(HCONN conn, uint16 chanid, BOOL request)
|
||||
{
|
||||
MCS_DATA dt;
|
||||
|
||||
POP_LAYER(conn->out, mcs_offset);
|
||||
dt.userid = conn->mcs_userid;
|
||||
dt.chanid = chanid;
|
||||
dt.flags = 0x70;
|
||||
dt.length = conn->out.end - conn->out.offset - 8;
|
||||
mcs_io_data(&conn->out, &dt, request);
|
||||
iso_send(conn);
|
||||
}
|
||||
|
||||
/* Receive a message on the MCS layer */
|
||||
BOOL mcs_recv(HCONN conn, BOOL request)
|
||||
{
|
||||
MCS_DATA data;
|
||||
|
||||
if (!iso_recv(conn) || !mcs_io_data(&conn->in, &data, request))
|
||||
return False;
|
||||
|
||||
conn->in.rdp_offset = conn->in.offset;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Initialise a DOMAIN_PARAMS structure */
|
||||
void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels,
|
||||
uint16 max_users, uint16 max_tokens, uint16 max_pdusize)
|
||||
{
|
||||
dp->max_channels = max_channels;
|
||||
dp->max_users = max_users;
|
||||
dp->max_tokens = max_tokens;
|
||||
dp->num_priorities = 1;
|
||||
dp->min_throughput = 0;
|
||||
dp->max_height = 1;
|
||||
dp->max_pdusize = max_pdusize;
|
||||
dp->ver_protocol = 2;
|
||||
}
|
||||
|
||||
/* RDP-specific 'user data'. Let's just get this right for now - to be
|
||||
decoded later. */
|
||||
char precanned_connect_userdata[] = {
|
||||
0x00,0x05,0x00,0x14,0x7c,0x00,0x01,0x80,0x9e,0x00,0x08,0x00,0x10,0x00,
|
||||
0x01,0xc0,0x00,0x44,0x75,0x63,0x61,0x80,0x90,0x01,0xc0,0x88,0x00,0x01,
|
||||
0x00,0x08,0x00,0x80,0x02,0xe0,0x01,0x01,0xca,0x03,0xaa,0x09,0x04,0x00,
|
||||
0x00,0xa3,0x01,0x00,0x00,0x52,0x00,0x45,0x00,0x53,0x00,0x31,0x00,0x2d,
|
||||
0x00,0x4e,0x00,0x45,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x01,0xca,0x00,0x00,0x02,0xc0,0x08,0x00,
|
||||
/* encryption disabled */ 0x00,0x00,0x00,0x00 };
|
||||
|
||||
char precanned_connect_userdata_e[] = {
|
||||
0x00,
|
||||
0x05,0x00,0x14,0x7c,0x00,0x01,0x80,0x9e,0x00,0x08,0x00,0x10,0x00,0x01,0xc0,0x00,
|
||||
0x44,0x75,0x63,0x61,0x80,0x90,0x01,0xc0,0x88,0x00,0x01,0x00,0x08,0x00,0x80,0x02,
|
||||
0xe0,0x01,0x01,0xca,0x03,0xaa,0x09,0x04,0x00,0x00,0xa3,0x01,0x00,0x00,0x57,0x00,
|
||||
0x49,0x00,0x4e,0x00,0x39,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xca,0x00,0x00,0x02,0xc0,
|
||||
0x08,0x00,0x01,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
char domain_data[] = {0x01};
|
||||
|
||||
/* Initialise a MCS_CONNECT_INITIAL structure */
|
||||
void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci)
|
||||
{
|
||||
mci->calling_domain.length = 1;
|
||||
mci->calling_domain.data = domain_data;
|
||||
|
||||
mci->called_domain.length = 1;
|
||||
mci->called_domain.data = domain_data;
|
||||
|
||||
mci->upward_flag = 0xff;
|
||||
|
||||
mcs_make_domain_params(&mci->target_params, 2, 2, 0, 0xffff);
|
||||
mcs_make_domain_params(&mci->minimum_params, 1, 1, 1, 0x420);
|
||||
mcs_make_domain_params(&mci->maximum_params, 0xffff, 0xfc17, 0xffff,
|
||||
0xffff);
|
||||
|
||||
mci->user_data.length = sizeof(precanned_connect_userdata);
|
||||
mci->user_data.data = precanned_connect_userdata;
|
||||
|
||||
mci->length = 2*2 + 3 + 3*34 + 4 + mci->user_data.length;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an ASN.1 BER header */
|
||||
BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length)
|
||||
{
|
||||
uint16 word_tag;
|
||||
uint8 byte_tag;
|
||||
uint16 word_len;
|
||||
uint8 byte_len;
|
||||
uint8 byte_int;
|
||||
int tag;
|
||||
BOOL res;
|
||||
|
||||
/* Read/write tag */
|
||||
if (islong)
|
||||
{
|
||||
word_tag = tagval;
|
||||
res = msb_io_uint16(s, &word_tag);
|
||||
tag = word_tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_tag = tagval;
|
||||
res = prs_io_uint8(s, &byte_tag);
|
||||
tag = byte_tag;
|
||||
}
|
||||
|
||||
if (!res || (tag != tagval))
|
||||
{
|
||||
ERROR("Invalid ASN.1 tag\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Read/write length */
|
||||
if (s->marshall)
|
||||
{
|
||||
if (*length >= 0x80)
|
||||
{
|
||||
byte_len = 0x82;
|
||||
word_len = (uint16)*length;
|
||||
res = prs_io_uint8(s, &byte_len);
|
||||
res = res ? msb_io_uint16(s, &word_len) : False;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_len = (uint8)*length;
|
||||
res = prs_io_uint8(s, &byte_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prs_io_uint8(s, &byte_len))
|
||||
return False;
|
||||
|
||||
if (byte_len & 0x80)
|
||||
{
|
||||
byte_len &= ~0x80;
|
||||
*length = 0;
|
||||
while (byte_len--)
|
||||
{
|
||||
if (!prs_io_uint8(s, &byte_int))
|
||||
return False;
|
||||
|
||||
*length <<= 8;
|
||||
*length += byte_int;
|
||||
}
|
||||
}
|
||||
else *length = byte_len;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an octet string (ASN.1 BER) */
|
||||
BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os)
|
||||
{
|
||||
if (!ber_io_header(s, False, 4, &os->length))
|
||||
return False;
|
||||
|
||||
if (os->length > s->end - s->offset)
|
||||
return False;
|
||||
|
||||
if (s->marshall)
|
||||
{
|
||||
memcpy(s->data + s->offset, os->data, os->length);
|
||||
}
|
||||
else
|
||||
{
|
||||
os->data = malloc(os->length);
|
||||
memcpy(os->data, s->data + s->offset, os->length);
|
||||
}
|
||||
|
||||
s->offset += os->length;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an integer (ASN.1 BER) */
|
||||
BOOL ber_io_integer(STREAM s, uint16 *word_int)
|
||||
{
|
||||
int length = 2;
|
||||
uint8 byte_int;
|
||||
BOOL res;
|
||||
|
||||
if (!ber_io_header(s, False, 2, &length))
|
||||
return False;
|
||||
|
||||
if (s->marshall)
|
||||
{
|
||||
res = msb_io_uint16(s, word_int);
|
||||
}
|
||||
else
|
||||
{
|
||||
*word_int = 0;
|
||||
while (length--)
|
||||
{
|
||||
if (!prs_io_uint8(s, &byte_int))
|
||||
return False;
|
||||
|
||||
*word_int <<= 8;
|
||||
*word_int += byte_int;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a simple uint8 type (ASN.1 BER) */
|
||||
BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval)
|
||||
{
|
||||
int length = 1;
|
||||
|
||||
if (!ber_io_header(s, False, tagval, &length))
|
||||
return False;
|
||||
|
||||
if (length != 1)
|
||||
{
|
||||
ERROR("Wrong length for simple type\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
return prs_io_uint8(s, i);
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a DOMAIN_PARAMS structure (ASN.1 BER) */
|
||||
BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp)
|
||||
{
|
||||
int length = 32;
|
||||
BOOL res;
|
||||
|
||||
res = ber_io_header(s, False, 0x30, &length);
|
||||
res = res ? ber_io_integer(s, &dp->max_channels ) : False;
|
||||
res = res ? ber_io_integer(s, &dp->max_users ) : False;
|
||||
res = res ? ber_io_integer(s, &dp->max_tokens ) : False;
|
||||
res = res ? ber_io_integer(s, &dp->num_priorities) : False;
|
||||
res = res ? ber_io_integer(s, &dp->min_throughput) : False;
|
||||
res = res ? ber_io_integer(s, &dp->max_height ) : False;
|
||||
res = res ? ber_io_integer(s, &dp->max_pdusize ) : False;
|
||||
res = res ? ber_io_integer(s, &dp->ver_protocol ) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a MCS_CONNECT_INITIAL structure (ASN.1 BER) */
|
||||
BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci)
|
||||
{
|
||||
BOOL res;
|
||||
|
||||
res = ber_io_header(s, True, 0x7f65, &mci->length);
|
||||
res = res ? ber_io_octet_string (s, &mci->calling_domain) : False;
|
||||
res = res ? ber_io_octet_string (s, &mci->called_domain ) : False;
|
||||
res = res ? ber_io_uint8 (s, &mci->upward_flag, 1) : False;
|
||||
res = res ? mcs_io_domain_params(s, &mci->target_params ) : False;
|
||||
res = res ? mcs_io_domain_params(s, &mci->minimum_params) : False;
|
||||
res = res ? mcs_io_domain_params(s, &mci->maximum_params) : False;
|
||||
res = res ? ber_io_octet_string (s, &mci->user_data ) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall a MCS_CONNECT_RESPONSE structure (ASN.1 BER) */
|
||||
BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr)
|
||||
{
|
||||
BOOL res;
|
||||
|
||||
res = ber_io_header(s, True, 0x7f66, &mcr->length);
|
||||
res = res ? ber_io_uint8 (s, &mcr->result, 10 ) : False;
|
||||
res = res ? ber_io_integer (s, &mcr->connect_id ) : False;
|
||||
res = res ? mcs_io_domain_params(s, &mcr->domain_params) : False;
|
||||
res = res ? ber_io_octet_string (s, &mcr->user_data ) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an EDrq structure (ASN.1 PER) */
|
||||
BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq)
|
||||
{
|
||||
uint8 opcode = (1) << 2;
|
||||
uint8 pkt_opcode = opcode;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if (pkt_opcode != opcode)
|
||||
{
|
||||
ERROR("Expected EDrq, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
res = res ? msb_io_uint16(s, &edrq->height ) : False;
|
||||
res = res ? msb_io_uint16(s, &edrq->interval) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an AUrq structure (ASN.1 PER) */
|
||||
BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq)
|
||||
{
|
||||
uint8 opcode = (10) << 2;
|
||||
uint8 pkt_opcode = opcode;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if (pkt_opcode != opcode)
|
||||
{
|
||||
ERROR("Expected AUrq, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an AUcf structure (ASN.1 PER) */
|
||||
BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf)
|
||||
{
|
||||
uint8 opcode = (11) << 2;
|
||||
uint8 pkt_opcode = opcode | 2;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if ((pkt_opcode & 0xfc) != opcode)
|
||||
{
|
||||
ERROR("Expected AUcf, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
res = res ? prs_io_uint8 (s, &aucf->result) : False;
|
||||
if (pkt_opcode & 2)
|
||||
res = res ? msb_io_uint16(s, &aucf->userid) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an CJrq structure (ASN.1 PER) */
|
||||
BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq)
|
||||
{
|
||||
uint8 opcode = (14) << 2;
|
||||
uint8 pkt_opcode = opcode;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if (pkt_opcode != opcode)
|
||||
{
|
||||
ERROR("Expected CJrq, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
res = res ? msb_io_uint16(s, &cjrq->userid) : False;
|
||||
res = res ? msb_io_uint16(s, &cjrq->chanid) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an CJcf structure (ASN.1 PER) */
|
||||
BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf)
|
||||
{
|
||||
uint8 opcode = (15) << 2;
|
||||
uint8 pkt_opcode = opcode | 2;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if ((pkt_opcode & 0xfc) != opcode)
|
||||
{
|
||||
ERROR("Expected CJcf, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
res = res ? prs_io_uint8 (s, &cjcf->result) : False;
|
||||
res = res ? msb_io_uint16(s, &cjcf->userid) : False;
|
||||
res = res ? msb_io_uint16(s, &cjcf->req_chanid) : False;
|
||||
if (pkt_opcode & 2)
|
||||
res = res ? msb_io_uint16(s, &cjcf->join_chanid) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Marshall/demarshall an SDrq or SDin packet (ASN.1 PER) */
|
||||
BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request)
|
||||
{
|
||||
uint8 opcode = (request ? 25 : 26) << 2;
|
||||
uint8 pkt_opcode = opcode;
|
||||
uint8 byte1, byte2;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
if (pkt_opcode != opcode)
|
||||
{
|
||||
ERROR("Expected MCS data, received %x\n", pkt_opcode);
|
||||
return False;
|
||||
}
|
||||
|
||||
res = res ? msb_io_uint16(s, &dt->userid) : False;
|
||||
res = res ? msb_io_uint16(s, &dt->chanid) : False;
|
||||
res = res ? prs_io_uint8 (s, &dt->flags ) : False;
|
||||
|
||||
if (s->marshall)
|
||||
{
|
||||
dt->length |= 0x8000;
|
||||
res = res ? msb_io_uint16(s, &dt->length) : False;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = res ? prs_io_uint8(s, &byte1) : False;
|
||||
if (byte1 & 0x80)
|
||||
{
|
||||
res = res ? prs_io_uint8(s, &byte2) : False;
|
||||
dt->length = ((byte1 & ~0x80) << 8) + byte2;
|
||||
}
|
||||
else dt->length = byte1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
120
mcs.h
120
mcs.h
@ -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
70
misc.c
@ -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
853
orders.c
Normal 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
254
orders.h
Normal 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
126
parse.c
@ -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
93
parse.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
Protocol services - parsing layer
|
||||
Parsing primitives
|
||||
Copyright (C) Matthew Chapman 1999-2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@ -21,47 +21,72 @@
|
||||
/* Parser state */
|
||||
typedef struct stream
|
||||
{
|
||||
/* Parsing layer */
|
||||
unsigned char *p;
|
||||
unsigned char *end;
|
||||
unsigned char *data;
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
unsigned int end;
|
||||
BOOL marshall;
|
||||
BOOL error;
|
||||
|
||||
/* Other layers */
|
||||
int iso_offset;
|
||||
int mcs_offset;
|
||||
int rdp_offset;
|
||||
/* Offsets of various headers */
|
||||
unsigned char *iso_hdr;
|
||||
unsigned char *mcs_hdr;
|
||||
unsigned char *sec_hdr;
|
||||
unsigned char *rdp_hdr;
|
||||
|
||||
} *STREAM;
|
||||
|
||||
/* Connection state */
|
||||
typedef struct connection
|
||||
{
|
||||
/* User interface */
|
||||
HWINDOW wnd;
|
||||
HBITMAP bmpcache[3][600];
|
||||
FONT_GLYPH fontcache[12][256];
|
||||
BLOB textcache[256];
|
||||
uint8 deskcache[0x38400];
|
||||
#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; }
|
||||
#define s_pop_layer(s,h) (s)->p = (s)->h;
|
||||
#define s_mark_end(s) (s)->end = (s)->p;
|
||||
#define s_check(s) ((s)->p <= (s)->end)
|
||||
#define s_check_rem(s,n) ((s)->p + n <= (s)->end)
|
||||
#define s_check_end(s) ((s)->p == (s)->end)
|
||||
|
||||
/* Parsing layer */
|
||||
struct stream in;
|
||||
struct stream out;
|
||||
#if defined(L_ENDIAN) && !defined(NEED_ALIGN)
|
||||
#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
|
||||
/* TCP layer */
|
||||
int tcp_socket;
|
||||
#else
|
||||
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
|
||||
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
|
||||
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
|
||||
#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
|
||||
#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
|
||||
#endif
|
||||
|
||||
/* MCS layer */
|
||||
uint16 mcs_userid;
|
||||
#if defined(B_ENDIAN) && !defined(NEED_ALIGN)
|
||||
#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||
#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||
#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||
#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||
|
||||
} *HCONN;
|
||||
#define B_ENDIAN_PREFERRED
|
||||
#define in_uint16(s,v) in_uint16_be(s,v)
|
||||
#define in_uint32(s,v) in_uint32_be(s,v)
|
||||
#define out_uint16(s,v) out_uint16_be(s,v)
|
||||
#define out_uint32(s,v) out_uint32_be(s,b)
|
||||
|
||||
#define STREAM_INIT(s,m) { s.data = xmalloc(2048); s.end = s.size = 2048; s.offset = 0; s.marshall = m; s.error = False; }
|
||||
#define STREAM_SIZE(s,l) { if (l > s.size) { s.data = xrealloc(s.data,l); s.end = s.size = l; } }
|
||||
#define REMAINING(s) ( s->end - s->offset )
|
||||
#define PUSH_LAYER(s,v,l) { s.v = s.offset; s.offset += l; }
|
||||
#define POP_LAYER(s,v) { s.offset = s.v; }
|
||||
#define MARK_END(s) { s.end = s.offset; }
|
||||
#define PRS_ERROR(s) (!(s)->error)
|
||||
#else
|
||||
#define next_be(s,v) v = ((v) << 8) + *((s)->p++);
|
||||
#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); }
|
||||
#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
|
||||
#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
|
||||
#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
|
||||
#endif
|
||||
|
||||
#ifndef B_ENDIAN_PREFERRED
|
||||
#define in_uint16(s,v) in_uint16_le(s,v)
|
||||
#define in_uint32(s,v) in_uint32_le(s,v)
|
||||
#define out_uint16(s,v) out_uint16_le(s,v)
|
||||
#define out_uint32(s,v) out_uint32_le(s,v)
|
||||
#endif
|
||||
|
||||
#define in_uint8(s,v) v = *((s)->p++);
|
||||
#define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; }
|
||||
#define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; }
|
||||
#define in_uint8s(s,n) (s)->p += n;
|
||||
#define out_uint8(s,v) *((s)->p++) = v;
|
||||
#define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; }
|
||||
#define out_uint8a(s,v,n) out_uint8p(s,v,n);
|
||||
#define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; }
|
||||
|
569
process.c
569
process.c
@ -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
269
proto.h
@ -1,184 +1,95 @@
|
||||
/* bitmap.c */
|
||||
BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size);
|
||||
/* cache.c */
|
||||
HBITMAP cache_get_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx);
|
||||
void cache_put_bitmap(HCONN conn, uint8 cache_id, uint16 cache_idx, HBITMAP bitmap);
|
||||
FONT_GLYPH *cache_get_font(HCONN conn, uint8 font, uint16 character);
|
||||
void cache_put_font(HCONN conn, uint8 font, uint32 character, uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap);
|
||||
BLOB *cache_get_text(HCONN conn, uint8 cache_id);
|
||||
void cache_put_text(HCONN conn, uint8 cache_id, void *data, int length);
|
||||
/* client.c */
|
||||
/* rdesktop.c */
|
||||
int main(int argc, char *argv[]);
|
||||
/* iso.c */
|
||||
HCONN iso_connect(char *server);
|
||||
void iso_disconnect(HCONN conn);
|
||||
BOOL iso_send_msg(HCONN conn, uint8 code);
|
||||
BOOL iso_recv_msg(HCONN conn, uint8 *code);
|
||||
void iso_init(struct connection *conn);
|
||||
BOOL iso_recv(HCONN conn);
|
||||
BOOL iso_send(HCONN conn);
|
||||
void iso_make_tpkt(TPKT *tpkt, int length);
|
||||
BOOL iso_io_tpkt(STREAM s, TPKT *tpkt);
|
||||
void iso_make_tpdu(TPDU *tpdu, uint8 code);
|
||||
BOOL iso_io_tpdu(STREAM s, TPDU *tpdu);
|
||||
/* mcs.c */
|
||||
HCONN mcs_connect(char *server);
|
||||
BOOL mcs_join_channel(HCONN conn, uint16 chanid);
|
||||
void mcs_disconnect(HCONN conn);
|
||||
void mcs_send_connect_initial(HCONN conn);
|
||||
void mcs_send_edrq(HCONN conn);
|
||||
void mcs_send_aurq(HCONN conn);
|
||||
void mcs_send_cjrq(HCONN conn, uint16 chanid);
|
||||
void mcs_init_data(HCONN conn);
|
||||
void mcs_send_data(HCONN conn, uint16 chanid, BOOL request);
|
||||
BOOL mcs_recv(HCONN conn, BOOL request);
|
||||
void mcs_make_domain_params(DOMAIN_PARAMS *dp, uint16 max_channels, uint16 max_users, uint16 max_tokens, uint16 max_pdusize);
|
||||
void mcs_make_connect_initial(MCS_CONNECT_INITIAL *mci);
|
||||
BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length);
|
||||
BOOL ber_io_octet_string(STREAM s, OCTET_STRING *os);
|
||||
BOOL ber_io_integer(STREAM s, uint16 *word_int);
|
||||
BOOL ber_io_uint8(STREAM s, uint8 *i, int tagval);
|
||||
BOOL mcs_io_domain_params(STREAM s, DOMAIN_PARAMS *dp);
|
||||
BOOL mcs_io_connect_initial(STREAM s, MCS_CONNECT_INITIAL *mci);
|
||||
BOOL mcs_io_connect_response(STREAM s, MCS_CONNECT_RESPONSE *mcr);
|
||||
BOOL mcs_io_edrq(STREAM s, MCS_EDRQ *edrq);
|
||||
BOOL mcs_io_aurq(STREAM s, MCS_AURQ *aurq);
|
||||
BOOL mcs_io_aucf(STREAM s, MCS_AUCF *aucf);
|
||||
BOOL mcs_io_cjrq(STREAM s, MCS_CJRQ *cjrq);
|
||||
BOOL mcs_io_cjcf(STREAM s, MCS_CJCF *cjcf);
|
||||
BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request);
|
||||
/* misc.c */
|
||||
void generate_random(uint8 *random);
|
||||
void *xmalloc(int size);
|
||||
void *xrealloc(void *oldmem, int size);
|
||||
void dump_data(unsigned char *p, int len);
|
||||
/* parse.c */
|
||||
BOOL prs_io_uint8(STREAM s, uint8 *i);
|
||||
BOOL prs_io_uint8s(STREAM s, uint8 *p, unsigned int length);
|
||||
BOOL msb_io_uint16(STREAM s, uint16 *i);
|
||||
BOOL lsb_io_uint16(STREAM s, uint16 *i);
|
||||
BOOL lsb_io_uint32(STREAM s, uint32 *i);
|
||||
/* process.c */
|
||||
void rdp_main_loop(HCONN conn);
|
||||
void process_demand_active(HCONN conn);
|
||||
void process_pointer_pdu(HCONN conn);
|
||||
void process_update_pdu(HCONN conn, RDP_ORDER_STATE *os);
|
||||
void process_orders(HCONN conn, RDP_ORDER_STATE *os);
|
||||
void process_destblt(HCONN conn, DESTBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_patblt(HCONN conn, PATBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_screenblt(HCONN conn, SCREENBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_line(HCONN conn, LINE_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_rect(HCONN conn, RECT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_desksave(HCONN conn, DESKSAVE_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_memblt(HCONN conn, MEMBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_triblt(HCONN conn, TRIBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_text2(HCONN conn, TEXT2_ORDER *os, uint32 present, BOOL delta);
|
||||
void process_raw_bmpcache(HCONN conn);
|
||||
void process_bmpcache(HCONN conn);
|
||||
void process_colcache(HCONN conn);
|
||||
void process_fontcache(HCONN conn);
|
||||
/* rdp.c */
|
||||
HCONN rdp_connect(char *server, int width, int height);
|
||||
void rdp_establish_key(HCONN conn);
|
||||
void rdp_establish_key_e1(HCONN conn);
|
||||
void rdp_establish_key_e2(HCONN conn);
|
||||
void rdp_send_cert(HCONN conn);
|
||||
void rdp_init(HCONN conn);
|
||||
void rdp_send(HCONN conn, uint16 pdu_type);
|
||||
void rdp_init_data(HCONN conn);
|
||||
void rdp_send_data(HCONN conn, uint16 data_pdu_type);
|
||||
void rdp_send_confirm_active(HCONN conn, uint32 shareid, int width, int height);
|
||||
void rdp_send_synchronize(HCONN conn);
|
||||
void rdp_send_control(HCONN conn, uint16 action);
|
||||
void rdp_send_fonts(HCONN conn, uint16 seqno);
|
||||
void rdp_send_input(HCONN conn, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2);
|
||||
BOOL rdp_recv_pdu(HCONN conn, uint8 *type);
|
||||
void rdp_disconnect(HCONN conn);
|
||||
void rdp_make_header(RDP_HEADER *hdr, uint16 length, uint16 pdu_type, uint16 userid);
|
||||
BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr);
|
||||
void rdp_make_data_header(RDP_DATA_HEADER *hdr, uint32 shareid, uint16 length, uint16 data_pdu_type);
|
||||
BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr);
|
||||
BOOL rdp_io_present(STREAM s, uint32 *present, uint8 flags, int size);
|
||||
BOOL rdp_io_coord(STREAM s, uint16 *coord, BOOL delta);
|
||||
BOOL rdp_io_colour(STREAM s, uint8 *colour);
|
||||
BOOL rdp_io_colourmap(STREAM s, COLOURMAP *colours);
|
||||
BOOL rdp_io_bounds(STREAM s, BOUNDS *bounds);
|
||||
BOOL rdp_io_pen(STREAM s, PEN *pen, uint32 present);
|
||||
BOOL rdp_io_brush(STREAM s, BRUSH *brush, uint32 present);
|
||||
void rdp_make_active_pdu(RDP_ACTIVE_PDU *pdu, uint32 shareid, uint16 userid, int width, int height);
|
||||
BOOL rdp_io_active_pdu(STREAM s, RDP_ACTIVE_PDU *pdu, int pdutype);
|
||||
void rdp_make_control_pdu(RDP_CONTROL_PDU *pdu, uint16 action);
|
||||
BOOL rdp_io_control_pdu(STREAM s, RDP_CONTROL_PDU *pdu);
|
||||
void rdp_make_synchronise_pdu(RDP_SYNCHRONISE_PDU *pdu, uint16 userid);
|
||||
BOOL rdp_io_synchronise_pdu(STREAM s, RDP_SYNCHRONISE_PDU *pdu);
|
||||
BOOL rdp_io_input_event(STREAM s, RDP_INPUT_EVENT *evt);
|
||||
void rdp_make_input_pdu(RDP_INPUT_PDU *pdu, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2);
|
||||
BOOL rdp_io_input_pdu(STREAM s, RDP_INPUT_PDU *pdu);
|
||||
void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno);
|
||||
BOOL rdp_io_font_info(STREAM s, RDP_FONT_INFO *font);
|
||||
BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu);
|
||||
BOOL rdp_io_pointer_pdu(STREAM s, RDP_POINTER_PDU *ptr);
|
||||
BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu);
|
||||
BOOL rdp_io_destblt_order(STREAM s, DESTBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_patblt_order(STREAM s, PATBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_screenblt_order(STREAM s, SCREENBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_line_order(STREAM s, LINE_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_rect_order(STREAM s, RECT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_desksave_order(STREAM s, DESKSAVE_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_memblt_order(STREAM s, MEMBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_triblt_order(STREAM s, TRIBLT_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_text2_order(STREAM s, TEXT2_ORDER *os, uint32 present, BOOL delta);
|
||||
BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso);
|
||||
BOOL rdp_io_raw_bmpcache_order(STREAM s, RDP_RAW_BMPCACHE_ORDER *rbo);
|
||||
BOOL rdp_io_bmpcache_order(STREAM s, RDP_BMPCACHE_ORDER *rbo);
|
||||
BOOL rdp_io_colcache_order(STREAM s, RDP_COLCACHE_ORDER *colours);
|
||||
BOOL rdp_io_fontcache_order(STREAM s, RDP_FONTCACHE_ORDER *font);
|
||||
void rdp_make_general_caps(RDP_GENERAL_CAPS *caps);
|
||||
BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps);
|
||||
void rdp_make_bitmap_caps(RDP_BITMAP_CAPS *caps, int width, int height);
|
||||
BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps);
|
||||
void rdp_make_order_caps(RDP_ORDER_CAPS *caps);
|
||||
BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps);
|
||||
void rdp_make_bmpcache_caps(RDP_BMPCACHE_CAPS *caps);
|
||||
BOOL rdp_io_bmpcache_info(STREAM s, RDP_BMPCACHE_INFO *info);
|
||||
BOOL rdp_io_bmpcache_caps(STREAM s, RDP_BMPCACHE_CAPS *caps);
|
||||
void rdp_make_control_caps(RDP_CONTROL_CAPS *caps);
|
||||
BOOL rdp_io_control_caps(STREAM s, RDP_CONTROL_CAPS *caps);
|
||||
void rdp_make_activate_caps(RDP_ACTIVATE_CAPS *caps);
|
||||
BOOL rdp_io_activate_caps(STREAM s, RDP_ACTIVATE_CAPS *caps);
|
||||
void rdp_make_pointer_caps(RDP_POINTER_CAPS *caps);
|
||||
BOOL rdp_io_pointer_caps(STREAM s, RDP_POINTER_CAPS *caps);
|
||||
void rdp_make_share_caps(RDP_SHARE_CAPS *caps, uint16 userid);
|
||||
BOOL rdp_io_share_caps(STREAM s, RDP_SHARE_CAPS *caps);
|
||||
void rdp_make_colcache_caps(RDP_COLCACHE_CAPS *caps);
|
||||
BOOL rdp_io_colcache_caps(STREAM s, RDP_COLCACHE_CAPS *caps);
|
||||
BOOL rdp_io_unknown_caps(STREAM s, void *caps);
|
||||
void xfree(void *mem);
|
||||
void hexdump(unsigned char *p, unsigned int len);
|
||||
|
||||
/* tcp.c */
|
||||
HCONN tcp_connect(char *server);
|
||||
void tcp_disconnect(HCONN conn);
|
||||
BOOL tcp_send(HCONN conn);
|
||||
BOOL tcp_recv(HCONN conn, int length);
|
||||
STREAM tcp_init(int maxlen);
|
||||
void tcp_send(STREAM s);
|
||||
STREAM tcp_recv(int length);
|
||||
BOOL tcp_connect(char *server);
|
||||
void tcp_disconnect(void);
|
||||
|
||||
/* iso.c */
|
||||
STREAM iso_init(int length);
|
||||
void iso_send(STREAM s);
|
||||
STREAM iso_recv(void);
|
||||
BOOL iso_connect(char *server);
|
||||
void iso_disconnect(void);
|
||||
|
||||
/* mcs.c */
|
||||
STREAM mcs_init(int length);
|
||||
void mcs_send(STREAM s);
|
||||
STREAM mcs_recv(void);
|
||||
BOOL mcs_connect(char *server, STREAM mcs_data);
|
||||
void mcs_disconnect(void);
|
||||
|
||||
/* secure.c */
|
||||
void sec_hash_48(uint8 *out, uint8 *in, uint8 *salt1, uint8 *salt2, uint8 salt);
|
||||
void sec_hash_16(uint8 *out, uint8 *in, uint8 *salt1, uint8 *salt2);
|
||||
void buf_out_uint32(uint8 *buffer, uint32 value);
|
||||
void sec_sign(uint8 *signature, uint8 *session_key, int length, uint8 *data, int datalen);
|
||||
STREAM sec_init(uint32 flags, int maxlen);
|
||||
void sec_send(STREAM s, uint32 flags);
|
||||
STREAM sec_recv(void);
|
||||
BOOL sec_connect(char *server);
|
||||
void sec_disconnect(void);
|
||||
|
||||
/* licence.c */
|
||||
void licence_generate_keys(uint8 *client_key, uint8 *server_key, uint8 *client_rsa);
|
||||
void licence_process(STREAM s);
|
||||
|
||||
/* rdp.c */
|
||||
void rdp_out_unistr(STREAM s, char *string, int len);
|
||||
void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2);
|
||||
void rdp_main_loop(void);
|
||||
BOOL rdp_connect(char *server);
|
||||
void rdp_disconnect(void);
|
||||
|
||||
/* orders.c */
|
||||
void process_orders(STREAM s);
|
||||
void reset_order_state(void);
|
||||
|
||||
/* bitmap.c */
|
||||
BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size);
|
||||
|
||||
/* cache.c */
|
||||
HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx);
|
||||
void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap);
|
||||
FONTGLYPH *cache_get_font(uint8 font, uint16 character);
|
||||
void cache_put_font(uint8 font, uint32 character, uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap);
|
||||
DATABLOB *cache_get_text(uint8 cache_id);
|
||||
void cache_put_text(uint8 cache_id, void *data, int length);
|
||||
uint8 *cache_get_desktop(uint32 offset, uint32 length);
|
||||
void cache_put_desktop(uint32 offset, uint32 length, uint8 *data);
|
||||
|
||||
/* xwin.c */
|
||||
HWINDOW ui_create_window(HCONN conn, int width, int height);
|
||||
void ui_destroy_window(HWINDOW wnd);
|
||||
void ui_process_events(HWINDOW wnd, HCONN conn);
|
||||
void ui_move_pointer(HWINDOW wnd, int x, int y);
|
||||
HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data);
|
||||
void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp);
|
||||
HGLYPH ui_create_glyph(HWINDOW wnd, int width, int height, uint8 *data);
|
||||
void ui_destroy_glyph(HWINDOW wnd, HGLYPH glyph);
|
||||
HCOLOURMAP ui_create_colourmap(HWINDOW wnd, COLOURMAP *colours);
|
||||
void ui_destroy_colourmap(HWINDOW wnd, HCOLOURMAP map);
|
||||
void ui_set_colourmap(HWINDOW wnd, HCOLOURMAP map);
|
||||
void ui_set_clip(HWINDOW wnd, int x, int y, int cx, int cy);
|
||||
void ui_reset_clip(HWINDOW wnd);
|
||||
void ui_destblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy);
|
||||
void ui_patblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, BRUSH *brush, int bgcolour, int fgcolour);
|
||||
void ui_screenblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy);
|
||||
void ui_memblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy);
|
||||
void ui_triblt(HWINDOW wnd, uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, BRUSH *brush, int bgcolour, int fgcolour);
|
||||
void ui_line(HWINDOW wnd, uint8 opcode, int startx, int starty, int endx, int endy, PEN *pen);
|
||||
void ui_rect(HWINDOW wnd, int x, int y, int cx, int cy, int colour);
|
||||
void ui_draw_glyph(HWINDOW wnd, int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour);
|
||||
void ui_draw_text(HWINDOW wnd, uint8 font, uint8 flags, int mixmode, int x, int y, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, int fgcolour, uint8 *text, uint8 length);
|
||||
void ui_desktop_save(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy);
|
||||
void ui_desktop_restore(HWINDOW wnd, uint8 *data, int x, int y, int cx, int cy);
|
||||
BOOL ui_create_window(char *title);
|
||||
void ui_destroy_window(void);
|
||||
void ui_process_events(void);
|
||||
void ui_move_pointer(int x, int y);
|
||||
HBITMAP ui_create_bitmap(int width, int height, uint8 *data);
|
||||
void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 *data);
|
||||
void ui_destroy_bitmap(HBITMAP bmp);
|
||||
HGLYPH ui_create_glyph(int width, int height, uint8 *data);
|
||||
void ui_destroy_glyph(HGLYPH glyph);
|
||||
HCOLOURMAP ui_create_colourmap(COLOURMAP *colours);
|
||||
void ui_destroy_colourmap(HCOLOURMAP map);
|
||||
void ui_set_colourmap(HCOLOURMAP map);
|
||||
void ui_set_clip(int x, int y, int cx, int cy);
|
||||
void ui_reset_clip(void);
|
||||
void ui_bell(void);
|
||||
void ui_destblt(uint8 opcode, int x, int y, int cx, int cy);
|
||||
void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH *brush, int bgcolour, int fgcolour);
|
||||
void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy);
|
||||
void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy);
|
||||
void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, BRUSH *brush, int bgcolour, int fgcolour);
|
||||
void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN *pen);
|
||||
void ui_rect(int x, int y, int cx, int cy, int colour);
|
||||
void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour);
|
||||
void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, int fgcolour, uint8 *text, uint8 length);
|
||||
void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy);
|
||||
void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy);
|
||||
|
236
rdesktop.c
Normal file
236
rdesktop.c
Normal 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;
|
||||
}
|
||||
}
|
@ -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"
|
575
rdp.h
575
rdp.h
@ -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
589
secure.c
Normal 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
189
tcp.c
@ -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 ∈
|
||||
}
|
||||
|
||||
/* 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
22
tcp.h
@ -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
|
@ -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
330
xwin.c
@ -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
40
xwin.h
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user