2003-07-01 11:31:25 +02:00
|
|
|
#include "rdesktop.h"
|
|
|
|
|
|
|
|
#define IRP_MJ_CREATE 0x00
|
|
|
|
#define IRP_MJ_CLOSE 0x02
|
|
|
|
#define IRP_MJ_READ 0x03
|
|
|
|
#define IRP_MJ_WRITE 0x04
|
|
|
|
#define IRP_MJ_DEVICE_CONTROL 0x0e
|
|
|
|
|
|
|
|
extern char hostname[16];
|
|
|
|
extern DEVICE_FNS serial_fns;
|
|
|
|
extern DEVICE_FNS printer_fns;
|
|
|
|
|
|
|
|
static VCHANNEL *rdpdr_channel;
|
|
|
|
|
|
|
|
void
|
|
|
|
rdpdr_send_connect(void)
|
|
|
|
{
|
|
|
|
uint8 magic[4] = "rDCC";
|
|
|
|
STREAM s;
|
|
|
|
|
|
|
|
s = channel_init(rdpdr_channel, 12);
|
|
|
|
out_uint8a(s, magic, 4);
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint16_le(s, 1); /* unknown */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint16_le(s, 5);
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
|
2003-07-01 11:31:25 +02:00
|
|
|
s_mark_end(s);
|
|
|
|
channel_send(s, rdpdr_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rdpdr_send_name(void)
|
|
|
|
{
|
|
|
|
uint8 magic[4] = "rDNC";
|
2003-07-09 11:18:20 +02:00
|
|
|
uint32 hostlen = (strlen(hostname) + 1) * 2;
|
2003-07-01 11:31:25 +02:00
|
|
|
STREAM s;
|
|
|
|
|
2003-07-09 11:18:20 +02:00
|
|
|
s = channel_init(rdpdr_channel, 16 + hostlen);
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint8a(s, magic, 4);
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint16_le(s, 0x63); /* unknown */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint16_le(s, 0x72);
|
|
|
|
out_uint32(s, 0);
|
|
|
|
out_uint32_le(s, hostlen);
|
2003-07-09 11:18:20 +02:00
|
|
|
rdp_out_unistr(s, hostname, hostlen - 2);
|
2003-07-01 11:31:25 +02:00
|
|
|
s_mark_end(s);
|
|
|
|
channel_send(s, rdpdr_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rdpdr_send_available(void)
|
|
|
|
{
|
|
|
|
uint8 magic[4] = "rDAD";
|
2003-07-09 11:18:20 +02:00
|
|
|
char *driver = "Digital turbo PrintServer 20"; /* Fairly generic PostScript driver */
|
2003-07-01 11:31:25 +02:00
|
|
|
char *printer = "PostScript";
|
2003-07-09 11:18:20 +02:00
|
|
|
uint32 driverlen = (strlen(driver) + 1) * 2;
|
|
|
|
uint32 printerlen = (strlen(printer) + 1) * 2;
|
2003-07-01 11:31:25 +02:00
|
|
|
STREAM s;
|
|
|
|
|
2003-07-09 11:18:20 +02:00
|
|
|
s = channel_init(rdpdr_channel, 8 + 20);
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint8a(s, magic, 4);
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 1); /* Number of devices */
|
2003-07-01 11:31:25 +02:00
|
|
|
|
|
|
|
#if 1
|
|
|
|
out_uint32_le(s, 0x1); /* Device type 0x1 - serial */
|
|
|
|
out_uint32_le(s, 0); /* Handle */
|
2003-12-09 10:59:26 +01:00
|
|
|
out_uint8p(s, "COM2", 4);
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint8s(s, 4); /* Pad to 8 */
|
|
|
|
out_uint32(s, 0);
|
|
|
|
#endif
|
|
|
|
#if 0
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 0x2); /* Device type 0x2 - parallel */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint32_le(s, 0);
|
|
|
|
out_uint8p(s, "LPT2", 4);
|
|
|
|
out_uint8s(s, 4);
|
|
|
|
out_uint32(s, 0);
|
|
|
|
#endif
|
|
|
|
#if 1
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 0x4); /* Device type 0x4 - printer */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint32_le(s, 1);
|
|
|
|
out_uint8p(s, "PRN1", 4);
|
|
|
|
out_uint8s(s, 4);
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 24 + driverlen + printerlen); /* length of extra info */
|
|
|
|
out_uint32_le(s, 2); /* unknown */
|
|
|
|
out_uint8s(s, 8); /* unknown */
|
|
|
|
out_uint32_le(s, driverlen); /* length of driver name */
|
|
|
|
out_uint32_le(s, printerlen); /* length of printer name */
|
|
|
|
out_uint32(s, 0); /* unknown */
|
|
|
|
rdp_out_unistr(s, driver, driverlen - 2);
|
|
|
|
rdp_out_unistr(s, printer, printerlen - 2);
|
2003-07-01 11:31:25 +02:00
|
|
|
#endif
|
|
|
|
#if 0
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 0x8); /* Device type 0x8 - disk */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint32_le(s, 0);
|
|
|
|
out_uint8p(s, "Z:", 2);
|
|
|
|
out_uint8s(s, 6);
|
|
|
|
out_uint32(s, 0);
|
|
|
|
#endif
|
|
|
|
#if 0
|
2003-07-09 11:18:20 +02:00
|
|
|
out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
|
2003-07-01 11:31:25 +02:00
|
|
|
out_uint32_le(s, 0);
|
|
|
|
out_uint8p(s, "SCARD", 5);
|
|
|
|
out_uint8s(s, 3);
|
|
|
|
out_uint32(s, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s_mark_end(s);
|
|
|
|
channel_send(s, rdpdr_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-07-09 11:18:20 +02:00
|
|
|
rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
|
|
|
|
uint32 length)
|
2003-07-01 11:31:25 +02:00
|
|
|
{
|
|
|
|
uint8 magic[4] = "rDCI";
|
|
|
|
STREAM s;
|
|
|
|
|
|
|
|
s = channel_init(rdpdr_channel, 20 + length);
|
|
|
|
out_uint8a(s, magic, 4);
|
|
|
|
out_uint32_le(s, device);
|
|
|
|
out_uint32_le(s, id);
|
|
|
|
out_uint32_le(s, status);
|
|
|
|
out_uint32_le(s, result);
|
|
|
|
out_uint8p(s, buffer, length);
|
|
|
|
s_mark_end(s);
|
2003-07-09 11:18:20 +02:00
|
|
|
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
|
2003-07-01 11:31:25 +02:00
|
|
|
channel_send(s, rdpdr_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdpdr_process_irp(STREAM s)
|
|
|
|
{
|
|
|
|
uint32 device, file, id, major, minor;
|
|
|
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
uint32 result = 0, length, request, bytes_in, bytes_out;
|
|
|
|
uint8 buffer[256];
|
|
|
|
uint32 buffer_len = 1;
|
|
|
|
struct stream out;
|
|
|
|
DEVICE_FNS *fns;
|
|
|
|
|
|
|
|
in_uint32_le(s, device);
|
|
|
|
in_uint32_le(s, file);
|
|
|
|
in_uint32_le(s, id);
|
|
|
|
in_uint32_le(s, major);
|
|
|
|
in_uint32_le(s, minor);
|
|
|
|
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
|
|
|
|
/* FIXME: this should probably be a more dynamic mapping */
|
|
|
|
switch (device)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
fns = &serial_fns;
|
|
|
|
case 1:
|
|
|
|
fns = &printer_fns;
|
|
|
|
default:
|
|
|
|
error("IRP for bad device %ld\n", device);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (major)
|
|
|
|
{
|
|
|
|
case IRP_MJ_CREATE:
|
|
|
|
if (fns->create)
|
|
|
|
status = fns->create(&result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_CLOSE:
|
|
|
|
if (fns->close)
|
|
|
|
status = fns->close(file);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_READ:
|
|
|
|
if (fns->read)
|
|
|
|
{
|
|
|
|
if (length > sizeof(buffer))
|
|
|
|
length = sizeof(buffer);
|
|
|
|
status = fns->read(file, buffer, length, &result);
|
|
|
|
buffer_len = result;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_WRITE:
|
|
|
|
if (fns->write)
|
|
|
|
status = fns->write(file, s->p, length, &result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
|
|
if (fns->device_control)
|
|
|
|
{
|
|
|
|
in_uint32_le(s, bytes_out);
|
|
|
|
in_uint32_le(s, bytes_in);
|
|
|
|
in_uint32_le(s, request);
|
|
|
|
in_uint8s(s, 0x14);
|
|
|
|
out.data = out.p = buffer;
|
|
|
|
out.size = sizeof(buffer);
|
|
|
|
status = fns->device_control(file, request, s, &out);
|
|
|
|
result = buffer_len = out.p - out.data;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdpdr_process(STREAM s)
|
|
|
|
{
|
|
|
|
uint32 handle;
|
2003-10-31 05:29:57 +01:00
|
|
|
uint8 *magic;
|
2003-07-01 11:31:25 +02:00
|
|
|
|
|
|
|
printf("rdpdr_process\n");
|
2003-07-09 11:18:20 +02:00
|
|
|
hexdump(s->p, s->end - s->p);
|
2003-07-01 11:31:25 +02:00
|
|
|
in_uint8p(s, magic, 4);
|
|
|
|
|
|
|
|
if ((magic[0] == 'r') && (magic[1] == 'D'))
|
|
|
|
{
|
|
|
|
if ((magic[2] == 'R') && (magic[3] == 'I'))
|
|
|
|
{
|
|
|
|
rdpdr_process_irp(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((magic[2] == 'n') && (magic[3] == 'I'))
|
|
|
|
{
|
|
|
|
rdpdr_send_connect();
|
|
|
|
rdpdr_send_name();
|
|
|
|
rdpdr_send_available();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ((magic[2] == 'C') && (magic[3] == 'C'))
|
|
|
|
{
|
|
|
|
/* connect from server */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ((magic[2] == 'r') && (magic[3] == 'd'))
|
|
|
|
{
|
|
|
|
/* connect to a specific resource */
|
|
|
|
in_uint32(s, handle);
|
|
|
|
printf("Server connected to resource %d\n", handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
rdpdr_init(void)
|
|
|
|
{
|
2003-07-09 11:18:20 +02:00
|
|
|
rdpdr_channel =
|
|
|
|
channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
|
|
|
|
rdpdr_process);
|
2003-07-01 11:31:25 +02:00
|
|
|
return (rdpdr_channel != NULL);
|
|
|
|
}
|