[rdpdr] fixed server side channel parsing

This commit is contained in:
akallabeth 2022-11-18 14:36:29 +01:00 committed by akallabeth
parent febc4b3073
commit a6593f2dc1

View File

@ -21,6 +21,7 @@
*/
#include <freerdp/config.h>
#include <freerdp/utils/rdpdr_utils.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
@ -31,10 +32,30 @@
#include <freerdp/channels/log.h>
#include "rdpdr_main.h"
#define TAG "rdpdr.server"
#define TAG CHANNELS_TAG("rdpdr.server")
#define RDPDR_ADD_PRINTER_EVENT 0x00000001
#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002
#define RDPDR_DELETE_PRINTER_EVENT 0x00000003
#define RDPDR_RENAME_PRINTER_EVENT 0x00000004
static UINT32 g_ClientId = 0;
static const WCHAR* rdpdr_read_ustring(wStream* s, size_t bytelen)
{
const size_t charlen = (bytelen + 1) / sizeof(WCHAR);
const WCHAR* str = (const WCHAR*)Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, bytelen))
return NULL;
if (_wcsnlen(str, charlen) == charlen)
{
WLog_WARN(TAG, "[rdpdr] unicode string not '\0' terminated");
return NULL;
}
Stream_Seek(s, bytelen);
return str;
}
static RDPDR_IRP* rdpdr_server_irp_new(void)
{
RDPDR_IRP* irp;
@ -153,6 +174,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context
RDPDR_HEADER* header)
{
UINT32 UnicodeFlag;
UINT32 CodePage;
UINT32 ComputerNameLen;
WINPR_ASSERT(context);
@ -165,12 +187,18 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */
Stream_Read_UINT32(s, CodePage); /* CodePage (4 bytes), MUST be set to zero */
Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
/* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored.
*/
UnicodeFlag = UnicodeFlag & 0x00000001;
if (CodePage != 0)
WLog_WARN(TAG,
"[MS-RDPEFS] 2.2.2.4 Client Name Request (DR_CORE_CLIENT_NAME_REQ)::CodePage "
"must be 0, but is 0x%08" PRIx32,
CodePage);
/**
* Caution: ComputerNameLen is given *bytes*,
* not in characters, including the NULL terminator!
@ -279,7 +307,7 @@ static UINT rdpdr_server_write_capability_set_header(wStream* s, RDPDR_CAPABILIT
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context, wStream* s,
RDPDR_CAPABILITY_HEADER* header)
const RDPDR_CAPABILITY_HEADER* header)
{
UINT32 ioCode1;
UINT32 extraFlags1;
@ -413,7 +441,7 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* contex
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, wStream* s,
RDPDR_CAPABILITY_HEADER* header)
const RDPDR_CAPABILITY_HEADER* header)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
@ -457,7 +485,7 @@ static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* contex
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wStream* s,
RDPDR_CAPABILITY_HEADER* header)
const RDPDR_CAPABILITY_HEADER* header)
{
WINPR_UNUSED(context);
WINPR_UNUSED(s);
@ -499,7 +527,7 @@ static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context,
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, wStream* s,
RDPDR_CAPABILITY_HEADER* header)
const RDPDR_CAPABILITY_HEADER* header)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
@ -542,7 +570,7 @@ static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context,
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* context, wStream* s,
RDPDR_CAPABILITY_HEADER* header)
const RDPDR_CAPABILITY_HEADER* header)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
@ -702,6 +730,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co
for (i = 0; i < numCapabilities; i++)
{
RDPDR_CAPABILITY_HEADER capabilityHeader = { 0 };
const size_t start = Stream_GetPosition(s);
if ((status = rdpdr_server_read_capability_set_header(s, &capabilityHeader)))
{
@ -776,11 +805,29 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co
break;
default:
WLog_DBG(TAG, "Unknown capabilityType %" PRIu16 "",
capabilityHeader.CapabilityType);
Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH);
WLog_WARN(TAG, "Unknown capabilityType %" PRIu16 "",
capabilityHeader.CapabilityType);
if (Stream_GetRemainingLength(s) < capabilityHeader.CapabilityLength)
WLog_WARN(TAG,
"short capability data, expected %" PRIu16 ", but only got %" PRIuz
" bytes",
capabilityHeader.CapabilityLength, Stream_GetRemainingLength(s));
else
Stream_Seek(s,
capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH);
return ERROR_INVALID_DATA;
}
const size_t end = Stream_GetPosition(s);
const size_t diff = end - start;
if (diff != capabilityHeader.CapabilityLength)
{
WLog_WARN(TAG,
"{capability %s[0x%04" PRIx16 "]} processed %" PRIuz
" bytes, but expected to be %" PRIu16,
rdpdr_cap_type_string(capabilityHeader.CapabilityType),
capabilityHeader.CapabilityType, diff, capabilityHeader.CapabilityLength);
}
}
return CHANNEL_RC_OK;
@ -922,6 +969,11 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext
break;
default:
WLog_WARN(TAG,
"[MS-RDPEFS] 2.2.2.9 Client Device List Announce Request "
"(DR_CORE_DEVICELIST_ANNOUNCE_REQ) unknown device type %04" PRIx16
" at position %" PRIu32,
DeviceType, i);
break;
}
@ -937,7 +989,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* context, wStream* s,
RDPDR_HEADER* header)
const RDPDR_HEADER* header)
{
UINT32 i;
UINT32 DeviceCount;
@ -1006,6 +1058,428 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext*
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
const WCHAR* path;
UINT32 DesiredAccess, AllocationSize, FileAttributes, SharedAccess, CreateDisposition,
CreateOptions, PathLength;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, DesiredAccess);
Stream_Read_UINT32(s, AllocationSize);
Stream_Read_UINT32(s, FileAttributes);
Stream_Read_UINT32(s, SharedAccess);
Stream_Read_UINT32(s, CreateDisposition);
Stream_Read_UINT32(s, CreateOptions);
Stream_Read_UINT32(s, PathLength);
path = rdpdr_read_ustring(s, PathLength);
if (!path && (PathLength > 0))
return ERROR_INVALID_DATA;
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.1.4.1 Device Create Request (DR_CREATE_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_close_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Seek(s, 32); /* Padding */
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.1.4.2 Device Close Request (DR_CLOSE_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
UINT32 Length;
UINT64 Offset;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, Length);
Stream_Read_UINT64(s, Offset);
Stream_Seek(s, 20); /* Padding */
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.1.4.3 Device Read Request (DR_READ_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
UINT32 Length;
UINT64 Offset;
const BYTE* data;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, Length);
Stream_Read_UINT64(s, Offset);
Stream_Seek(s, 20); /* Padding */
data = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
return ERROR_INVALID_DATA;
Stream_Seek(s, Length);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.1.4.4 Device Write Request (DR_WRITE_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
UINT32 OutputBufferLength;
UINT32 InputBufferLength;
UINT32 IoControlCode;
const BYTE* InputBuffer;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, OutputBufferLength);
Stream_Read_UINT32(s, InputBufferLength);
Stream_Read_UINT32(s, IoControlCode);
Stream_Seek(s, 20); /* Padding */
InputBuffer = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, InputBufferLength))
return ERROR_INVALID_DATA;
Stream_Seek(s, InputBufferLength);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.1.4.5 Device Control Request (DR_CONTROL_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_query_volume_information_request(RdpdrServerContext* context,
wStream* s, UINT32 DeviceId,
UINT32 FileId,
UINT32 CompletionId)
{
UINT32 FsInformationClass;
UINT32 Length;
const BYTE* QueryVolumeBuffer;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, FsInformationClass);
Stream_Read_UINT32(s, Length);
Stream_Seek(s, 24); /* Padding */
QueryVolumeBuffer = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
return ERROR_INVALID_DATA;
Stream_Seek(s, Length);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.6 Server Drive Query Volume Information Request "
"(DR_DRIVE_QUERY_VOLUME_INFORMATION_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_set_volume_information_request(RdpdrServerContext* context,
wStream* s, UINT32 DeviceId,
UINT32 FileId,
UINT32 CompletionId)
{
UINT32 FsInformationClass;
UINT32 Length;
const BYTE* SetVolumeBuffer;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, FsInformationClass);
Stream_Read_UINT32(s, Length);
Stream_Seek(s, 24); /* Padding */
SetVolumeBuffer = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
return ERROR_INVALID_DATA;
Stream_Seek(s, Length);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.7 Server Drive Set Volume Information Request "
"(DR_DRIVE_SET_VOLUME_INFORMATION_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext* context,
wStream* s, UINT32 DeviceId,
UINT32 FileId, UINT32 CompletionId)
{
UINT32 FsInformationClass;
UINT32 Length;
const BYTE* QueryBuffer;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, FsInformationClass);
Stream_Read_UINT32(s, Length);
Stream_Seek(s, 24); /* Padding */
QueryBuffer = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
return ERROR_INVALID_DATA;
Stream_Seek(s, Length);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.8 Server Drive Query Information Request "
"(DR_DRIVE_QUERY_INFORMATION_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
UINT32 FsInformationClass;
UINT32 Length;
const BYTE* SetBuffer;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, FsInformationClass);
Stream_Read_UINT32(s, Length);
Stream_Seek(s, 24); /* Padding */
SetBuffer = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, Length))
return ERROR_INVALID_DATA;
Stream_Seek(s, Length);
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.9 Server Drive Set Information Request "
"(DR_DRIVE_SET_INFORMATION_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
BYTE InitialQuery;
UINT32 FsInformationClass;
UINT32 PathLength;
const WCHAR* Path;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, FsInformationClass);
Stream_Read_UINT8(s, InitialQuery);
Stream_Read_UINT32(s, PathLength);
Stream_Seek(s, 23); /* Padding */
Path = rdpdr_read_ustring(s, PathLength);
if (!Path && (PathLength > 0))
return ERROR_INVALID_DATA;
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.10 Server Drive Query Directory Request "
"(DR_DRIVE_QUERY_DIRECTORY_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* context,
wStream* s, UINT32 DeviceId,
UINT32 FileId, UINT32 CompletionId)
{
BYTE WatchTree;
UINT32 CompletionFilter;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT8(s, WatchTree);
Stream_Read_UINT32(s, CompletionFilter);
Stream_Seek(s, 27); /* Padding */
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.11 Server Drive NotifyChange Directory Request "
"(DR_DRIVE_NOTIFY_CHANGE_DIRECTORY_REQ) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_io_directory_control_request(RdpdrServerContext* context,
wStream* s, UINT32 DeviceId,
UINT32 FileId, UINT32 CompletionId,
UINT32 MinorFunction)
{
WINPR_ASSERT(context);
switch (MinorFunction)
{
case IRP_MN_QUERY_DIRECTORY:
return rdpdr_server_receive_io_query_directory_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
return rdpdr_server_receive_io_change_directory_request(context, s, DeviceId, FileId,
CompletionId);
default:
WLog_WARN(TAG,
"[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) "
"MajorFunction=%s, MinorFunction=%08" PRIx32 " is not supported",
rdpdr_irp_string(IRP_MJ_DIRECTORY_CONTROL), MinorFunction);
return ERROR_INVALID_DATA;
}
}
static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* context, wStream* s,
UINT32 DeviceId, UINT32 FileId,
UINT32 CompletionId)
{
UINT32 Operation;
UINT32 Lock;
UINT32 NumLocks;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, Operation);
Stream_Read_UINT32(s, Lock);
Stream_Read_UINT32(s, NumLocks);
Stream_Seek(s, 20); /* Padding */
Lock &= 0x01; /* Only byte 0 is of importance */
for (UINT32 x = 0; x < NumLocks; x++)
{
UINT64 Length;
UINT64 Offset;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
return ERROR_INVALID_DATA;
Stream_Read_UINT64(s, Length);
Stream_Read_UINT64(s, Offset);
}
WLog_WARN(TAG, "[MS-RDPEFS] 2.2.3.3.12 Server Drive Lock Control Request (DR_DRIVE_LOCK_REQ) "
"not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, wStream* s,
RDPDR_HEADER* header)
{
UINT32 DeviceId;
UINT32 FileId;
UINT32 CompletionId;
UINT32 MajorFunction;
UINT32 MinorFunction;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, DeviceId);
Stream_Read_UINT32(s, FileId);
Stream_Read_UINT32(s, CompletionId);
Stream_Read_UINT32(s, MajorFunction);
Stream_Read_UINT32(s, MinorFunction);
if ((MinorFunction != 0) && (MajorFunction != IRP_MJ_DIRECTORY_CONTROL))
WLog_WARN(TAG,
"[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) MajorFunction=%s, "
"MinorFunction=0x%08" PRIx32 " != 0",
rdpdr_irp_string(MajorFunction), MinorFunction);
switch (MajorFunction)
{
case IRP_MJ_CREATE:
return rdpdr_server_receive_io_create_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_CLOSE:
return rdpdr_server_receive_io_close_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_READ:
return rdpdr_server_receive_io_read_request(context, s, DeviceId, FileId, CompletionId);
case IRP_MJ_WRITE:
return rdpdr_server_receive_io_write_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_DEVICE_CONTROL:
return rdpdr_server_receive_io_device_control_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_QUERY_VOLUME_INFORMATION:
return rdpdr_server_receive_io_query_volume_information_request(context, s, DeviceId,
FileId, CompletionId);
case IRP_MJ_QUERY_INFORMATION:
return rdpdr_server_receive_io_query_information_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_SET_INFORMATION:
return rdpdr_server_receive_io_set_information_request(context, s, DeviceId, FileId,
CompletionId);
case IRP_MJ_DIRECTORY_CONTROL:
return rdpdr_server_receive_io_directory_control_request(context, s, DeviceId, FileId,
CompletionId, MinorFunction);
case IRP_MJ_LOCK_CONTROL:
return rdpdr_server_receive_io_lock_control_request(context, s, DeviceId, FileId,
CompletionId);
default:
WLog_WARN(
TAG,
"[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) not implemented");
WLog_WARN(TAG,
"got DeviceId=0x%08" PRIx32 ", FileId=0x%08" PRIx32
", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
", MinorFunction=0x%08" PRIx32,
DeviceId, FileId, CompletionId, MajorFunction, MinorFunction);
return ERROR_INVALID_DATA;
}
}
/**
* Function description
*
@ -1077,6 +1551,183 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
return rdpdr_seal_send_free_request(context, s);
}
static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* context, wStream* s)
{
char PortDosName[9] = { 0 };
UINT32 PnPNameLen;
UINT32 DriverNameLen;
UINT32 PrinterNameLen;
UINT32 CachedFieldsLen;
const WCHAR* PnPName;
const WCHAR* DriverName;
const WCHAR* PrinterName;
const BYTE* config;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
return ERROR_INVALID_DATA;
Stream_Read(s, PortDosName, 8);
Stream_Read_UINT32(s, PnPNameLen);
Stream_Read_UINT32(s, DriverNameLen);
Stream_Read_UINT32(s, PrinterNameLen);
Stream_Read_UINT32(s, CachedFieldsLen);
PnPName = rdpdr_read_ustring(s, PnPNameLen);
if (!PnPName && (PnPNameLen > 0))
return ERROR_INVALID_DATA;
DriverName = rdpdr_read_ustring(s, DriverNameLen);
if (!DriverName && (DriverNameLen > 0))
return ERROR_INVALID_DATA;
PrinterName = rdpdr_read_ustring(s, PrinterNameLen);
if (!PrinterName && (PrinterNameLen > 0))
return ERROR_INVALID_DATA;
config = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, CachedFieldsLen))
return ERROR_INVALID_DATA;
Stream_Seek(s, CachedFieldsLen);
WLog_WARN(TAG,
"[MS-RDPEPC] 2.2.2.3 Add Printer Cachedata (DR_PRN_ADD_CACHEDATA) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* context, wStream* s)
{
UINT32 PrinterNameLen;
UINT32 CachedFieldsLen;
const WCHAR* PrinterName;
const BYTE* config;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, PrinterNameLen);
Stream_Read_UINT32(s, CachedFieldsLen);
PrinterName = rdpdr_read_ustring(s, PrinterNameLen);
if (!PrinterName && (PrinterNameLen > 0))
return ERROR_INVALID_DATA;
config = Stream_Pointer(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, CachedFieldsLen))
return ERROR_INVALID_DATA;
Stream_Seek(s, CachedFieldsLen);
WLog_WARN(
TAG,
"[MS-RDPEPC] 2.2.2.4 Update Printer Cachedata (DR_PRN_UPDATE_CACHEDATA) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* context, wStream* s)
{
UINT32 PrinterNameLen;
const WCHAR* PrinterName;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, PrinterNameLen);
PrinterName = rdpdr_read_ustring(s, PrinterNameLen);
if (!PrinterName && (PrinterNameLen > 0))
return ERROR_INVALID_DATA;
WLog_WARN(
TAG,
"[MS-RDPEPC] 2.2.2.5 Delete Printer Cachedata (DR_PRN_DELETE_CACHEDATA) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* context, wStream* s)
{
UINT32 OldPrinterNameLen;
UINT32 NewPrinterNameLen;
const WCHAR* OldPrinterName;
const WCHAR* NewPrinterName;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, OldPrinterNameLen);
Stream_Read_UINT32(s, NewPrinterNameLen);
OldPrinterName = rdpdr_read_ustring(s, OldPrinterNameLen);
if (!OldPrinterName && (OldPrinterNameLen > 0))
return ERROR_INVALID_DATA;
NewPrinterName = rdpdr_read_ustring(s, NewPrinterNameLen);
if (!NewPrinterName && (NewPrinterNameLen > 0))
return ERROR_INVALID_DATA;
WLog_WARN(
TAG,
"[MS-RDPEPC] 2.2.2.6 Rename Printer Cachedata (DR_PRN_RENAME_CACHEDATA) not implemented");
WLog_WARN(TAG, "TODO");
return CHANNEL_RC_OK;
}
static UINT rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream* s,
const RDPDR_HEADER* header)
{
UINT32 EventId;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, EventId);
switch (EventId)
{
case RDPDR_ADD_PRINTER_EVENT:
return rdpdr_server_receive_prn_cache_add_printer(context, s);
case RDPDR_UPDATE_PRINTER_EVENT:
return rdpdr_server_receive_prn_cache_update_printer(context, s);
case RDPDR_DELETE_PRINTER_EVENT:
return rdpdr_server_receive_prn_cache_delete_printer(context, s);
case RDPDR_RENAME_PRINTER_EVENT:
return rdpdr_server_receive_prn_cache_rename_cachedata(context, s);
default:
WLog_WARN(TAG, "[MS-RDPEPC] PAKID_PRN_CACHE_DATA unknown EventId=0x%08" PRIx32,
EventId);
return ERROR_INVALID_DATA;
}
}
static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* context, wStream* s,
const RDPDR_HEADER* header)
{
UINT32 PrinterId;
UINT32 Flags;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, PrinterId);
Stream_Read_UINT32(s, Flags);
WLog_WARN(TAG,
"[MS-RDPEPC] 2.2.2.2 Server Printer Set XPS Mode (DR_PRN_USING_XPS) not implemented");
WLog_WARN(TAG, "PrinterId=0x%08" PRIx32 ", Flags=0x%08" PRIx32, PrinterId, Flags);
return CHANNEL_RC_OK;
}
/**
* Function description
*
@ -1084,124 +1735,83 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
*/
static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
{
UINT error = CHANNEL_RC_OK;
UINT error = ERROR_INVALID_DATA;
WINPR_ASSERT(context);
WINPR_ASSERT(s);
WINPR_ASSERT(header);
WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04" PRIX16 " PacketId: 0x%04" PRIX16 "",
header->Component, header->PacketId);
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s));
WLog_DBG(TAG,
"RdpdrServerReceivePdu: Component: %s [0x%04" PRIx16 "] PacketId: %s [0x%04" PRIx16
"]",
rdpdr_component_string(header->Component), header->Component,
rdpdr_packetid_string(header->PacketId), header->PacketId);
if (header->Component == RDPDR_CTYP_CORE)
{
switch (header->PacketId)
{
case PAKID_CORE_CLIENTID_CONFIRM:
if ((error = rdpdr_server_receive_announce_response(context, s, header)))
{
WLog_ERR(TAG,
"rdpdr_server_receive_announce_response failed with error %" PRIu32
"!",
error);
return error;
}
case PAKID_CORE_SERVER_ANNOUNCE:
WLog_ERR(TAG, "[MS-RDPEFS] 2.2.2.2 Server Announce Request "
"(DR_CORE_SERVER_ANNOUNCE_REQ) must not be sent by a client!");
break;
case PAKID_CORE_CLIENTID_CONFIRM:
error = rdpdr_server_receive_announce_response(context, s, header);
break;
case PAKID_CORE_CLIENT_NAME:
if ((error = rdpdr_server_receive_client_name_request(context, s, header)))
{
WLog_ERR(TAG,
"rdpdr_server_receive_client_name_request failed with error %" PRIu32
"!",
error);
return error;
}
error = rdpdr_server_receive_client_name_request(context, s, header);
if (error == CHANNEL_RC_OK)
error = rdpdr_server_send_core_capability_request(context);
if (error == CHANNEL_RC_OK)
error = rdpdr_server_send_client_id_confirm(context);
break;
if ((error = rdpdr_server_send_core_capability_request(context)))
{
WLog_ERR(TAG,
"rdpdr_server_send_core_capability_request failed with error %" PRIu32
"!",
error);
return error;
}
if ((error = rdpdr_server_send_client_id_confirm(context)))
{
WLog_ERR(TAG,
"rdpdr_server_send_client_id_confirm failed with error %" PRIu32 "!",
error);
return error;
}
case PAKID_CORE_USER_LOGGEDON:
WLog_ERR(TAG, "[MS-RDPEFS] 2.2.2.5 Server User Logged On (DR_CORE_USER_LOGGEDON) "
"must not be sent by a client!");
break;
case PAKID_CORE_SERVER_CAPABILITY:
WLog_ERR(TAG, "[MS-RDPEFS] 2.2.2.7 Server Core Capability Request "
"(DR_CORE_CAPABILITY_REQ) must not be sent by a client!");
break;
case PAKID_CORE_CLIENT_CAPABILITY:
if ((error = rdpdr_server_receive_core_capability_response(context, s, header)))
error = rdpdr_server_receive_core_capability_response(context, s, header);
if (error == CHANNEL_RC_OK)
{
WLog_ERR(
TAG,
"rdpdr_server_receive_core_capability_response failed with error %" PRIu32
"!",
error);
return error;
if (context->priv->UserLoggedOnPdu)
error = rdpdr_server_send_user_logged_on(context);
}
if (context->priv->UserLoggedOnPdu)
if ((error = rdpdr_server_send_user_logged_on(context)))
{
WLog_ERR(TAG,
"rdpdr_server_send_user_logged_on failed with error %" PRIu32 "!",
error);
return error;
}
break;
case PAKID_CORE_DEVICELIST_ANNOUNCE:
if ((error = rdpdr_server_receive_device_list_announce_request(context, s, header)))
{
WLog_ERR(TAG,
"rdpdr_server_receive_device_list_announce_request failed with error "
"%" PRIu32 "!",
error);
return error;
}
break;
case PAKID_CORE_DEVICE_REPLY:
break;
case PAKID_CORE_DEVICE_IOREQUEST:
break;
case PAKID_CORE_DEVICE_IOCOMPLETION:
if ((error = rdpdr_server_receive_device_io_completion(context, s, header)))
{
WLog_ERR(TAG,
"rdpdr_server_receive_device_io_completion failed with error %" PRIu32
"!",
error);
return error;
}
error = rdpdr_server_receive_device_list_announce_request(context, s, header);
break;
case PAKID_CORE_DEVICELIST_REMOVE:
if ((error = rdpdr_server_receive_device_list_remove_request(context, s, header)))
{
WLog_ERR(TAG,
"rdpdr_server_receive_device_io_completion failed with error %" PRIu32
"!",
error);
return error;
}
error = rdpdr_server_receive_device_list_remove_request(context, s, header);
break;
case PAKID_CORE_DEVICE_REPLY:
WLog_ERR(TAG, "[MS-RDPEFS] 2.2.2.1 Server Device Announce Response "
"(DR_CORE_DEVICE_ANNOUNCE_RSP) must not be sent by a client!");
break;
case PAKID_CORE_DEVICE_IOREQUEST:
error = rdpdr_server_receive_device_io_request(context, s, header);
break;
case PAKID_CORE_DEVICE_IOCOMPLETION:
error = rdpdr_server_receive_device_io_completion(context, s, header);
break;
default:
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
rdpdr_component_string(header->Component), header->Component,
rdpdr_packetid_string(header->PacketId));
break;
}
}
@ -1210,19 +1820,25 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RD
switch (header->PacketId)
{
case PAKID_PRN_CACHE_DATA:
error = rdpdr_server_receive_prn_cache_data_request(context, s, header);
break;
case PAKID_PRN_USING_XPS:
error = rdpdr_server_receive_prn_using_xps_request(context, s, header);
break;
default:
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
rdpdr_component_string(header->Component), header->Component,
rdpdr_packetid_string(header->PacketId));
break;
}
}
else
{
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04" PRIX16 "", header->Component);
return ERROR_INVALID_DATA;
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s",
rdpdr_component_string(header->Component), header->Component,
rdpdr_packetid_string(header->PacketId));
}
return error;
@ -1318,21 +1934,20 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg)
if (BytesReturned >= RDPDR_HEADER_LENGTH)
{
RDPDR_HEADER header = { 0 };
Stream_SetPosition(s, 0);
Stream_SetLength(s, BytesReturned);
while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH)
{
RDPDR_HEADER header = { 0 };
Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
if ((error = rdpdr_server_receive_pdu(context, s, &header)))
{
WLog_ERR(TAG, "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error);
// goto out_stream;
error = CHANNEL_RC_OK;
goto out_stream;
}
}
}