--- sourceforge.net/trunk/rdesktop/rdp.c 2003/05/05 12:20:53 371 +++ sourceforge.net/trunk/rdesktop/rdp.c 2003/10/29 14:14:46 532 @@ -2,17 +2,17 @@ rdesktop: A Remote Desktop Protocol client. Protocol services - RDP layer Copyright (C) Matthew Chapman 1999-2002 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -20,20 +20,21 @@ #include "rdesktop.h" -extern uint16 mcs_userid; -extern char username[16]; -extern BOOL bitmap_compression; -extern BOOL orders; -extern BOOL encryption; -extern BOOL desktop_save; -extern BOOL use_rdp5; -extern uint16 server_rdp_version; +extern uint16 g_mcs_userid; +extern char g_username[16]; +extern BOOL g_bitmap_compression; +extern BOOL g_orders; +extern BOOL g_encryption; +extern BOOL g_desktop_save; +extern BOOL g_use_rdp5; +extern uint16 g_server_rdp_version; +extern int g_server_bpp; -uint8 *next_packet; -uint32 rdp_shareid; +uint8 *g_next_packet; +uint32 g_rdp_shareid; #if WITH_DEBUG -static uint32 packetno; +static uint32 g_packetno; #endif /* Receive an RDP packet */ @@ -43,24 +44,24 @@ static STREAM rdp_s; uint16 length, pdu_type; - if ((rdp_s == NULL) || (next_packet >= rdp_s->end)) + if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end)) { rdp_s = sec_recv(); if (rdp_s == NULL) return NULL; - next_packet = rdp_s->p; + g_next_packet = rdp_s->p; } else { - rdp_s->p = next_packet; + rdp_s->p = g_next_packet; } in_uint16_le(rdp_s, length); /* 32k packets are really 8, keepalive fix */ if (length == 0x8000) { - next_packet += 8; + g_next_packet += 8; *type = 0; return rdp_s; } @@ -69,11 +70,11 @@ *type = pdu_type & 0xf; #if WITH_DEBUG - DEBUG(("RDP packet #%d, (type %x)\n", ++packetno, *type)); - // hexdump(next_packet, length); + DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type)); + hexdump(g_next_packet, length); #endif /* */ - next_packet += length; + g_next_packet += length; return rdp_s; } @@ -83,7 +84,7 @@ { STREAM s; - s = sec_init(encryption ? SEC_ENCRYPT : 0, maxlen + 18); + s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18); s_push_layer(s, rdp_hdr, 18); return s; @@ -100,9 +101,9 @@ out_uint16_le(s, length); out_uint16_le(s, (RDP_PDU_DATA | 0x10)); - out_uint16_le(s, (mcs_userid + 1001)); + out_uint16_le(s, (g_mcs_userid + 1001)); - out_uint32_le(s, rdp_shareid); + out_uint32_le(s, g_rdp_shareid); out_uint8(s, 0); /* pad */ out_uint8(s, 1); /* streamid */ out_uint16_le(s, (length - 14)); @@ -110,7 +111,7 @@ out_uint8(s, 0); /* compress_type */ out_uint16(s, 0); /* compress_len */ - sec_send(s, encryption ? SEC_ENCRYPT : 0); + sec_send(s, g_encryption ? SEC_ENCRYPT : 0); } /* Output a string in Unicode */ @@ -143,10 +144,10 @@ int len_ip = 2 * strlen("127.0.0.1"); int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll"); int packetlen = 0; - uint32 sec_flags = encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; + uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; STREAM s; - if (!use_rdp5 || 1 == server_rdp_version) + if (!g_use_rdp5 || 1 == g_server_rdp_version) { DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); @@ -170,37 +171,33 @@ { flags |= RDP_LOGON_BLOB; DEBUG_RDP5(("Sending RDP5-style Logon packet\n")); - packetlen = 4 + // Unknown uint32 - 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 - - s = sec_init(sec_flags, packetlen); + packetlen = 4 + // Unknown uint32 + 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 + + s = sec_init(sec_flags, packetlen); DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); - out_uint32(s, 0); // Unknown + out_uint32(s, 0); // Unknown out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_user); @@ -209,55 +206,61 @@ out_uint16_le(s, len_password); } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) { + if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) + { out_uint16_le(s, 0); } out_uint16_le(s, len_program); out_uint16_le(s, len_directory); if (0 < len_domain) rdp_out_unistr(s, domain, len_domain); - else + else out_uint16_le(s, 0); rdp_out_unistr(s, user, len_user); if (flags & RDP_LOGON_AUTO) { rdp_out_unistr(s, password, len_password); } - if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) { + if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) + { out_uint16_le(s, 0); } - if (0 < len_program) { + if (0 < len_program) + { rdp_out_unistr(s, program, len_program); - - } else { + + } + else + { out_uint16_le(s, 0); } - if (0 < len_directory) { + if (0 < len_directory) + { rdp_out_unistr(s, directory, len_directory); - } else { + } + else + { out_uint16_le(s, 0); - } + } out_uint16_le(s, 2); - out_uint16_le(s, len_ip+2); // Length of client ip + out_uint16_le(s, len_ip + 2); // Length of client ip rdp_out_unistr(s, "127.0.0.1", len_ip); - out_uint16_le(s, len_dll+2); + out_uint16_le(s, len_dll + 2); rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll); out_uint16_le(s, 0xffc4); out_uint16_le(s, 0xffff); - rdp_out_unistr(s, "GTB, normaltid", - 2*strlen("GTB, normaltid")); - out_uint8s(s, 62-2*strlen("GTB, normaltid")); - + 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")); + + 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); @@ -355,7 +358,7 @@ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16(s, 0); /* Pad */ out_uint16(s, 0); /* Compression types */ - out_uint16_le(s, use_rdp5 ? 0x40d : 0); + out_uint16_le(s, g_use_rdp5 ? 0x40d : 0); /* Pad, according to T.128. 0x40d seems to trigger the server to start sending RDP5 packets. @@ -384,7 +387,7 @@ out_uint16_le(s, 600); /* Desktop height */ out_uint16(s, 0); /* Pad */ out_uint16(s, 0); /* Allow resize */ - out_uint16_le(s, bitmap_compression ? 1 : 0); /* Support compression */ + out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */ out_uint16(s, 0); /* Unknown */ out_uint16_le(s, 1); /* Unknown */ out_uint16(s, 0); /* Pad */ @@ -405,7 +408,7 @@ order_caps[8] = 1; /* line */ order_caps[9] = 1; /* line */ order_caps[10] = 1; /* rect */ - order_caps[11] = (desktop_save == False ? 0 : 1); /* desksave */ + order_caps[11] = (g_desktop_save == False ? 0 : 1); /* desksave */ order_caps[13] = 1; /* memblt */ order_caps[14] = 1; /* triblt */ order_caps[22] = 1; /* polyline */ @@ -423,7 +426,7 @@ out_uint8p(s, order_caps, 32); /* Orders supported */ out_uint16_le(s, 0x6a1); /* Text capability flags */ out_uint8s(s, 6); /* Pad */ - out_uint32_le(s, desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ + out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ out_uint32(s, 0); /* Unknown */ out_uint32_le(s, 0x4e4); /* Unknown */ } @@ -432,16 +435,18 @@ static void rdp_out_bmpcache_caps(STREAM s) { + int Bpp; out_uint16_le(s, RDP_CAPSET_BMPCACHE); out_uint16_le(s, RDP_CAPLEN_BMPCACHE); + Bpp = (g_server_bpp + 7) / 8; out_uint8s(s, 24); /* unused */ out_uint16_le(s, 0x258); /* entries */ - out_uint16_le(s, 0x100); /* max cell size */ + out_uint16_le(s, 0x100 * Bpp); /* max cell size */ out_uint16_le(s, 0x12c); /* entries */ - out_uint16_le(s, 0x400); /* max cell size */ + out_uint16_le(s, 0x400 * Bpp); /* max cell size */ out_uint16_le(s, 0x106); /* entries */ - out_uint16_le(s, 0x1000); /* max cell size */ + out_uint16_le(s, 0x1000 * Bpp); /* max cell size */ } /* Output control capability set */ @@ -541,7 +546,7 @@ rdp_send_confirm_active(void) { STREAM s; - uint32 sec_flags = encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG; + 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 + @@ -552,9 +557,9 @@ out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE)); out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */ - out_uint16_le(s, (mcs_userid + 1001)); + out_uint16_le(s, (g_mcs_userid + 1001)); - out_uint32_le(s, rdp_shareid); + out_uint32_le(s, g_rdp_shareid); out_uint16_le(s, 0x3ea); /* userid */ out_uint16_le(s, sizeof(RDP_SOURCE)); out_uint16_le(s, caplen); @@ -584,9 +589,9 @@ { uint8 type; - in_uint32_le(s, rdp_shareid); + in_uint32_le(s, g_rdp_shareid); - DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", rdp_shareid)); + DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid)); rdp_send_confirm_active(); rdp_send_synchronise(); @@ -602,15 +607,6 @@ reset_order_state(); } -/* Process a null system pointer PDU */ -void -process_null_system_pointer_pdu(STREAM s) -{ - // FIXME: We should probably set another cursor here, - // like the X window system base cursor or something. - ui_set_cursor(cache_get_cursor(0)); -} - /* Process a colour pointer PDU */ void process_colour_pointer_pdu(STREAM s) @@ -643,6 +639,23 @@ ui_set_cursor(cache_get_cursor(cache_idx)); } +/* Process a system pointer PDU */ +void +process_system_pointer_pdu(STREAM s) +{ + uint16 system_pointer_type; + + in_uint16(s, system_pointer_type); + switch (system_pointer_type) + { + case RDP_NULL_POINTER: + ui_set_null_cursor(); + break; + + default: + unimpl("System pointer message 0x%x\n", system_pointer_type); + } +} /* Process a pointer PDU */ static void @@ -671,8 +684,12 @@ process_cached_pointer_pdu(s); break; + case RDP_POINTER_SYSTEM: + process_system_pointer_pdu(s); + break; + default: - DEBUG(("Pointer message 0x%x\n", message_type)); + unimpl("Pointer message 0x%x\n", message_type); } } @@ -707,10 +724,17 @@ DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n", left, top, right, bottom, width, height, Bpp, compress)); + /* Server may limit bpp - this is how we find out */ + if (g_server_bpp != bpp) + { + warning("Server limited colour depth to %d bits\n", bpp); + g_server_bpp = bpp; + } + if (!compress) { int y; - bmpdata = xmalloc(width * height * Bpp); + bmpdata = (uint8 *) xmalloc(width * height * Bpp); for (y = 0; y < height; y++) { in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)], @@ -733,7 +757,7 @@ in_uint8s(s, 4); /* line_size, final_size */ } in_uint8p(s, data, size); - bmpdata = xmalloc(width * height * Bpp); + bmpdata = (uint8 *) xmalloc(width * height * Bpp); if (bitmap_decompress(bmpdata, width, height, data, size, Bpp)) { ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); @@ -760,7 +784,7 @@ in_uint16_le(s, map.ncolours); in_uint8s(s, 2); /* pad */ - map.colours = xmalloc(3 * map.ncolours); + map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours); DEBUG(("PALETTE(c=%d)\n", map.ncolours)); @@ -841,13 +865,19 @@ /* User logged on */ break; + case RDP_DATA_PDU_DISCONNECT: + /* Normally received when user logs out or disconnects from a + console session on Windows XP and 2003 Server */ + DEBUG(("Received disconnect PDU\n")); + break; + default: unimpl("data PDU %d\n", data_pdu_type); } } /* Process incoming packets */ -void +BOOL rdp_main_loop(void) { uint8 type; @@ -862,6 +892,13 @@ break; case RDP_PDU_DEACTIVATE: + DEBUG(("RDP_PDU_DEACTIVATE\n")); + /* We thought we could detect a clean + shutdown of the session by this + packet, but it seems Windows 2003 + is sending us one of these when we + reconnect to a disconnected session + return True; */ break; case RDP_PDU_DATA: @@ -875,6 +912,10 @@ unimpl("PDU %d\n", type); } } + return True; + /* We want to detect if we got a clean shutdown, but we + can't. Se above. + return False; */ } /* Establish a connection up to the RDP layer */ @@ -882,10 +923,10 @@ rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, char *directory) { - if (!sec_connect(server, username)) + if (!sec_connect(server, g_username)) return False; - rdp_send_logon_info(flags, domain, username, password, command, directory); + rdp_send_logon_info(flags, domain, g_username, password, command, directory); return True; }