Blame libfreerdp/core/tpdu.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X.224 Transport Protocol Data Units (TPDUs)
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include "tpdu.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core")
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * TPDUs are defined in:
Packit 1fb8d4
 *
Packit 1fb8d4
 * http://www.itu.int/rec/T-REC-X.224-199511-I/
Packit Service 5a9772
 * X.224: Information technology - Open Systems Interconnection - Protocol for providing the
Packit Service 5a9772
 * connection-mode transport service
Packit 1fb8d4
 *
Packit 1fb8d4
 * RDP uses only TPDUs of class 0, the "simple class" defined in section 8 of X.224
Packit 1fb8d4
 *
Packit 1fb8d4
 *       TPDU Header
Packit 1fb8d4
 *  ____________________   byte
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |         LI         |   1
Packit 1fb8d4
 * |____________________|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |        Code        |   2
Packit 1fb8d4
 * |____________________|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |                    |   3
Packit 1fb8d4
 * |_______DST-REF______|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |                    |   4
Packit 1fb8d4
 * |____________________|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |                    |   5
Packit 1fb8d4
 * |_______SRC-REF______|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |                    |   6
Packit 1fb8d4
 * |____________________|
Packit 1fb8d4
 * |                    |
Packit 1fb8d4
 * |        Class       |   7
Packit 1fb8d4
 * |____________________|
Packit 1fb8d4
 * |         ...        |
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
static void tpdu_write_header(wStream* s, UINT16 length, BYTE code);
Packit Service 5a9772
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read TPDU header.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param code variable pointer to receive TPDU code
Packit 1fb8d4
 * @return TPDU length indicator (LI)
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li, UINT16 tpktlength)
Packit 1fb8d4
{
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 3)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Read_UINT8(s, *li);   /* LI */
Packit 1fb8d4
	Stream_Read_UINT8(s, *code); /* Code */
Packit 1fb8d4
Packit Service 5a9772
	if (*li + 4 > tpktlength)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_ERR(TAG, "tpdu length %" PRIu16 " > tpkt header length %" PRIu16, li, tpktlength);
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit 1fb8d4
	if (*code == X224_TPDU_DATA)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* EOT (1 byte) */
Packit 1fb8d4
		Stream_Seek(s, 1);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		/* DST-REF (2 bytes) */
Packit 1fb8d4
		/* SRC-REF (2 bytes) */
Packit 1fb8d4
		/* Class 0 (1 byte) */
Packit 1fb8d4
		return Stream_SafeSeek(s, 5);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write TDPU header.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length length
Packit 1fb8d4
 * @param code TPDU code
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void tpdu_write_header(wStream* s, UINT16 length, BYTE code)
Packit 1fb8d4
{
Packit 1fb8d4
	Stream_Write_UINT8(s, length); /* LI */
Packit Service 5a9772
	Stream_Write_UINT8(s, code);   /* code */
Packit 1fb8d4
Packit 1fb8d4
	if (code == X224_TPDU_DATA)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Write_UINT8(s, 0x80); /* EOT */
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Write_UINT16(s, 0); /* DST-REF */
Packit 1fb8d4
		Stream_Write_UINT16(s, 0); /* SRC-REF */
Packit Service 5a9772
		Stream_Write_UINT8(s, 0);  /* Class 0 */
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read Connection Request TPDU
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @return length indicator (LI)
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE code;
Packit 1fb8d4
Packit Service 5a9772
	if (!tpdu_read_header(s, &code, li, tpktlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (code != X224_TPDU_CONNECTION_REQUEST)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write Connection Request TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length TPDU length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void tpdu_write_connection_request(wStream* s, UINT16 length)
Packit 1fb8d4
{
Packit 1fb8d4
	tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read Connection Confirm TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @return length indicator (LI)
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE code;
Packit 1fb8d4
	size_t position;
Packit 1fb8d4
	size_t bytes_read = 0;
Packit 1fb8d4
Packit 1fb8d4
	/* save the position to determine the number of bytes read */
Packit 1fb8d4
	position = Stream_GetPosition(s);
Packit 1fb8d4
Packit Service 5a9772
	if (!tpdu_read_header(s, &code, li, tpktlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (code != X224_TPDU_CONNECTION_CONFIRM)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * To ensure that there are enough bytes remaining for processing
Packit 1fb8d4
	 * check against the length indicator (li). Already read bytes need
Packit 1fb8d4
	 * to be taken into account.
Packit 1fb8d4
	 * The -1 is because li was read but isn't included in the TPDU size.
Packit 1fb8d4
	 * For reference see ITU-T Rec. X.224 - 13.2.1
Packit 1fb8d4
	 */
Packit 1fb8d4
	bytes_read = (Stream_GetPosition(s) - position) - 1;
Packit 1fb8d4
Packit Service 5a9772
	return (Stream_GetRemainingLength(s) >= (size_t)(*li - bytes_read));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write Connection Confirm TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length TPDU length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void tpdu_write_connection_confirm(wStream* s, UINT16 length)
Packit 1fb8d4
{
Packit 1fb8d4
	tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write Disconnect Request TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 * @param length TPDU length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void tpdu_write_disconnect_request(wStream* s, UINT16 length)
Packit 1fb8d4
{
Packit 1fb8d4
	tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write Data TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void tpdu_write_data(wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	tpdu_write_header(s, 2, X224_TPDU_DATA);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read Data TPDU.
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE code;
Packit 1fb8d4
	BYTE li;
Packit 1fb8d4
Packit Service 5a9772
	if (!tpdu_read_header(s, &code, &li, tpktlength))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (code != X224_TPDU_DATA)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	*LI = li;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}