a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* -*- c-basic-offset: 8 -*-
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop: A Remote Desktop Protocol client.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright 2004-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright 2010-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is free software: you can redistribute it and/or modify
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it under the terms of the GNU General Public License as published by
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the Free Software Foundation, either version 3 of the License, or
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (at your option) any later version.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is distributed in the hope that it will be useful,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync but WITHOUT ANY WARRANTY; without even the implied warranty of
a180a41bba1d50822df23fff0099e90b86638b89vboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync GNU General Public License for more details.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync You should have received a copy of the GNU General Public License
a180a41bba1d50822df23fff0099e90b86638b89vboxsync along with this program. If not, see <http://www.gnu.org/licenses/>.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * the General Public License version 2 (GPLv2) at this time for any software where
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * a choice of GPL license versions is made available with the language indicating
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * that GPLv2 or any later version may be used, or where a choice of which version
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * of the GPL is applied is otherwise unspecified.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Here are some resources, for your IRP hacking pleasure:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup
a180a41bba1d50822df23fff0099e90b86638b89vboxsync http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <dirent.h> /* opendir, closedir, readdir */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Table with information about rdpdr devices */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Used to store incoming io request, until they are ready to be completed */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* using a linked list ensures that they are processed in the right order, */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* if multiple ios are being done on the same fd */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 fd, major, minor, offset, device, id, length, partial_len;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync itv_timeout; /* Interval timeout (between serial characters) */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync struct async_iorequest *next; /* next element in list */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Return device_id for a given handle */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync for (i = 0; i < RDPDR_MAX_DEVICES; i++)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Converts a windows path to a unix path */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Add a new io request to the table containing pending io requests so it won't block rdesktop */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncadd_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* create new element if needed */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* DR_CORE_CLIENT_ANNOUNCE_RSP */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync out_uint16_le(s, 1); /* VersionMajor, MUST be set to 0x1 */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* DR_CORE_CLIENT_NAME_REQ */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Returns the size of the payload of the announce packet */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync for (i = 0; i < g_num_devices; i++)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* DR_CORE_CLIENT_ANNOUNCE_RSP */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync s = channel_init(rdpdr_channel, announcedata_size());
a180a41bba1d50822df23fff0099e90b86638b89vboxsync for (i = 0; i < g_num_devices; i++)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Is it possible to use share names longer than 8 chars?
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /astrand */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncrdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RD_NTSTATUS status = RD_STATUS_INVALID_DEVICE_REQUEST;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync error("invalid irp device 0x%lx file 0x%lx id 0x%lx major 0x%lx minor 0x%lx\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_in_unistr(s, length, &filename, &filename_len);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = fns->create(device, desired_access, share_mode, disposition,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync buffer = (uint8 *) xrealloc((void *) buffer, length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = fns->read(file, buffer, length, offset, &result);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Add request to table */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync serial_get_timeout(file, length, &total_timeout, &interval_timeout);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (device, file, id, major, length, fns, total_timeout, interval_timeout,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = fns->write(file, s->p, length, offset, &result);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Add to table */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = disk_query_information(file, info_level, &out);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = disk_set_information(file, info_level, s, &out);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = disk_query_volume_information(file, info_level, &out);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_in_unistr(s, length, &filename, &filename_len);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = disk_query_directory(file, info_level, filename,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync add_async_iorequest(device, file, id, major, length,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync scardSetInfo(g_epoch, device, id, bytes_out + 0x14);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync status = fns->device_control(file, request, s, &out);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Serial SERIAL_WAIT_ON_MASK */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (device, file, id, major, length, fns, 0, 0, NULL, 0))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (status == (RD_STATUS_PENDING | 0xC0000000))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* FIXME: Perhaps consider actually *do*
a180a41bba1d50822df23fff0099e90b86638b89vboxsync something here :-) */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* DR_CORE_CAPABILITY_RSP */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* DR_CORE_SERVER_ANNOUNCE_REQ */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* The RDP client is responsibility to provide a random client id
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if server version is < 12 */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_client_id = 0x815ed39d; /* IP address (use 127.0.0.1) 0x815ed39d */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG(("RDPDR: Server connected to resource %d\n", handle));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unimpl("RDPDR pakid 0x%x of component 0x%x\n", pakid, component);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Add file descriptors of pending io request to select() */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncrdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 select_timeout = 0; /* Timeout value to be used for select() (in millisecons). */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Is this FD valid? FDs will
a180a41bba1d50822df23fff0099e90b86638b89vboxsync be invalid when
a180a41bba1d50822df23fff0099e90b86638b89vboxsync reconnecting. FIXME: Real
a180a41bba1d50822df23fff0099e90b86638b89vboxsync support for reconnects. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Check if io request timeout is smaller than current (but not 0). */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Set new timeout */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Set new timeout */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* FD still valid? See above. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF))
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncrdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Even if NULL */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync_rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* check serial iv_timeout */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* iv_timeout between 2 chars, send partial_len */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdpdr_abort_io(g_min_timeout_fd, 0, RD_STATUS_TIMEOUT);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Read the data */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* never read larger chunks than 8k - chances are that it will block */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((long) result > 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* only delete link if all data has been transfered */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* or if result was 0 and status success - EOF */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Write data. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* never write larger chunks than 8k - chances are that it will block */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((long) result > 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* only delete link if all data has been transfered */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* or we couldn't write */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync buffer = (uint8 *) xrealloc((void *) buffer, 0x14);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Check notify */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncrdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* fist check event queue only,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync any serial wait event must be done before read block will be sent
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Abort a pending io request for a given handle and major */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncrdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Only remove from table when major is not set, or when correct major is supplied.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Abort read should not abort a write io request. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((iorq->fd == fd) && (major == 0 || iorq->major == major))