📄 rdp.c
字号:
/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP layer Copyright (C) Matthew Chapman 1999-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <time.h>#include <errno.h>#include <unistd.h>#include "rdesktop.h"#ifdef HAVE_ICONV#ifdef HAVE_ICONV_H#include <iconv.h>#endif#ifndef ICONV_CONST#define ICONV_CONST ""#endif#endifextern uint16 g_mcs_userid;extern char g_username[64];extern char g_codepage[16];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 uint16 g_server_rdp_version;extern uint32 g_rdp5_performanceflags;extern int g_server_bpp;extern int g_width;extern int g_height;extern BOOL g_bitmap_cache;extern BOOL g_bitmap_cache_persist_enable;extern BOOL g_rdp_compression;uint8 *g_next_packet;uint32 g_rdp_shareid;extern RDPCOMP g_mppc_dict;#if WITH_DEBUGstatic uint32 g_packetno;#endif#ifdef HAVE_ICONVstatic BOOL g_iconv_works = True;#endif/* Receive an RDP packet */static STREAMrdp_recv(uint8 * type){ static STREAM rdp_s; uint16 length, pdu_type; uint8 rdpver; if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end)) { rdp_s = sec_recv(&rdpver); if (rdp_s == NULL) return NULL; if (rdpver == 0xff) { g_next_packet = rdp_s->end; *type = 0; return rdp_s; } else if (rdpver != 3) { /* rdp5_process should move g_next_packet ok */ rdp5_process(rdp_s); *type = 0; return rdp_s; } g_next_packet = rdp_s->p; } else { rdp_s->p = g_next_packet; } in_uint16_le(rdp_s, length); /* 32k packets are really 8, keepalive fix */ if (length == 0x8000) { g_next_packet += 8; *type = 0; return rdp_s; } in_uint16_le(rdp_s, pdu_type); in_uint8s(rdp_s, 2); /* userid */ *type = pdu_type & 0xf;#if WITH_DEBUG DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type)); hexdump(g_next_packet, length);#endif /* */ g_next_packet += length; return rdp_s;}/* Initialise an RDP data packet */static STREAMrdp_init_data(int maxlen){ STREAM s; s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18); s_push_layer(s, rdp_hdr, 18); return s;}/* Send an RDP data packet */static voidrdp_send_data(STREAM s, uint8 data_pdu_type){ uint16 length; s_pop_layer(s, rdp_hdr); length = s->end - s->p; out_uint16_le(s, length); out_uint16_le(s, (RDP_PDU_DATA | 0x10)); out_uint16_le(s, (g_mcs_userid + 1001)); out_uint32_le(s, g_rdp_shareid); out_uint8(s, 0); /* pad */ out_uint8(s, 1); /* streamid */ out_uint16_le(s, (length - 14)); out_uint8(s, data_pdu_type); out_uint8(s, 0); /* compress_type */ out_uint16(s, 0); /* compress_len */ sec_send(s, g_encryption ? SEC_ENCRYPT : 0);}/* Output a string in Unicode */voidrdp_out_unistr(STREAM s, char *string, int len){#ifdef HAVE_ICONV size_t ibl = strlen(string), obl = len + 2; static iconv_t iconv_h = (iconv_t) - 1; char *pin = string, *pout = (char *) s->p; memset(pout, 0, len + 4); if (g_iconv_works) { if (iconv_h == (iconv_t) - 1) { size_t i = 1, o = 4; if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1) { warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n", g_codepage, WINDOWS_CODEPAGE, (int) iconv_h); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) == (size_t) - 1) { iconv_close(iconv_h); iconv_h = (iconv_t) - 1; warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } pin = string; pout = (char *) s->p; } 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_out_unistr: iconv(2) fail, errno %d\n", errno); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } s->p += len + 2; } else#endif { int i = 0, j = 0; len += 2; while (i < len) { s->p[i++] = string[j++]; s->p[i++] = 0; } s->p += len; }}/* Input a string in Unicode * * Returns str_len of string */intrdp_in_unistr(STREAM s, char *string, int uni_len){#ifdef HAVE_ICONV size_t ibl = uni_len, obl = uni_len; char *pin = (char *) s->p, *pout = string; static iconv_t iconv_h = (iconv_t) - 1; if (g_iconv_works) { if (iconv_h == (iconv_t) - 1) { if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1) { warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n", WINDOWS_CODEPAGE, g_codepage, (int) iconv_h); g_iconv_works = False; return rdp_in_unistr(s, string, uni_len); } } 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); g_iconv_works = False; return rdp_in_unistr(s, string, uni_len); } return pout - string; } else#endif { int i = 0; while (i < uni_len / 2) { in_uint8a(s, &string[i++], 1); in_uint8s(s, 1); } return i - 1; }}/* Parse a logon info packet */static voidrdp_send_logon_info(uint32 flags, char *domain, char *user, char *password, char *program, char *directory){ char *ipaddr = tcp_get_address(); 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"); int packetlen = 0; uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; STREAM s; time_t t = time(NULL); time_t tzone; if (!g_use_rdp5 || 1 == g_server_rdp_version) { DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); s = sec_init(sec_flags, 18 + len_domain + len_user + len_password + len_program + len_directory + 10); out_uint32(s, 0); out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_user); out_uint16_le(s, len_password); out_uint16_le(s, len_program); out_uint16_le(s, len_directory); rdp_out_unistr(s, domain, len_domain); rdp_out_unistr(s, user, len_user); rdp_out_unistr(s, password, len_password); rdp_out_unistr(s, program, len_program); rdp_out_unistr(s, directory, len_directory); } else { 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); DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); out_uint32(s, 0); /* Unknown */ 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_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) { rdp_out_unistr(s, password, len_password); } if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO)) { out_uint16_le(s, 0); } if (0 < len_program) { rdp_out_unistr(s, program, len_program); } 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); 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, g_rdp5_performanceflags); out_uint32(s, 0); } s_mark_end(s); sec_send(s, sec_flags);}/* Send a control PDU */static voidrdp_send_control(uint16 action){ STREAM s; s = rdp_init_data(8); out_uint16_le(s, action); out_uint16(s, 0); /* userid */ out_uint32(s, 0); /* control id */ s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_CONTROL);}/* Send a synchronisation PDU */static voidrdp_send_synchronise(void){ STREAM s; s = rdp_init_data(4); out_uint16_le(s, 1); /* type */ out_uint16_le(s, 1002); s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);}/* Send a single input event */voidrdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2){ STREAM s; s = rdp_init_data(16); out_uint16_le(s, 1); /* number of events */ out_uint16(s, 0); /* pad */ out_uint32_le(s, time); out_uint16_le(s, message_type); out_uint16_le(s, device_flags); out_uint16_le(s, param1); out_uint16_le(s, param2); s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_INPUT);}/* Inform the server on the contents of the persistent bitmap cache */static voidrdp_enum_bmpcache2(void){ STREAM s; HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS]; uint32 num_keys, offset, count, flags; offset = 0; num_keys = pstcache_enumerate(2, keylist); while (offset < num_keys) { count = MIN(num_keys - offset, 169); s = rdp_init_data(24 + count * sizeof(HASH_KEY)); flags = 0; if (offset == 0) flags |= PDU_FLAG_FIRST; if (num_keys - offset <= 169) flags |= PDU_FLAG_LAST; /* header */ out_uint32_le(s, 0); out_uint16_le(s, count); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, num_keys); out_uint32_le(s, 0); out_uint32_le(s, flags); /* list */ out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY)); s_mark_end(s); rdp_send_data(s, 0x2b); offset += 169; }}/* Send an (empty) font information PDU */static voidrdp_send_fonts(uint16 seq){ STREAM s; s = rdp_init_data(8); out_uint16(s, 0); /* number of fonts */ out_uint16_le(s, 0); /* pad? */ out_uint16_le(s, seq); /* unknown */ out_uint16_le(s, 0x32); /* entry size */ s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_FONT2);}/* Output general capability set */static voidrdp_out_general_caps(STREAM s){ out_uint16_le(s, RDP_CAPSET_GENERAL); out_uint16_le(s, RDP_CAPLEN_GENERAL); out_uint16_le(s, 1); /* OS major type */ out_uint16_le(s, 3); /* OS minor type */ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16(s, 0); /* Pad */ out_uint16(s, 0); /* Compression types */ out_uint16_le(s, g_use_rdp5 ? 0x40d : 0); /* Pad, according to T.128. 0x40d seems to trigger the server to start sending RDP5 packets. However, the value is 0x1d04 with W2KTSK and NT4MS. Hmm.. Anyway, thankyou, Microsoft, for sending such information in a padding field.. */ out_uint16(s, 0); /* Update capability */ out_uint16(s, 0); /* Remote unshare capability */ out_uint16(s, 0); /* Compression level */ out_uint16(s, 0); /* Pad */}/* Output bitmap capability set */static voidrdp_out_bitmap_caps(STREAM s){ out_uint16_le(s, RDP_CAPSET_BITMAP); out_uint16_le(s, RDP_CAPLEN_BITMAP); out_uint16_le(s, g_server_bpp); /* Preferred BPP */ out_uint16_le(s, 1); /* Receive 1 BPP */ out_uint16_le(s, 1); /* Receive 4 BPP */ out_uint16_le(s, 1); /* Receive 8 BPP */ out_uint16_le(s, 800); /* Desktop width */ out_uint16_le(s, 600); /* Desktop height */ out_uint16(s, 0); /* Pad */ out_uint16(s, 1); /* Allow resize */ 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 */}/* Output order capability set */static voidrdp_out_order_caps(STREAM s){ uint8 order_caps[32]; memset(order_caps, 0, 32); order_caps[0] = 1; /* dest blt */ order_caps[1] = 1; /* pat blt */ order_caps[2] = 1; /* screen blt */ order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */ order_caps[4] = 0; /* triblt */ order_caps[8] = 1; /* line */ order_caps[9] = 1; /* line */ order_caps[10] = 1; /* rect */ order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */ order_caps[13] = 1; /* memblt */ order_caps[14] = 1; /* triblt */ order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */ order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */ order_caps[22] = 1; /* polyline */ order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */ order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */ order_caps[27] = 1; /* text2 */ out_uint16_le(s, RDP_CAPSET_ORDER); out_uint16_le(s, RDP_CAPLEN_ORDER); out_uint8s(s, 20); /* Terminal desc, pad */ out_uint16_le(s, 1); /* Cache X granularity */ out_uint16_le(s, 20); /* Cache Y granularity */ out_uint16(s, 0); /* Pad */ out_uint16_le(s, 1); /* Max order level */ out_uint16_le(s, 0x147); /* Number of fonts */ out_uint16_le(s, 0x2a); /* Capability flags */ out_uint8p(s, order_caps, 32); /* Orders supported */ out_uint16_le(s, 0x6a1); /* Text capability flags */ out_uint8s(s, 6); /* Pad */ out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ out_uint32(s, 0); /* Unknown */ out_uint32_le(s, 0x4e4); /* Unknown */}/* Output bitmap cache capability set */static voidrdp_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 * Bpp); /* max cell size */ out_uint16_le(s, 0x12c); /* entries */ out_uint16_le(s, 0x400 * Bpp); /* max cell size */ out_uint16_le(s, 0x106); /* entries */ out_uint16_le(s, 0x1000 * Bpp); /* max cell size */}/* Output bitmap cache v2 capability set */static voidrdp_out_bmpcache2_caps(STREAM s){ out_uint16_le(s, RDP_CAPSET_BMPCACHE2); out_uint16_le(s, RDP_CAPLEN_BMPCACHE2); out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */ out_uint16_be(s, 3); /* number of caches in this set */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -