Index: reactos/base/applications/mstsc/asn.c =================================================================== --- reactos/base/applications/mstsc/asn.c (revision 0) +++ reactos/base/applications/mstsc/asn.c (working copy) @@ -0,0 +1,109 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + ASN.1 utility functions + Copyright 2012 Henrik Andersson for Cendio AB + + 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 3 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, see . +*/ + +#include "precomp.h" + + +/* Parse an ASN.1 BER header */ +RD_BOOL +ber_parse_header(STREAM s, int tagval, int *length) +{ + int tag, len; + + if (tagval > 0xff) + { + in_uint16_be(s, tag); + } + else + { + in_uint8(s, tag); + } + + if (tag != tagval) + { + error("expected tag %d, got %d\n", tagval, tag); + return False; + } + + in_uint8(s, len); + + if (len & 0x80) + { + len &= ~0x80; + *length = 0; + while (len--) + next_be(s, *length); + } + else + *length = len; + + return s_check(s); +} + +/* Output an ASN.1 BER header */ +void +ber_out_header(STREAM s, int tagval, int length) +{ + if (tagval > 0xff) + { + out_uint16_be(s, tagval); + } + else + { + out_uint8(s, tagval); + } + + if (length >= 0x80) + { + out_uint8(s, 0x82); + out_uint16_be(s, length); + } + else + out_uint8(s, length); +} + +/* Output an ASN.1 BER integer */ +void +ber_out_integer(STREAM s, int value) +{ + ber_out_header(s, BER_TAG_INTEGER, 2); + out_uint16_be(s, value); +} + +RD_BOOL +ber_in_header(STREAM s, int *tagval, int *decoded_len) +{ + in_uint8(s, *tagval); + in_uint8(s, *decoded_len); + + if (*decoded_len < 0x80) + return True; + else if (*decoded_len == 0x81) + { + in_uint8(s, *decoded_len); + return True; + } + else if (*decoded_len == 0x82) + { + in_uint16_be(s, *decoded_len); + return True; + } + + return False; +} Index: reactos/base/applications/mstsc/bitmap.c =================================================================== --- reactos/base/applications/mstsc/bitmap.c (revision 66177) +++ reactos/base/applications/mstsc/bitmap.c (working copy) @@ -1,11 +1,11 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Bitmap decompression routines - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,15 +13,13 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -/* three seperate function for speed when decompressing the bitmaps */ -/* when modifing one function make the change in the others */ -/* comment out #define BITMAP_SPEED_OVER_SIZE below for one slower function */ -/* j@american-data.com */ +/* three seperate function for speed when decompressing the bitmaps + when modifing one function make the change in the others + jay.sorg@gmail.com */ /* indent is confused by this file */ /* *INDENT-OFF* */ @@ -28,8 +26,6 @@ #include "precomp.h" -#define BITMAP_SPEED_OVER_SIZE - #define CVAL(p) (*(p++)) #ifdef NEED_ALIGN #ifdef L_ENDIAN @@ -66,10 +62,8 @@ } \ } -#ifdef BITMAP_SPEED_OVER_SIZE - /* 1 byte bitmap decompress */ -static BOOL +static RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; @@ -267,7 +261,7 @@ } /* 2 byte bitmap decompress */ -static BOOL +static RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; @@ -466,7 +460,7 @@ } /* 3 byte bitmap decompress */ -static BOOL +static RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; @@ -751,254 +745,146 @@ return True; } -#else - -static uint32 -cvalx(uint8 **input, int Bpp) +/* decompress a colour plane */ +static int +process_plane(uint8 * in, int width, int height, uint8 * out, int size) { - uint32 rv = 0; - memcpy(&rv, *input, Bpp); - *input += Bpp; - return rv; -} + int indexw; + int indexh; + int code; + int collen; + int replen; + int color; + int x; + int revcode; + uint8 * last_line; + uint8 * this_line; + uint8 * org_in; + uint8 * org_out; -static void -setli(uint8 *input, int offset, uint32 value, int Bpp) -{ - input += offset * Bpp; - memcpy(input, &value, Bpp); -} - -static uint32 -getli(uint8 *input, int offset, int Bpp) -{ - uint32 rv = 0; - input += offset * Bpp; - memcpy(&rv, input, Bpp); - return rv; -} - -static BOOL -bitmap_decompressx(uint8 *output, int width, int height, uint8 *input, int size, int Bpp) -{ - uint8 *end = input + size; - uint8 *prevline = NULL, *line = NULL; - int opcode, count, offset, isfillormix, x = width; - int lastopcode = -1, insertmix = False, bicolour = False; - uint8 code; - uint32 colour1 = 0, colour2 = 0; - uint8 mixmask, mask = 0; - uint32 mix = 0xffffffff; - int fom_mask = 0; - - while (input < end) + org_in = in; + org_out = out; + last_line = 0; + indexh = 0; + while (indexh < height) { - fom_mask = 0; - code = CVAL(input); - opcode = code >> 4; - - /* Handle different opcode forms */ - switch (opcode) + out = (org_out + width * height * 4) - ((indexh + 1) * width * 4); + color = 0; + this_line = out; + indexw = 0; + if (last_line == 0) { - case 0xc: - case 0xd: - case 0xe: - opcode -= 6; - count = code & 0xf; - offset = 16; - break; - - case 0xf: - opcode = code & 0xf; - if (opcode < 9) + while (indexw < width) + { + code = CVAL(in); + replen = code & 0xf; + collen = (code >> 4) & 0xf; + revcode = (replen << 4) | collen; + if ((revcode <= 47) && (revcode >= 16)) { - count = CVAL(input); - count |= CVAL(input) << 8; + replen = revcode; + collen = 0; } - else + while (collen > 0) { - count = (opcode < 0xb) ? 8 : 1; + color = CVAL(in); + *out = color; + out += 4; + indexw++; + collen--; } - offset = 0; - break; - - default: - opcode >>= 1; - count = code & 0x1f; - offset = 32; - break; - } - - /* Handle strange cases for counts */ - if (offset != 0) - { - isfillormix = ((opcode == 2) || (opcode == 7)); - - if (count == 0) - { - if (isfillormix) - count = CVAL(input) + 1; - else - count = CVAL(input) + offset; + while (replen > 0) + { + *out = color; + out += 4; + indexw++; + replen--; + } } - else if (isfillormix) - { - count <<= 3; - } } - - /* Read preliminary data */ - switch (opcode) + else { - case 0: /* Fill */ - if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) - insertmix = True; - break; - case 8: /* Bicolour */ - colour1 = cvalx(&input, Bpp); - case 3: /* Colour */ - colour2 = cvalx(&input, Bpp); - break; - case 6: /* SetMix/Mix */ - case 7: /* SetMix/FillOrMix */ - mix = cvalx(&input, Bpp); - opcode -= 5; - break; - case 9: /* FillOrMix_1 */ - mask = 0x03; - opcode = 0x02; - fom_mask = 3; - break; - case 0x0a: /* FillOrMix_2 */ - mask = 0x05; - opcode = 0x02; - fom_mask = 5; - break; - - } - - lastopcode = opcode; - mixmask = 0; - - /* Output body */ - while (count > 0) - { - if (x >= width) + while (indexw < width) { - if (height <= 0) - return False; - - x = 0; - height--; - - prevline = line; - line = output + height * width * Bpp; - } - - switch (opcode) - { - case 0: /* Fill */ - if (insertmix) + code = CVAL(in); + replen = code & 0xf; + collen = (code >> 4) & 0xf; + revcode = (replen << 4) | collen; + if ((revcode <= 47) && (revcode >= 16)) + { + replen = revcode; + collen = 0; + } + while (collen > 0) + { + x = CVAL(in); + if (x & 1) { - if (prevline == NULL) - setli(line, x, mix, Bpp); - else - setli(line, x, - getli(prevline, x, Bpp) ^ mix, Bpp); - - insertmix = False; - count--; - x++; + x = x >> 1; + x = x + 1; + color = -x; } - - if (prevline == NULL) - { - REPEAT(setli(line, x, 0, Bpp))} else { - REPEAT(setli - (line, x, getli(prevline, x, Bpp), Bpp)); + x = x >> 1; + color = x; } - break; - - case 1: /* Mix */ - if (prevline == NULL) - { - REPEAT(setli(line, x, mix, Bpp)); - } - else - { - REPEAT(setli - (line, x, getli(prevline, x, Bpp) ^ mix, - Bpp)); - } - break; - - case 2: /* Fill or Mix */ - if (prevline == NULL) - { - REPEAT(MASK_UPDATE(); - if (mask & mixmask) setli(line, x, mix, Bpp); - else - setli(line, x, 0, Bpp);); - } - else - { - REPEAT(MASK_UPDATE(); - if (mask & mixmask) - setli(line, x, getli(prevline, x, Bpp) ^ mix, - Bpp); - else - setli(line, x, getli(prevline, x, Bpp), - Bpp);); - } - break; - - case 3: /* Colour */ - REPEAT(setli(line, x, colour2, Bpp)); - break; - - case 4: /* Copy */ - REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp)); - break; - - case 8: /* Bicolour */ - REPEAT(if (bicolour) - { - setli(line, x, colour2, Bpp); bicolour = False;} - else - { - setli(line, x, colour1, Bpp); bicolour = True; - count++;} - ); - break; - - case 0xd: /* White */ - REPEAT(setli(line, x, 0xffffffff, Bpp)); - break; - - case 0xe: /* Black */ - REPEAT(setli(line, x, 0, Bpp)); - break; - - default: - unimpl("bitmap opcode 0x%x\n", opcode); - return False; + x = last_line[indexw * 4] + color; + *out = x; + out += 4; + indexw++; + collen--; + } + while (replen > 0) + { + x = last_line[indexw * 4] + color; + *out = x; + out += 4; + indexw++; + replen--; + } } } + indexh++; + last_line = this_line; } + return (int) (in - org_in); +} - return True; +/* 4 byte bitmap decompress */ +static RD_BOOL +bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size) +{ + int code; + int bytes_pro; + int total_pro; + + code = CVAL(input); + if (code != 0x10) + { + return False; + } + total_pro = 1; + bytes_pro = process_plane(input, width, height, output + 3, size - total_pro); + total_pro += bytes_pro; + input += bytes_pro; + bytes_pro = process_plane(input, width, height, output + 2, size - total_pro); + total_pro += bytes_pro; + input += bytes_pro; + bytes_pro = process_plane(input, width, height, output + 1, size - total_pro); + total_pro += bytes_pro; + input += bytes_pro; + bytes_pro = process_plane(input, width, height, output + 0, size - total_pro); + total_pro += bytes_pro; + return size == total_pro; } -#endif - /* main decompress function */ -BOOL +RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp) { -#ifdef BITMAP_SPEED_OVER_SIZE - BOOL rv = False; + RD_BOOL rv = False; + switch (Bpp) { case 1: @@ -1010,11 +896,13 @@ case 3: rv = bitmap_decompress3(output, width, height, input, size); break; + case 4: + rv = bitmap_decompress4(output, width, height, input, size); + break; + default: + unimpl("Bpp %d\n", Bpp); + break; } -#else - BOOL rv; - rv = bitmap_decompressx(output, width, height, input, size, Bpp); -#endif return rv; } Index: reactos/base/applications/mstsc/cache.c =================================================================== --- reactos/base/applications/mstsc/cache.c (revision 66177) +++ reactos/base/applications/mstsc/cache.c (working copy) @@ -1,12 +1,13 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Cache routines - Copyright (C) Matthew Chapman 1999-2005 - Copyright (C) Jeroen Meijer 2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright (C) Jeroen Meijer 2005 + Copyright 2003-2011 Peter Astrand for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,9 +15,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -50,6 +50,7 @@ static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET }; static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET }; + static int g_bmpcache_count[3]; /* Setup the bitmap cache lru/mru linked list */ @@ -94,7 +95,7 @@ { error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c, g_bmpcache_count[id]); - exit(1); + exit(EX_SOFTWARE); } } @@ -176,7 +177,7 @@ idx = g_bmpcache_lru[id]; n_idx = g_bmpcache[id][idx].next; - DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx, + DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=%p\n", id, idx, n_idx, g_bmpcache[id][idx].bitmap)); ui_destroy_bitmap(g_bmpcache[id][idx].bitmap); @@ -262,7 +263,7 @@ idx = g_bmpcache_lru[id]; while (idx >= 0) { - pstcache_touch_bitmap((uint8) id, (uint16) idx, ++t); + pstcache_touch_bitmap(id, idx, ++t); idx = g_bmpcache[id][idx].next; } DEBUG_RDP5((" %d stamps written.\n", t)); @@ -430,3 +431,43 @@ error("put cursor %d\n", cache_idx); } } + +/* BRUSH CACHE */ +/* index 0 is 2 colour brush, index 1 is muti colour brush */ +static BRUSHDATA g_brushcache[2][64]; + +/* Retrieve brush from cache */ +BRUSHDATA * +cache_get_brush_data(uint8 colour_code, uint8 idx) +{ + colour_code = colour_code == 1 ? 0 : 1; + if (idx < NUM_ELEMENTS(g_brushcache[0])) + { + return &g_brushcache[colour_code][idx]; + } + error("get brush %d %d\n", colour_code, idx); + return NULL; +} + +/* Store brush in cache */ +/* this function takes over the data pointer in struct, eg, caller gives it up */ +void +cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data) +{ + BRUSHDATA *bd; + + colour_code = colour_code == 1 ? 0 : 1; + if (idx < NUM_ELEMENTS(g_brushcache[0])) + { + bd = &g_brushcache[colour_code][idx]; + if (bd->data != 0) + { + xfree(bd->data); + } + memcpy(bd, brush_data, sizeof(BRUSHDATA)); + } + else + { + error("put brush %d %d\n", colour_code, idx); + } +} Index: reactos/base/applications/mstsc/channels.c =================================================================== --- reactos/base/applications/mstsc/channels.c (revision 66177) +++ reactos/base/applications/mstsc/channels.c (working copy) @@ -1,12 +1,12 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Virtual channels - Copyright (C) Erik Forsberg 2003 - Copyright (C) Matthew Chapman 2003-2005 + Copyright 2003 Erik Forsberg for Cendio AB + Copyright (C) Matthew Chapman 2003-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,9 +14,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -27,8 +26,8 @@ #define CHANNEL_FLAG_LAST 0x02 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10 -extern BOOL g_use_rdp5; -extern BOOL g_encryption; +extern RDP_VERSION g_rdp_version; +extern RD_BOOL g_encryption; VCHANNEL g_channels[MAX_CHANNELS]; unsigned int g_num_channels; @@ -48,7 +47,7 @@ { VCHANNEL *channel; - if (!g_use_rdp5) + if (g_rdp_version < RDP_V5) return NULL; if (g_num_channels >= MAX_CHANNELS) @@ -83,6 +82,10 @@ uint32 thislength, remaining; uint8 *data; +#ifdef WITH_SCARD + scard_lock(SCARD_LOCK_CHANNEL); +#endif + /* first fragment sent in-place */ s_pop_layer(s, channel_hdr); length = s->end - s->p - 8; @@ -125,6 +128,10 @@ data += thislength; } + +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_CHANNEL); +#endif } void Index: reactos/base/applications/mstsc/CMakeLists.txt =================================================================== --- reactos/base/applications/mstsc/CMakeLists.txt (revision 66177) +++ reactos/base/applications/mstsc/CMakeLists.txt (working copy) @@ -1,5 +1,6 @@ list(APPEND SOURCE + asn.c bitmap.c bsops.c cache.c @@ -19,6 +20,14 @@ tcp.c uimain.c win32.c + bsops.h + constants.h + orders.h + proto.h + rdesktop.h + resource.h + types.h + uimain.h precomp.h) add_executable(mstsc ${SOURCE} rdc.rc) Index: reactos/base/applications/mstsc/constants.h =================================================================== --- reactos/base/applications/mstsc/constants.h (revision 66177) +++ reactos/base/applications/mstsc/constants.h (working copy) @@ -1,11 +1,11 @@ /* rdesktop: A Remote Desktop Protocol client. Miscellaneous protocol constants - Copyright (C) Matthew Chapman 1999-2005 - - This program is free software; you can redistribute it and/or modify + Copyright (C) Matthew Chapman 1999-2008 + + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,8 +14,7 @@ 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. + along with this program. If not, see . */ /* TCP port for Remote Desktop Protocol */ @@ -34,6 +33,31 @@ ISO_PDU_ER = 0x70 /* Error */ }; +/* RDP protocol negotiating constants */ +enum RDP_NEG_TYPE_CODE +{ + RDP_NEG_REQ = 1, + RDP_NEG_RSP = 2, + RDP_NEG_FAILURE = 3 +}; + +enum RDP_NEG_REQ_CODE +{ + PROTOCOL_RDP = 0, + PROTOCOL_SSL = 1, + PROTOCOL_HYBRID = 2 +}; + +enum RDP_NEG_FAILURE_CODE +{ + SSL_REQUIRED_BY_SERVER = 1, + SSL_NOT_ALLOWED_BY_SERVER = 2, + SSL_CERT_NOT_ON_SERVER = 3, + INCONSISTENT_FLAGS = 4, + HYBRID_REQUIRED_BY_SERVER = 5, + SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 6 +}; + /* MCS PDU codes */ enum MCS_PDU_TYPE { @@ -54,6 +78,10 @@ #define BER_TAG_INTEGER 2 #define BER_TAG_OCTET_STRING 4 #define BER_TAG_RESULT 10 +#define BER_TAG_SEQUENCE 16 +#define BER_TAG_CONSTRUCTED 0x20 +#define BER_TAG_CTXT_SPECIFIC 0x80 + #define MCS_TAG_DOMAIN_PARAMS 0x30 #define MCS_GLOBAL_CHANNEL 1003 @@ -60,11 +88,11 @@ #define MCS_USERCHANNEL_BASE 1001 /* RDP secure transport constants */ -#define SEC_RANDOM_SIZE 32 -#define SEC_MODULUS_SIZE 64 +#define SEC_RANDOM_SIZE 32 +#define SEC_MODULUS_SIZE 64 #define SEC_MAX_MODULUS_SIZE 256 -#define SEC_PADDING_SIZE 8 -#define SEC_EXPONENT_SIZE 4 +#define SEC_PADDING_SIZE 8 +#define SEC_EXPONENT_SIZE 4 #define SEC_CLIENT_RANDOM 0x0001 #define SEC_ENCRYPT 0x0008 @@ -79,7 +107,7 @@ #define SEC_TAG_CLI_INFO 0xc001 #define SEC_TAG_CLI_CRYPT 0xc002 #define SEC_TAG_CLI_CHANNELS 0xc003 -#define SEC_TAG_CLI_4 0xc004 +#define SEC_TAG_CLI_CLUSTER 0xc004 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 @@ -86,22 +114,33 @@ #define SEC_RSA_MAGIC 0x31415352 /* RSA1 */ +/* Client cluster constants */ +#define SEC_CC_REDIRECTION_SUPPORTED 0x00000001 +#define SEC_CC_REDIRECT_SESSIONID_FIELD_VALID 0x00000002 +#define SEC_CC_REDIRECTED_SMARTCARD 0x00000040 +#define SEC_CC_REDIRECT_VERSION_MASK 0x0000003c + +#define SEC_CC_REDIRECT_VERSION_3 0x02 +#define SEC_CC_REDIRECT_VERSION_4 0x03 +#define SEC_CC_REDIRECT_VERSION_5 0x04 +#define SEC_CC_REDIRECT_VERSION_6 0x05 + /* RDP licensing constants */ #define LICENCE_TOKEN_SIZE 10 #define LICENCE_HWID_SIZE 20 #define LICENCE_SIGNATURE_SIZE 16 -#define LICENCE_TAG_DEMAND 0x01 -#define LICENCE_TAG_AUTHREQ 0x02 -#define LICENCE_TAG_ISSUE 0x03 -#define LICENCE_TAG_REISSUE 0x04 -#define LICENCE_TAG_PRESENT 0x12 -#define LICENCE_TAG_REQUEST 0x13 -#define LICENCE_TAG_AUTHRESP 0x15 -#define LICENCE_TAG_RESULT 0xff +#define LICENCE_TAG_REQUEST 0x01 +#define LICENCE_TAG_PLATFORM_CHALLANGE 0x02 +#define LICENCE_TAG_NEW_LICENCE 0x03 +#define LICENCE_TAG_UPGRADE_LICENCE 0x04 +#define LICENCE_TAG_LICENCE_INFO 0x12 +#define LICENCE_TAG_NEW_LICENCE_REQUEST 0x13 +#define LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE 0x15 +#define LICENCE_TAG_ERROR_ALERT 0xff -#define LICENCE_TAG_USER 0x000f -#define LICENCE_TAG_HOST 0x0010 +#define BB_CLIENT_USER_NAME_BLOB 0x000f +#define BB_CLIENT_MACHINE_NAME_BLOB 0x0010 /* RDP PDU codes */ enum RDP_PDU_TYPE @@ -108,9 +147,10 @@ { RDP_PDU_DEMAND_ACTIVE = 1, RDP_PDU_CONFIRM_ACTIVE = 3, - RDP_PDU_REDIRECT = 4, /* MS Server 2003 Session Redirect */ + RDP_PDU_REDIRECT = 4, /* Standard Server Redirect */ RDP_PDU_DEACTIVATE = 6, - RDP_PDU_DATA = 7 + RDP_PDU_DATA = 7, + RDP_PDU_ENHANCED_REDIRECT = 10 /* Enhanced Server Redirect */ }; enum RDP_DATA_PDU_TYPE @@ -122,12 +162,27 @@ RDP_DATA_PDU_SYNCHRONISE = 31, RDP_DATA_PDU_BELL = 34, RDP_DATA_PDU_CLIENT_WINDOW_STATUS = 35, - RDP_DATA_PDU_LOGON = 38, + RDP_DATA_PDU_LOGON = 38, /* PDUTYPE2_SAVE_SESSION_INFO */ RDP_DATA_PDU_FONT2 = 39, RDP_DATA_PDU_KEYBOARD_INDICATORS = 41, - RDP_DATA_PDU_DISCONNECT = 47 + RDP_DATA_PDU_DISCONNECT = 47, + RDP_DATA_PDU_AUTORECONNECT_STATUS = 50 }; +enum RDP_SAVE_SESSION_PDU_TYPE +{ + INFOTYPE_LOGON = 0, + INFOTYPE_LOGON_LONG = 1, + INFOTYPE_LOGON_PLAINNOTIFY = 2, + INFOTYPE_LOGON_EXTENDED_INF = 3 +}; + +enum RDP_LOGON_INFO_EXTENDED_TYPE +{ + LOGON_EX_AUTORECONNECTCOOKIE = 1, + LOGON_EX_LOGONERRORS = 2 +}; + enum RDP_CONTROL_PDU_TYPE { RDP_CTL_REQUEST_CONTROL = 1, @@ -149,7 +204,8 @@ RDP_POINTER_SYSTEM = 1, RDP_POINTER_MOVE = 3, RDP_POINTER_COLOR = 6, - RDP_POINTER_CACHED = 7 + RDP_POINTER_CACHED = 7, + RDP_POINTER_NEW = 8 }; enum RDP_SYSTEM_POINTER_TYPE @@ -192,9 +248,8 @@ #define MOUSE_FLAG_DOWN 0x8000 /* Raster operation masks */ -#define ROP2_S(rop3) ((uint8) (rop3 & 0xf)) -#define ROP2_P(rop3) ((uint8) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2))) -#define ROP_MINUS_1(rop) ((uint8) (rop - 1)) +#define ROP2_S(rop3) (rop3 & 0xf) +#define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)) #define ROP2_COPY 0xc #define ROP2_XOR 0x6 @@ -245,6 +300,7 @@ #define RDP_CAPSET_POINTER 8 #define RDP_CAPLEN_POINTER 0x08 +#define RDP_CAPLEN_NEWPOINTER 0x0a #define RDP_CAPSET_SHARE 9 #define RDP_CAPLEN_SHARE 0x08 @@ -252,6 +308,9 @@ #define RDP_CAPSET_COLCACHE 10 #define RDP_CAPLEN_COLCACHE 0x08 +#define RDP_CAPSET_BRUSHCACHE 15 +#define RDP_CAPLEN_BRUSHCACHE 0x08 + #define RDP_CAPSET_BMPCACHE2 19 #define RDP_CAPLEN_BMPCACHE2 0x28 #define BMPCACHE2_FLAG_PERSIST ((uint32)1<<31) @@ -259,12 +318,16 @@ #define RDP_SOURCE "MSTSC" /* Logon flags */ -#define RDP_LOGON_AUTO 0x0008 -#define RDP_LOGON_NORMAL 0x0033 -#define RDP_LOGON_COMPRESSION 0x0080 /* mppc compression with 8kB histroy buffer */ -#define RDP_LOGON_BLOB 0x0100 -#define RDP_LOGON_COMPRESSION2 0x0200 /* rdp5 mppc compression with 64kB history buffer */ -#define RDP_LOGON_LEAVE_AUDIO 0x2000 +#define RDP_INFO_MOUSE 0x00000001 +#define RDP_INFO_DISABLECTRLALTDEL 0x00000002 +#define RDP_INFO_AUTOLOGON 0x00000008 +#define RDP_INFO_UNICODE 0x00000010 +#define RDP_INFO_MAXIMIZESHELL 0x00000020 +#define RDP_INFO_COMPRESSION 0x00000080 /* mppc compression with 8kB histroy buffer */ +#define RDP_INFO_ENABLEWINDOWSKEY 0x00000100 +#define RDP_INFO_COMPRESSION2 0x00000200 /* rdp5 mppc compression with 64kB history buffer */ +#define RDP_INFO_REMOTE_CONSOLE_AUDIO 0x00002000 +#define RDP_INFO_PASSWORD_IS_SC_PIN 0x00040000 #define RDP5_DISABLE_NOTHING 0x00 #define RDP5_NO_WALLPAPER 0x01 @@ -313,7 +376,8 @@ #define MASK_CHANGE_BIT(var, mask, active) (var = ((var & ~mask) | (active ? mask : 0))) /* Clipboard constants, "borrowed" from GCC system headers in - the w32 cross compiler */ + the w32 cross compiler + this is the CF_ set when WINVER is 0x0400 */ #ifndef CF_TEXT #define CF_TEXT 1 @@ -357,37 +421,53 @@ #define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000 /* NT status codes for RDPDR */ -#undef STATUS_SUCCESS -#define STATUS_SUCCESS 0x00000000 -#undef STATUS_NOT_IMPLEMENTED -#define STATUS_NOT_IMPLEMENTED 0x00000001 -#undef STATUS_PENDING -#define STATUS_PENDING 0x00000103 +#define RD_STATUS_SUCCESS 0x00000000 +#define RD_STATUS_NOT_IMPLEMENTED 0x00000001 +#define RD_STATUS_PENDING 0x00000103 -#ifndef STATUS_NO_MORE_FILES -#define STATUS_NO_MORE_FILES 0x80000006 -#define STATUS_DEVICE_PAPER_EMPTY 0x8000000e -#define STATUS_DEVICE_POWERED_OFF 0x8000000f -#define STATUS_DEVICE_OFF_LINE 0x80000010 -#define STATUS_DEVICE_BUSY 0x80000011 -#endif +#define RD_STATUS_NO_MORE_FILES 0x80000006 +#define RD_STATUS_DEVICE_PAPER_EMPTY 0x8000000e +#define RD_STATUS_DEVICE_POWERED_OFF 0x8000000f +#define RD_STATUS_DEVICE_OFF_LINE 0x80000010 +#define RD_STATUS_DEVICE_BUSY 0x80000011 -#ifndef STATUS_INVALID_HANDLE -#define STATUS_INVALID_HANDLE 0xc0000008 -#define STATUS_INVALID_PARAMETER 0xc000000d -#define STATUS_NO_SUCH_FILE 0xc000000f -#define STATUS_INVALID_DEVICE_REQUEST 0xc0000010 -#define STATUS_ACCESS_DENIED 0xc0000022 -#define STATUS_OBJECT_NAME_COLLISION 0xc0000035 -#define STATUS_DISK_FULL 0xc000007f -#define STATUS_FILE_IS_A_DIRECTORY 0xc00000ba -#define STATUS_NOT_SUPPORTED 0xc00000bb -#define STATUS_TIMEOUT 0xc0000102 -#define STATUS_NOTIFY_ENUM_DIR 0xc000010c -#define STATUS_CANCELLED 0xc0000120 -#endif +#define RD_STATUS_INVALID_HANDLE 0xc0000008 +#define RD_STATUS_INVALID_PARAMETER 0xc000000d +#define RD_STATUS_NO_SUCH_FILE 0xc000000f +#define RD_STATUS_INVALID_DEVICE_REQUEST 0xc0000010 +#define RD_STATUS_ACCESS_DENIED 0xc0000022 +#define RD_STATUS_OBJECT_NAME_COLLISION 0xc0000035 +#define RD_STATUS_DISK_FULL 0xc000007f +#define RD_STATUS_FILE_IS_A_DIRECTORY 0xc00000ba +#define RD_STATUS_NOT_SUPPORTED 0xc00000bb +#define RD_STATUS_TIMEOUT 0xc0000102 +#define RD_STATUS_NOTIFY_ENUM_DIR 0xc000010c +#define RD_STATUS_CANCELLED 0xc0000120 +#define RD_STATUS_DIRECTORY_NOT_EMPTY 0xc0000101 +/* RDPSND constants */ +#define TSSNDCAPS_ALIVE 0x00000001 +#define TSSNDCAPS_VOLUME 0x00000002 + /* RDPDR constants */ + +#define RDPDR_CTYP_CORE 0x4472 +#define RDPDR_CTYP_PRN 0x5052 + +#define PAKID_CORE_SERVER_ANNOUNCE 0x496e +#define PAKID_CORE_CLIENTID_CONFIRM 0x4343 +#define PAKID_CORE_CLIENT_NAME 0x434e +#define PAKID_CORE_DEVICE_LIST_ANNOUNCE 0x4441 +#define PAKID_CORE_DEVICE_REPLY 0x6472 +#define PAKID_CORE_DEVICE_IOREQUEST 0x4952 +#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 +#define PAKID_CORE_SERVER_CAPABILITY 0x5350 +#define PAKID_CORE_CLIENT_CAPABILITY 0x4350 +#define PAKID_CORE_DEVICELIST_REMOVE 0x444d +#define PAKID_PRN_CACHE_DATA 0x5043 +#define PAKID_CORE_USER_LOGGEDON 0x554c +#define PAKID_PRN_USING_XPS 0x5543 + #define RDPDR_MAX_DEVICES 0x10 #define DEVICE_TYPE_SERIAL 0x01 #define DEVICE_TYPE_PARALLEL 0x02 @@ -411,6 +491,10 @@ #define exDiscReasonOutOfMemory 0x0006 #define exDiscReasonServerDeniedConnection 0x0007 #define exDiscReasonServerDeniedConnectionFips 0x0008 +#define exDiscReasonServerInsufficientPrivileges 0x0009 +#define exDiscReasonServerFreshCredentialsRequired 0x000a +#define exDiscReasonRPCInitiatedDisconnectByUser 0x000b +#define exDiscReasonByUser 0x000c #define exDiscReasonLicenseInternal 0x0100 #define exDiscReasonLicenseNoLicenseServer 0x0101 #define exDiscReasonLicenseNoLicense 0x0102 @@ -431,6 +515,31 @@ #define SEAMLESSRDP_POSITION_TIMER 200000 #define SEAMLESSRDP_CREATE_MODAL 0x0001 +#define SEAMLESSRDP_CREATE_TOPMOST 0x0002 #define SEAMLESSRDP_HELLO_RECONNECT 0x0001 #define SEAMLESSRDP_HELLO_HIDDEN 0x0002 + +/* Smartcard constants */ +#define SCARD_LOCK_TCP 0 +#define SCARD_LOCK_SEC 1 +#define SCARD_LOCK_CHANNEL 2 +#define SCARD_LOCK_RDPDR 3 +#define SCARD_LOCK_LAST 4 + + +/* redirect flags, from [MS-RDPBCGR] 2.2.13.1 */ +enum RDP_PDU_REDIRECT_FLAGS +{ + PDU_REDIRECT_HAS_IP = 0x1, + PDU_REDIRECT_HAS_LOAD_BALANCE_INFO = 0x2, + PDU_REDIRECT_HAS_USERNAME = 0x4, + PDU_REDIRECT_HAS_DOMAIN = 0x8, + PDU_REDIRECT_HAS_PASSWORD = 0x10, + PDU_REDIRECT_DONT_STORE_USERNAME = 0x20, + PDU_REDIRECT_USE_SMARTCARD = 0x40, + PDU_REDIRECT_INFORMATIONAL = 0x80, + PDU_REDIRECT_HAS_TARGET_FQDN = 0x100, + PDU_REDIRECT_HAS_TARGET_NETBIOS = 0x200, + PDU_REDIRECT_HAS_TARGET_IP_ARRAY = 0x800 +}; Index: reactos/base/applications/mstsc/iso.c =================================================================== --- reactos/base/applications/mstsc/iso.c (revision 66177) +++ reactos/base/applications/mstsc/iso.c (working copy) @@ -1,11 +1,13 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - ISO layer - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2005-2011 Peter Astrand for Cendio AB + Copyright 2012 Henrik Andersson for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,13 +15,25 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" +extern RD_BOOL g_encryption; +extern RD_BOOL g_encryption_initial; +extern RDP_VERSION g_rdp_version; +extern RD_BOOL g_use_password_as_pin; + +static RD_BOOL g_negotiate_rdp_protocol = True; + +extern char *g_sc_csp_name; +extern char *g_sc_reader_name; +extern char *g_sc_card_name; +extern char *g_sc_container_name; + + /* Send a self-contained ISO PDU */ static void iso_send_msg(uint8 code) @@ -43,11 +57,14 @@ } static void -iso_send_connection_request(char *username) +iso_send_connection_request(char *username, uint32 neg_proto) { STREAM s; int length = 30 + strlen(username); + if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) + length += 8; + s = tcp_init(length); out_uint8(s, 3); /* version */ @@ -63,9 +80,18 @@ out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash=")); out_uint8p(s, username, strlen(username)); - out_uint8(s, 0x0d); /* Unknown */ - out_uint8(s, 0x0a); /* Unknown */ + out_uint8(s, 0x0d); /* cookie termination string: CR+LF */ + out_uint8(s, 0x0a); + if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) + { + /* optional rdp protocol negotiation request for RDPv5 */ + out_uint8(s, RDP_NEG_REQ); + out_uint8(s, 0); + out_uint16(s, 8); + out_uint32(s, neg_proto); + } + s_mark_end(s); tcp_send(s); } @@ -98,6 +124,11 @@ next_be(s, length); } } + if (length < 4) + { + error("Bad packet header\n"); + return NULL; + } s = tcp_recv(s, length - 4); if (s == NULL) return NULL; @@ -168,17 +199,38 @@ } /* Establish a connection up to the ISO layer */ -BOOL -iso_connect(char *server, char *username) +RD_BOOL +iso_connect(char *server, char *username, char *domain, char *password, + RD_BOOL reconnect, uint32 * selected_protocol) { - uint8 code = 0; + STREAM s; + uint8 code; + uint32 neg_proto; + g_negotiate_rdp_protocol = True; + + neg_proto = PROTOCOL_SSL; + +#ifdef WITH_CREDSSP + if (!g_use_password_as_pin) + neg_proto |= PROTOCOL_HYBRID; + else if (g_sc_csp_name || g_sc_reader_name || g_sc_card_name || g_sc_container_name) + neg_proto |= PROTOCOL_HYBRID; + else + warning("Disables CredSSP due to missing smartcard information for SSO.\n"); +#endif + + retry: + *selected_protocol = PROTOCOL_RDP; + code = 0; + if (!tcp_connect(server)) return False; - iso_send_connection_request(username); + iso_send_connection_request(username, neg_proto); - if (iso_recv_msg(&code, NULL) == NULL) + s = iso_recv_msg(&code, NULL); + if (s == NULL) return False; if (code != ISO_PDU_CC) @@ -188,30 +240,120 @@ return False; } - return True; -} + if (g_rdp_version >= RDP_V5 && s_check_rem(s, 8)) + { + /* handle RDP_NEG_REQ response */ + const char *reason = NULL; -/* Establish a reconnection up to the ISO layer */ -BOOL -iso_reconnect(char *server) -{ - uint8 code = 0; + uint8 type = 0, flags = 0; + uint16 length = 0; + uint32 data = 0; - if (!tcp_connect(server)) - return False; + in_uint8(s, type); + in_uint8(s, flags); + in_uint16(s, length); + in_uint32(s, data); - iso_send_msg(ISO_PDU_CR); + if (type == RDP_NEG_FAILURE) + { + RD_BOOL retry_without_neg = False; - if (iso_recv_msg(&code, NULL) == NULL) - return False; + switch (data) + { + case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER: + reason = "SSL with user authentication required by server"; + break; + case SSL_NOT_ALLOWED_BY_SERVER: + reason = "SSL not allowed by server"; + retry_without_neg = True; + break; + case SSL_CERT_NOT_ON_SERVER: + reason = "no valid authentication certificate on server"; + retry_without_neg = True; + break; + case INCONSISTENT_FLAGS: + reason = "inconsistent negotiation flags"; + break; + case SSL_REQUIRED_BY_SERVER: + reason = "SSL required by server"; + break; + case HYBRID_REQUIRED_BY_SERVER: + reason = "CredSSP required by server"; + break; + default: + reason = "unknown reason"; + } - if (code != ISO_PDU_CC) - { - error("expected CC, got 0x%x\n", code); - tcp_disconnect(); - return False; + tcp_disconnect(); + + if (retry_without_neg) + { + fprintf(stderr, + "Failed to negotiate protocol, retrying with plain RDP.\n"); + g_negotiate_rdp_protocol = False; + goto retry; + } + + fprintf(stderr, "Failed to connect, %s.\n", reason); + return False; + } + + if (type != RDP_NEG_RSP) + { + tcp_disconnect(); + error("Expected RDP_NEG_RSP, got type = 0x%x\n", type); + return False; + } + + /* handle negotiation response */ + if (data == PROTOCOL_SSL) + { +#ifdef WITH_SSL + if (!tcp_tls_connect()) + { + /* failed to connect using cssp, let retry with plain TLS */ + tcp_disconnect(); + neg_proto = PROTOCOL_RDP; + goto retry; + } + /* do not use encryption when using TLS */ + g_encryption = False; + fprintf(stderr, "Connection established using SSL.\n"); +#else /* WITH_SSL */ + fprintf(stderr, "SSL not compiled in.\n"); +#endif /* WITH_SSL */ + } +#ifdef WITH_CREDSSP + else if (data == PROTOCOL_HYBRID) + { + if (!cssp_connect(server, username, domain, password, s)) + { + /* failed to connect using cssp, let retry with plain TLS */ + tcp_disconnect(); + neg_proto = PROTOCOL_SSL; + goto retry; + } + + /* do not use encryption when using TLS */ + fprintf(stderr, "Connection established using CredSSP.\n"); + g_encryption = False; + } +#endif + else if (data == PROTOCOL_RDP) + { + fprintf(stderr, "Connection established using plain RDP.\n"); + } + else if (data != PROTOCOL_RDP) + { + tcp_disconnect(); + error("Unexpected protocol in negotiation response, got data = 0x%x.\n", + data); + return False; + } + if (length || flags) {} + + *selected_protocol = data; } - return True; } @@ -227,5 +369,6 @@ void iso_reset_state(void) { + g_encryption = g_encryption_initial; tcp_reset_state(); } Index: reactos/base/applications/mstsc/licence.c =================================================================== --- reactos/base/applications/mstsc/licence.c (revision 66177) +++ reactos/base/applications/mstsc/licence.c (working copy) @@ -1,11 +1,14 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. RDP licensing negotiation - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright (C) Thomas Uhle 2011 + Copyright (C) Henrik Andersson 2014 - This program is free software; you can redistribute it and/or modify + + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,9 +16,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -32,13 +34,15 @@ ssl_mod_exp(char* out, int out_len, char* in, int in_len, char* mod, int mod_len, char* exp, int exp_len); -extern char g_username[]; -extern char g_hostname[]; +extern char g_username[256]; +extern char g_hostname[256]; +extern RDP_VERSION g_rdp_version; static uint8 g_licence_key[16]; static uint8 g_licence_sign_key[16]; -BOOL g_licence_issued = False; +RD_BOOL g_licence_issued = False; +RD_BOOL g_licence_error_result = False; /* Generate a session key and RC4 keys, given client and server randoms */ static void @@ -65,21 +69,21 @@ strncpy((char *) (hwid + 4), g_hostname, LICENCE_HWID_SIZE - 4); } -/* Present an existing licence to the server */ +/* Send a lincece info packet to server */ static void -licence_present(uint8 * client_random, uint8 * rsa_data, - uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) +licence_info(uint8 * client_random, uint8 * rsa_data, + uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 length = - 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + + 24 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; STREAM s; - s = sec_init(sec_flags, length + 4); + s = sec_init(sec_flags, length + 2); - out_uint8(s, LICENCE_TAG_PRESENT); - out_uint8(s, 2); /* version */ + out_uint8(s, LICENCE_TAG_LICENCE_INFO); + out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); out_uint32_le(s, 1); @@ -87,7 +91,7 @@ out_uint16_le(s, 0x0201); out_uint8p(s, client_random, SEC_RANDOM_SIZE); - out_uint16(s, 0); + out_uint16_le(s, 2); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); @@ -106,37 +110,40 @@ sec_send(s, sec_flags); } -/* Send a licence request packet */ +/* Send a new licence request packet */ static void -licence_send_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) +licence_send_new_licence_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 userlen = strlen(user) + 1; uint16 hostlen = strlen(host) + 1; - uint16 length = 128 + userlen + hostlen; + uint16 length = + 24 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + userlen + hostlen; STREAM s; s = sec_init(sec_flags, length + 2); - out_uint8(s, LICENCE_TAG_REQUEST); - out_uint8(s, 2); /* version */ + out_uint8(s, LICENCE_TAG_NEW_LICENCE_REQUEST); + out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); - out_uint32_le(s, 1); + out_uint32_le(s, 1); // KEY_EXCHANGE_ALG_RSA out_uint16(s, 0); out_uint16_le(s, 0xff01); out_uint8p(s, client_random, SEC_RANDOM_SIZE); - out_uint16(s, 0); + out_uint16_le(s, 2); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); - out_uint16_le(s, LICENCE_TAG_USER); + /* Username LICENSE_BINARY_BLOB */ + out_uint16_le(s, BB_CLIENT_USER_NAME_BLOB); out_uint16_le(s, userlen); out_uint8p(s, user, userlen); - out_uint16_le(s, LICENCE_TAG_HOST); + /* Machinename LICENSE_BINARY_BLOB */ + out_uint16_le(s, BB_CLIENT_MACHINE_NAME_BLOB); out_uint16_le(s, hostlen); out_uint8p(s, host, hostlen); @@ -144,9 +151,9 @@ sec_send(s, sec_flags); } -/* Process a licence demand packet */ +/* Process a licence request packet */ static void -licence_process_demand(STREAM s) +licence_process_request(STREAM s) { uint8 null_data[SEC_MODULUS_SIZE]; uint8 *server_random; @@ -177,17 +184,24 @@ ssl_rc4_crypt(crypt_key, (char *)hwid, (char *)hwid, sizeof(hwid)); ssl_rc4_info_delete(crypt_key); - licence_present(null_data, null_data, licence_data, licence_size, hwid, signature); +#if WITH_DEBUG + DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_LICENCE_INFO)); +#endif + licence_info(null_data, null_data, licence_data, licence_size, hwid, signature); + xfree(licence_data); return; } - licence_send_request(null_data, null_data, g_username, g_hostname); +#if WITH_DEBUG + DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_NEW_LICENCE_REQUEST)); +#endif + licence_send_new_licence_request(null_data, null_data, g_username, g_hostname); } -/* Send an authentication response packet */ +/* Send a platform challange response packet */ static void -licence_send_authresp(uint8 * token, uint8 * crypt_hwid, uint8 * signature) +licence_send_platform_challange_response(uint8 * token, uint8 * crypt_hwid, uint8 * signature) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 length = 58; @@ -195,8 +209,8 @@ s = sec_init(sec_flags, length + 2); - out_uint8(s, LICENCE_TAG_AUTHRESP); - out_uint8(s, 2); /* version */ + out_uint8(s, LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE); + out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); out_uint16_le(s, 1); @@ -213,9 +227,9 @@ sec_send(s, sec_flags); } -/* Parse an authentication request packet */ -static BOOL -licence_parse_authreq(STREAM s, uint8 ** token, uint8 ** signature) +/* Parse an platform challange request packet */ +static RD_BOOL +licence_parse_platform_challange(STREAM s, uint8 ** token, uint8 ** signature) { uint16 tokenlen; @@ -234,9 +248,9 @@ return s_check_end(s); } -/* Process an authentication request packet */ +/* Process a platform challange packet */ static void -licence_process_authreq(STREAM s) +licence_process_platform_challange(STREAM s) { uint8 *in_token = NULL, *in_sig; uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE]; @@ -246,7 +260,7 @@ void * crypt_key; /* Parse incoming packet and save the encrypted token */ - licence_parse_authreq(s, &in_token, &in_sig); + licence_parse_platform_challange(s, &in_token, &in_sig); memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); /* Decrypt the token. It should read TEST in Unicode. */ @@ -267,19 +281,18 @@ ssl_rc4_crypt(crypt_key, (char *)hwid, (char *)crypt_hwid, LICENCE_HWID_SIZE); ssl_rc4_info_delete(crypt_key); - licence_send_authresp(out_token, crypt_hwid, out_sig); + licence_send_platform_challange_response(out_token, crypt_hwid, out_sig); } -/* Process an licence issue packet */ +/* Process a new licence packet */ static void -licence_process_issue(STREAM s) +licence_process_new_license(STREAM s) { void * crypt_key; uint32 length; - uint16 check; int i; - in_uint8s(s, 2); /* 3d 45 - unknown */ + in_uint8s(s, 2); // Skip license binary blob type in_uint16_le(s, length); if (!s_check_rem(s, length)) return; @@ -289,15 +302,11 @@ ssl_rc4_crypt(crypt_key, (char *)s->p, (char *)s->p, length); ssl_rc4_info_delete(crypt_key); - in_uint16(s, check); - if (check != 0) - return; + /* Parse NEW_LICENSE_INFO block */ + in_uint8s(s, 4); // skip dwVersion - g_licence_issued = True; - - in_uint8s(s, 2); /* pad */ - - /* advance to fourth string */ + /* Skip strings, Scope, CompanyName and ProductId to get + to the LicenseInfo which we store in license blob. */ length = 0; for (i = 0; i < 4; i++) { @@ -311,6 +320,60 @@ save_licence(s->p, length); } +/* process a licence error alert packet */ +void +licence_process_error_alert(STREAM s) +{ + uint32 error_code; + uint32 state_transition; + uint32 error_info; + in_uint32(s, error_code); + in_uint32(s, state_transition); + in_uint32(s, error_info); + + /* There is a special case in the error alert handling, when licensing is all good + and the server is not sending a license to client, a "Server License Error PDU - + Valid Client" packet is sent which means, every thing is ok. + + Therefor we should flag that everything is ok with license here. + */ + if (error_code == 0x07) + { + g_licence_issued = True; + return; + } + + /* handle error codes, for now, jsut report them */ + switch (error_code) + { + case 0x6: // ERR_NO_LICENSE_SERVER + warning("License error alert from server: No license server\n"); + break; + + case 0x8: // ERR_INVALID_CLIENT + warning("License error alert from server: Invalid client\n"); + break; + + case 0x4: // ERR_INVALID_SCOPE + case 0xb: // ERR_INVALID_PRODUCTID + case 0xc: // ERR_INVALID_MESSAGE_LENGTH + default: + warning("License error alert from server: code %u, state transition %u\n", + error_code, state_transition); + break; + } + + /* handle error codes, for now, jsut report them */ + switch (error_info) + { + default: + break; + } + + g_licence_error_result = True; +} + + /* Process a licence packet */ void licence_process(STREAM s) @@ -320,25 +383,31 @@ in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ +#if WITH_DEBUG + DEBUG(("Received licensing PDU (message type 0x%02x)\n", tag)); +#endif + switch (tag) { - case LICENCE_TAG_DEMAND: - licence_process_demand(s); + case LICENCE_TAG_REQUEST: + licence_process_request(s); break; - case LICENCE_TAG_AUTHREQ: - licence_process_authreq(s); + case LICENCE_TAG_PLATFORM_CHALLANGE: + licence_process_platform_challange(s); break; - case LICENCE_TAG_ISSUE: - licence_process_issue(s); + case LICENCE_TAG_NEW_LICENCE: + case LICENCE_TAG_UPGRADE_LICENCE: + /* we can handle new and upgrades of licences the same way. */ + licence_process_new_license(s); break; - case LICENCE_TAG_REISSUE: - case LICENCE_TAG_RESULT: + case LICENCE_TAG_ERROR_ALERT: + licence_process_error_alert(s); break; default: - unimpl("licence tag 0x%x\n", tag); + unimpl("licence tag 0x%02x\n", tag); } } Index: reactos/base/applications/mstsc/mcs.c =================================================================== --- reactos/base/applications/mstsc/mcs.c (revision 66177) +++ reactos/base/applications/mstsc/mcs.c (working copy) @@ -1,11 +1,12 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Multipoint Communications Service - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2005-2011 Peter Astrand for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,9 +14,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -24,71 +24,7 @@ extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; -/* Parse an ASN.1 BER header */ -static BOOL -ber_parse_header(STREAM s, int tagval, int *length) -{ - int tag, len; - if (tagval > 0xff) - { - in_uint16_be(s, tag); - } - else - { - in_uint8(s, tag)} - - if (tag != tagval) - { - error("expected tag %d, got %d\n", tagval, tag); - return False; - } - - in_uint8(s, len); - - if (len & 0x80) - { - len &= ~0x80; - *length = 0; - while (len--) - next_be(s, *length); - } - else - *length = len; - - return s_check(s); -} - -/* Output an ASN.1 BER header */ -static void -ber_out_header(STREAM s, int tagval, int length) -{ - if (tagval > 0xff) - { - out_uint16_be(s, tagval); - } - else - { - out_uint8(s, tagval); - } - - if (length >= 0x80) - { - out_uint8(s, 0x82); - out_uint16_be(s, length); - } - else - out_uint8(s, length); -} - -/* Output an ASN.1 BER integer */ -static void -ber_out_integer(STREAM s, int value) -{ - ber_out_header(s, BER_TAG_INTEGER, 2); - out_uint16_be(s, value); -} - /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */ static void mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize) @@ -105,7 +41,7 @@ } /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */ -static BOOL +static RD_BOOL mcs_parse_domain_params(STREAM s) { int length; @@ -147,7 +83,7 @@ } /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ -static BOOL +static RD_BOOL mcs_recv_connect_response(STREAM mcs_data) { uint8 result; @@ -221,7 +157,7 @@ } /* Expect a AUcf message (ASN.1 PER) */ -static BOOL +static RD_BOOL mcs_recv_aucf(uint16 * mcs_userid) { uint8 opcode, result; @@ -270,7 +206,7 @@ } /* Expect a CJcf message (ASN.1 PER) */ -static BOOL +static RD_BOOL mcs_recv_cjcf(void) { uint8 opcode, result; @@ -371,56 +307,18 @@ return s; } -/* Establish a connection up to the MCS layer */ -BOOL -mcs_connect(char *server, STREAM mcs_data, char *username) +RD_BOOL +mcs_connect_start(char *server, char *username, char *domain, char *password, + RD_BOOL reconnect, uint32 * selected_protocol) { - unsigned int i; - - if (!iso_connect(server, username)) - 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(&g_mcs_userid)) - goto error; - - mcs_send_cjrq((uint16) (g_mcs_userid + MCS_USERCHANNEL_BASE)); - - if (!mcs_recv_cjcf()) - goto error; - - mcs_send_cjrq(MCS_GLOBAL_CHANNEL); - if (!mcs_recv_cjcf()) - goto error; - - for (i = 0; i < g_num_channels; i++) - { - mcs_send_cjrq(g_channels[i].mcs_id); - if (!mcs_recv_cjcf()) - goto error; - } - return True; - - error: - iso_disconnect(); - return False; + return iso_connect(server, username, domain, password, reconnect, selected_protocol); } -/* Establish a connection up to the MCS layer */ -BOOL -mcs_reconnect(char *server, STREAM mcs_data) +RD_BOOL +mcs_connect_finalize(STREAM mcs_data) { unsigned int i; - if (!iso_reconnect(server)) - return False; - mcs_send_connect_initial(mcs_data); if (!mcs_recv_connect_response(mcs_data)) goto error; @@ -431,7 +329,7 @@ if (!mcs_recv_aucf(&g_mcs_userid)) goto error; - mcs_send_cjrq((uint16) (g_mcs_userid + MCS_USERCHANNEL_BASE)); + mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE); if (!mcs_recv_cjcf()) goto error; Index: reactos/base/applications/mstsc/mppc.c =================================================================== --- reactos/base/applications/mstsc/mppc.c (revision 66177) +++ reactos/base/applications/mstsc/mppc.c (working copy) @@ -1,11 +1,11 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP decompression - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,11 +13,13 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ +#include +#include + #include "precomp.h" /* mppc decompression */ @@ -60,7 +62,7 @@ int next_offset, match_off; int match_len; int old_offset, match_bits; - BOOL big = ctype & RDP_MPPC_BIG ? True : False; + RD_BOOL big = ctype & RDP_MPPC_BIG ? True : False; uint8 *dict = g_mppc_dict.hist; Index: reactos/base/applications/mstsc/orders.c =================================================================== --- reactos/base/applications/mstsc/orders.c (revision 66177) +++ reactos/base/applications/mstsc/orders.c (working copy) @@ -1,11 +1,11 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. RDP order processing - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,18 +13,16 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" - #include "orders.h" extern uint8 *g_next_packet; static RDP_ORDER_STATE g_order_state; -extern BOOL g_use_rdp5; +extern RDP_VERSION g_rdp_version; /* Read field indicating which parameters are present */ static void @@ -56,7 +54,7 @@ /* Read a co-ordinate (16-bit, or 8-bit delta) */ static void -rdp_in_coord(STREAM s, sint16 * coord, BOOL delta) +rdp_in_coord(STREAM s, sint16 * coord, RD_BOOL delta) { sint8 change; @@ -103,7 +101,7 @@ } /* Parse bounds information */ -static BOOL +static RD_BOOL rdp_parse_bounds(STREAM s, BOUNDS * bounds) { uint8 present; @@ -134,7 +132,7 @@ } /* Parse a pen */ -static BOOL +static RD_BOOL rdp_parse_pen(STREAM s, PEN * pen, uint32 present) { if (present & 1) @@ -149,8 +147,35 @@ return s_check(s); } +static void +setup_brush(BRUSH * out_brush, BRUSH * in_brush) +{ + BRUSHDATA *brush_data; + uint8 cache_idx; + uint8 colour_code; + + memcpy(out_brush, in_brush, sizeof(BRUSH)); + if (out_brush->style & 0x80) + { + colour_code = out_brush->style & 0x0f; + cache_idx = out_brush->pattern[0]; + brush_data = cache_get_brush_data(colour_code, cache_idx); + if ((brush_data == NULL) || (brush_data->data == NULL)) + { + error("error getting brush data, style %x\n", out_brush->style); + out_brush->bd = NULL; + memset(out_brush->pattern, 0, 8); + } + else + { + out_brush->bd = brush_data; + } + out_brush->style = 3; + } +} + /* Parse a brush */ -static BOOL +static RD_BOOL rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present) { if (present & 1) @@ -173,7 +198,7 @@ /* Process a destination blt order */ static void -process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta) +process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x01) rdp_in_coord(s, &os->x, delta); @@ -198,8 +223,10 @@ /* Process a pattern blt order */ static void -process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta) +process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, RD_BOOL delta) { + BRUSH brush; + if (present & 0x0001) rdp_in_coord(s, &os->x, delta); @@ -226,13 +253,15 @@ 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)); + setup_brush(&brush, &os->brush); + ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy, - &os->brush, os->bgcolour, os->fgcolour); + &brush, os->bgcolour, os->fgcolour); } /* Process a screen blt order */ static void -process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta) +process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x0001) rdp_in_coord(s, &os->x, delta); @@ -263,7 +292,7 @@ /* Process a line order */ static void -process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta) +process_line(STREAM s, LINE_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x0001) in_uint16_le(s, os->mixmode); @@ -297,12 +326,12 @@ return; } - ui_line(ROP_MINUS_1(os->opcode), os->startx, os->starty, os->endx, os->endy, &os->pen); + 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) +process_rect(STREAM s, RECT_ORDER * os, uint32 present, RD_BOOL delta) { uint32 i; if (present & 0x01) @@ -342,7 +371,7 @@ /* Process a desktop save order */ static void -process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta) +process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, RD_BOOL delta) { int width, height; @@ -378,9 +407,9 @@ /* Process a memory blt order */ static void -process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta) +process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, RD_BOOL delta) { - HBITMAP bitmap; + RD_HBITMAP bitmap; if (present & 0x0001) { @@ -424,9 +453,10 @@ /* Process a 3-way blt order */ static void -process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta) +process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, RD_BOOL delta) { - HBITMAP bitmap; + RD_HBITMAP bitmap; + BRUSH brush; if (present & 0x000001) { @@ -477,17 +507,19 @@ if (bitmap == NULL) return; + setup_brush(&brush, &os->brush); + ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy, - bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour); + bitmap, os->srcx, os->srcy, &brush, os->bgcolour, os->fgcolour); } /* Process a polygon order */ static void -process_polygon(STREAM s, POLYGON_ORDER * os, uint32 present, BOOL delta) +process_polygon(STREAM s, POLYGON_ORDER * os, uint32 present, RD_BOOL delta) { int index, data, next; uint8 flags = 0; - POINT *points; + RD_POINT *points; if (present & 0x01) rdp_in_coord(s, &os->x, delta); @@ -529,8 +561,8 @@ return; } - points = (POINT *) xmalloc((os->npoints + 1) * sizeof(POINT)); - memset(points, 0, (os->npoints + 1) * sizeof(POINT)); + points = (RD_POINT *) xmalloc((os->npoints + 1) * sizeof(RD_POINT)); + memset(points, 0, (os->npoints + 1) * sizeof(RD_POINT)); points[0].x = os->x; points[0].y = os->y; @@ -552,7 +584,7 @@ } if (next - 1 == os->npoints) - ui_polygon(ROP_MINUS_1(os->opcode), os->fillmode, points, os->npoints + 1, NULL, 0, + ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0, os->fgcolour); else error("polygon parse error\n"); @@ -562,11 +594,12 @@ /* Process a polygon2 order */ static void -process_polygon2(STREAM s, POLYGON2_ORDER * os, uint32 present, BOOL delta) +process_polygon2(STREAM s, POLYGON2_ORDER * os, uint32 present, RD_BOOL delta) { int index, data, next; uint8 flags = 0; - POINT *points; + RD_POINT *points; + BRUSH brush; if (present & 0x0001) rdp_in_coord(s, &os->x, delta); @@ -614,9 +647,11 @@ return; } - points = (POINT *) xmalloc((os->npoints + 1) * sizeof(POINT)); - memset(points, 0, (os->npoints + 1) * sizeof(POINT)); + setup_brush(&brush, &os->brush); + points = (RD_POINT *) xmalloc((os->npoints + 1) * sizeof(RD_POINT)); + memset(points, 0, (os->npoints + 1) * sizeof(RD_POINT)); + points[0].x = os->x; points[0].y = os->y; @@ -637,8 +672,8 @@ } if (next - 1 == os->npoints) - ui_polygon(ROP_MINUS_1(os->opcode), os->fillmode, points, os->npoints + 1, - &os->brush, os->bgcolour, os->fgcolour); + ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, + &brush, os->bgcolour, os->fgcolour); else error("polygon2 parse error\n"); @@ -647,12 +682,12 @@ /* Process a polyline order */ static void -process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta) +process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, RD_BOOL delta) { int index, next, data; uint8 flags = 0; PEN pen; - POINT *points; + RD_POINT *points; if (present & 0x01) rdp_in_coord(s, &os->x, delta); @@ -691,8 +726,8 @@ return; } - points = (POINT *) xmalloc((os->lines + 1) * sizeof(POINT)); - memset(points, 0, (os->lines + 1) * sizeof(POINT)); + points = (RD_POINT *) xmalloc((os->lines + 1) * sizeof(RD_POINT)); + memset(points, 0, (os->lines + 1) * sizeof(RD_POINT)); points[0].x = os->x; points[0].y = os->y; @@ -716,7 +751,7 @@ } if (next - 1 == os->lines) - ui_polyline(ROP_MINUS_1(os->opcode), points, os->lines + 1, &pen); + ui_polyline(os->opcode - 1, points, os->lines + 1, &pen); else error("polyline parse error\n"); @@ -725,7 +760,7 @@ /* Process an ellipse order */ static void -process_ellipse(STREAM s, ELLIPSE_ORDER * os, uint32 present, BOOL delta) +process_ellipse(STREAM s, ELLIPSE_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x01) rdp_in_coord(s, &os->left, delta); @@ -751,14 +786,16 @@ DEBUG(("ELLIPSE(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,fg=0x%x)\n", os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->fgcolour)); - ui_ellipse(ROP_MINUS_1(os->opcode), os->fillmode, os->left, os->top, os->right - os->left, + ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left, os->bottom - os->top, NULL, 0, os->fgcolour); } /* Process an ellipse2 order */ static void -process_ellipse2(STREAM s, ELLIPSE2_ORDER * os, uint32 present, BOOL delta) +process_ellipse2(STREAM s, ELLIPSE2_ORDER * os, uint32 present, RD_BOOL delta) { + BRUSH brush; + if (present & 0x0001) rdp_in_coord(s, &os->left, delta); @@ -789,15 +826,18 @@ os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour)); - ui_ellipse(ROP_MINUS_1(os->opcode), os->fillmode, os->left, os->top, os->right - os->left, - os->bottom - os->top, &os->brush, os->bgcolour, os->fgcolour); + setup_brush(&brush, &os->brush); + + ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left, + os->bottom - os->top, &brush, os->bgcolour, os->fgcolour); } /* Process a text order */ static void -process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta) +process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, RD_BOOL delta) { int i; + BRUSH brush; if (present & 0x000001) in_uint8(s, os->font); @@ -864,11 +904,13 @@ DEBUG(("\n")); - ui_draw_text(os->font, os->flags, ROP_MINUS_1(os->opcode), os->mixmode, os->x, os->y, + setup_brush(&brush, &os->brush); + + ui_draw_text(os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y, os->clipleft, os->cliptop, os->clipright - os->clipleft, os->clipbottom - os->cliptop, os->boxleft, os->boxtop, os->boxright - os->boxleft, os->boxbottom - os->boxtop, - &os->brush, os->bgcolour, os->fgcolour, os->text, os->length); + &brush, os->bgcolour, os->fgcolour, os->text, os->length); } /* Process a raw bitmap cache order */ @@ -875,7 +917,7 @@ static void process_raw_bmpcache(STREAM s) { - HBITMAP bitmap; + RD_HBITMAP bitmap; uint16 cache_idx, bufsize; uint8 cache_id, width, height, bpp, Bpp; uint8 *data, *inverted; @@ -908,7 +950,7 @@ static void process_bmpcache(STREAM s) { - HBITMAP bitmap; + RD_HBITMAP bitmap; uint16 cache_idx, size; uint8 cache_id, width, height, bpp, Bpp; uint8 *data, *bmpdata; @@ -926,7 +968,7 @@ in_uint16_le(s, bufsize); /* bufsize */ in_uint16_le(s, cache_idx); - if (g_use_rdp5) + if (g_rdp_version >= RDP_V5) { size = bufsize; } @@ -944,7 +986,6 @@ in_uint8p(s, data, size); DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d,bpp=%d,size=%d,pad1=%d,bufsize=%d,pad2=%d,rs=%d,fs=%d)\n", width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, final_size)); - (void)pad1; (void)pad2; bmpdata = (uint8 *) xmalloc(width * height * Bpp); @@ -957,6 +998,7 @@ { DEBUG(("Failed to decompress bitmap data\n")); } + if (pad1 || pad2) {} xfree(bmpdata); } @@ -963,9 +1005,9 @@ /* Process a bitmap cache v2 order */ static void -process_bmpcache2(STREAM s, uint16 flags, BOOL compressed) +process_bmpcache2(STREAM s, uint16 flags, RD_BOOL compressed) { - HBITMAP bitmap; + RD_HBITMAP bitmap; int y; uint8 cache_id, cache_idx_low, width, height, Bpp; uint16 cache_idx, bufsize; @@ -1031,7 +1073,7 @@ cache_put_bitmap(cache_id, cache_idx, bitmap); if (flags & PERSIST) pstcache_save_bitmap(cache_id, cache_idx, bitmap_id, width, height, - (uint16) (width * height * Bpp), bmpdata); + width * height * Bpp, bmpdata); } else { @@ -1106,6 +1148,109 @@ } } +static void +process_compressed_8x8_brush_data(uint8 * in, uint8 * out, int Bpp) +{ + int x, y, pal_index, in_index, shift, do2, i; + uint8 *pal; + + in_index = 0; + pal = in + 16; + /* read it bottom up */ + for (y = 7; y >= 0; y--) + { + /* 2 bytes per row */ + x = 0; + for (do2 = 0; do2 < 2; do2++) + { + /* 4 pixels per byte */ + shift = 6; + while (shift >= 0) + { + pal_index = (in[in_index] >> shift) & 3; + /* size of palette entries depends on Bpp */ + for (i = 0; i < Bpp; i++) + { + out[(y * 8 + x) * Bpp + i] = pal[pal_index * Bpp + i]; + } + x++; + shift -= 2; + } + in_index++; + } + } +} + +/* Process a brush cache order */ +static void +process_brushcache(STREAM s, uint16 flags) +{ + BRUSHDATA brush_data; + uint8 cache_idx, colour_code, width, height, size, type; + uint8 *comp_brush; + int index; + int Bpp; + + in_uint8(s, cache_idx); + in_uint8(s, colour_code); + in_uint8(s, width); + in_uint8(s, height); + in_uint8(s, type); /* type, 0x8x = cached */ + in_uint8(s, size); + + DEBUG(("BRUSHCACHE(idx=%d,wd=%d,ht=%d,sz=%d)\n", cache_idx, width, height, size)); + + if ((width == 8) && (height == 8)) + { + if (colour_code == 1) + { + brush_data.colour_code = 1; + brush_data.data_size = 8; + brush_data.data = xmalloc(8); + if (size == 8) + { + /* read it bottom up */ + for (index = 7; index >= 0; index--) + { + in_uint8(s, brush_data.data[index]); + } + } + else + { + warning("incompatible brush, colour_code %d size %d\n", colour_code, + size); + } + cache_put_brush_data(1, cache_idx, &brush_data); + } + else if ((colour_code >= 3) && (colour_code <= 6)) + { + Bpp = colour_code - 2; + brush_data.colour_code = colour_code; + brush_data.data_size = 8 * 8 * Bpp; + brush_data.data = xmalloc(8 * 8 * Bpp); + if (size == 16 + 4 * Bpp) + { + in_uint8p(s, comp_brush, 16 + 4 * Bpp); + process_compressed_8x8_brush_data(comp_brush, brush_data.data, Bpp); + } + else + { + in_uint8a(s, brush_data.data, 8 * 8 * Bpp); + } + cache_put_brush_data(colour_code, cache_idx, &brush_data); + } + else + { + warning("incompatible brush, colour_code %d size %d\n", colour_code, size); + } + } + else + { + warning("incompatible brush, width height %d %d\n", width, height); + } + if (type) {} +} + /* Process a secondary order */ static void process_secondary_order(STREAM s) @@ -1150,6 +1295,10 @@ process_bmpcache2(s, flags, True); /* compressed */ break; + case RDP_ORDER_BRUSHCACHE: + process_brushcache(s, flags); + break; + default: unimpl("secondary order %d\n", type); } @@ -1165,7 +1314,7 @@ uint32 present; uint8 order_flags; int size, processed = 0; - BOOL delta; + RD_BOOL delta; while (processed < num_orders) { Index: reactos/base/applications/mstsc/orders.h =================================================================== --- reactos/base/applications/mstsc/orders.h (revision 66177) +++ reactos/base/applications/mstsc/orders.h (working copy) @@ -1,11 +1,11 @@ /* rdesktop: A Remote Desktop Protocol client. RDP order processing - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,13 +13,10 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#pragma once - #define RDP_ORDER_STANDARD 0x01 #define RDP_ORDER_SECONDARY 0x02 #define RDP_ORDER_BOUNDS 0x04 Index: reactos/base/applications/mstsc/parse.h =================================================================== --- reactos/base/applications/mstsc/parse.h (revision 66177) +++ reactos/base/applications/mstsc/parse.h (working copy) @@ -1,11 +1,12 @@ /* rdesktop: A Remote Desktop Protocol client. Parsing primitives - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2012 Henrik Andersson for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,9 +14,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ /* Parser state */ @@ -42,6 +42,8 @@ #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) +#define s_length(s) ((s)->end - (s)->data) +#define s_reset(s) ((s)->end = (s)->p = (s)->data) #if defined(L_ENDIAN) && !defined(NEED_ALIGN) #define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } Index: reactos/base/applications/mstsc/precomp.h =================================================================== --- reactos/base/applications/mstsc/precomp.h (revision 66177) +++ reactos/base/applications/mstsc/precomp.h (working copy) @@ -20,6 +20,22 @@ #ifndef __TODO_MSTSC_H #define __TODO_MSTSC_H +#define RDP_INFO_MOUSE 0x00000001 +#define RDP_INFO_DISABLECTRLALTDEL 0x00000002 +#define RDP_INFO_AUTOLOGON 0x00000008 +#define RDP_INFO_UNICODE 0x00000010 +#define RDP_INFO_MAXIMIZESHELL 0x00000020 +#define RDP_INFO_COMPRESSION 0x00000080 /* mppc compression with 8kB histroy buffer */ +#define RDP_INFO_ENABLEWINDOWSKEY 0x00000100 +#define RDP_INFO_COMPRESSION2 0x00000200 /* rdp5 mppc compression with 64kB history buffer */ +#define RDP_INFO_REMOTE_CONSOLE_AUDIO 0x00002000 +#define RDP_INFO_PASSWORD_IS_SC_PIN 0x00040000 + +#define RDP5_DISABLE_NOTHING 0x00 +#define RDP5_NO_WALLPAPER 0x01 + +#define RDP_LOGON_NORMAL (RDP_INFO_MOUSE | RDP_INFO_DISABLECTRLALTDEL | RDP_INFO_UNICODE | RDP_INFO_MAXIMIZESHELL) + #define IS_PERSISTENT(id) (id < 8 && g_pstcache_fd[id] > 0) #define MAXKEY 256 Index: reactos/base/applications/mstsc/proto.h =================================================================== --- reactos/base/applications/mstsc/proto.h (revision 66177) +++ reactos/base/applications/mstsc/proto.h (working copy) @@ -1,10 +1,10 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -12,12 +12,12 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#pragma once +#ifndef RDESKTOP_PROTO_H +#define RDESKTOP_PROTO_H /* *INDENT-OFF* */ #ifdef __cplusplus @@ -24,8 +24,14 @@ extern "C" { #endif /* *INDENT-ON* */ +/* utils.c */ +char *utils_string_escape(const char *str); +char *utils_string_unescape(const char *str); +int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os); +int utils_mkdir_safe(const char *path, int mask); +int utils_mkdir_p(const char *path, int mask); /* bitmap.c */ -BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp); +RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp); /* cache.c */ void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count); void cache_bump_bitmap(uint8 id, uint16 idx, int bump); @@ -43,6 +49,8 @@ uint8 * data); RD_HCURSOR cache_get_cursor(uint16 cache_idx); void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor); +BRUSHDATA *cache_get_brush_data(uint8 colour_code, uint8 idx); +void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data); /* channels.c */ VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM)); STREAM channel_init(VCHANNEL * channel, uint32 length); @@ -54,7 +62,15 @@ void cliprdr_send_data_request(uint32 format); void cliprdr_send_data(uint8 * data, uint32 length); void cliprdr_set_mode(const char *optarg); -BOOL cliprdr_init(void); +RD_BOOL cliprdr_init(void); +/* ctrl.c */ +int ctrl_init(const char *user, const char *domain, const char *host); +void ctrl_cleanup(); +RD_BOOL ctrl_is_slave(); +int ctrl_send_command(const char *cmd, const char *args); +void ctrl_add_fds(int *n, fd_set * rfds); +void ctrl_check_fds(fd_set * rfds, fd_set * wfds); + /* disk.c */ int disk_enum_devices(uint32 * id, char *optarg); RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out); @@ -72,10 +88,12 @@ STREAM iso_init(int length); void iso_send(STREAM s); STREAM iso_recv(uint8 * rdpver); -BOOL iso_connect(char *server, char *username); -BOOL iso_reconnect(char *server); +RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, + uint32 * selected_protocol); void iso_disconnect(void); void iso_reset_state(void); +/* cssp.c */ +RD_BOOL cssp_connect(char *server, char *user, char *domain, char *password, STREAM s); /* licence.c */ void licence_process(STREAM s); /* mcs.c */ @@ -83,8 +101,9 @@ void mcs_send_to_channel(STREAM s, uint16 channel); void mcs_send(STREAM s); STREAM mcs_recv(uint16 * channel, uint8 * rdpver); -BOOL mcs_connect(char *server, STREAM mcs_data, char *username); -BOOL mcs_reconnect(char *server, STREAM mcs_data); +RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, + RD_BOOL reconnect, uint32 * selected_protocol); +RD_BOOL mcs_connect_finalize(STREAM s); void mcs_disconnect(void); void mcs_reset_state(void); /* orders.c */ @@ -99,17 +118,18 @@ void printercache_process(STREAM s); /* pstcache.c */ void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp); -BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx); -BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width, - uint8 height, uint16 length, uint8 * data); +RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx); +RD_BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width, + uint8 height, uint16 length, uint8 * data); int pstcache_enumerate(uint8 id, HASH_KEY * keylist); -BOOL pstcache_init(uint8 cache_id); +RD_BOOL pstcache_init(uint8 cache_id); /* rdesktop.c */ int main(int argc, char *argv[]); void generate_random(uint8 * random); void *xmalloc(int size); +void exit_if_null(void *ptr); char *xstrdup(const char *s); -void *xrealloc(void *oldmem, int size); +void *xrealloc(void *oldmem, size_t size); void xfree(void *mem); void error(char *format, ...); void warning(char *format, ...); @@ -117,62 +137,67 @@ void hexdump(unsigned char *p, unsigned int len); char *next_arg(char *src, char needle); void toupper_str(char *p); -BOOL str_startswith(const char *s, const char *prefix); -BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data); -BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data); +RD_BOOL str_startswith(const char *s, const char *prefix); +RD_BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, + void *data); +RD_BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data); char *l_to_a(long N, int base); int load_licence(unsigned char **data); void save_licence(unsigned char *data, int length); -BOOL rd_pstcache_mkdir(void); +void rd_create_ui(void); +RD_BOOL rd_pstcache_mkdir(void); int rd_open_file(char *filename); void rd_close_file(int fd); int rd_read_file(int fd, void *ptr, int len); int rd_write_file(int fd, void *ptr, int len); int rd_lseek_file(int fd, int offset); -BOOL rd_lock_file(int fd, int start, int len); +RD_BOOL rd_lock_file(int fd, int start, int len); /* rdp5.c */ void rdp5_process(STREAM s); /* rdp.c */ void rdp_out_unistr(STREAM s, char *string, int len); -int rdp_in_unistr(STREAM s, char *string, int uni_len); +void rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size); void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2); void rdp_send_client_window_status(int status); void process_colour_pointer_pdu(STREAM s); +void process_new_pointer_pdu(STREAM s); void process_cached_pointer_pdu(STREAM s); void process_system_pointer_pdu(STREAM s); void process_bitmap_updates(STREAM s); void process_palette(STREAM s); void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason); -void rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason); -BOOL rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason); -BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, - char *directory); -BOOL rdp_reconnect(char *server, uint32 flags, char *domain, char *password, char *command, - char *directory, char *cookie); +void rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason); +RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason); +RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, + char *directory, RD_BOOL reconnect); void rdp_reset_state(void); void rdp_disconnect(void); /* rdpdr.c */ int get_device_index(RD_NTHANDLE handle); void convert_to_unix_filename(char *filename); -BOOL rdpdr_init(void); -void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout); +void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer, + uint32 length); +RD_BOOL rdpdr_init(); +void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout); struct async_iorequest *rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq); -void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out); -BOOL rdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status); +void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out); +RD_BOOL rdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status); /* rdpsnd.c */ -void rdpsnd_send_completion(uint16 tick, uint8 packet_index); -BOOL rdpsnd_init(void); -/* rdpsnd_oss.c */ -BOOL wave_out_open(void); -void wave_out_close(void); -BOOL wave_out_format_supported(WAVEFORMATEX * pwfx); -BOOL wave_out_set_format(WAVEFORMATEX * pwfx); -void wave_out_volume(uint16 left, uint16 right); -void wave_out_write(STREAM s, uint16 tick, uint8 index); -void wave_out_play(void); +void rdpsnd_record(const void *data, unsigned int size); +RD_BOOL rdpsnd_init(char *optarg); +void rdpsnd_show_help(void); +void rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv); +void rdpsnd_check_fds(fd_set * rfds, fd_set * wfds); +struct audio_packet *rdpsnd_queue_current_packet(void); +RD_BOOL rdpsnd_queue_empty(void); +void rdpsnd_queue_next(unsigned long completed_in_us); +int rdpsnd_queue_next_tick(void); +void rdpsnd_reset_state(void); /* secure.c */ +void sec_hash_to_string(char *out, int out_size, uint8 * in, int in_size); +void sec_hash_sha1_16(uint8 * out, uint8 * in, uint8 * salt1); 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); @@ -184,22 +209,33 @@ void sec_send(STREAM s, uint32 flags); void sec_process_mcs_data(STREAM s); STREAM sec_recv(uint8 * rdpver); -BOOL sec_connect(char *server, char *username); -BOOL sec_reconnect(char *server); +RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect); void sec_disconnect(void); void sec_reset_state(void); /* serial.c */ int serial_enum_devices(uint32 * id, char *optarg); -BOOL serial_get_event(RD_NTHANDLE handle, uint32 * result); -BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout); +RD_BOOL serial_get_event(RD_NTHANDLE handle, uint32 * result); +RD_BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, + uint32 * itv_timeout); /* tcp.c */ STREAM tcp_init(uint32 maxlen); void tcp_send(STREAM s); STREAM tcp_recv(STREAM s, uint32 length); -BOOL tcp_connect(char *server); +RD_BOOL tcp_connect(char *server); void tcp_disconnect(void); char *tcp_get_address(void); +RD_BOOL tcp_is_connected(void); void tcp_reset_state(void); +RD_BOOL tcp_tls_connect(void); +RD_BOOL tcp_tls_get_server_pubkey(STREAM s); +void tcp_run_ui(RD_BOOL run); + +/* asn.c */ +RD_BOOL ber_in_header(STREAM s, int *tagval, int *length); +void ber_out_header(STREAM s, int tagval, int length); +RD_BOOL ber_parse_header(STREAM s, int tagval, int *length); +void ber_out_integer(STREAM s, int value); + /* xclip.c */ void ui_clip_format_announce(uint8 * data, uint32 length); void ui_clip_handle_data(uint8 * data, uint32 length); @@ -208,14 +244,15 @@ void ui_clip_sync(void); void ui_clip_set_mode(const char *optarg); void xclip_init(void); +void xclip_deinit(void); /* xkeymap.c */ -BOOL xkeymap_from_locale(const char *locale); +RD_BOOL xkeymap_from_locale(const char *locale); FILE *xkeymap_open(const char *filename); void xkeymap_init(void); -BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed); +RD_BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed); key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state); void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, - BOOL pressed, uint8 nesting); + RD_BOOL pressed, uint8 nesting); uint16 xkeymap_translate_button(unsigned int button); char *get_ksname(uint32 keysym); void save_remote_modifiers(uint8 scancode); @@ -226,12 +263,14 @@ void reset_modifier_keys(void); void rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode); /* xwin.c */ -BOOL get_key_state(unsigned int state, uint32 keysym); -BOOL ui_init(void); +RD_BOOL get_key_state(unsigned int state, uint32 keysym); +RD_BOOL ui_init(void); +void ui_init_connection(void); void ui_deinit(void); -BOOL ui_create_window(void); +RD_BOOL ui_create_window(void); void ui_resize_window(void); void ui_destroy_window(void); +RD_BOOL ui_have_window(void); void xwin_toggle_fullscreen(void); int ui_select(int rdp_socket); void ui_move_pointer(int x, int y); @@ -241,7 +280,7 @@ RD_HGLYPH ui_create_glyph(int width, int height, uint8 * data); void ui_destroy_glyph(RD_HGLYPH glyph); RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask, - uint8 * xormask); + uint8 * xormask, int bpp); void ui_set_cursor(RD_HCURSOR cursor); void ui_destroy_cursor(RD_HCURSOR cursor); void ui_set_null_cursor(void); @@ -260,9 +299,9 @@ 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_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, BRUSH * brush, +void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, BRUSH * brush, int bgcolour, int fgcolour); -void ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen); +void ui_polyline(uint8 opcode, RD_POINT * points, int npoints, PEN * pen); void ui_ellipse(uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour); void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, RD_HGLYPH glyph, int srcx, int srcy, @@ -274,7 +313,8 @@ void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy); void ui_begin_update(void); void ui_end_update(void); -void ui_seamless_begin(BOOL hidden); +void ui_seamless_begin(RD_BOOL hidden); +void ui_seamless_end(); void ui_seamless_hide_desktop(void); void ui_seamless_unhide_desktop(void); void ui_seamless_toggle(void); @@ -281,6 +321,10 @@ void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent, unsigned long flags); void ui_seamless_destroy_window(unsigned long id, unsigned long flags); +void ui_seamless_destroy_group(unsigned long id, unsigned long flags); +void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, + const char *data, int chunk_len); +void ui_seamless_delicon(unsigned long id, const char *format, int width, int height); void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags); void ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags); @@ -289,9 +333,10 @@ void ui_seamless_syncbegin(unsigned long flags); void ui_seamless_ack(unsigned int serial); /* lspci.c */ -BOOL lspci_init(void); +RD_BOOL lspci_init(void); /* seamless.c */ -BOOL seamless_init(void); +RD_BOOL seamless_init(void); +void seamless_reset_state(void); unsigned int seamless_send_sync(void); unsigned int seamless_send_state(unsigned long id, unsigned int state, unsigned long flags); unsigned int seamless_send_position(unsigned long id, int x, int y, int width, int height, @@ -299,9 +344,21 @@ void seamless_select_timeout(struct timeval *tv); unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags); unsigned int seamless_send_focus(unsigned long id, unsigned long flags); +unsigned int seamless_send_destroy(unsigned long id); +unsigned int seamless_send_spawn(char *cmd); +unsigned int seamless_send_persistent(RD_BOOL); +/* scard.c */ +void scard_lock(int lock); +void scard_unlock(int lock); +int scard_enum_devices(uint32 * id, char *optarg); +void scardSetInfo(uint32 epoch, uint32 device, uint32 id, uint32 bytes_out); +void scard_reset_state(); + /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* *INDENT-ON* */ + +#endif Index: reactos/base/applications/mstsc/pstcache.c =================================================================== --- reactos/base/applications/mstsc/pstcache.c (revision 66177) +++ reactos/base/applications/mstsc/pstcache.c (working copy) @@ -1,11 +1,11 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Persistent Bitmap Cache routines - Copyright (C) Jeroen Meijer 2004-2005 + Copyright (C) Jeroen Meijer 2004-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,9 +13,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -22,14 +21,16 @@ #define MAX_CELL_SIZE 0x1000 /* pixels */ +#define IS_PERSISTENT(id) (id < 8 && g_pstcache_fd[id] > 0) + extern int g_server_depth; -extern BOOL g_bitmap_cache; -extern BOOL g_bitmap_cache_persist_enable; -extern BOOL g_bitmap_cache_precache; +extern RD_BOOL g_bitmap_cache; +extern RD_BOOL g_bitmap_cache_persist_enable; +extern RD_BOOL g_bitmap_cache_precache; int g_pstcache_fd[8]; int g_pstcache_Bpp; -BOOL g_pstcache_enumerated = False; +RD_BOOL g_pstcache_enumerated = False; uint8 zero_key[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -48,13 +49,13 @@ } /* Load a bitmap from the persistent cache */ -BOOL +RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx) { uint8 *celldata; int fd; CELLHEADER cellhdr; - HBITMAP bitmap; + RD_HBITMAP bitmap; if (!g_bitmap_cache_persist_enable) return False; @@ -62,8 +63,6 @@ if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS) return False; - memset(&cellhdr, 0, sizeof(CELLHEADER)); - fd = g_pstcache_fd[cache_id]; rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER))); rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)); @@ -71,7 +70,7 @@ rd_read_file(fd, celldata, cellhdr.length); bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata); - DEBUG(("Load bitmap from disk: id=%d, idx=%d, bmp=0x%x)\n", cache_id, cache_idx, bitmap)); + DEBUG(("Load bitmap from disk: id=%d, idx=%d, bmp=%p)\n", cache_id, cache_idx, bitmap)); cache_put_bitmap(cache_id, cache_idx, bitmap); xfree(celldata); @@ -79,7 +78,7 @@ } /* Store a bitmap in the persistent cache */ -BOOL +RD_BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width, uint8 height, uint16 length, uint8 * data) { @@ -160,7 +159,7 @@ } /* initialise the persistent bitmap cache */ -BOOL +RD_BOOL pstcache_init(uint8 cache_id) { int fd; Index: reactos/base/applications/mstsc/rdesktop.h =================================================================== --- reactos/base/applications/mstsc/rdesktop.h (revision 66177) +++ reactos/base/applications/mstsc/rdesktop.h (working copy) @@ -1,11 +1,11 @@ /* rdesktop: A Remote Desktop Protocol client. Master include file - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,19 +13,22 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #pragma once +#include +#include +#include #ifdef _WIN32 #include /* winsock2.h first */ #include +#include +#define DIR int #else /* WIN32 */ #include -#include #include #ifdef HAVE_SYS_SELECT_H #include @@ -35,9 +38,91 @@ #endif /* HAVE_SYS_SELECT_H */ #endif /* WIN32 */ //#include /* PATH_MAX */ +#ifdef HAVE_SYSEXITS_H +#include +#endif -#define VERSION "1.4.1" +#define VERSION "1.8.3" +/* standard exit codes */ +#ifndef EX_OK +#define EX_OK 0 +#endif +#ifndef EX_USAGE +#define EX_USAGE 64 +#endif +#ifndef EX_DATAERR +#define EX_DATAERR 65 +#endif +#ifndef EX_NOINPUT +#define EX_NOINPUT 66 +#endif +#ifndef EX_NOUSER +#define EX_NOUSER 67 +#endif +#ifndef EX_NOHOST +#define EX_NOHOST 68 +#endif +#ifndef EX_UNAVAILABLE +#define EX_UNAVAILABLE 69 +#endif +#ifndef EX_SOFTWARE +#define EX_SOFTWARE 70 +#endif +#ifndef EX_OSERR +#define EX_OSERR 71 +#endif +#ifndef EX_OSFILE +#define EX_OSFILE 72 +#endif +#ifndef EX_CANTCREAT +#define EX_CANTCREAT 73 +#endif +#ifndef EX_IOERR +#define EX_IOERR 74 +#endif +#ifndef EX_TEMPFAIL +#define EX_TEMPFAIL 75 +#endif +#ifndef EX_PROTOCOL +#define EX_PROTOCOL 76 +#endif +#ifndef EX_NOPERM +#define EX_NOPERM 77 +#endif +#ifndef EX_CONFIG +#define EX_CONFIG 78 +#endif + +/* rdesktop specific exit codes, lined up with disconnect PDU reasons */ +#define EXRD_API_DISCONNECT 1 +#define EXRD_API_LOGOFF 2 +#define EXRD_IDLE_TIMEOUT 3 +#define EXRD_LOGON_TIMEOUT 4 +#define EXRD_REPLACED 5 +#define EXRD_OUT_OF_MEM 6 +#define EXRD_DENIED 7 +#define EXRD_DENIED_FIPS 8 +#define EXRD_INSUFFICIENT_PRIVILEGES 9 +#define EXRD_FRESH_CREDENTIALS_REQUIRED 10 +#define EXRD_RPC_DISCONNECT_BY_USER 11 +#define EXRD_DISCONNECT_BY_USER 12 +#define EXRD_LIC_INTERNAL 16 +#define EXRD_LIC_NOSERVER 17 +#define EXRD_LIC_NOLICENSE 18 +#define EXRD_LIC_MSG 19 +#define EXRD_LIC_HWID 20 +#define EXRD_LIC_CLIENT 21 +#define EXRD_LIC_NET 22 +#define EXRD_LIC_PROTO 23 +#define EXRD_LIC_ENC 24 +#define EXRD_LIC_UPGRADE 25 +#define EXRD_LIC_NOREMOTE 26 + +/* other exit codes */ +#define EXRD_WINDOW_CLOSED 62 +#define EXRD_UNKNOWN 63 + #ifdef WITH_DEBUG #define DEBUG(args) printf args; #else @@ -62,6 +147,12 @@ #define DEBUG_CLIPBOARD(args) #endif +#ifdef WITH_DEBUG_SOUND +#define DEBUG_SOUND(args) printf args; +#else +#define DEBUG_SOUND(args) +#endif + #ifdef WITH_DEBUG_CHANNEL #define DEBUG_CHANNEL(args) printf args; #else @@ -68,6 +159,12 @@ #define DEBUG_CHANNEL(args) #endif +#ifdef WITH_DEBUG_SCARD +#define DEBUG_SCARD(args) printf args; +#else +#define DEBUG_SCARD(args) +#endif + #define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } #ifndef MIN Index: reactos/base/applications/mstsc/rdp.c =================================================================== --- reactos/base/applications/mstsc/rdp.c (revision 66177) +++ reactos/base/applications/mstsc/rdp.c (working copy) @@ -1,11 +1,13 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP layer - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2003-2011 Peter Astrand for Cendio AB + Copyright 2011-2014 Henrik Andersson for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,29 +15,32 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" extern uint16 g_mcs_userid; -extern char g_username[]; -extern char g_codepage[]; -extern BOOL g_bitmap_compression; -extern BOOL g_orders; -extern BOOL g_encryption; -extern BOOL g_desktop_save; -extern BOOL g_polygon_ellipse_orders; -extern BOOL g_use_rdp5; +extern char g_username[256]; +extern char g_password[256]; +char g_codepage[16]; +extern RD_BOOL g_bitmap_compression; +extern RD_BOOL g_orders; +extern RD_BOOL g_encryption; +extern RD_BOOL g_desktop_save; +extern RD_BOOL g_polygon_ellipse_orders; +extern RDP_VERSION g_rdp_version; extern uint16 g_server_rdp_version; extern uint32 g_rdp5_performanceflags; extern int g_server_depth; extern int g_width; extern int g_height; -extern BOOL g_bitmap_cache; -extern BOOL g_bitmap_cache_persist_enable; +extern RD_BOOL g_bitmap_cache; +extern RD_BOOL g_bitmap_cache_persist_enable; +extern RD_BOOL g_numlock_sync; +extern RD_BOOL g_pending_resize; +extern RD_BOOL g_network_error; uint8 *g_next_packet; uint32 g_rdp_shareid; @@ -43,21 +48,34 @@ extern RDPCOMP g_mppc_dict; /* Session Directory support */ -extern BOOL g_redirect; -extern char g_redirect_server[64]; -extern char g_redirect_domain[16]; -extern char g_redirect_password[64]; -extern char g_redirect_username[64]; -extern char g_redirect_cookie[128]; +extern RD_BOOL g_redirect; +extern char *g_redirect_server; +extern uint32 g_redirect_server_len; +extern char *g_redirect_domain; +extern uint32 g_redirect_domain_len; +extern char *g_redirect_username; +extern uint32 g_redirect_username_len; +extern uint8 *g_redirect_lb_info; +extern uint32 g_redirect_lb_info_len; +extern uint8 *g_redirect_cookie; +extern uint32 g_redirect_cookie_len; extern uint32 g_redirect_flags; +extern uint32 g_redirect_session_id; + /* END Session Directory support */ -#ifdef WITH_DEBUG +extern uint32 g_reconnect_logonid; +extern char g_reconnect_random[16]; +extern time_t g_reconnect_random_ts; +extern RD_BOOL g_has_reconnect_random; +extern uint8 g_client_random[SEC_RANDOM_SIZE]; + +#if WITH_DEBUG static uint32 g_packetno; #endif #ifdef HAVE_ICONV -static BOOL g_iconv_works = True; +static RD_BOOL g_iconv_works = True; #endif /* Receive an RDP packet */ @@ -155,6 +173,9 @@ void rdp_out_unistr(STREAM s, char *string, int len) { + if (string == NULL || len == 0) + return; + #ifdef HAVE_ICONV size_t ibl = strlen(string), obl = len + 2; static iconv_t iconv_h = (iconv_t) - 1; @@ -226,12 +247,16 @@ * * Returns str_len of string */ -int -rdp_in_unistr(STREAM s, char *string, int uni_len) +void +rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size) { + /* Dynamic allocate of destination string if not provided */ + *string = xmalloc(in_len * 2); + *str_size = in_len * 2; + #ifdef HAVE_ICONV - size_t ibl = uni_len, obl = uni_len; - char *pin = (char *) s->p, *pout = string; + size_t ibl = in_len, obl = *str_size - 1; + char *pin = (char *) s->p, *pout = *string; static iconv_t iconv_h = (iconv_t) - 1; if (g_iconv_works) @@ -244,37 +269,57 @@ WINDOWS_CODEPAGE, g_codepage, (int) iconv_h); g_iconv_works = False; - return rdp_in_unistr(s, string, uni_len); + return rdp_in_unistr(s, in_len, string, str_size); } } if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) { - iconv_close(iconv_h); - iconv_h = (iconv_t) - 1; - warning("rdp_in_unistr: iconv fail, errno %d\n", errno); + if (errno == E2BIG) + { + warning("server sent an unexpectedly long string, truncating\n"); + } + else + { + warning("rdp_in_unistr: iconv fail, errno %d\n", errno); - g_iconv_works = False; - return rdp_in_unistr(s, string, uni_len); + free(*string); + *string = NULL; + *str_size = 0; + } } /* we must update the location of the current STREAM for future reads of s->p */ - s->p += uni_len; + s->p += in_len; - return pout - string; + *pout = 0; + + if (*string) + *str_size = pout - *string; } else #endif { int i = 0; + int rem = 0; + uint32 len = in_len / 2; - while (i < uni_len / 2) + if (len > *str_size - 1) { + warning("server sent an unexpectedly long string, truncating\n"); + len = *str_size - 1; + rem = in_len - 2 * len; + } + + while (i < len) + { in_uint8a(s, &string[i++], 1); in_uint8s(s, 1); } - return i - 1; + in_uint8s(s, rem); + string[len] = 0; + *str_size = len; } } @@ -285,20 +330,25 @@ char *password, char *program, char *directory) { //char *ipaddr = tcp_get_address(); + /* length of string in TS_INFO_PACKET excludes null terminator */ int len_domain = 2 * strlen(domain); int len_user = 2 * strlen(user); int len_password = 2 * strlen(password); int len_program = 2 * strlen(program); int len_directory = 2 * strlen(directory); - //int len_ip = 2 * strlen(ipaddr); - //int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll"); + + /* length of strings in TS_EXTENDED_PACKET includes null terminator */ + //int len_ip = 2 * strlen(ipaddr) + 2; + //int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll") + 2; + //int packetlen = 0; uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; STREAM s = NULL; //time_t t = time(NULL); //time_t tzone; + //uint8 security_verifier[16]; - if (!g_use_rdp5 || 1 == g_server_rdp_version) + if (g_rdp_version == RDP_V4 || 1 == g_server_rdp_version) { DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); @@ -321,112 +371,148 @@ else { #if 0 - flags |= RDP_LOGON_BLOB; + DEBUG_RDP5(("Sending RDP5-style Logon packet\n")); - packetlen = 4 + /* Unknown uint32 */ + + if (g_redirect == True && g_redirect_cookie_len > 0) + { + len_password = g_redirect_cookie_len; + len_password -= 2; /* substract 2 bytes which is added below */ + } + + packetlen = + /* size of TS_INFO_PACKET */ + 4 + /* CodePage */ 4 + /* flags */ - 2 + /* len_domain */ - 2 + /* len_user */ - (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */ - (flags & RDP_LOGON_BLOB ? 2 : 0) + /* Length of BLOB */ - 2 + /* len_program */ - 2 + /* len_directory */ - (0 < len_domain ? len_domain : 2) + /* domain */ - len_user + (flags & RDP_LOGON_AUTO ? len_password : 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */ - (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */ - (0 < len_program ? len_program : 2) + (0 < len_directory ? len_directory : 2) + 2 + /* Unknown (2) */ - 2 + /* Client ip length */ - len_ip + /* Client ip */ - 2 + /* DLL string length */ - len_dll + /* DLL string */ - 2 + /* Unknown */ - 2 + /* Unknown */ - 64 + /* Time zone #0 */ - 2 + /* Unknown */ - 64 + /* Time zone #1 */ - 32; /* Unknown */ + 2 + /* cbDomain */ + 2 + /* cbUserName */ + 2 + /* cbPassword */ + 2 + /* cbAlternateShell */ + 2 + /* cbWorkingDir */ + 2 + len_domain + /* Domain */ + 2 + len_user + /* UserName */ + 2 + len_password + /* Password */ + 2 + len_program + /* AlternateShell */ + 2 + len_directory + /* WorkingDir */ + /* size of TS_EXTENDED_INFO_PACKET */ + 2 + /* clientAdressFamily */ + 2 + /* cbClientAdress */ + len_ip + /* clientAddress */ + 2 + /* cbClientDir */ + len_dll + /* clientDir */ + /* size of TS_TIME_ZONE_INFORMATION */ + 4 + /* Bias, (UTC = local time + bias */ + 64 + /* StandardName, 32 unicode char array, Descriptive standard time on client */ + 16 + /* StandardDate */ + 4 + /* StandardBias */ + 64 + /* DaylightName, 32 unicode char array */ + 16 + /* DaylightDate */ + 4 + /* DaylightBias */ + 4 + /* clientSessionId */ + 4 + /* performanceFlags */ + 2 + /* cbAutoReconnectCookie, either 0 or 0x001c */ + /* size of ARC_CS_PRIVATE_PACKET */ + 28; /* autoReconnectCookie */ + s = sec_init(sec_flags, packetlen); DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); - out_uint32(s, 0); /* Unknown */ + /* TS_INFO_PACKET */ + out_uint32(s, 0); /* Code Page */ out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_user); - if (flags & RDP_LOGON_AUTO) - { - out_uint16_le(s, len_password); - - } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) - { - out_uint16_le(s, 0); - } + out_uint16_le(s, len_password); out_uint16_le(s, len_program); out_uint16_le(s, len_directory); + if (0 < len_domain) rdp_out_unistr(s, domain, len_domain); else - out_uint16_le(s, 0); - rdp_out_unistr(s, user, len_user); - if (flags & RDP_LOGON_AUTO) + out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + + if (0 < len_user) + rdp_out_unistr(s, user, len_user); + else + out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + + if (0 < len_password) { - rdp_out_unistr(s, password, len_password); + if (g_redirect == True && 0 < g_redirect_cookie_len) + { + out_uint8p(s, g_redirect_cookie, g_redirect_cookie_len); + } + else + { + rdp_out_unistr(s, password, len_password); + } } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) - { - out_uint16_le(s, 0); - } + else + out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + if (0 < len_program) - { rdp_out_unistr(s, program, len_program); + else + out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ - } - else - { - out_uint16_le(s, 0); - } if (0 < len_directory) - { rdp_out_unistr(s, directory, len_directory); - } else - { - out_uint16_le(s, 0); - } - out_uint16_le(s, 2); - out_uint16_le(s, len_ip + 2); /* Length of client ip */ - rdp_out_unistr(s, ipaddr, len_ip); - out_uint16_le(s, len_dll + 2); - rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll); + out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + /* TS_EXTENDED_INFO_PACKET */ + out_uint16_le(s, 2); /* clientAddressFamily = AF_INET */ + out_uint16_le(s, len_ip); /* cbClientAddress, Length of client ip */ + rdp_out_unistr(s, ipaddr, len_ip - 2); /* clientAddress */ + out_uint16_le(s, len_dll); /* cbClientDir */ + rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll - 2); /* clientDir */ + + /* TS_TIME_ZONE_INFORMATION */ tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60; out_uint32_le(s, tzone); - rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid")); out_uint8s(s, 62 - 2 * strlen("GTB, normaltid")); - out_uint32_le(s, 0x0a0000); out_uint32_le(s, 0x050000); out_uint32_le(s, 3); out_uint32_le(s, 0); out_uint32_le(s, 0); - rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid")); out_uint8s(s, 62 - 2 * strlen("GTB, sommartid")); - out_uint32_le(s, 0x30000); out_uint32_le(s, 0x050000); out_uint32_le(s, 2); out_uint32(s, 0); - out_uint32_le(s, 0xffffffc4); - out_uint32_le(s, 0xfffffffe); + out_uint32_le(s, 0xffffffc4); /* DaylightBias */ + + /* Rest of TS_EXTENDED_INFO_PACKET */ + out_uint32_le(s, 0); /* clientSessionId (Ignored by server MUST be 0) */ out_uint32_le(s, g_rdp5_performanceflags); - out_uint32(s, 0); + /* Client Auto-Reconnect */ + if (g_has_reconnect_random) + { + out_uint16_le(s, 28); /* cbAutoReconnectLen */ + /* ARC_CS_PRIVATE_PACKET */ + out_uint32_le(s, 28); /* cbLen */ + out_uint32_le(s, 1); /* Version */ + out_uint32_le(s, g_reconnect_logonid); /* LogonId */ + rdssl_hmac_md5(g_reconnect_random, sizeof(g_reconnect_random), + g_client_random, SEC_RANDOM_SIZE, security_verifier); + out_uint8a(s, security_verifier, sizeof(security_verifier)); + } + else + { + out_uint16_le(s, 0); /* cbAutoReconnectLen */ + } #endif } s_mark_end(s); + + /* clear the redirect flag */ + g_redirect = False; + sec_send(s, sec_flags); } @@ -586,7 +672,7 @@ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16(s, 0); /* Pad */ out_uint16(s, 0); /* Compression types */ - out_uint16_le(s, g_use_rdp5 ? 0x40d : 0); + out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 0x40d : 0); /* Pad, according to T.128. 0x40d seems to trigger the server to start sending RDP5 packets. @@ -743,6 +829,18 @@ out_uint16_le(s, 20); /* Cache size */ } +/* Output new pointer capability set */ +static void +rdp_out_newpointer_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_NEWPOINTER); + + out_uint16_le(s, 1); /* Colour pointer */ + out_uint16_le(s, 20); /* Cache size */ + out_uint16_le(s, 20); /* Cache size for new pointers */ +} + /* Output share capability set */ static void rdp_out_share_caps(STREAM s) @@ -765,6 +863,15 @@ out_uint16(s, 0); /* pad */ } +/* Output brush cache capability set */ +static void +rdp_out_brushcache_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_BRUSHCACHE); + out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE); + out_uint32_le(s, 1); /* cache type */ +} + static uint8 caps_0x0d[] = { 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -811,12 +918,23 @@ uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG; uint16 caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + - RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + + RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + - RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + - 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + - 4 /* w2k fix, why? */ ; + RDP_CAPLEN_SHARE + + RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + + 4 /* w2k fix, sessionid */ ; + if (g_rdp_version >= RDP_V5) + { + caplen += RDP_CAPLEN_BMPCACHE2; + caplen += RDP_CAPLEN_NEWPOINTER; + } + else + { + caplen += RDP_CAPLEN_BMPCACHE; + caplen += RDP_CAPLEN_POINTER; + } + s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE)); out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE)); @@ -829,23 +947,32 @@ out_uint16_le(s, caplen); out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE)); - out_uint16_le(s, 0xd); /* num_caps */ + out_uint16_le(s, 0xe); /* num_caps */ out_uint8s(s, 2); /* pad */ rdp_out_general_caps(s); rdp_out_bitmap_caps(s); rdp_out_order_caps(s); - g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s); + if (g_rdp_version >= RDP_V5) + { + rdp_out_bmpcache2_caps(s); + rdp_out_newpointer_caps(s); + } + else + { + rdp_out_bmpcache_caps(s); + rdp_out_pointer_caps(s); + } rdp_out_colcache_caps(s); rdp_out_activate_caps(s); rdp_out_control_caps(s); - rdp_out_pointer_caps(s); rdp_out_share_caps(s); + rdp_out_brushcache_caps(s); - rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */ - rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); - rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); - rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */ + rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* CAPSTYPE_INPUT */ + rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); /* CAPSTYPE_SOUND */ + rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); /* CAPSTYPE_FONT */ + rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* CAPSTYPE_GLYPHCACHE */ s_mark_end(s); sec_send(s, sec_flags); @@ -861,7 +988,7 @@ in_uint16_le(s, pad2octetsB); if (!pad2octetsB) - g_use_rdp5 = False; + g_rdp_version = RDP_V4; } /* Process a bitmap capability set */ @@ -958,9 +1085,10 @@ rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */ rdp_recv(&type); /* RDP_CTL_COOPERATE */ rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */ - rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(read_keyboard_state()), 0); + rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, + g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0); - if (g_use_rdp5) + if (g_rdp_version >= RDP_V5) { rdp_enum_bmpcache2(); rdp_send_fonts(3); @@ -976,12 +1104,14 @@ } /* Process a colour pointer PDU */ -void -process_colour_pointer_pdu(STREAM s) +static void +process_colour_pointer_common(STREAM s, int bpp) { - uint16 x, y, width, height, cache_idx, masklen, datalen; - uint8 *mask, *data; - HCURSOR cursor; + uint16 width, height, cache_idx, masklen, datalen; + uint16 x, y; + uint8 *mask; + uint8 *data; + RD_HCURSOR cursor; in_uint16_le(s, cache_idx); in_uint16_le(s, x); @@ -992,11 +1122,36 @@ in_uint16_le(s, datalen); in_uint8p(s, data, datalen); in_uint8p(s, mask, masklen); - cursor = ui_create_cursor(x, y, width, height, mask, data); + if ((width != 32) || (height != 32)) + { + warning("process_colour_pointer_common: " "width %d height %d\n", width, height); + } + + /* keep hotspot within cursor bounding box */ + x = MIN(x, width - 1); + y = MIN(y, height - 1); + cursor = ui_create_cursor(x, y, width, height, mask, data, bpp); ui_set_cursor(cursor); cache_put_cursor(cache_idx, cursor); } +/* Process a colour pointer PDU */ +void +process_colour_pointer_pdu(STREAM s) +{ + process_colour_pointer_common(s, 24); +} + +/* Process a New Pointer PDU - these pointers have variable bit depth */ +void +process_new_pointer_pdu(STREAM s) +{ + int xor_bpp; + + in_uint16_le(s, xor_bpp); + process_colour_pointer_common(s, xor_bpp); +} + /* Process a cached pointer PDU */ void process_cached_pointer_pdu(STREAM s) @@ -1013,7 +1168,7 @@ { uint16 system_pointer_type; - in_uint16(s, system_pointer_type); + in_uint16_le(s, system_pointer_type); switch (system_pointer_type) { case RDP_NULL_POINTER: @@ -1056,6 +1211,10 @@ process_system_pointer_pdu(s); break; + case RDP_POINTER_NEW: + process_new_pointer_pdu(s); + break; + default: unimpl("Pointer message 0x%x\n", message_type); } @@ -1198,6 +1357,52 @@ ui_end_update(); } + +/* Process a Save Session Info PDU */ +void +process_pdu_logon(STREAM s) +{ + uint32 infotype; + in_uint32_le(s, infotype); + if (infotype == INFOTYPE_LOGON_EXTENDED_INF) + { + uint32 fieldspresent; + + in_uint8s(s, 2); /* Length */ + in_uint32_le(s, fieldspresent); + if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE) + { + uint32 len; + uint32 version; + + /* TS_LOGON_INFO_FIELD */ + in_uint8s(s, 4); /* cbFieldData */ + + /* ARC_SC_PRIVATE_PACKET */ + in_uint32_le(s, len); + if (len != 28) + { + warning("Invalid length in Auto-Reconnect packet\n"); + return; + } + + in_uint32_le(s, version); + if (version != 1) + { + warning("Unsupported version of Auto-Reconnect packet\n"); + return; + } + + in_uint32_le(s, g_reconnect_logonid); + in_uint8a(s, g_reconnect_random, 16); + g_has_reconnect_random = True; + g_reconnect_random_ts = time(NULL); + DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid)); + } + } +} + + /* Process a disconnect PDU */ void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason) @@ -1208,7 +1413,7 @@ } /* Process data PDU */ -static BOOL +static RD_BOOL process_data_pdu(STREAM s, uint32 * ext_disc_reason) { uint8 data_pdu_type; @@ -1221,10 +1426,10 @@ struct stream *ns = &(g_mppc_dict.ns); in_uint8s(s, 6); /* shareid, pad, streamid */ - in_uint16(s, len); + in_uint16_le(s, len); in_uint8(s, data_pdu_type); in_uint8(s, ctype); - in_uint16(s, clen); + in_uint16_le(s, clen); clen -= 18; if (ctype & RDP_MPPC_COMPRESSED) @@ -1274,12 +1479,23 @@ case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ + process_pdu_logon(s); break; case RDP_DATA_PDU_DISCONNECT: process_disconnect_pdu(s, ext_disc_reason); - return True; + /* We used to return true and disconnect immediately here, but + * Windows Vista sends a disconnect PDU with reason 0 when + * reconnecting to a disconnected session, and MSTSC doesn't + * drop the connection. I think we should just save the status. + */ + break; + + case RDP_DATA_PDU_AUTORECONNECT_STATUS: + warning("Automatic reconnect using cookie, failed.\n"); + break; + default: unimpl("data PDU %d\n", data_pdu_type); } @@ -1287,69 +1503,175 @@ } /* Process redirect PDU from Session Directory */ -static BOOL -process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ ) +static RD_BOOL +process_redirect_pdu(STREAM s, RD_BOOL enhanced_redirect /*, uint32 * ext_disc_reason */ ) { uint32 len; + uint16 redirect_identifier; + /* reset any previous redirection information */ + g_redirect = True; + free(g_redirect_server); + free(g_redirect_username); + free(g_redirect_domain); + free(g_redirect_lb_info); + free(g_redirect_cookie); + + g_redirect_server = NULL; + g_redirect_username = NULL; + g_redirect_domain = NULL; + g_redirect_lb_info = NULL; + g_redirect_cookie = NULL; + /* these 2 bytes are unknown, seem to be zeros */ in_uint8s(s, 2); + /* FIXME: Previous implementation only reads 4 bytes which has been working + but todays spec says something different. Investigate and retest + server redirection using WTS 2003 cluster. + */ + + if (enhanced_redirect) + { + /* read identifier */ + in_uint16_le(s, redirect_identifier); + if (redirect_identifier != 0x0400) + error("Protocol error in server redirection, unexpected data."); + + /* FIXME: skip total length */ + in_uint8s(s, 2); + + /* read session_id */ + in_uint32_le(s, g_redirect_session_id); + } + /* read connection flags */ in_uint32_le(s, g_redirect_flags); - /* read length of ip string */ - in_uint32_le(s, len); + if (g_redirect_flags & PDU_REDIRECT_HAS_IP) + { + /* read length of ip string */ + in_uint32_le(s, len); - /* read ip string */ - rdp_in_unistr(s, g_redirect_server, len); + /* read ip string */ + rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); + } - /* read length of cookie string */ - in_uint32_le(s, len); + if (g_redirect_flags & PDU_REDIRECT_HAS_LOAD_BALANCE_INFO) + { + /* read length of load balance info blob */ + in_uint32_le(s, g_redirect_lb_info_len); - /* read cookie string (plain ASCII) */ - in_uint8a(s, g_redirect_cookie, len); - g_redirect_cookie[len] = 0; + /* reallocate a loadbalance info blob */ + if (g_redirect_lb_info != NULL) + free(g_redirect_lb_info); - /* read length of username string */ - in_uint32_le(s, len); + g_redirect_lb_info = xmalloc(g_redirect_lb_info_len); - /* read username string */ - rdp_in_unistr(s, g_redirect_username, len); + /* read load balance info blob */ + in_uint8p(s, g_redirect_lb_info, g_redirect_lb_info_len); + } - /* read length of domain string */ - in_uint32_le(s, len); + if (g_redirect_flags & PDU_REDIRECT_HAS_USERNAME) + { + /* read length of username string */ + in_uint32_le(s, len); - /* read domain string */ - rdp_in_unistr(s, g_redirect_domain, len); + /* read username string */ + rdp_in_unistr(s, len, &g_redirect_username, &g_redirect_username_len); + } - /* read length of password string */ - in_uint32_le(s, len); + if (g_redirect_flags & PDU_REDIRECT_HAS_DOMAIN) + { + /* read length of domain string */ + in_uint32_le(s, len); - /* read password string */ - rdp_in_unistr(s, g_redirect_password, len); + /* read domain string */ + rdp_in_unistr(s, len, &g_redirect_domain, &g_redirect_domain_len); + } - g_redirect = True; + if (g_redirect_flags & PDU_REDIRECT_HAS_PASSWORD) + { + /* the information in this blob is either a password or a cookie that + should be passed though as blob and not parsed as a unicode string */ + /* read blob length */ + in_uint32_le(s, g_redirect_cookie_len); + + /* reallocate cookie blob */ + if (g_redirect_cookie != NULL) + free(g_redirect_cookie); + + g_redirect_cookie = xmalloc(g_redirect_cookie_len); + + /* read cookie as is */ + in_uint8p(s, g_redirect_cookie, g_redirect_cookie_len); + } + + if (g_redirect_flags & PDU_REDIRECT_DONT_STORE_USERNAME) + { + warning("PDU_REDIRECT_DONT_STORE_USERNAME set\n"); + } + + if (g_redirect_flags & PDU_REDIRECT_USE_SMARTCARD) + { + warning("PDU_REDIRECT_USE_SMARTCARD set\n"); + } + + if (g_redirect_flags & PDU_REDIRECT_INFORMATIONAL) + { + /* By spec this is only for information and doesn't mean that an actual + redirect should be performed. How it should be used is not mentioned. */ + g_redirect = False; + } + + if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_FQDN) + { + in_uint32_le(s, len); + + /* Let target fqdn replace target ip address */ + if (g_redirect_server) + { + free(g_redirect_server); + g_redirect_server = NULL; + } + + /* read fqdn string */ + rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); + } + + if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_NETBIOS) + { + warning("PDU_REDIRECT_HAS_TARGET_NETBIOS set\n"); + } + + if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_IP_ARRAY) + { + warning("PDU_REDIRECT_HAS_TARGET_IP_ARRAY set\n"); + } + return True; } /* Process incoming packets */ -/* nevers gets out of here till app is done */ void -rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason) +rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { while (rdp_loop(deactivated, ext_disc_reason)) - ; + { + if (g_pending_resize || g_redirect) + { + return; + } + } } /* used in uiports and rdp_main_loop, processes the rdp packets waiting */ -BOOL -rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason) +RD_BOOL +rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { uint8 type; - BOOL disc = False; /* True when a disconnect PDU was received */ - BOOL cont = True; + RD_BOOL cont = True; STREAM s; while (cont) @@ -1368,10 +1690,18 @@ *deactivated = True; break; case RDP_PDU_REDIRECT: - return process_redirect_pdu(s); + return process_redirect_pdu(s, False); break; + case RDP_PDU_ENHANCED_REDIRECT: + return process_redirect_pdu(s, True); + break; case RDP_PDU_DATA: - disc = process_data_pdu(s, ext_disc_reason); + /* If we got a data PDU, we don't need to keep the password in memory + anymore and therefor we should clear it for security reasons. */ + if (g_password[0] != '\0') + memset(g_password, 0, sizeof(g_password)); + + process_data_pdu(s, ext_disc_reason); break; case 0: break; @@ -1378,8 +1708,6 @@ default: unimpl("PDU %d\n", type); } - if (disc) - return False; cont = g_next_packet < s->end; } return True; @@ -1386,26 +1714,30 @@ } /* Establish a connection up to the RDP layer */ -BOOL +RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, - char *command, char *directory) + char *command, char *directory, RD_BOOL reconnect) { - if (!sec_connect(server, g_username)) + RD_BOOL deactivated = False; + uint32 ext_disc_reason = 0; + + if (!sec_connect(server, g_username, domain, password, reconnect)) return False; rdp_send_logon_info(flags, domain, g_username, password, command, directory); - return True; -} -/* Establish a reconnection up to the RDP layer */ -BOOL -rdp_reconnect(char *server, uint32 flags, char *domain, char *password, - char *command, char *directory, char *cookie) -{ - if (!sec_reconnect(server)) - return False; + /* run RDP loop until first licence demand active PDU */ + while (!g_rdp_shareid) + { + if (g_network_error) + return False; - rdp_send_logon_info(flags, domain, g_username, password, command, directory); + if (!rdp_loop(&deactivated, &ext_disc_reason)) + return False; + + if (g_redirect) + return True; + } return True; } Index: reactos/base/applications/mstsc/rdp5.c =================================================================== --- reactos/base/applications/mstsc/rdp5.c (revision 66177) +++ reactos/base/applications/mstsc/rdp5.c (working copy) @@ -1,12 +1,12 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP5 short form PDU processing - Copyright (C) Matthew Chapman 1999-2005 - Copyright (C) Erik Forsberg 2003 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2003-2008 Erik Forsberg for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,9 +14,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -111,6 +110,9 @@ case 10: /* cached pointer */ process_cached_pointer_pdu(ts); break; + case 11: + process_new_pointer_pdu(ts); + break; default: unimpl("RDP5 opcode %d\n", type); } Index: reactos/base/applications/mstsc/secure.c =================================================================== --- reactos/base/applications/mstsc/secure.c (revision 66177) +++ reactos/base/applications/mstsc/secure.c (working copy) @@ -1,11 +1,12 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP encryption and licensing - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2005-2011 Peter Astrand for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,8 +15,7 @@ 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. + along with this program. If not, see . */ #include "precomp.h" @@ -55,6 +55,9 @@ int ssl_mod_exp(char* out, int out_len, char* in, int in_len, char* mod, int mod_len, char* exp, int exp_len); +//int +//ssl_sig_ok(char * exp, int exp_size, char * mod, int mod_len, +// char * sig, int sig_len); extern char g_hostname[16]; extern int g_width; @@ -63,35 +66,37 @@ extern int g_keyboard_type; extern int g_keyboard_subtype; extern int g_keyboard_functionkeys; -extern BOOL g_encryption; -extern BOOL g_licence_issued; -extern BOOL g_use_rdp5; -extern BOOL g_console_session; +extern RD_BOOL g_encryption; +extern RD_BOOL g_licence_issued; +extern RD_BOOL g_licence_error_result; +extern RDP_VERSION g_rdp_version; +extern RD_BOOL g_console_session; +extern uint32 g_redirect_session_id; extern int g_server_depth; -extern uint16 mcs_userid; extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; +extern uint8 g_client_random[SEC_RANDOM_SIZE]; -static int rc4_key_len; -static void * rc4_decrypt_key = 0; -static void * rc4_encrypt_key = 0; -//static RSA *server_public_key; -static void * server_public_key; -static uint32 server_public_key_len; +static int g_rc4_key_len; +static void * g_rc4_decrypt_key; +static void * g_rc4_encrypt_key; +static uint32 g_server_public_key_len; -static uint8 sec_sign_key[16]; -static uint8 sec_decrypt_key[16]; -static uint8 sec_encrypt_key[16]; -static uint8 sec_decrypt_update_key[16]; -static uint8 sec_encrypt_update_key[16]; -static uint8 sec_crypted_random[SEC_MAX_MODULUS_SIZE]; +static uint8 g_sec_sign_key[16]; +static uint8 g_sec_decrypt_key[16]; +static uint8 g_sec_encrypt_key[16]; +static uint8 g_sec_decrypt_update_key[16]; +static uint8 g_sec_encrypt_update_key[16]; +static uint8 g_sec_crypted_random[SEC_MAX_MODULUS_SIZE]; uint16 g_server_rdp_version = 0; /* These values must be available to reset state - Session Directory */ -static int sec_encrypt_use_count = 0; -static int sec_decrypt_use_count = 0; +static int g_sec_encrypt_use_count = 0; +static int g_sec_decrypt_use_count = 0; +#define SEC_MODULUS_SIZE 64 + /* * I believe this is based on SSLv3 with the following differences: * MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields @@ -152,6 +157,33 @@ ssl_md5_info_delete(md5); } +/* + * 16-byte sha1 hash + */ +void +sec_hash_sha1_16(uint8 * out, uint8 * in, uint8 * salt1) +{ + void * sha; + sha = ssl_sha1_info_create(); + ssl_sha1_clear(sha); + ssl_sha1_transform(&sha, (char *)in, 16); + ssl_sha1_transform(&sha, (char *)salt1, 16); + ssl_sha1_complete(&sha, (char *)out); + ssl_sha1_info_delete(sha); +} + +/* create string from hash */ +void +sec_hash_to_string(char *out, int out_size, uint8 * in, int in_size) +{ + int k; + memset(out, 0, out_size); + for (k = 0; k < in_size; k++, out += 2) + { + sprintf(out, "%.2x", in[k]); + } +} + /* Reduce key entropy from 64 to 40 bits */ static void sec_make_40bit(uint8 * key) @@ -178,39 +210,39 @@ sec_hash_48(key_block, master_secret, client_random, server_random, 'X'); /* First 16 bytes of key material is MAC secret */ - memcpy(sec_sign_key, key_block, 16); + memcpy(g_sec_sign_key, key_block, 16); /* Generate export keys from next two blocks of 16 bytes */ - sec_hash_16(sec_decrypt_key, &key_block[16], client_random, server_random); - sec_hash_16(sec_encrypt_key, &key_block[32], client_random, server_random); + sec_hash_16(g_sec_decrypt_key, &key_block[16], client_random, server_random); + sec_hash_16(g_sec_encrypt_key, &key_block[32], client_random, server_random); 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; + sec_make_40bit(g_sec_sign_key); + sec_make_40bit(g_sec_decrypt_key); + sec_make_40bit(g_sec_encrypt_key); + g_rc4_key_len = 8; } else { DEBUG(("rc_4_key_size == %d, 128-bit encryption enabled\n", rc4_key_size)); - rc4_key_len = 16; + g_rc4_key_len = 16; } /* Save initial RC4 keys as update keys */ - memcpy(sec_decrypt_update_key, sec_decrypt_key, 16); - memcpy(sec_encrypt_update_key, sec_encrypt_key, 16); + memcpy(g_sec_decrypt_update_key, g_sec_decrypt_key, 16); + memcpy(g_sec_encrypt_update_key, g_sec_encrypt_key, 16); /* Initialise RC4 state arrays */ - ssl_rc4_info_delete(rc4_decrypt_key); - rc4_decrypt_key = ssl_rc4_info_create(); - ssl_rc4_set_key(rc4_decrypt_key, (char *)sec_decrypt_key, rc4_key_len); + ssl_rc4_info_delete(g_rc4_decrypt_key); + g_rc4_decrypt_key = ssl_rc4_info_create(); + ssl_rc4_set_key(g_rc4_decrypt_key, (char *)g_sec_decrypt_key, g_rc4_key_len); - ssl_rc4_info_delete(rc4_encrypt_key); - rc4_encrypt_key = ssl_rc4_info_create(); - ssl_rc4_set_key(rc4_encrypt_key, (char *)sec_encrypt_key, rc4_key_len); + ssl_rc4_info_delete(g_rc4_encrypt_key); + g_rc4_encrypt_key = ssl_rc4_info_create(); + ssl_rc4_set_key(g_rc4_encrypt_key, (char *)g_sec_encrypt_key, g_rc4_key_len); } static uint8 pad_54[40] = { @@ -280,15 +312,15 @@ sha = ssl_sha1_info_create(); ssl_sha1_clear(sha); - ssl_sha1_transform(sha, (char *)update_key, rc4_key_len); + ssl_sha1_transform(sha, (char *)update_key, g_rc4_key_len); ssl_sha1_transform(sha, (char *)pad_54, 40); - ssl_sha1_transform(sha, (char *)key, rc4_key_len); + ssl_sha1_transform(sha, (char *)key, g_rc4_key_len); ssl_sha1_complete(sha, (char *)shasig); ssl_sha1_info_delete(sha); md5 = ssl_md5_info_create(); ssl_md5_clear(md5); - ssl_md5_transform(md5, (char *)update_key, rc4_key_len); + ssl_md5_transform(md5, (char *)update_key, g_rc4_key_len); ssl_md5_transform(md5, (char *)pad_92, 48); ssl_md5_transform(md5, (char *)shasig, 20); ssl_md5_complete(md5, (char *)key); @@ -296,11 +328,11 @@ update = ssl_rc4_info_create(); - ssl_rc4_set_key(update, (char *)key, rc4_key_len); - ssl_rc4_crypt(update, (char *)key, (char *)key, rc4_key_len); + ssl_rc4_set_key(update, (char *)key, g_rc4_key_len); + ssl_rc4_crypt(update, (char *)key, (char *)key, g_rc4_key_len); ssl_rc4_info_delete(update); - - if (rc4_key_len == 8) + + if (g_rc4_key_len == 8) sec_make_40bit(key); } @@ -308,14 +340,15 @@ static void sec_encrypt(uint8 * data, int length) { - if (sec_encrypt_use_count == 4096) + if (g_sec_encrypt_use_count == 4096) { - sec_update(sec_encrypt_key, sec_encrypt_update_key); - ssl_rc4_set_key(rc4_encrypt_key, (char *)sec_encrypt_key, rc4_key_len); - sec_encrypt_use_count = 0; + sec_update(g_sec_encrypt_key, g_sec_encrypt_update_key); + ssl_rc4_set_key(&g_rc4_encrypt_key, (char *)g_sec_encrypt_key, g_rc4_key_len); + g_sec_encrypt_use_count = 0; } - ssl_rc4_crypt(rc4_encrypt_key, (char *)data, (char *)data, length); - sec_encrypt_use_count++; + + ssl_rc4_crypt(&g_rc4_encrypt_key, (char *)data, (char *)data, length); + g_sec_encrypt_use_count++; } /* Decrypt data using RC4 */ @@ -322,82 +355,23 @@ void sec_decrypt(uint8 * data, int length) { - if (sec_decrypt_use_count == 4096) + if (g_sec_decrypt_use_count == 4096) { - sec_update(sec_decrypt_key, sec_decrypt_update_key); - ssl_rc4_set_key(rc4_decrypt_key, (char *)sec_decrypt_key, rc4_key_len); - sec_decrypt_use_count = 0; + sec_update(g_sec_decrypt_key, g_sec_decrypt_update_key); + ssl_rc4_set_key(&g_rc4_decrypt_key, (char *)g_sec_decrypt_key, g_rc4_key_len); + g_sec_decrypt_use_count = 0; } - ssl_rc4_crypt(rc4_decrypt_key, (char *)data, (char *)data, length); - sec_decrypt_use_count++; + + ssl_rc4_crypt(&g_rc4_decrypt_key,(char *)data, (char *)data, length); + g_sec_decrypt_use_count++; } -/*static void -reverse(uint8 * p, int len) -{ - int i, j; - uint8 temp; - - for (i = 0, j = len - 1; i < j; i++, j--) - { - temp = p[i]; - p[i] = p[j]; - p[j] = temp; - } -}*/ - /* Perform an RSA public key encryption operation */ static void -//sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint8 * modulus, uint8 * exponent) -sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) +sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, + uint8 * exponent) { ssl_mod_exp((char *)out, 64, (char *)in, 32, (char *)modulus, 64, (char *)exponent, 4); -/* -ssl_mod_exp(out, 64, in, 32, modulus, 64, exponent, 4); - -ssl_mod_exp(char* out, int out_len, char* in, int in_len, - char* mod, int mod_len, char* exp, int exp_len) - -e = (DIGIT_T*)l_exp; -x = (DIGIT_T*)l_in; -y = (DIGIT_T*)l_out; -m = (DIGIT_T*)l_mod; - -*/ - - //BN_CTX *ctx; - -/* - BN_CTX *ctx; - BIGNUM mod, exp, x, y; - uint8 inr[SEC_MAX_MODULUS_SIZE]; - int outlen; - - reverse(modulus, modulus_size); - reverse(exponent, SEC_EXPONENT_SIZE); - memcpy(inr, in, len); - reverse(inr, len); - - ctx = BN_CTX_new(); - BN_init(&mod); - BN_init(&exp); - BN_init(&x); - BN_init(&y); - - BN_bin2bn(modulus, modulus_size, &mod); - BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp); - BN_bin2bn(inr, len, &x); - BN_mod_exp(&y, &x, &exp, &mod, ctx); - outlen = BN_bn2bin(&y, out); - reverse(out, outlen); - if (outlen < modulus_size) - memset(out + outlen, 0, modulus_size - outlen); - - BN_free(&y); - BN_clear_free(&x); - BN_free(&exp); - BN_free(&mod); - BN_CTX_free(ctx);*/ } /* Initialise secure transport packet */ @@ -407,7 +381,7 @@ int hdrlen; STREAM s; - if (!g_licence_issued) + if (!g_licence_issued && !g_licence_error_result) hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; else hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; @@ -423,8 +397,12 @@ { int datalen; +#ifdef WITH_SCARD + scard_lock(SCARD_LOCK_SEC); +#endif + s_pop_layer(s, sec_hdr); - if (!g_licence_issued || (flags & SEC_ENCRYPT)) + if ((!g_licence_issued && !g_licence_error_result) || (flags & SEC_ENCRYPT)) out_uint32_le(s, flags); if (flags & SEC_ENCRYPT) @@ -437,11 +415,15 @@ hexdump(s->p + 8, datalen); #endif - sec_sign(s->p, 8, sec_sign_key, rc4_key_len, s->p + 8, datalen); + sec_sign(s->p, 8, g_sec_sign_key, g_rc4_key_len, s->p + 8, datalen); sec_encrypt(s->p + 8, datalen); } mcs_send_to_channel(s, channel); + +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_SEC); +#endif } /* Transmit secure transport packet */ @@ -457,14 +439,14 @@ static void sec_establish_key(void) { - uint32 length = server_public_key_len + SEC_PADDING_SIZE; + uint32 length = g_server_public_key_len + SEC_PADDING_SIZE; uint32 flags = SEC_CLIENT_RANDOM; STREAM s; - s = sec_init(flags, length+4); + s = sec_init(flags, length + 4); out_uint32_le(s, length); - out_uint8p(s, sec_crypted_random, server_public_key_len); + out_uint8p(s, g_sec_crypted_random, g_server_public_key_len); out_uint8s(s, SEC_PADDING_SIZE); s_mark_end(s); @@ -473,11 +455,12 @@ /* Output connect initial data blob */ static void -sec_out_mcs_data(STREAM s) +sec_out_mcs_data(STREAM s, uint32 selected_protocol) { int hostlen = 2 * strlen(g_hostname); - int length = 158 + 76 + 12 + 4; + int length = 162 + 76 + 12 + 4; unsigned int i; + uint32 cluster_flags = 0; if (g_num_channels > 0) length += g_num_channels * 12 + 8; @@ -504,8 +487,8 @@ /* Client information */ out_uint16_le(s, SEC_TAG_CLI_INFO); - out_uint16_le(s, 212); /* length */ - out_uint16_le(s, g_use_rdp5 ? 4 : 1); /* RDP version. 1 == RDP4, 4 == RDP5. */ + out_uint16_le(s, 216); /* length */ + out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 4 : 1); /* RDP version. 1 == RDP4, 4 >= RDP5 to RDP8 */ out_uint16_le(s, 8); out_uint16_le(s, g_width); out_uint16_le(s, g_height); @@ -532,13 +515,22 @@ out_uint16_le(s, 0x0700); out_uint8(s, 0); out_uint32_le(s, 1); - out_uint8s(s, 64); /* End of client info */ + out_uint8s(s, 64); + out_uint32_le(s, selected_protocol); /* End of client info */ - out_uint16_le(s, SEC_TAG_CLI_4); - out_uint16_le(s, 12); - out_uint32_le(s, g_console_session ? 0xb : 9); - out_uint32(s, 0); + /* Write a Client Cluster Data (TS_UD_CS_CLUSTER) */ + out_uint16_le(s, SEC_TAG_CLI_CLUSTER); /* header.type */ + out_uint16_le(s, 12); /* length */ + cluster_flags |= SEC_CC_REDIRECTION_SUPPORTED; + cluster_flags |= (SEC_CC_REDIRECT_VERSION_3 << 2); + + if (g_console_session || g_redirect_session_id != 0) + cluster_flags |= SEC_CC_REDIRECT_SESSIONID_FIELD_VALID; + + out_uint32_le(s, cluster_flags); + out_uint32(s, g_redirect_session_id); + /* Client encryption settings */ out_uint16_le(s, SEC_TAG_CLI_CRYPT); out_uint16_le(s, 12); /* length */ @@ -563,8 +555,8 @@ } /* Parse a public key structure */ -static BOOL -sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent) +static RD_BOOL +sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent) { uint32 magic, modulus_len; @@ -577,36 +569,60 @@ in_uint32_le(s, modulus_len); modulus_len -= SEC_PADDING_SIZE; - if ((modulus_len < 64) || (modulus_len > SEC_MAX_MODULUS_SIZE)) + if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) { - error("Bad server public key size (%u bits)\n", modulus_len*8); + error("Bad server public key size (%u bits)\n", modulus_len * 8); return False; } in_uint8s(s, 8); /* modulus_bits, unknown */ - in_uint8p(s, *exponent, SEC_EXPONENT_SIZE); - in_uint8p(s, *modulus, modulus_len); + in_uint8a(s, exponent, SEC_EXPONENT_SIZE); + in_uint8a(s, modulus, modulus_len); in_uint8s(s, SEC_PADDING_SIZE); - server_public_key_len = modulus_len; + g_server_public_key_len = modulus_len; return s_check(s); } +/* Parse a public signature structure */ +static RD_BOOL +sec_parse_public_sig(STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) +{ + uint8 signature[SEC_MAX_MODULUS_SIZE]; + uint32 sig_len; + + if (len != 72) + { + return True; + } + memset(signature, 0, sizeof(signature)); + sig_len = len - 8; + in_uint8a(s, signature, sig_len); + //return ssl_sig_ok((char *)exponent, SEC_EXPONENT_SIZE, (char *)modulus, g_server_public_key_len, + // (char *)signature, sig_len); + return TRUE; +} + /* Parse a crypto information structure */ -static BOOL +static RD_BOOL sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, - uint8 ** server_random, uint8 ** modulus, uint8 ** exponent) + uint8 ** server_random, uint8 * modulus, uint8 * exponent) { uint32 crypt_level, random_len, rsa_info_len; uint32 /*cacert_len, cert_len,*/ flags; - //X509 *cacert, *server_cert; + //RDSSL_CERT *cacert, *server_cert; + //RDSSL_RKEY *server_public_key; uint16 tag, length; uint8 *next_tag, *end; in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */ - if (crypt_level == 0) /* no encryption */ + if (crypt_level == 0) + { + /* no encryption */ return False; + } + in_uint32_le(s, random_len); in_uint32_le(s, rsa_info_len); @@ -646,10 +662,8 @@ break; case SEC_TAG_KEYSIG: - /* Is this a Microsoft key that we just got? */ - /* Care factor: zero! */ - /* Actually, it would probably be a good idea to check if the public key is signed with this key, and then store this - key as a known key of the hostname. This would prevent some MITM-attacks. */ + if (!sec_parse_public_sig(s, length, modulus, exponent)) + return False; break; default: @@ -660,30 +674,27 @@ } } else - { + { #if 0 uint32 certcount; DEBUG_RDP5(("We're going for the RDP5-style encryption\n")); in_uint32_le(s, certcount); /* Number of certificates */ - if (certcount < 2) { error("Server didn't send enough X509 certificates\n"); return False; } - for (; certcount > 2; certcount--) { /* ignore all the certificates between the root and the signing CA */ uint32 ignorelen; - X509 *ignorecert; + RDSSL_CERT *ignorecert; DEBUG_RDP5(("Ignored certs left: %d\n", certcount)); - in_uint32_le(s, ignorelen); DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen)); - ignorecert = d2i_X509(NULL, &(s->p), ignorelen); - + ignorecert = rdssl_cert_read(s->p, ignorelen); + in_uint8s(s, ignorelen); if (ignorecert == NULL) { /* XXX: error out? */ DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n")); @@ -691,12 +702,11 @@ #ifdef WITH_DEBUG_RDP5 DEBUG_RDP5(("cert #%d (ignored):\n", certcount)); - X509_print_fp(stdout, ignorecert); + rdssl_cert_print_fp(stdout, ignorecert); #endif } + /* Do da funky X.509 stuffy - /* Do da funky X.509 stuffy - "How did I find out about this? I looked up and saw a bright light and when I came to I had a scar on my forehead and knew about X.500" @@ -703,52 +713,58 @@ - Peter Gutman in a early version of http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt */ - in_uint32_le(s, cacert_len); DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len)); - cacert = d2i_X509(NULL, &(s->p), cacert_len); - /* Note: We don't need to move s->p here - d2i_X509 is - "kind" enough to do it for us */ + cacert = rdssl_cert_read(s->p, cacert_len); + in_uint8s(s, cacert_len); if (NULL == cacert) { error("Couldn't load CA Certificate from server\n"); return False; } - - /* Currently, we don't use the CA Certificate. - FIXME: - *) Verify the server certificate (server_cert) with the - CA certificate. - *) Store the CA Certificate with the hostname of the - server we are connecting to as key, and compare it - when we connect the next time, in order to prevent - MITM-attacks. - */ - - X509_free(cacert); - in_uint32_le(s, cert_len); DEBUG_RDP5(("Certificate length is %d\n", cert_len)); - server_cert = d2i_X509(NULL, &(s->p), cert_len); + server_cert = rdssl_cert_read(s->p, cert_len); + in_uint8s(s, cert_len); if (NULL == server_cert) { + rdssl_cert_free(cacert); error("Couldn't load Certificate from server\n"); return False; } - + if (!rdssl_certs_ok(server_cert, cacert)) + { + rdssl_cert_free(server_cert); + rdssl_cert_free(cacert); + error("Security error CA Certificate invalid\n"); + return False; + } + rdssl_cert_free(cacert); in_uint8s(s, 16); /* Padding */ - - /* Note: Verifying the server certificate must be done here, - before sec_parse_public_key since we'll have to apply - serious violence to the key after this */ - - if (!sec_parse_x509_key(server_cert)) + server_public_key = rdssl_cert_to_rkey(server_cert, &g_server_public_key_len); + if (NULL == server_public_key) { DEBUG_RDP5(("Didn't parse X509 correctly\n")); - X509_free(server_cert); + rdssl_cert_free(server_cert); return False; } - X509_free(server_cert); + rdssl_cert_free(server_cert); + if ((g_server_public_key_len < SEC_MODULUS_SIZE) || + (g_server_public_key_len > SEC_MAX_MODULUS_SIZE)) + { + error("Bad server public key size (%u bits)\n", + g_server_public_key_len * 8); + rdssl_rkey_free(server_public_key); + return False; + } + if (rdssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE, + modulus, SEC_MAX_MODULUS_SIZE) != 0) + { + error("Problem extracting RSA exponent, modulus"); + rdssl_rkey_free(server_public_key); + return False; + } + rdssl_rkey_free(server_public_key); return True; /* There's some garbage here we don't care about */ #endif } @@ -759,51 +775,23 @@ static void sec_process_crypt_info(STREAM s) { - uint8 *server_random, *modulus, *exponent; - uint8 client_random[SEC_RANDOM_SIZE]; + uint8 *server_random = NULL; + uint8 modulus[SEC_MAX_MODULUS_SIZE]; + uint8 exponent[SEC_EXPONENT_SIZE]; uint32 rc4_key_size; - //uint8 inr[SEC_MODULUS_SIZE]; - if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent)) + memset(modulus, 0, sizeof(modulus)); + memset(exponent, 0, sizeof(exponent)); + if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent)) { DEBUG(("Failed to parse crypt info\n")); return; } - DEBUG(("Generating client random\n")); - /* Generate a client random, and hence determine encryption keys */ - /* This is what the MS client do: */ - //memset(inr, 0, SEC_RANDOM_SIZE); - /* *ARIGL!* Plaintext attack, anyone? - I tried doing: - generate_random(inr); - ..but that generates connection errors now and then (yes, - "now and then". Something like 0 to 3 attempts needed before a - successful connection. Nice. Not! - */ - generate_random(client_random); - if (NULL != server_public_key) - { /* Which means we should use - RDP5-style encryption */ -#if 0 - memcpy(inr + SEC_RANDOM_SIZE, client_random, SEC_RANDOM_SIZE); - reverse(inr + SEC_RANDOM_SIZE, SEC_RANDOM_SIZE); - - RSA_public_encrypt(SEC_MODULUS_SIZE, - inr, sec_crypted_random, server_public_key, RSA_NO_PADDING); - - reverse(sec_crypted_random, SEC_MODULUS_SIZE); - - RSA_free(server_public_key); - server_public_key = NULL; -#endif - } - else - { /* RDP4-style encryption */ - sec_rsa_encrypt(sec_crypted_random, - client_random, SEC_RANDOM_SIZE, server_public_key_len, modulus, exponent); - } - sec_generate_keys(client_random, server_random, rc4_key_size); + generate_random(g_client_random); + sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE, + g_server_public_key_len, modulus, exponent); + sec_generate_keys(g_client_random, server_random, rc4_key_size); } @@ -815,7 +803,7 @@ DEBUG_RDP5(("Server RDP version is %d\n", g_server_rdp_version)); if (1 == g_server_rdp_version) { - g_use_rdp5 = 0; + g_rdp_version = RDP_V4; g_server_depth = 8; } } @@ -890,62 +878,74 @@ return s; } } - if (g_encryption || !g_licence_issued) + if (g_encryption || (!g_licence_issued && !g_licence_error_result)) { in_uint32_le(s, sec_flags); - if (sec_flags & SEC_ENCRYPT) + if (g_encryption) { - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); - } + if (sec_flags & SEC_ENCRYPT) + { + in_uint8s(s, 8); /* signature */ + sec_decrypt(s->p, s->end - s->p); + } - if (sec_flags & SEC_LICENCE_NEG) - { - licence_process(s); - continue; - } + if (sec_flags & SEC_LICENCE_NEG) + { + licence_process(s); + continue; + } - if (sec_flags & 0x0400) /* SEC_REDIRECT_ENCRYPT */ - { - uint8 swapbyte; + if (sec_flags & 0x0400) /* SEC_REDIRECT_ENCRYPT */ + { + uint8 swapbyte; - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); + in_uint8s(s, 8); /* signature */ + sec_decrypt(s->p, s->end - s->p); - /* Check for a redirect packet, starts with 00 04 */ - if (s->p[0] == 0 && s->p[1] == 4) - { - /* for some reason the PDU and the length seem to be swapped. - This isn't good, but we're going to do a byte for byte - swap. So the first foure value appear as: 00 04 XX YY, - where XX YY is the little endian length. We're going to - use 04 00 as the PDU type, so after our swap this will look - like: XX YY 04 00 */ - swapbyte = s->p[0]; - s->p[0] = s->p[2]; - s->p[2] = swapbyte; + /* Check for a redirect packet, starts with 00 04 */ + if (s->p[0] == 0 && s->p[1] == 4) + { + /* for some reason the PDU and the length seem to be swapped. + This isn't good, but we're going to do a byte for byte + swap. So the first foure value appear as: 00 04 XX YY, + where XX YY is the little endian length. We're going to + use 04 00 as the PDU type, so after our swap this will look + like: XX YY 04 00 */ + swapbyte = s->p[0]; + s->p[0] = s->p[2]; + s->p[2] = swapbyte; - swapbyte = s->p[1]; - s->p[1] = s->p[3]; - s->p[3] = swapbyte; + swapbyte = s->p[1]; + s->p[1] = s->p[3]; + s->p[3] = swapbyte; - swapbyte = s->p[2]; - s->p[2] = s->p[3]; - s->p[3] = swapbyte; - } + swapbyte = s->p[2]; + s->p[2] = s->p[3]; + s->p[3] = swapbyte; + } #ifdef WITH_DEBUG - /* warning! this debug statement will show passwords in the clear! */ - hexdump(s->p, s->end - s->p); + /* warning! this debug statement will show passwords in the clear! */ + hexdump(s->p, s->end - s->p); #endif + } } - + else + { + if ((sec_flags & 0xffff) == SEC_LICENCE_NEG) + { + licence_process(s); + continue; + } + s->p -= 4; + } } if (channel != MCS_GLOBAL_CHANNEL) { channel_process(s, channel); - *rdpver = 0xff; + if (rdpver != NULL) + *rdpver = 0xff; return s; } @@ -956,41 +956,26 @@ } /* Establish a secure connection */ -BOOL -sec_connect(char *server, char *username) +RD_BOOL +sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect) { + uint32 selected_proto; struct stream mcs_data; - /* We exchange some RDP data during the MCS-Connect */ - mcs_data.size = 512; - mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size); - sec_out_mcs_data(&mcs_data); - - if (!mcs_connect(server, &mcs_data, username)) + /* Start a MCS connect sequence */ + if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto)) return False; - /* sec_process_mcs_data(&mcs_data); */ - if (g_encryption) - sec_establish_key(); - xfree(mcs_data.data); - return True; -} - -/* Establish a secure connection */ -BOOL -sec_reconnect(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 = (uint8 *) xmalloc(mcs_data.size); - sec_out_mcs_data(&mcs_data); + sec_out_mcs_data(&mcs_data, selected_proto); - if (!mcs_reconnect(server, &mcs_data)) + /* finialize the MCS connect sequence */ + if (!mcs_connect_finalize(&mcs_data)) return False; - /* sec_process_mcs_data(&mcs_data); */ + /* sec_process_mcs_data(&mcs_data); */ if (g_encryption) sec_establish_key(); xfree(mcs_data.data); @@ -1009,7 +994,9 @@ sec_reset_state(void) { g_server_rdp_version = 0; - sec_encrypt_use_count = 0; - sec_decrypt_use_count = 0; + g_sec_encrypt_use_count = 0; + g_sec_decrypt_use_count = 0; + g_licence_issued = 0; + g_licence_error_result = 0; mcs_reset_state(); } Index: reactos/base/applications/mstsc/tcp.c =================================================================== --- reactos/base/applications/mstsc/tcp.c (revision 66177) +++ reactos/base/applications/mstsc/tcp.c (working copy) @@ -1,11 +1,13 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - TCP layer - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2005-2011 Peter Astrand for Cendio AB + Copyright 2012-2013 Henrik Andersson for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,9 +15,8 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "precomp.h" @@ -37,24 +38,51 @@ #define INADDR_NONE ((unsigned long) -1) #endif -static int sock; -static struct stream in; -static struct stream out; +#ifdef WITH_SCARD +#define STREAM_COUNT 8 +#else +#define STREAM_COUNT 1 +#endif + +#ifdef WITH_SSL +static RD_BOOL g_ssl_initialized = False; +static SSL *g_ssl = NULL; +static SSL_CTX *g_ssl_ctx = NULL; +#endif /* WITH_SSL */ +static int g_sock; +static RD_BOOL g_run_ui = False; +static struct stream g_in; +static struct stream g_out[STREAM_COUNT]; int g_tcp_port_rdp = TCP_PORT_RDP; +extern RD_BOOL g_user_quit; +extern RD_BOOL g_network_error; +extern RD_BOOL g_reconnect_loop; /* Initialise TCP transport data packet */ STREAM tcp_init(uint32 maxlen) { - if (maxlen > out.size) + static int cur_stream_id = 0; + STREAM result = NULL; + +#ifdef WITH_SCARD + scard_lock(SCARD_LOCK_TCP); +#endif + result = &g_out[cur_stream_id]; + cur_stream_id = (cur_stream_id + 1) % STREAM_COUNT; + + if (maxlen > result->size) { - out.data = (uint8 *) xrealloc(out.data, maxlen); - out.size = maxlen; + result->data = (uint8 *) xrealloc(result->data, maxlen); + result->size = maxlen; } - out.p = out.data; - out.end = out.data + out.size; - return &out; + result->p = result->data; + result->end = result->data + result->size; +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_TCP); +#endif + return result; } /* Send TCP transport data packet */ @@ -61,27 +89,75 @@ void tcp_send(STREAM s) { +#ifdef WITH_SSL + int ssl_err; +#endif /* WITH_SSL */ int length = s->end - s->data; int sent, total = 0; + if (g_network_error == True) + return; + +#ifdef WITH_SCARD + scard_lock(SCARD_LOCK_TCP); +#endif while (total < length) { - sent = send(sock, (char *)s->data + total, length - total, 0); - if (sent <= 0) +#ifdef WITH_SSL + if (g_ssl) { - if (sent == -1 && TCP_BLOCKS) + sent = SSL_write(g_ssl, s->data + total, length - total); + if (sent <= 0) { - TCP_SLEEP(0); - sent = 0; + ssl_err = SSL_get_error(g_ssl, sent); + if (sent < 0 && (ssl_err == SSL_ERROR_WANT_READ || + ssl_err == SSL_ERROR_WANT_WRITE)) + { + TCP_SLEEP(0); + sent = 0; + } + else + { +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_TCP); +#endif + + error("SSL_write: %d (%s)\n", ssl_err, TCP_STRERROR); + g_network_error = True; + return; + } } - else + } + else + { +#endif /* WITH_SSL */ + sent = send(g_sock, (const char *)s->data + total, length - total, 0); + if (sent <= 0) { - error("send: %s\n", TCP_STRERROR); - return; + if (sent == -1 && TCP_BLOCKS) + { + TCP_SLEEP(0); + sent = 0; + } + else + { +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_TCP); +#endif + + error("send: %s\n", TCP_STRERROR); + g_network_error = True; + return; + } } +#ifdef WITH_SSL } +#endif /* WITH_SSL */ total += sent; } +#ifdef WITH_SCARD + scard_unlock(SCARD_LOCK_TCP); +#endif } /* Receive a message on the TCP layer */ @@ -88,19 +164,25 @@ STREAM tcp_recv(STREAM s, uint32 length) { - unsigned int new_length, end_offset, p_offset; + uint32 new_length, end_offset, p_offset; int rcvd = 0; +#ifdef WITH_SSL + int ssl_err; +#endif /* WITH_SSL */ + if (g_network_error == True) + return NULL; + if (s == NULL) { /* read into "new" stream */ - if (length > in.size) + if (length > g_in.size) { - in.data = (uint8 *) xrealloc(in.data, length); - in.size = length; + g_in.data = (uint8 *) xrealloc(g_in.data, length); + g_in.size = length; } - in.end = in.p = in.data; - s = ∈ + g_in.end = g_in.p = g_in.data; + s = &g_in; } else { @@ -119,29 +201,76 @@ while (length > 0) { - if (!ui_select(sock)) - /* User quit */ - return NULL; +#ifdef WITH_SSL + if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui) +#else /* WITH_SSL */ + if (g_run_ui) +#endif /* WITH_SSL */ + { + if (!ui_select(g_sock)) + { + /* User quit */ + g_user_quit = True; + return NULL; + } + } - rcvd = recv(sock, (char *)s->end, length, 0); - if (rcvd < 0) +#ifdef WITH_SSL + if (g_ssl) { - if (rcvd == -1 && TCP_BLOCKS) + rcvd = SSL_read(g_ssl, s->end, length); + ssl_err = SSL_get_error(g_ssl, rcvd); + + if (ssl_err == SSL_ERROR_SSL) { - TCP_SLEEP(0); + if (SSL_get_shutdown(g_ssl) & SSL_RECEIVED_SHUTDOWN) + { + error("Remote peer initiated ssl shutdown.\n"); + return NULL; + } + + ERR_print_errors_fp(stdout); + g_network_error = True; + return NULL; + } + + if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) + { rcvd = 0; } - else + else if (ssl_err != SSL_ERROR_NONE) { - error("recv: %s\n", TCP_STRERROR); + error("SSL_read: %d (%s)\n", ssl_err, TCP_STRERROR); + g_network_error = True; return NULL; } + } - else if (rcvd == 0) + else { - error("Connection closed\n"); - return NULL; +#endif /* WITH_SSL */ + rcvd = recv(g_sock, (char *)s->end, length, 0); + if (rcvd < 0) + { + if (rcvd == -1 && TCP_BLOCKS) + { + rcvd = 0; + } + else + { + error("recv: %s\n", TCP_STRERROR); + g_network_error = True; + return NULL; + } + } + else if (rcvd == 0) + { + error("Connection closed\n"); + return NULL; + } +#ifdef WITH_SSL } +#endif /* WITH_SSL */ s->end += rcvd; length -= rcvd; @@ -150,11 +279,137 @@ return s; } +#ifdef WITH_SSL +/* Establish a SSL/TLS 1.0 connection */ +RD_BOOL +tcp_tls_connect(void) +{ + int err; + long options; + + if (!g_ssl_initialized) + { + SSL_load_error_strings(); + SSL_library_init(); + g_ssl_initialized = True; + } + + /* create process context */ + if (g_ssl_ctx == NULL) + { + g_ssl_ctx = SSL_CTX_new(TLSv1_client_method()); + if (g_ssl_ctx == NULL) + { + error("tcp_tls_connect: SSL_CTX_new() failed to create TLS v1.0 context\n"); + goto fail; + } + + options = 0; +#ifdef SSL_OP_NO_COMPRESSION + options |= SSL_OP_NO_COMPRESSION; +#endif // __SSL_OP_NO_COMPRESSION + options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + SSL_CTX_set_options(g_ssl_ctx, options); + } + + /* free old connection */ + if (g_ssl) + SSL_free(g_ssl); + + /* create new ssl connection */ + g_ssl = SSL_new(g_ssl_ctx); + if (g_ssl == NULL) + { + error("tcp_tls_connect: SSL_new() failed\n"); + goto fail; + } + + if (SSL_set_fd(g_ssl, g_sock) < 1) + { + error("tcp_tls_connect: SSL_set_fd() failed\n"); + goto fail; + } + + do + { + err = SSL_connect(g_ssl); + } + while (SSL_get_error(g_ssl, err) == SSL_ERROR_WANT_READ); + + if (err < 0) + { + ERR_print_errors_fp(stdout); + goto fail; + } + + return True; + + fail: + if (g_ssl) + SSL_free(g_ssl); + if (g_ssl_ctx) + SSL_CTX_free(g_ssl_ctx); + + g_ssl = NULL; + g_ssl_ctx = NULL; + return False; +} + +/* Get public key from server of TLS 1.0 connection */ +RD_BOOL +tcp_tls_get_server_pubkey(STREAM s) +{ + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + + s->data = s->p = NULL; + s->size = 0; + + if (g_ssl == NULL) + goto out; + + cert = SSL_get_peer_certificate(g_ssl); + if (cert == NULL) + { + error("tcp_tls_get_server_pubkey: SSL_get_peer_certificate() failed\n"); + goto out; + } + + pkey = X509_get_pubkey(cert); + if (pkey == NULL) + { + error("tcp_tls_get_server_pubkey: X509_get_pubkey() failed\n"); + goto out; + } + + s->size = i2d_PublicKey(pkey, NULL); + if (s->size < 1) + { + error("tcp_tls_get_server_pubkey: i2d_PublicKey() failed\n"); + goto out; + } + + s->data = s->p = xmalloc(s->size); + i2d_PublicKey(pkey, &s->p); + s->p = s->data; + s->end = s->p + s->size; + + out: + if (cert) + X509_free(cert); + if (pkey) + EVP_PKEY_free(pkey); + return (s->size != 0); +} +#endif /* WITH_SSL */ + /* Establish a connection on the TCP layer */ -BOOL +RD_BOOL tcp_connect(char *server) { - int true_value = 1; + socklen_t option_len; + uint32 option_value; + int i; #ifdef IPv6 @@ -175,22 +430,22 @@ } ressave = res; - sock = -1; + g_sock = -1; while (res) { - sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (!(sock < 0)) + g_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (!(g_sock < 0)) { - if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) + if (connect(g_sock, res->ai_addr, res->ai_addrlen) == 0) break; - TCP_CLOSE(sock); - sock = -1; + TCP_CLOSE(g_sock); + g_sock = -1; } res = res->ai_next; } freeaddrinfo(ressave); - if (sock == -1) + if (g_sock == -1) { error("%s: unable to connect\n", server); return False; @@ -211,7 +466,7 @@ return False; } - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + if ((g_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("socket: %s\n", TCP_STRERROR); return False; @@ -220,22 +475,41 @@ servaddr.sin_family = AF_INET; servaddr.sin_port = htons((uint16) g_tcp_port_rdp); - if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) + if (connect(g_sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) { - error("connect: %s\n", TCP_STRERROR); - TCP_CLOSE(sock); + if (!g_reconnect_loop) + error("connect: %s\n", TCP_STRERROR); + + TCP_CLOSE(g_sock); + g_sock = -1; return False; } #endif /* IPv6 */ - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value)); + option_value = 1; + option_len = sizeof(option_value); + setsockopt(g_sock, IPPROTO_TCP, TCP_NODELAY, (void *) &option_value, option_len); + /* receive buffer must be a least 16 K */ + if (getsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, &option_len) == 0) + { + if (option_value < (1024 * 16)) + { + option_value = 1024 * 16; + option_len = sizeof(option_value); + setsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, + option_len); + } + } - in.size = 4096; - in.data = (uint8 *) xmalloc(in.size); + g_in.size = 4096; + g_in.data = (uint8 *) xmalloc(g_in.size); - out.size = 4096; - out.data = (uint8 *) xmalloc(out.size); + for (i = 0; i < STREAM_COUNT; i++) + { + g_out[i].size = 4096; + g_out[i].data = (uint8 *) xmalloc(g_out[i].size); + } return True; } @@ -244,7 +518,19 @@ void tcp_disconnect(void) { - TCP_CLOSE(sock); +#ifdef WITH_SSL + if (g_ssl) + { + if (!g_network_error) + (void) SSL_shutdown(g_ssl); + SSL_free(g_ssl); + g_ssl = NULL; + SSL_CTX_free(g_ssl_ctx); + g_ssl_ctx = NULL; + } +#endif /* WITH_SSL */ + TCP_CLOSE(g_sock); + g_sock = -1; } char * @@ -253,9 +539,9 @@ static char ipaddr[32]; struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); - if (getsockname(sock, (struct sockaddr *) &sockaddr, &len) == 0) + if (getsockname(g_sock, (struct sockaddr *) &sockaddr, &len) == 0) { - unsigned char *ip = (unsigned char *) &sockaddr.sin_addr; + uint8 *ip = (uint8 *) & sockaddr.sin_addr; sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } else @@ -263,36 +549,55 @@ return ipaddr; } +RD_BOOL +tcp_is_connected() +{ + struct sockaddr_in sockaddr; + socklen_t len = sizeof(sockaddr); + if (getpeername(g_sock, (struct sockaddr *) &sockaddr, &len)) + return True; + return False; +} + /* reset the state of the tcp layer */ /* Support for Session Directory */ void tcp_reset_state(void) { - sock = -1; /* reset socket */ + int i; /* Clear the incoming stream */ - if (in.data != NULL) - xfree(in.data); - in.p = NULL; - in.end = NULL; - in.data = NULL; - in.size = 0; - in.iso_hdr = NULL; - in.mcs_hdr = NULL; - in.sec_hdr = NULL; - in.rdp_hdr = NULL; - in.channel_hdr = NULL; + if (g_in.data != NULL) + xfree(g_in.data); + g_in.p = NULL; + g_in.end = NULL; + g_in.data = NULL; + g_in.size = 0; + g_in.iso_hdr = NULL; + g_in.mcs_hdr = NULL; + g_in.sec_hdr = NULL; + g_in.rdp_hdr = NULL; + g_in.channel_hdr = NULL; - /* Clear the outgoing stream */ - if (out.data != NULL) - xfree(out.data); - out.p = NULL; - out.end = NULL; - out.data = NULL; - out.size = 0; - out.iso_hdr = NULL; - out.mcs_hdr = NULL; - out.sec_hdr = NULL; - out.rdp_hdr = NULL; - out.channel_hdr = NULL; + /* Clear the outgoing stream(s) */ + for (i = 0; i < STREAM_COUNT; i++) + { + if (g_out[i].data != NULL) + xfree(g_out[i].data); + g_out[i].p = NULL; + g_out[i].end = NULL; + g_out[i].data = NULL; + g_out[i].size = 0; + g_out[i].iso_hdr = NULL; + g_out[i].mcs_hdr = NULL; + g_out[i].sec_hdr = NULL; + g_out[i].rdp_hdr = NULL; + g_out[i].channel_hdr = NULL; + } } + +void +tcp_run_ui(RD_BOOL run) +{ + g_run_ui = run; +} Index: reactos/base/applications/mstsc/types.h =================================================================== --- reactos/base/applications/mstsc/types.h (revision 66177) +++ reactos/base/applications/mstsc/types.h (working copy) @@ -1,11 +1,12 @@ /* rdesktop: A Remote Desktop Protocol client. Common data types - Copyright (C) Matthew Chapman 1999-2005 + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2014 Henrik Andersson for Cendio AB - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -13,11 +14,12 @@ 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ +typedef int RD_BOOL; + #ifndef True #define True (1) #define False (0) @@ -35,6 +37,15 @@ typedef void *RD_HCOLOURMAP; typedef void *RD_HCURSOR; + +typedef enum _RDP_VERSION +{ + RDP_V4 = 4, + RDP_V5 = 5, + RDP_V6 = 6 +} RDP_VERSION; + + typedef struct _RD_POINT { sint16 x, y; @@ -77,6 +88,15 @@ } PEN; +/* this is whats in the brush cache */ +typedef struct _BRUSHDATA +{ + uint32 colour_code; + uint32 data_size; + uint8 *data; +} +BRUSHDATA; + typedef struct _BRUSH { uint8 xorigin; @@ -83,7 +103,7 @@ uint8 yorigin; uint8 style; uint8 pattern[8]; - + BRUSHDATA *bd; } BRUSH; @@ -117,6 +137,16 @@ } key_translation; +typedef struct _key_translation_entry +{ + key_translation *tr; + /* The full KeySym for this entry, not KEYMAP_MASKed */ + uint32 keysym; + /* This will be non-NULL if there has been a hash collision */ + struct _key_translation_entry *next; +} +key_translation_entry; + typedef struct _VCHANNEL { uint16 mcs_id; @@ -143,7 +173,7 @@ #define MAX_CBSIZE 256 /* RDPSND */ -typedef struct +typedef struct _RD_WAVEFORMATEX { uint16 wFormatTag; uint16 nChannels; @@ -170,13 +200,13 @@ typedef struct _DEVICE_FNS { RD_NTSTATUS(*create) (uint32 device, uint32 desired_access, uint32 share_mode, - uint32 create_disposition, uint32 flags_and_attributes, char *filename, - RD_NTHANDLE * handle); + uint32 create_disposition, uint32 flags_and_attributes, + char *filename, RD_NTHANDLE * handle); RD_NTSTATUS(*close) (RD_NTHANDLE handle); RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, - uint32 * result); + uint32 * result); RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, - uint32 * result); + uint32 * result); RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out); } DEVICE_FNS; @@ -233,7 +263,7 @@ char *driver, *printer; uint32 bloblen; uint8 *blob; - BOOL default_printer; + RD_BOOL default_printer; } PRINTER; @@ -250,7 +280,6 @@ #define PATH_MAX 256 #endif -#ifndef _WIN32 typedef struct fileinfo { uint32 device_id, flags_and_attributes, accessmask; @@ -258,11 +287,10 @@ DIR *pdir; struct dirent *pdirent; char pattern[PATH_MAX]; - BOOL delete_on_close; + RD_BOOL delete_on_close; NOTIFY notify; uint32 info_class; } FILEINFO; -#endif -typedef BOOL(*str_handle_lines_t) (const char *line, void *data); +typedef RD_BOOL(*str_handle_lines_t) (const char *line, void *data); Index: reactos/base/applications/mstsc/uimain.c =================================================================== --- reactos/base/applications/mstsc/uimain.c (revision 66177) +++ reactos/base/applications/mstsc/uimain.c (working copy) @@ -29,17 +29,17 @@ char g_shell[256] = ""; char g_directory[256] = ""; char g_domain[256] = ""; -BOOL g_desktop_save = False; /* desktop save order */ -BOOL g_polygon_ellipse_orders = False; /* polygon / ellipse orders */ -BOOL g_bitmap_compression = True; +RD_BOOL g_desktop_save = False; /* desktop save order */ +RD_BOOL g_polygon_ellipse_orders = False; /* polygon / ellipse orders */ +RD_BOOL g_bitmap_compression = True; uint32 g_rdp5_performanceflags = - RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS; -BOOL g_bitmap_cache_persist_enable = False; -BOOL g_bitmap_cache_precache = True; -BOOL g_bitmap_cache = True; -BOOL g_encryption = True; + RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS | RDP5_NO_CURSOR_SHADOW; +RD_BOOL g_bitmap_cache_persist_enable = False; +RD_BOOL g_bitmap_cache_precache = True; +RD_BOOL g_bitmap_cache = True; +RD_BOOL g_encryption = True; int g_server_depth = 8; -BOOL g_use_rdp5 = False; +RD_BOOL g_use_rdp5 = False; int g_width = 800; int g_height = 600; uint32 g_keylayout = 0x409; /* Defaults to US keyboard layout */ @@ -46,7 +46,7 @@ int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */ int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */ int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */ -BOOL g_console_session = False; +RD_BOOL g_console_session = False; /* can't be static, hardware file or bsops need these */ int g_tcp_sck = 0; @@ -53,13 +53,19 @@ int pal_entries[256]; /* Session Directory redirection */ -BOOL g_redirect = False; -char g_redirect_server[64]; -char g_redirect_domain[16]; -char g_redirect_password[64]; -char g_redirect_username[64]; -char g_redirect_cookie[128]; +RD_BOOL g_redirect = False; +char g_redirect_server[256]; +uint32 g_redirect_server_len; +char g_redirect_domain[256]; +uint32 g_redirect_domain_len; +char g_redirect_username[256]; +uint32 g_redirect_username_len; +uint8 g_redirect_lb_info[256]; +uint32 g_redirect_lb_info_len; +uint8 g_redirect_cookie[256]; +uint32 g_redirect_cookie_len; uint32 g_redirect_flags = 0; +uint32 g_redirect_session_id = 0; extern int g_tcp_port_rdp; @@ -66,6 +72,20 @@ static int g_deactivated = 0; static uint32 g_ext_disc_reason = 0; +RDP_VERSION g_rdp_version = RDP_V5; /* Default to version 5 */ +RD_BOOL g_encryption_initial = True; +RD_BOOL g_user_quit = False; +RD_BOOL g_network_error = False; +uint8 g_client_random[SEC_RANDOM_SIZE]; +RD_BOOL g_pending_resize = False; +RD_BOOL g_numlock_sync = False; + +uint32 g_reconnect_logonid = 0; +char g_reconnect_random[16]; +time_t g_reconnect_random_ts; +RD_BOOL g_has_reconnect_random = False; +RD_BOOL g_reconnect_loop = False; + struct bitmap { uint8 * data; @@ -153,9 +173,9 @@ /*****************************************************************************/ void * -ui_create_cursor(uint32 x, uint32 y, +ui_create_cursor(unsigned int x, unsigned int y, int width, int height, - uint8 * andmask, uint8 * xormask) + uint8 * andmask, uint8 * xormask, int bpp) { int i; int j; @@ -645,7 +665,7 @@ /*****************************************************************************/ void -ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, +ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, BRUSH * brush, int bgcolour, int fgcolour) { /* not used */ @@ -653,7 +673,7 @@ /*****************************************************************************/ void -ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen) +ui_polyline(uint8 opcode, RD_POINT * points, int npoints, PEN * pen) { int i, x, y, dx, dy; if (npoints > 0) @@ -710,7 +730,7 @@ /*****************************************************************************/ void * -xrealloc(void * in, int size) +xrealloc(void * in, size_t size) { if (size < 1) { @@ -933,10 +953,10 @@ flags = RDP_LOGON_NORMAL; if (g_password[0] != 0) { - flags |= RDP_LOGON_AUTO; + flags |= RDP_INFO_AUTOLOGON; } if (!rdp_connect(g_servername, flags, g_domain, g_password, - g_shell, g_directory)) + g_shell, g_directory, FALSE)) { return 0; }