📄 rdpdr.c
字号:
/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. 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.*//* Here are some resources, for your IRP hacking pleasure: http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup http://win32.mvps.org/ntfs/streams.cpp http://www.acc.umu.se/~bosse/ntifs.h http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/ http://us1.samba.org/samba/ftp/specs/smb-nt01.txt http://www.osronline.com/*/#include <unistd.h>#include <sys/types.h>#include <sys/time.h>#include <dirent.h> /* opendir, closedir, readdir */#include <time.h>#include <errno.h>#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_QUERY_INFORMATION 0x05#define IRP_MJ_SET_INFORMATION 0x06#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a#define IRP_MJ_DIRECTORY_CONTROL 0x0c#define IRP_MJ_DEVICE_CONTROL 0x0e#define IRP_MJ_LOCK_CONTROL 0x11#define IRP_MN_QUERY_DIRECTORY 0x01#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02extern char g_hostname[16];extern DEVICE_FNS serial_fns;extern DEVICE_FNS printer_fns;extern DEVICE_FNS parallel_fns;extern DEVICE_FNS disk_fns;extern FILEINFO g_fileinfo[];extern BOOL g_notify_stamp;static VCHANNEL *rdpdr_channel;/* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */NTHANDLE g_min_timeout_fd;uint32 g_num_devices;/* Table with information about rdpdr devices */RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];char *g_rdpdr_clientname = NULL;/* Used to store incoming io request, until they are ready to be completed *//* using a linked list ensures that they are processed in the right order, *//* if multiple ios are being done on the same fd */struct async_iorequest{ uint32 fd, major, minor, offset, device, id, length, partial_len; long timeout, /* Total timeout */ itv_timeout; /* Interval timeout (between serial characters) */ uint8 *buffer; DEVICE_FNS *fns; struct async_iorequest *next; /* next element in list */};struct async_iorequest *g_iorequest;/* Return device_id for a given handle */intget_device_index(NTHANDLE handle){ int i; for (i = 0; i < RDPDR_MAX_DEVICES; i++) { if (g_rdpdr_device[i].handle == handle) return i; } return -1;}/* Converts a windows path to a unix path */voidconvert_to_unix_filename(char *filename){ char *p; while ((p = strchr(filename, '\\'))) { *p = '/'; }}static BOOLrdpdr_handle_ok(int device, int handle){ switch (g_rdpdr_device[device].device_type) { case DEVICE_TYPE_PARALLEL: case DEVICE_TYPE_SERIAL: case DEVICE_TYPE_PRINTER: case DEVICE_TYPE_SCARD: if (g_rdpdr_device[device].handle != handle) return False; break; case DEVICE_TYPE_DISK: if (g_fileinfo[handle].device_id != device) return False; break; } return True;}/* Add a new io request to the table containing pending io requests so it won't block rdesktop */static BOOLadd_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length, DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer, uint32 offset){ struct async_iorequest *iorq; if (g_iorequest == NULL) { g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest)); if (!g_iorequest) return False; g_iorequest->fd = 0; g_iorequest->next = NULL; } iorq = g_iorequest; while (iorq->fd != 0) { /* create new element if needed */ if (iorq->next == NULL) { iorq->next = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest)); if (!iorq->next) return False; iorq->next->fd = 0; iorq->next->next = NULL; } iorq = iorq->next; } iorq->device = device; iorq->fd = file; iorq->id = id; iorq->major = major; iorq->length = length; iorq->partial_len = 0; iorq->fns = fns; iorq->timeout = total_timeout; iorq->itv_timeout = interval_timeout; iorq->buffer = buffer; iorq->offset = offset; return True;}static voidrdpdr_send_connect(void){ uint8 magic[4] = "rDCC"; STREAM s; s = channel_init(rdpdr_channel, 12); out_uint8a(s, magic, 4); out_uint16_le(s, 1); /* unknown */ out_uint16_le(s, 5); out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */ s_mark_end(s); channel_send(s, rdpdr_channel);}static voidrdpdr_send_name(void){ uint8 magic[4] = "rDNC"; STREAM s; uint32 hostlen; if (NULL == g_rdpdr_clientname) { g_rdpdr_clientname = g_hostname; } hostlen = (strlen(g_rdpdr_clientname) + 1) * 2; s = channel_init(rdpdr_channel, 16 + hostlen); out_uint8a(s, magic, 4); out_uint16_le(s, 0x63); /* unknown */ out_uint16_le(s, 0x72); out_uint32(s, 0); out_uint32_le(s, hostlen); rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2); s_mark_end(s); channel_send(s, rdpdr_channel);}/* Returns the size of the payload of the announce packet */static intannouncedata_size(){ int size, i; PRINTER *printerinfo; size = 8; /* static announce size */ size += g_num_devices * 0x14; for (i = 0; i < g_num_devices; i++) { if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER) { printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; printerinfo->bloblen = printercache_load_blob(printerinfo->printer, &(printerinfo->blob)); size += 0x18; size += 2 * strlen(printerinfo->driver) + 2; size += 2 * strlen(printerinfo->printer) + 2; size += printerinfo->bloblen; } } return size;}static voidrdpdr_send_available(void){ uint8 magic[4] = "rDAD"; uint32 driverlen, printerlen, bloblen; int i; STREAM s; PRINTER *printerinfo; s = channel_init(rdpdr_channel, announcedata_size()); out_uint8a(s, magic, 4); out_uint32_le(s, g_num_devices); for (i = 0; i < g_num_devices; i++) { out_uint32_le(s, g_rdpdr_device[i].device_type); out_uint32_le(s, i); /* RDP Device ID */ /* Is it possible to use share names longer than 8 chars? /astrand */ out_uint8p(s, g_rdpdr_device[i].name, 8); switch (g_rdpdr_device[i].device_type) { case DEVICE_TYPE_PRINTER: printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; driverlen = 2 * strlen(printerinfo->driver) + 2; printerlen = 2 * strlen(printerinfo->printer) + 2; bloblen = printerinfo->bloblen; out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */ out_uint32_le(s, printerinfo->default_printer ? 2 : 0); out_uint8s(s, 8); /* unknown */ out_uint32_le(s, driverlen); out_uint32_le(s, printerlen); out_uint32_le(s, bloblen); rdp_out_unistr(s, printerinfo->driver, driverlen - 2); rdp_out_unistr(s, printerinfo->printer, printerlen - 2); out_uint8a(s, printerinfo->blob, bloblen); if (printerinfo->blob) xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */ break; default: out_uint32(s, 0); } }#if 0 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */ 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);}static voidrdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer, uint32 length){ 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); /* JIF */#ifdef WITH_DEBUG_RDP5 printf("--> rdpdr_send_completion\n"); /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */#endif channel_send(s, rdpdr_channel);}static voidrdpdr_process_irp(STREAM s){ uint32 result = 0, length = 0, desired_access = 0, request, file, info_level, buffer_len, id, major, minor, device, offset, bytes_in, bytes_out, error_mode, share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0; char filename[PATH_MAX]; uint8 *buffer, *pst_buf; struct stream out; DEVICE_FNS *fns; BOOL rw_blocking = True; NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; 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); buffer_len = 0; buffer = (uint8 *) xmalloc(1024); buffer[0] = 0; switch (g_rdpdr_device[device].device_type) { case DEVICE_TYPE_SERIAL: fns = &serial_fns; rw_blocking = False; break; case DEVICE_TYPE_PARALLEL: fns = ¶llel_fns; rw_blocking = False; break; case DEVICE_TYPE_PRINTER: fns = &printer_fns; break; case DEVICE_TYPE_DISK: fns = &disk_fns; rw_blocking = False; break; case DEVICE_TYPE_SCARD: default: error("IRP for bad device %ld\n", device); return; } switch (major) { case IRP_MJ_CREATE: in_uint32_be(s, desired_access); in_uint8s(s, 0x08); /* unknown */ in_uint32_le(s, error_mode); in_uint32_le(s, share_mode); in_uint32_le(s, disposition); in_uint32_le(s, flags_and_attributes); in_uint32_le(s, length); if (length && (length / 2) < 256) { rdp_in_unistr(s, filename, length); convert_to_unix_filename(filename); } else { filename[0] = 0; } if (!fns->create) { status = STATUS_NOT_SUPPORTED; break; } status = fns->create(device, desired_access, share_mode, disposition, flags_and_attributes, filename, &result); buffer_len = 1; break; case IRP_MJ_CLOSE: if (!fns->close) { status = STATUS_NOT_SUPPORTED; break; } status = fns->close(file); break; case IRP_MJ_READ: if (!fns->read) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset);#if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));#endif if (!rdpdr_handle_ok(device, file)) { status = STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete read immediately */ { buffer = (uint8 *) xrealloc((void *) buffer, length); if (!buffer) { status = STATUS_CANCELLED; break; } status = fns->read(file, buffer, length, offset, &result); buffer_len = result; break; } /* Add request to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = STATUS_CANCELLED; break; } serial_get_timeout(file, length, &total_timeout, &interval_timeout); if (add_async_iorequest (device, file, id, major, length, fns, total_timeout, interval_timeout, pst_buf, offset)) { status = STATUS_PENDING; break; } status = STATUS_CANCELLED; break; case IRP_MJ_WRITE: buffer_len = 1; if (!fns->write) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset); in_uint8s(s, 0x18);#if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Write (length: %d)\n", result));#endif if (!rdpdr_handle_ok(device, file)) { status = STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete immediately */ { status = fns->write(file, s->p, length, offset, &result); break; } /* Add to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = STATUS_CANCELLED; break; } in_uint8a(s, pst_buf, length); if (add_async_iorequest (device, file, id, major, length, fns, 0, 0, pst_buf, offset)) { status = STATUS_PENDING; break; } status = STATUS_CANCELLED; break; case IRP_MJ_QUERY_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_information(file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_SET_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_set_information(file, info_level, s, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_QUERY_VOLUME_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_volume_information(file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_DIRECTORY_CONTROL: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } switch (minor)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -