⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rdp.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- 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
#endif

/* Receive an RDP packet */
static STREAM
rdp_recv(RDPCLIENT * This, uint8 * type)
{
	static STREAM rdp_s; // FIXME HORROR
	uint16 length, pdu_type;
	uint8 rdpver;

	if ((rdp_s == NULL) || (This->next_packet >= rdp_s->end) || (This->next_packet == NULL))
	{
		rdp_s = sec_recv(This, &rdpver);
		if (rdp_s == NULL)
			return NULL;
		if (rdpver == 0xff)
		{
			This->next_packet = rdp_s->end;
			*type = 0;
			return rdp_s;
		}
		else if (rdpver != 3)
		{
			/* rdp5_process should move This->next_packet ok */
			if(!rdp5_process(This, rdp_s))
				return NULL;
			*type = 0;
			return rdp_s;
		}

		This->next_packet = rdp_s->p;
	}
	else
	{
		rdp_s->p = This->next_packet;
	}

	in_uint16_le(rdp_s, length);
	/* 32k packets are really 8, keepalive fix */
	if (length == 0x8000)
	{
		This->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", ++This->rdp.packetno, *type));
	hexdump(This->next_packet, length);
#endif /*  */

	This->next_packet += length;
	return rdp_s;
}

/* Initialise an RDP data packet */
static STREAM
rdp_init_data(RDPCLIENT * This, int maxlen)
{
	STREAM s;

	s = sec_init(This, This->encryption ? SEC_ENCRYPT : 0, maxlen + 18);

	if(s == NULL)
		return NULL;

	s_push_layer(s, rdp_hdr, 18);

	return s;
}

/* Send an RDP data packet */
static BOOL
rdp_send_data(RDPCLIENT * This, STREAM s, uint8 data_pdu_type)
{
	uint16 length;

	s_pop_layer(s, rdp_hdr);
	length = (uint16)(s->end - s->p);

	out_uint16_le(s, length);
	out_uint16_le(s, (RDP_PDU_DATA | 0x10));
	out_uint16_le(s, (This->mcs_userid + 1001));

	out_uint32_le(s, This->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 */

	return sec_send(This, s, This->encryption ? SEC_ENCRYPT : 0);
}

/* Output a string in Unicode */
void
rdp_out_unistr(RDPCLIENT * This, STREAM s, wchar_t *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 (This->rdp.iconv_works)
	{
		if (iconv_h == (iconv_t) - 1)
		{
			size_t i = 1, o = 4;
			if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, This->codepage)) == (iconv_t) - 1)
			{
				warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
					This->codepage, WINDOWS_CODEPAGE, (int) iconv_h);

				This->rdp.iconv_works = False;
				rdp_out_unistr(This, 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);

				This->rdp.iconv_works = False;
				rdp_out_unistr(This, 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);

			This->rdp.iconv_works = False;
			rdp_out_unistr(This, s, string, len);
			return;
		}

		s->p += len + 2;

	}
	else
#endif
	// TODO
	{
		int i = 0, j = 0;

		len += 2;

		while (i < len)
		{
			int c = string[j++];
			s->p[i++] = (c >> 0) & 0xFF;
			s->p[i++] = (c >> 8) & 0xFF;
		}

		s->p += len;
	}
}

/* Input a string in Unicode
 *
 * Returns str_len of string
 */
int
rdp_in_unistr(RDPCLIENT * This, STREAM s, wchar_t *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 (This->rdp.iconv_works)
	{
		if (iconv_h == (iconv_t) - 1)
		{
			if ((iconv_h = iconv_open(This->codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
			{
				warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
					WINDOWS_CODEPAGE, This->codepage, (int) iconv_h);

				This->rdp.iconv_works = False;
				return rdp_in_unistr(This, 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);

			This->rdp.iconv_works = False;
			return rdp_in_unistr(This, s, string, uni_len);
		}

		/* we must update the location of the current STREAM for future reads of s->p */
		s->p += uni_len;

		return pout - string;
	}
	else
#endif
	// TODO
	{
		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 BOOL
rdp_send_logon_info(RDPCLIENT * This, uint32 flags, wchar_t *domain, wchar_t *user,
		    wchar_t *password, wchar_t *program, wchar_t *directory)
{
	wchar_t *ipaddr = tcp_get_address(This);
	int len_domain = 2 * (int)wcslen(domain);
	int len_user = 2 * (int)wcslen(user);
	int len_password = 2 * (int)wcslen(password);
	int len_program = 2 * (int)wcslen(program);
	int len_directory = 2 * (int)wcslen(directory);
	int len_ip = 2 * (int)wcslen(ipaddr);
	int len_dll = 2 * (int)wcslen(L"C:\\WINNT\\System32\\mstscax.dll");
	int packetlen = 0;
	uint32 sec_flags = This->encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
	STREAM s;
	time_t t = time(NULL);
	time_t tzone;

	if (!This->use_rdp5 || 1 == This->server_rdp_version)
	{
		DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));

		s = sec_init(This, sec_flags, 18 + len_domain + len_user + len_password
			     + len_program + len_directory + 10);

		if(s == NULL)
			return False;

		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(This, s, domain, len_domain);
		rdp_out_unistr(This, s, user, len_user);
		rdp_out_unistr(This, s, password, len_password);
		rdp_out_unistr(This, s, program, len_program);
		rdp_out_unistr(This, 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(This, sec_flags, packetlen);
		DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));

		if(s == NULL)
			return False;

		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(This, s, domain, len_domain);
		else
			out_uint16_le(s, 0);
		rdp_out_unistr(This, s, user, len_user);
		if (flags & RDP_LOGON_AUTO)
		{
			rdp_out_unistr(This, 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(This, s, program, len_program);

		}
		else
		{
			out_uint16_le(s, 0);
		}
		if (0 < len_directory)
		{
			rdp_out_unistr(This, 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(This, s, ipaddr, len_ip);
		out_uint16_le(s, len_dll + 2);
		rdp_out_unistr(This, s, L"C:\\WINNT\\System32\\mstscax.dll", len_dll);

		tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
		out_uint32_le(s, (uint32)tzone);

		rdp_out_unistr(This, s, L"GTB, normaltid", 2 * (int)wcslen(L"GTB, normaltid"));
		out_uint8s(s, 62 - 2 * wcslen(L"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(This, s, L"GTB, sommartid", 2 * (int)wcslen(L"GTB, sommartid"));
		out_uint8s(s, 62 - 2 * wcslen(L"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, This->rdp5_performanceflags);
		out_uint32(s, 0);


	}
	s_mark_end(s);
	return sec_send(This, s, sec_flags);
}

/* Send a control PDU */
static BOOL
rdp_send_control(RDPCLIENT * This, uint16 action)
{
	STREAM s;

	s = rdp_init_data(This, 8);

	if(s == NULL)
		return False;

	out_uint16_le(s, action);
	out_uint16(s, 0);	/* userid */
	out_uint32(s, 0);	/* control id */

	s_mark_end(s);
	return rdp_send_data(This, s, RDP_DATA_PDU_CONTROL);
}

/* Send a synchronisation PDU */
static BOOL
rdp_send_synchronise(RDPCLIENT * This)
{
	STREAM s;

	s = rdp_init_data(This, 4);

	if(s == NULL)
		return False;

	out_uint16_le(s, 1);	/* type */
	out_uint16_le(s, 1002);

	s_mark_end(s);
	return rdp_send_data(This, s, RDP_DATA_PDU_SYNCHRONISE);
}

/* Send a single input event */
BOOL
rdp_send_input(RDPCLIENT * This, uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
{
	STREAM s;

	s = rdp_init_data(This, 16);

	if(s == NULL)
		return False;

	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);
	return rdp_send_data(This, s, RDP_DATA_PDU_INPUT);
}

/* Send a client window information PDU */
BOOL
rdp_send_client_window_status(RDPCLIENT * This, int status)
{
	STREAM s;

	if (This->rdp.current_status == status)
		return True;

	s = rdp_init_data(This, 12);

	if(s == NULL)
		return False;

	out_uint32_le(s, status);

	switch (status)
	{
		case 0:	/* shut the server up */
			break;

		case 1:	/* receive data again */
			out_uint32_le(s, 0);	/* unknown */
			out_uint16_le(s, This->width);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -