redirection of disk, lptport, printer, comport.
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@568 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
f76ace37f2
commit
a61eac7b19
2
Makefile
2
Makefile
@ -15,7 +15,7 @@ datadir = $(prefix)/share/rdesktop
|
|||||||
VERSION = 1.3.1
|
VERSION = 1.3.1
|
||||||
KEYMAP_PATH = $(datadir)/keymaps/
|
KEYMAP_PATH = $(datadir)/keymaps/
|
||||||
|
|
||||||
RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o
|
RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o
|
||||||
X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
|
X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
|
||||||
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
|
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
|
||||||
CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/bn_exp.o crypto/bn_mul.o crypto/bn_div.o crypto/bn_sqr.o crypto/bn_add.o crypto/bn_shift.o crypto/bn_asm.o crypto/bn_ctx.o crypto/bn_lib.o
|
CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/bn_exp.o crypto/bn_mul.o crypto/bn_div.o crypto/bn_sqr.o crypto/bn_add.o crypto/bn_shift.o crypto/bn_asm.o crypto/bn_ctx.o crypto/bn_lib.o
|
||||||
|
19
constants.h
19
constants.h
@ -7,7 +7,7 @@
|
|||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
@ -317,3 +317,20 @@ enum RDP_INPUT_DEVICE
|
|||||||
#define STATUS_INVALID_PARAMETER 0xc000000d
|
#define STATUS_INVALID_PARAMETER 0xc000000d
|
||||||
#define STATUS_INVALID_DEVICE_REQUEST 0xc0000010
|
#define STATUS_INVALID_DEVICE_REQUEST 0xc0000010
|
||||||
#define STATUS_ACCESS_DENIED 0xc0000022
|
#define STATUS_ACCESS_DENIED 0xc0000022
|
||||||
|
#define STATUS_NO_SUCH_FILE 0xc000000f
|
||||||
|
#define STATUS_NO_MORE_FILES 0x80000006
|
||||||
|
#define STATUS_INVALID_HANDLE 0xc0000008
|
||||||
|
#define STATUS_NOT_SUPPORTED 0xc00000bb
|
||||||
|
#define STATUS_PENDING 0x00000103
|
||||||
|
#define STATUS_CANCELLED 0xc0000120
|
||||||
|
#define STATUS_TIMEOUT 0xc0000102
|
||||||
|
|
||||||
|
/* RDPDR constants */
|
||||||
|
#define RDPDR_MAX_DEVICES 0x10
|
||||||
|
#define DEVICE_TYPE_SERIAL 0x01
|
||||||
|
#define DEVICE_TYPE_PARALLEL 0x02
|
||||||
|
#define DEVICE_TYPE_PRINTER 0x04
|
||||||
|
#define DEVICE_TYPE_DISK 0x08
|
||||||
|
#define DEVICE_TYPE_SCARD 0x20
|
||||||
|
|
||||||
|
#define FILE_DIRECTORY_FILE 0x00000001
|
||||||
|
630
disk.c
Normal file
630
disk.c
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
/* -*- c-basic-offset: 8 -*-
|
||||||
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
|
Disk Redirection
|
||||||
|
Copyright (C) Jeroen Meijer 2003
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
||||||
|
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
||||||
|
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
||||||
|
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||||
|
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
|
||||||
|
#define FILE_ATTRIBUTE_DEVICE 0x00000040
|
||||||
|
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||||
|
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
|
||||||
|
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
|
||||||
|
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
|
||||||
|
#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
|
||||||
|
#define FILE_ATTRIBUTE_OFFLINE 0x00001000
|
||||||
|
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
|
||||||
|
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
|
||||||
|
|
||||||
|
#define FILE_BASIC_INFORMATION 0x04
|
||||||
|
#define FILE_STANDARD_INFORMATION 0x05
|
||||||
|
|
||||||
|
#define FS_CASE_SENSITIVE 0x00000001
|
||||||
|
#define FS_CASE_IS_PRESERVED 0x00000002
|
||||||
|
#define FS_UNICODE_STORED_ON_DISK 0x00000004
|
||||||
|
#define FS_PERSISTENT_ACLS 0x00000008
|
||||||
|
#define FS_FILE_COMPRESSION 0x00000010
|
||||||
|
#define FS_VOLUME_QUOTAS 0x00000020
|
||||||
|
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
|
||||||
|
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
|
||||||
|
#define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
|
||||||
|
#define FS_VOL_IS_COMPRESSED 0x00008000
|
||||||
|
#define FILE_READ_ONLY_VOLUME 0x00080000
|
||||||
|
|
||||||
|
#define OPEN_EXISTING 1
|
||||||
|
#define CREATE_NEW 2
|
||||||
|
#define OPEN_ALWAYS 3
|
||||||
|
#define TRUNCATE_EXISTING 4
|
||||||
|
#define CREATE_ALWAYS 5
|
||||||
|
|
||||||
|
#define GENERIC_READ 0x80000000
|
||||||
|
#define GENERIC_WRITE 0x40000000
|
||||||
|
#define GENERIC_EXECUTE 0x20000000
|
||||||
|
#define GENERIC_ALL 0x10000000
|
||||||
|
|
||||||
|
#define ERROR_FILE_NOT_FOUND 2L
|
||||||
|
#define ERROR_ALREADY_EXISTS 183L
|
||||||
|
|
||||||
|
#define MAX_OPEN_FILES 0x100
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/vfs.h> /* linux statfs */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h> /* open, close */
|
||||||
|
#include <dirent.h> /* opendir, closedir, readdir */
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <errno.h> /* errno */
|
||||||
|
#include "rdesktop.h"
|
||||||
|
|
||||||
|
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||||
|
|
||||||
|
struct fileinfo
|
||||||
|
{
|
||||||
|
uint32 device_id, flags_and_attributes;
|
||||||
|
char path[256];
|
||||||
|
DIR *pdir;
|
||||||
|
struct dirent *pdirent;
|
||||||
|
char pattern[64];
|
||||||
|
BOOL delete_on_close;
|
||||||
|
}
|
||||||
|
g_fileinfo[MAX_OPEN_FILES];
|
||||||
|
|
||||||
|
/* Convert seconds since 1970 to a filetime */
|
||||||
|
void
|
||||||
|
seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
|
||||||
|
{
|
||||||
|
unsigned long long ticks;
|
||||||
|
|
||||||
|
ticks = (seconds + 11644473600LL) * 10000000;
|
||||||
|
*low = (uint32) ticks;
|
||||||
|
*high = (uint32) (ticks >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enumeration of devices from rdesktop.c */
|
||||||
|
/* returns numer of units found and initialized. */
|
||||||
|
/* optarg looks like ':h:=/mnt/floppy,b:=/mnt/usbdevice1' */
|
||||||
|
/* when it arrives to this function. */
|
||||||
|
int
|
||||||
|
disk_enum_devices(int *id, char *optarg)
|
||||||
|
{
|
||||||
|
char *pos = optarg;
|
||||||
|
char *pos2;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// skip the first colon
|
||||||
|
optarg++;
|
||||||
|
while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
|
||||||
|
{
|
||||||
|
pos2 = next_arg(optarg, '=');
|
||||||
|
strcpy(g_rdpdr_device[*id].name, optarg);
|
||||||
|
|
||||||
|
toupper(g_rdpdr_device[*id].name);
|
||||||
|
|
||||||
|
/* add trailing colon to name. */
|
||||||
|
strcat(g_rdpdr_device[*id].name, ":");
|
||||||
|
|
||||||
|
g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1);
|
||||||
|
strcpy(g_rdpdr_device[*id].local_path, pos2);
|
||||||
|
printf("DISK %s to %s\n", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path);
|
||||||
|
g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK;
|
||||||
|
count++;
|
||||||
|
(*id)++;
|
||||||
|
|
||||||
|
optarg = pos;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Opens of creates a file or directory */
|
||||||
|
NTSTATUS
|
||||||
|
disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition,
|
||||||
|
uint32 flags_and_attributes, char *filename, HANDLE * phandle)
|
||||||
|
{
|
||||||
|
HANDLE handle;
|
||||||
|
DIR *dirp;
|
||||||
|
int flags, mode;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
handle = 0;
|
||||||
|
dirp = NULL;
|
||||||
|
flags = 0;
|
||||||
|
mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||||
|
|
||||||
|
if (filename[strlen(filename) - 1] == '/')
|
||||||
|
filename[strlen(filename) - 1] = 0;
|
||||||
|
sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename);
|
||||||
|
//printf("Open: %s\n", path);
|
||||||
|
|
||||||
|
switch (create_disposition)
|
||||||
|
{
|
||||||
|
case CREATE_ALWAYS:
|
||||||
|
|
||||||
|
// Delete existing file/link.
|
||||||
|
unlink(path);
|
||||||
|
flags |= O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CREATE_NEW:
|
||||||
|
|
||||||
|
// If the file already exists, then fail.
|
||||||
|
flags |= O_CREAT | O_EXCL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPEN_ALWAYS:
|
||||||
|
|
||||||
|
// Create if not already exists.
|
||||||
|
flags |= O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPEN_EXISTING:
|
||||||
|
|
||||||
|
// Default behaviour
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRUNCATE_EXISTING:
|
||||||
|
|
||||||
|
// If the file does not exist, then fail.
|
||||||
|
flags |= O_TRUNC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags_and_attributes & FILE_DIRECTORY_FILE)
|
||||||
|
{
|
||||||
|
if (flags & O_CREAT)
|
||||||
|
{
|
||||||
|
mkdir(path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirp = opendir(path);
|
||||||
|
if (!dirp)
|
||||||
|
{
|
||||||
|
switch (errno)
|
||||||
|
{
|
||||||
|
case EACCES:
|
||||||
|
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
case ENOENT:
|
||||||
|
|
||||||
|
return STATUS_NO_SUCH_FILE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
perror("opendir");
|
||||||
|
return STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle = dirfd(dirp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (accessmask & GENERIC_ALL
|
||||||
|
|| (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
|
||||||
|
{
|
||||||
|
flags |= O_RDWR;
|
||||||
|
}
|
||||||
|
else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ))
|
||||||
|
{
|
||||||
|
flags |= O_WRONLY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags |= O_RDONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = open(path, flags, mode);
|
||||||
|
if (handle == -1)
|
||||||
|
{
|
||||||
|
switch (errno)
|
||||||
|
{
|
||||||
|
case EACCES:
|
||||||
|
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
case ENOENT:
|
||||||
|
|
||||||
|
return STATUS_NO_SUCH_FILE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
perror("open");
|
||||||
|
return STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle >= MAX_OPEN_FILES)
|
||||||
|
{
|
||||||
|
error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n",
|
||||||
|
handle);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirp)
|
||||||
|
g_fileinfo[handle].pdir = dirp;
|
||||||
|
g_fileinfo[handle].device_id = device_id;
|
||||||
|
g_fileinfo[handle].flags_and_attributes = flags_and_attributes;
|
||||||
|
strncpy(g_fileinfo[handle].path, path, 255);
|
||||||
|
|
||||||
|
*phandle = handle;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_close(HANDLE handle)
|
||||||
|
{
|
||||||
|
struct fileinfo *pfinfo;
|
||||||
|
|
||||||
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
|
|
||||||
|
if (pfinfo->flags_and_attributes & FILE_DIRECTORY_FILE)
|
||||||
|
{
|
||||||
|
closedir(pfinfo->pdir);
|
||||||
|
//FIXME: Should check exit code
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_read(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
lseek(handle, offset, SEEK_SET);
|
||||||
|
n = read(handle, data, length);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
perror("read");
|
||||||
|
*result = 0;
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = n;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_write(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
lseek(handle, offset, SEEK_SET);
|
||||||
|
|
||||||
|
n = write(handle, data, length);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
perror("write");
|
||||||
|
*result = 0;
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = n;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_query_information(HANDLE handle, uint32 info_class, STREAM out)
|
||||||
|
{
|
||||||
|
uint32 file_attributes, ft_high, ft_low;
|
||||||
|
struct stat filestat;
|
||||||
|
char *path, *filename;
|
||||||
|
|
||||||
|
path = g_fileinfo[handle].path;
|
||||||
|
|
||||||
|
// Get information about file
|
||||||
|
if (fstat(handle, &filestat) != 0)
|
||||||
|
{
|
||||||
|
perror("stat");
|
||||||
|
out_uint8(out, 0);
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set file attributes
|
||||||
|
file_attributes = 0;
|
||||||
|
if (S_ISDIR(filestat.st_mode))
|
||||||
|
{
|
||||||
|
file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
}
|
||||||
|
filename = 1 + strrchr(path, '/');
|
||||||
|
if (filename && filename[0] == '.')
|
||||||
|
{
|
||||||
|
file_attributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return requested data
|
||||||
|
switch (info_class)
|
||||||
|
{
|
||||||
|
case 4: /* FileBasicInformation */
|
||||||
|
|
||||||
|
out_uint8s(out, 8); //create_time not available;
|
||||||
|
|
||||||
|
seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low);
|
||||||
|
out_uint32_le(out, ft_low); //last_access_time
|
||||||
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
|
seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low);
|
||||||
|
out_uint32_le(out, ft_low); //last_write_time
|
||||||
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
|
out_uint8s(out, 8); //unknown zero
|
||||||
|
out_uint32_le(out, file_attributes);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: /* FileStandardInformation */
|
||||||
|
|
||||||
|
out_uint32_le(out, filestat.st_size); //Allocation size
|
||||||
|
out_uint32_le(out, 0);
|
||||||
|
out_uint32_le(out, filestat.st_size); //End of file
|
||||||
|
out_uint32_le(out, 0);
|
||||||
|
out_uint32_le(out, filestat.st_nlink); //Number of links
|
||||||
|
out_uint8(out, 0); //Delete pending
|
||||||
|
out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); //Directory
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 35: /* FileObjectIdInformation */
|
||||||
|
|
||||||
|
out_uint32_le(out, file_attributes); /* File Attributes */
|
||||||
|
out_uint32_le(out, 0); /* Reparse Tag */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
unimpl("IRP Query (File) Information class: 0x%x\n", info_class);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_set_information(HANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||||
|
{
|
||||||
|
uint32 device_id, length, file_attributes, ft_high, ft_low;
|
||||||
|
char newname[256], fullpath[256];
|
||||||
|
struct fileinfo *pfinfo;
|
||||||
|
|
||||||
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
|
|
||||||
|
switch (info_class)
|
||||||
|
{
|
||||||
|
case 4: /* FileBasicInformation */
|
||||||
|
|
||||||
|
// Probably safe to ignore
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10: /* FileRenameInformation */
|
||||||
|
|
||||||
|
in_uint8s(in, 4); /* Handle of root dir? */
|
||||||
|
in_uint8s(in, 0x1a); /* unknown */
|
||||||
|
in_uint32_le(in, length);
|
||||||
|
|
||||||
|
if (length && (length / 2) < 256)
|
||||||
|
{
|
||||||
|
rdp_in_unistr(in, newname, length);
|
||||||
|
convert_to_unix_filename(newname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
|
||||||
|
newname);
|
||||||
|
|
||||||
|
if (rename(pfinfo->path, fullpath) != 0)
|
||||||
|
{
|
||||||
|
perror("rename");
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13: /* FileDispositionInformation */
|
||||||
|
|
||||||
|
//unimpl("IRP Set File Information class: FileDispositionInformation\n");
|
||||||
|
// in_uint32_le(in, delete_on_close);
|
||||||
|
// disk_close(handle);
|
||||||
|
unlink(pfinfo->path);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19: /* FileAllocationInformation */
|
||||||
|
|
||||||
|
unimpl("IRP Set File Information class: FileAllocationInformation\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 20: /* FileEndOfFileInformation */
|
||||||
|
|
||||||
|
unimpl("IRP Set File Information class: FileEndOfFileInformation\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
unimpl("IRP Set File Information class: 0x%x\n", info_class);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_query_volume_information(HANDLE handle, uint32 info_class, STREAM out)
|
||||||
|
{
|
||||||
|
char *volume, *fs_type;
|
||||||
|
struct statfs stat_fs;
|
||||||
|
struct fileinfo *pfinfo;
|
||||||
|
|
||||||
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
|
volume = "RDESKTOP";
|
||||||
|
fs_type = "RDPFS";
|
||||||
|
|
||||||
|
if (statfs(pfinfo->path, &stat_fs) != 0) /* FIXME: statfs is not portable */
|
||||||
|
{
|
||||||
|
perror("statfs");
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (info_class)
|
||||||
|
{
|
||||||
|
case 1: /* FileFsVolumeInformation */
|
||||||
|
|
||||||
|
out_uint32_le(out, 0); /* volume creation time low */
|
||||||
|
out_uint32_le(out, 0); /* volume creation time high */
|
||||||
|
out_uint32_le(out, 0); /* serial */
|
||||||
|
out_uint32_le(out, 2 * strlen(volume)); /* length of string */
|
||||||
|
out_uint8(out, 0); /* support objects? */
|
||||||
|
rdp_out_unistr(out, volume, 2 * strlen(volume) - 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* FileFsSizeInformation */
|
||||||
|
|
||||||
|
out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */
|
||||||
|
out_uint32_le(out, 0); /* Total allocation high units */
|
||||||
|
out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */
|
||||||
|
out_uint32_le(out, 0); /* Available allowcation units */
|
||||||
|
out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
|
||||||
|
out_uint32_le(out, 0x200); /* Bytes per sector */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: /* FileFsAttributeInformation */
|
||||||
|
|
||||||
|
out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */
|
||||||
|
out_uint32_le(out, stat_fs.f_namelen); /* max length of filename */
|
||||||
|
out_uint32_le(out, 2 * strlen(fs_type)); /* length of fs_type */
|
||||||
|
rdp_out_unistr(out, fs_type, 2 * strlen(fs_type) - 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* FileFsLabelInformation */
|
||||||
|
case 4: /* FileFsDeviceInformation */
|
||||||
|
case 6: /* FileFsControlInformation */
|
||||||
|
case 7: /* FileFsFullSizeInformation */
|
||||||
|
case 8: /* FileFsObjectIdInformation */
|
||||||
|
case 9: /* FileFsMaximumInformation */
|
||||||
|
default:
|
||||||
|
|
||||||
|
unimpl("IRP Query Volume Information class: 0x%x\n", info_class);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out)
|
||||||
|
{
|
||||||
|
uint32 file_attributes, ft_low, ft_high;
|
||||||
|
char *dirname, fullpath[256];
|
||||||
|
DIR *pdir;
|
||||||
|
struct dirent *pdirent;
|
||||||
|
struct stat fstat;
|
||||||
|
struct fileinfo *pfinfo;
|
||||||
|
|
||||||
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
|
pdir = pfinfo->pdir;
|
||||||
|
dirname = pfinfo->path;
|
||||||
|
file_attributes = 0;
|
||||||
|
|
||||||
|
switch (info_class)
|
||||||
|
{
|
||||||
|
case 3: //FIXME: Why 3?
|
||||||
|
|
||||||
|
// If a search pattern is received, remember this pattern, and restart search
|
||||||
|
if (pattern[0] != 0)
|
||||||
|
{
|
||||||
|
strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), 64);
|
||||||
|
rewinddir(pdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find next dirent matching pattern
|
||||||
|
pdirent = readdir(pdir);
|
||||||
|
while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0)
|
||||||
|
{
|
||||||
|
pdirent = readdir(pdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdirent == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_NO_MORE_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get information for directory entry
|
||||||
|
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
|
||||||
|
/* JIF
|
||||||
|
printf("Stat: %s\n", fullpath); */
|
||||||
|
if (stat(fullpath, &fstat))
|
||||||
|
{
|
||||||
|
perror("stat");
|
||||||
|
out_uint8(out, 0);
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(fstat.st_mode))
|
||||||
|
file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
if (pdirent->d_name[0] == '.')
|
||||||
|
file_attributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||||
|
|
||||||
|
// Return requested information
|
||||||
|
out_uint8s(out, 8); //unknown zero
|
||||||
|
out_uint8s(out, 8); //create_time not available in posix;
|
||||||
|
|
||||||
|
seconds_since_1970_to_filetime(fstat.st_atime, &ft_high, &ft_low);
|
||||||
|
out_uint32_le(out, ft_low); //last_access_time
|
||||||
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
|
seconds_since_1970_to_filetime(fstat.st_mtime, &ft_high, &ft_low);
|
||||||
|
out_uint32_le(out, ft_low); //last_write_time
|
||||||
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
|
out_uint8s(out, 8); //unknown zero
|
||||||
|
out_uint32_le(out, fstat.st_size); //filesize low
|
||||||
|
out_uint32_le(out, 0); //filesize high
|
||||||
|
out_uint32_le(out, fstat.st_size); //filesize low
|
||||||
|
out_uint32_le(out, 0); //filesize high
|
||||||
|
out_uint32_le(out, file_attributes);
|
||||||
|
out_uint8(out, 2 * strlen(pdirent->d_name) + 2); //unicode length
|
||||||
|
out_uint8s(out, 7); //pad?
|
||||||
|
out_uint8(out, 0); //8.3 file length
|
||||||
|
out_uint8s(out, 2 * 12); //8.3 unicode length
|
||||||
|
rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
unimpl("IRP Query Directory sub: 0x%x\n", info_class);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_FNS disk_fns = {
|
||||||
|
disk_create,
|
||||||
|
disk_close,
|
||||||
|
disk_read,
|
||||||
|
disk_write,
|
||||||
|
NULL /* device_control */
|
||||||
|
};
|
125
parallel.c
Normal file
125
parallel.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#define MAX_PARALLEL_DEVICES 1
|
||||||
|
|
||||||
|
#define FILE_DEVICE_PARALLEL 0x22
|
||||||
|
|
||||||
|
#define IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x0c
|
||||||
|
|
||||||
|
#define PARALLELDEV0 "/dev/lp0"
|
||||||
|
|
||||||
|
#include "rdesktop.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||||
|
|
||||||
|
PARALLEL_DEVICE * get_parallel_data(HANDLE handle)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (index = 0; index < RDPDR_MAX_DEVICES; index++)
|
||||||
|
{
|
||||||
|
if (handle == g_rdpdr_device[index].handle)
|
||||||
|
return (PARALLEL_DEVICE *) g_rdpdr_device[index].pdevice_data;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Enumeration of devices from rdesktop.c */
|
||||||
|
/* returns numer of units found and initialized. */
|
||||||
|
/* optarg looks like ':LPT1=/dev/lp0' */
|
||||||
|
/* when it arrives to this function. */
|
||||||
|
int
|
||||||
|
parallel_enum_devices(int *id, char *optarg)
|
||||||
|
{
|
||||||
|
//TODO: Read from configuration file? CUPS?
|
||||||
|
PARALLEL_DEVICE *ppar_info;
|
||||||
|
|
||||||
|
char *pos = optarg;
|
||||||
|
char *pos2;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// skip the first colon
|
||||||
|
optarg++;
|
||||||
|
while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
|
||||||
|
{
|
||||||
|
ppar_info = (PARALLEL_DEVICE *) xmalloc(sizeof(PARALLEL_DEVICE));
|
||||||
|
|
||||||
|
pos2 = next_arg(optarg, '=');
|
||||||
|
strcpy(g_rdpdr_device[*id].name, optarg);
|
||||||
|
|
||||||
|
toupper(g_rdpdr_device[*id].name);
|
||||||
|
|
||||||
|
g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1);
|
||||||
|
strcpy(g_rdpdr_device[*id].local_path, pos2);
|
||||||
|
printf("PARALLEL %s to %s\n", optarg, pos2);
|
||||||
|
|
||||||
|
// set device type
|
||||||
|
g_rdpdr_device[*id].device_type = DEVICE_TYPE_PARALLEL;
|
||||||
|
g_rdpdr_device[*id].pdevice_data = (void *) ppar_info;
|
||||||
|
count++;
|
||||||
|
(*id)++;
|
||||||
|
|
||||||
|
optarg = pos;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
parallel_create(uint32 device_id, HANDLE * handle)
|
||||||
|
{
|
||||||
|
int parallel_fd;
|
||||||
|
|
||||||
|
parallel_fd = open(PARALLELDEV0, O_WRONLY);
|
||||||
|
if (parallel_fd == -1)
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
*handle = parallel_fd;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
parallel_close(HANDLE handle)
|
||||||
|
{
|
||||||
|
close(handle);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
parallel_write(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
||||||
|
{
|
||||||
|
*result = write(handle, data, length);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
parallel_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||||
|
{
|
||||||
|
if ((request >> 16) != FILE_DEVICE_PARALLEL)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/* extract operation */
|
||||||
|
request >>= 2;
|
||||||
|
request &= 0xfff;
|
||||||
|
|
||||||
|
printf("PARALLEL IOCTL %d: ", request);
|
||||||
|
|
||||||
|
switch (request)
|
||||||
|
{
|
||||||
|
case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
unimpl("UNKNOWN IOCTL %d\n", request);
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_FNS parallel_fns = {
|
||||||
|
parallel_create,
|
||||||
|
parallel_close,
|
||||||
|
NULL,
|
||||||
|
parallel_write,
|
||||||
|
parallel_device_control
|
||||||
|
};
|
127
printer.c
127
printer.c
@ -1,26 +1,139 @@
|
|||||||
|
#define MAX_PRINTERS 5
|
||||||
|
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
|
||||||
FILE *printer_fp;
|
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||||
|
|
||||||
|
PRINTER * get_printer_data(HANDLE handle)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (index = 0; index < RDPDR_MAX_DEVICES; index++)
|
||||||
|
{
|
||||||
|
if (handle == g_rdpdr_device[index].handle)
|
||||||
|
return (PRINTER *) g_rdpdr_device[index].pdevice_data;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
printer_enum_devices(int *id, char *optarg)
|
||||||
|
{
|
||||||
|
PRINTER *pprinter_data;
|
||||||
|
|
||||||
|
char *pos = optarg;
|
||||||
|
char *pos2;
|
||||||
|
int count = 0;
|
||||||
|
int already = 0;
|
||||||
|
|
||||||
|
// we need to know how many printers we've already set up
|
||||||
|
// supplied from other -r flags than this one.
|
||||||
|
while (count < *id)
|
||||||
|
{
|
||||||
|
if (g_rdpdr_device[count].device_type == DEVICE_TYPE_PRINTER)
|
||||||
|
already++;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
if (*optarg == ':')
|
||||||
|
optarg++;
|
||||||
|
|
||||||
|
while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
|
||||||
|
{
|
||||||
|
pprinter_data = (PRINTER *) xmalloc(sizeof(PRINTER));
|
||||||
|
|
||||||
|
strcpy(g_rdpdr_device[*id].name, "PRN");
|
||||||
|
strcat(g_rdpdr_device[*id].name, ltoa(already + count + 1, 10));
|
||||||
|
|
||||||
|
/* first printer is set as default printer */
|
||||||
|
if ((already + count) == 0)
|
||||||
|
pprinter_data->default_printer = True;
|
||||||
|
else
|
||||||
|
pprinter_data->default_printer = False;
|
||||||
|
|
||||||
|
pos2 = next_arg(optarg, ':');
|
||||||
|
if (*optarg == (char) 0x00)
|
||||||
|
pprinter_data->printer = "mydeskjet"; /* set default */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pprinter_data->printer = xmalloc(strlen(optarg) + 1);
|
||||||
|
strcpy(pprinter_data->printer, optarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pos2 || (*pos2 == (char) 0x00))
|
||||||
|
pprinter_data->driver = "HP LaserJet IIIP"; /* no printer driver supplied set default */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pprinter_data->driver = xmalloc(strlen(pos2) + 1);
|
||||||
|
strcpy(pprinter_data->driver, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("PRINTER %s to %s driver %s\n", g_rdpdr_device[*id].name,
|
||||||
|
pprinter_data->printer, pprinter_data->driver);
|
||||||
|
g_rdpdr_device[*id].device_type = DEVICE_TYPE_PRINTER;
|
||||||
|
g_rdpdr_device[*id].pdevice_data = (void *) pprinter_data;
|
||||||
|
count++;
|
||||||
|
(*id)++;
|
||||||
|
|
||||||
|
optarg = pos;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
printer_create(HANDLE * handle)
|
printer_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags,
|
||||||
|
char *filename, HANDLE * handle)
|
||||||
{
|
{
|
||||||
printer_fp = popen("lpr", "w");
|
char cmd[256];
|
||||||
*handle = 0;
|
PRINTER *pprinter_data;
|
||||||
|
|
||||||
|
pprinter_data = (PRINTER *) g_rdpdr_device[device_id].pdevice_data;
|
||||||
|
|
||||||
|
/* default printer name use default printer queue as well in unix */
|
||||||
|
if (pprinter_data->printer == "mydeskjet")
|
||||||
|
{
|
||||||
|
pprinter_data->printer_fp = popen("lpr", "w");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(cmd, "lpr -P %s", pprinter_data->printer);
|
||||||
|
pprinter_data->printer_fp = popen(cmd, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_rdpdr_device[device_id].handle = pprinter_data->printer_fp->_fileno;
|
||||||
|
*handle = g_rdpdr_device[device_id].handle;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
printer_close(HANDLE handle)
|
printer_close(HANDLE handle)
|
||||||
{
|
{
|
||||||
pclose(printer_fp);
|
PRINTER *pprinter_data;
|
||||||
|
|
||||||
|
pprinter_data = get_printer_data(handle);
|
||||||
|
|
||||||
|
g_rdpdr_device[get_device_index(handle)].handle = 0;
|
||||||
|
|
||||||
|
pclose(pprinter_data->printer_fp);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
printer_write(HANDLE handle, uint8 * data, uint32 length, uint32 * result)
|
printer_write(HANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
*result = fwrite(data, 1, length, printer_fp);
|
PRINTER *pprinter_data;
|
||||||
|
|
||||||
|
pprinter_data = get_printer_data(handle);
|
||||||
|
*result = length * fwrite(data, length, 1, pprinter_data->printer_fp);
|
||||||
|
|
||||||
|
if (ferror(pprinter_data->printer_fp))
|
||||||
|
{
|
||||||
|
*result = 0;
|
||||||
|
return STATUS_INVALID_HANDLE;
|
||||||
|
}
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
169
printercache.c
Normal file
169
printercache.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/* -*- c-basic-offset: 8 -*-
|
||||||
|
* rdesktop: A Remote Desktop Protocol client.
|
||||||
|
* Entrypoint and utility functions
|
||||||
|
* Copyright (C) Matthew Chapman 1999-2003
|
||||||
|
* Copyright (C) Jeroen Meijer 2003
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* According to the W2K RDP Printer Redirection WhitePaper, a data
|
||||||
|
* blob is sent to the client after the configuration of the printer
|
||||||
|
* is changed at the server.
|
||||||
|
*
|
||||||
|
* This data blob is saved to the registry. The client returns this
|
||||||
|
* data blob in a new session with the printer announce data.
|
||||||
|
* The data is not interpreted by the client.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "rdesktop.h"
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
printercache_mkdir(char *base, char *printer)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
path = (char *) xmalloc(strlen(base) + sizeof("/.rdesktop/rdpdr/") + strlen(printer));
|
||||||
|
|
||||||
|
sprintf(path, "%s/.rdesktop", base);
|
||||||
|
if ((mkdir(path, 0700) == -1) && errno != EEXIST)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(path, "/rdpdr");
|
||||||
|
if ((mkdir(path, 0700) == -1) && errno != EEXIST)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(path, "/");
|
||||||
|
strcat(path, printer);
|
||||||
|
if ((mkdir(path, 0700) == -1) && errno != EEXIST)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(path);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
printercache_load_blob(char *printer_name, uint8 ** data)
|
||||||
|
{
|
||||||
|
char *home, *path;
|
||||||
|
struct stat st;
|
||||||
|
int fd, length;
|
||||||
|
|
||||||
|
if (printer_name == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
home = getenv("HOME");
|
||||||
|
if (home == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) + sizeof("/AutoPrinterCacheData"));
|
||||||
|
sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (fstat(fd, &st))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*data = (uint8 *) xmalloc(st.st_size);
|
||||||
|
length = read(fd, *data, st.st_size);
|
||||||
|
close(fd);
|
||||||
|
xfree(path);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printercache_save_blob(char *printer_name, uint8 * data, uint32 length)
|
||||||
|
{
|
||||||
|
char *home, *path;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (printer_name == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
home = getenv("HOME");
|
||||||
|
if (home == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!printercache_mkdir(home, printer_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) + sizeof("/AutoPrinterCacheData"));
|
||||||
|
sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
|
||||||
|
|
||||||
|
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(fd, data, length) != length)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
xfree(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printercache_process(STREAM s)
|
||||||
|
{
|
||||||
|
uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
|
||||||
|
char device_name[9], printer[256], driver[256];
|
||||||
|
|
||||||
|
in_uint32_le(s, type);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
|
||||||
|
in_uint32_le(s, printer_unicode_length);
|
||||||
|
in_uint32_le(s, blob_length);
|
||||||
|
|
||||||
|
if (printer_unicode_length < 2 * 255)
|
||||||
|
{
|
||||||
|
rdp_in_unistr(s, printer, printer_unicode_length);
|
||||||
|
printercache_save_blob(printer, s->p, blob_length);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
// TODO: I think this one just tells us what printer is on LPT? but why?
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
unimpl("RDPDR Printer Cache Packet Type: %d\n", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
25
proto.h
25
proto.h
@ -26,6 +26,12 @@ void cliprdr_send_native_format_announce(uint8 * data, uint32 length);
|
|||||||
void cliprdr_send_data_request(uint32 format);
|
void cliprdr_send_data_request(uint32 format);
|
||||||
void cliprdr_send_data(uint8 * data, uint32 length);
|
void cliprdr_send_data(uint8 * data, uint32 length);
|
||||||
BOOL cliprdr_init(void);
|
BOOL cliprdr_init(void);
|
||||||
|
/* disk.c */
|
||||||
|
NTSTATUS disk_query_information(HANDLE handle, uint32 info_class, STREAM out);
|
||||||
|
NTSTATUS disk_set_information(HANDLE handle, uint32 info_class, STREAM in, STREAM out);
|
||||||
|
NTSTATUS disk_query_volume_information(HANDLE handle, uint32 info_class, STREAM out);
|
||||||
|
NTSTATUS disk_query_directory(HANDLE handle, uint32 info_class, char *pattern, STREAM out);
|
||||||
|
int disk_enum_devices(int *id, char *optarg);
|
||||||
/* ewmhints.c */
|
/* ewmhints.c */
|
||||||
int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height);
|
int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height);
|
||||||
/* iso.c */
|
/* iso.c */
|
||||||
@ -46,7 +52,13 @@ void mcs_disconnect(void);
|
|||||||
/* orders.c */
|
/* orders.c */
|
||||||
void process_orders(STREAM s, uint16 num_orders);
|
void process_orders(STREAM s, uint16 num_orders);
|
||||||
void reset_order_state(void);
|
void reset_order_state(void);
|
||||||
|
/* parallel.c */
|
||||||
|
int parallel_enum_devices(int *id, char *optarg);
|
||||||
/* printer.c */
|
/* printer.c */
|
||||||
|
int printer_enum_devices(int *id, char *optarg);
|
||||||
|
/* printercache.c */
|
||||||
|
int printercache_load_blob(char *printer_name, uint8 ** data);
|
||||||
|
void printercache_process(STREAM s);
|
||||||
/* rdesktop.c */
|
/* rdesktop.c */
|
||||||
int main(int argc, char *argv[]);
|
int main(int argc, char *argv[]);
|
||||||
void generate_random(uint8 * random);
|
void generate_random(uint8 * random);
|
||||||
@ -56,13 +68,17 @@ void xfree(void *mem);
|
|||||||
void error(char *format, ...);
|
void error(char *format, ...);
|
||||||
void warning(char *format, ...);
|
void warning(char *format, ...);
|
||||||
void unimpl(char *format, ...);
|
void unimpl(char *format, ...);
|
||||||
void hexdump(unsigned char *p, int len);
|
void hexdump(unsigned char *p, unsigned int len);
|
||||||
|
char *toupper(char* p);
|
||||||
|
char *ltoa(long N, int base);
|
||||||
int load_licence(unsigned char **data);
|
int load_licence(unsigned char **data);
|
||||||
void save_licence(unsigned char *data, int length);
|
void save_licence(unsigned char *data, int length);
|
||||||
|
char *next_arg(char *src, char needle);
|
||||||
/* rdp5.c */
|
/* rdp5.c */
|
||||||
void rdp5_process(STREAM s, BOOL encryption);
|
void rdp5_process(STREAM s, BOOL encryption);
|
||||||
/* rdp.c */
|
/* rdp.c */
|
||||||
void rdp_out_unistr(STREAM s, char *string, int len);
|
void rdp_out_unistr(STREAM s, char *string, int len);
|
||||||
|
int rdp_in_unistr(STREAM s, char *string, int uni_len);
|
||||||
void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1,
|
void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1,
|
||||||
uint16 param2);
|
uint16 param2);
|
||||||
void process_colour_pointer_pdu(STREAM s);
|
void process_colour_pointer_pdu(STREAM s);
|
||||||
@ -75,12 +91,15 @@ BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char
|
|||||||
char *directory);
|
char *directory);
|
||||||
void rdp_disconnect(void);
|
void rdp_disconnect(void);
|
||||||
/* rdpdr.c */
|
/* rdpdr.c */
|
||||||
|
void convert_to_unix_filename(char *filename);
|
||||||
void rdpdr_send_connect(void);
|
void rdpdr_send_connect(void);
|
||||||
void rdpdr_send_name(void);
|
void rdpdr_send_name(void);
|
||||||
void rdpdr_send_available(void);
|
void rdpdr_send_available(void);
|
||||||
void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
|
void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
|
||||||
uint32 length);
|
uint32 length);
|
||||||
BOOL rdpdr_init(void);
|
BOOL rdpdr_init();
|
||||||
|
int get_device_index(HANDLE handle);
|
||||||
|
BOOL rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status);
|
||||||
/* rdpsnd.c */
|
/* rdpsnd.c */
|
||||||
STREAM rdpsnd_init_packet(uint16 type, uint16 size);
|
STREAM rdpsnd_init_packet(uint16 type, uint16 size);
|
||||||
void rdpsnd_send(STREAM s);
|
void rdpsnd_send(STREAM s);
|
||||||
@ -112,6 +131,8 @@ STREAM sec_recv(void);
|
|||||||
BOOL sec_connect(char *server, char *username);
|
BOOL sec_connect(char *server, char *username);
|
||||||
void sec_disconnect(void);
|
void sec_disconnect(void);
|
||||||
/* serial.c */
|
/* serial.c */
|
||||||
|
BOOL serial_get_timeout(uint32 handle, uint32 length, uint32 * timeout, uint32 * itv_timeout);
|
||||||
|
int serial_enum_devices(int *id, char *optarg);
|
||||||
/* tcp.c */
|
/* tcp.c */
|
||||||
STREAM tcp_init(uint32 maxlen);
|
STREAM tcp_init(uint32 maxlen);
|
||||||
void tcp_send(STREAM s);
|
void tcp_send(STREAM s);
|
||||||
|
147
rdesktop.c
147
rdesktop.c
@ -1,7 +1,7 @@
|
|||||||
/* -*- c-basic-offset: 8 -*-
|
/* -*- c-basic-offset: 8 -*-
|
||||||
rdesktop: A Remote Desktop Protocol client.
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
Entrypoint and utility functions
|
Entrypoint and utility functions
|
||||||
Copyright (C) Matthew Chapman 1999-2004
|
Copyright (C) Matthew Chapman 1999-2003
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -73,6 +73,9 @@ extern BOOL g_owncolmap;
|
|||||||
BOOL g_rdpsnd = False;
|
BOOL g_rdpsnd = False;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||||
|
extern uint32 g_num_devices;
|
||||||
|
|
||||||
#ifdef RDP2VNC
|
#ifdef RDP2VNC
|
||||||
extern int rfb_port;
|
extern int rfb_port;
|
||||||
extern int defer_time;
|
extern int defer_time;
|
||||||
@ -111,9 +114,18 @@ usage(char *program)
|
|||||||
fprintf(stderr, " -K: keep window manager key bindings\n");
|
fprintf(stderr, " -K: keep window manager key bindings\n");
|
||||||
fprintf(stderr, " -S: caption button size (single application mode)\n");
|
fprintf(stderr, " -S: caption button size (single application mode)\n");
|
||||||
fprintf(stderr, " -T: window title\n");
|
fprintf(stderr, " -T: window title\n");
|
||||||
fprintf(stderr, " -N: enable numlock synchronisation\n");
|
fprintf(stderr, " -N: enable numlock syncronization\n");
|
||||||
fprintf(stderr, " -a: connection colour depth\n");
|
fprintf(stderr, " -a: connection colour depth\n");
|
||||||
fprintf(stderr, " -r: enable specified device redirection (currently: sound)\n");
|
fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
|
||||||
|
fprintf(stderr, " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
|
||||||
|
fprintf(stderr, " or :COM1=/dev/ttyS0:9600,0|1|2,0|2,5|6|7|8:dtr \n");
|
||||||
|
fprintf(stderr, " '-r disk:A=/mnt/floppy': enable redirection of /mnt/floppy to A:\n");
|
||||||
|
fprintf(stderr, " or A=/mnt/floppy,D=/mnt/cdrom'\n");
|
||||||
|
fprintf(stderr, " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
|
||||||
|
fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
|
||||||
|
fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
|
||||||
|
fprintf(stderr, " or mydeskjet:\"HP Laserjet IIIP\" to enter server driver as well\n");
|
||||||
|
fprintf(stderr, " '-r sound': enable sound redirection\n");
|
||||||
fprintf(stderr, " -0: attach to console\n");
|
fprintf(stderr, " -0: attach to console\n");
|
||||||
fprintf(stderr, " -4: use RDP version 4\n");
|
fprintf(stderr, " -4: use RDP version 4\n");
|
||||||
fprintf(stderr, " -5: use RDP version 5 (default)\n");
|
fprintf(stderr, " -5: use RDP version 5 (default)\n");
|
||||||
@ -218,6 +230,7 @@ main(int argc, char *argv[])
|
|||||||
uint32 flags;
|
uint32 flags;
|
||||||
char *p;
|
char *p;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
int username_option = 0;
|
int username_option = 0;
|
||||||
|
|
||||||
flags = RDP_LOGON_NORMAL;
|
flags = RDP_LOGON_NORMAL;
|
||||||
@ -225,6 +238,8 @@ main(int argc, char *argv[])
|
|||||||
domain[0] = password[0] = shell[0] = directory[0] = 0;
|
domain[0] = password[0] = shell[0] = directory[0] = 0;
|
||||||
strcpy(keymapname, "en-us");
|
strcpy(keymapname, "en-us");
|
||||||
|
|
||||||
|
g_num_devices = 0;
|
||||||
|
|
||||||
#ifdef RDP2VNC
|
#ifdef RDP2VNC
|
||||||
#define VNCOPT "V:Q:"
|
#define VNCOPT "V:Q:"
|
||||||
#else
|
#else
|
||||||
@ -385,12 +400,36 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
if (!strcmp(optarg, "sound"))
|
|
||||||
|
if (strncmp("sound", optarg, 5) == 0)
|
||||||
|
{
|
||||||
#ifdef WITH_RDPSND
|
#ifdef WITH_RDPSND
|
||||||
g_rdpsnd = True;
|
g_rdpsnd = True;
|
||||||
#else
|
#else
|
||||||
warning("Not compiled with sound support");
|
warning("Not compiled with sound support");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else if (strncmp("disk", optarg, 4) == 0)
|
||||||
|
{
|
||||||
|
/* -r disk:h:=/mnt/floppy */
|
||||||
|
disk_enum_devices(&g_num_devices, optarg + 4);
|
||||||
|
}
|
||||||
|
else if (strncmp("comport", optarg, 7) == 0)
|
||||||
|
{
|
||||||
|
serial_enum_devices(&g_num_devices, optarg + 7);
|
||||||
|
}
|
||||||
|
else if (strncmp("lptport", optarg, 7) == 0)
|
||||||
|
{
|
||||||
|
parallel_enum_devices(&g_num_devices, optarg + 7);
|
||||||
|
}
|
||||||
|
else if (strncmp("printer", optarg, 7) == 0)
|
||||||
|
{
|
||||||
|
printer_enum_devices(&g_num_devices, optarg + 7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '0':
|
case '0':
|
||||||
@ -470,7 +509,7 @@ main(int argc, char *argv[])
|
|||||||
if (g_rdpsnd)
|
if (g_rdpsnd)
|
||||||
rdpsnd_init();
|
rdpsnd_init();
|
||||||
#endif
|
#endif
|
||||||
/* rdpdr_init(); */
|
rdpdr_init();
|
||||||
|
|
||||||
if (!rdp_connect(server, flags, domain, password, shell, directory))
|
if (!rdp_connect(server, flags, domain, password, shell, directory))
|
||||||
return 1;
|
return 1;
|
||||||
@ -660,7 +699,7 @@ unimpl(char *format, ...)
|
|||||||
|
|
||||||
/* produce a hex dump */
|
/* produce a hex dump */
|
||||||
void
|
void
|
||||||
hexdump(unsigned char *p, int len)
|
hexdump(unsigned char *p, unsigned int len)
|
||||||
{
|
{
|
||||||
unsigned char *line = p;
|
unsigned char *line = p;
|
||||||
int i, thisline, offset = 0;
|
int i, thisline, offset = 0;
|
||||||
@ -687,6 +726,102 @@ hexdump(unsigned char *p, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
input: src is the string we look in for needle
|
||||||
|
return value: returns next src pointer, for
|
||||||
|
succesive executions, like in a while loop
|
||||||
|
if retval is 0, then there are no more args.
|
||||||
|
pitfalls:
|
||||||
|
src is modified. 0x00 chars are inserted to
|
||||||
|
terminate strings.
|
||||||
|
return val, points on the next val chr after ins
|
||||||
|
0x00
|
||||||
|
|
||||||
|
example usage:
|
||||||
|
while( (pos = next_arg( optarg, ',')) ){
|
||||||
|
printf("%s\n",optarg);
|
||||||
|
optarg=pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
next_arg(char *src, char needle)
|
||||||
|
{
|
||||||
|
char *nextval;
|
||||||
|
|
||||||
|
// EOS
|
||||||
|
if (*src == (char) 0x00)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// more args available.
|
||||||
|
nextval = strchr(src, needle);
|
||||||
|
if (nextval)
|
||||||
|
{
|
||||||
|
*nextval = (char) 0x00;
|
||||||
|
return ++nextval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no more args after this, jump to EOS
|
||||||
|
nextval = src + strlen(src);
|
||||||
|
return nextval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
toupper(char* p)
|
||||||
|
{
|
||||||
|
while( *p ){
|
||||||
|
if( (*p >= 'a') && (*p <= 'z') )
|
||||||
|
*p = *p - 32;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* not all clibs got ltoa */
|
||||||
|
#define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
|
||||||
|
|
||||||
|
char *
|
||||||
|
ltoa(long N, int base)
|
||||||
|
{
|
||||||
|
static char ret[LTOA_BUFSIZE];
|
||||||
|
|
||||||
|
register int i = 2;
|
||||||
|
long uarg;
|
||||||
|
char *tail, *head = ret, buf[LTOA_BUFSIZE];
|
||||||
|
|
||||||
|
if (36 < base || 2 > base)
|
||||||
|
base = 10;
|
||||||
|
|
||||||
|
tail = &buf[LTOA_BUFSIZE - 1];
|
||||||
|
*tail-- = '\0';
|
||||||
|
|
||||||
|
if (10 == base && N < 0L)
|
||||||
|
{
|
||||||
|
*head++ = '-';
|
||||||
|
uarg = -N;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
uarg = N;
|
||||||
|
|
||||||
|
if (uarg)
|
||||||
|
{
|
||||||
|
for (i = 1; uarg; ++i)
|
||||||
|
{
|
||||||
|
register ldiv_t r;
|
||||||
|
|
||||||
|
r = ldiv(uarg, base);
|
||||||
|
*tail-- = (char) (r.rem + ((9L < r.rem) ? ('A' - 10L) : '0'));
|
||||||
|
uarg = r.quot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*tail-- = '0';
|
||||||
|
|
||||||
|
memcpy(head, ++tail, i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
load_licence(unsigned char **data)
|
load_licence(unsigned char **data)
|
||||||
|
@ -49,9 +49,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; }
|
#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; }
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MAX
|
#ifndef MAX
|
||||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||||
#endif
|
#endif
|
||||||
|
19
rdp.c
19
rdp.c
@ -132,6 +132,25 @@ rdp_out_unistr(STREAM s, char *string, int len)
|
|||||||
s->p += len;
|
s->p += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Input a string in Unicode
|
||||||
|
*
|
||||||
|
* Returns str_len of string
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
rdp_in_unistr(STREAM s, char *string, int uni_len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < uni_len / 2)
|
||||||
|
{
|
||||||
|
in_uint8a(s, &string[i++], 1);
|
||||||
|
in_uint8s(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse a logon info packet */
|
/* Parse a logon info packet */
|
||||||
static void
|
static void
|
||||||
rdp_send_logon_info(uint32 flags, char *domain, char *user,
|
rdp_send_logon_info(uint32 flags, char *domain, char *user,
|
||||||
|
718
rdpdr.c
718
rdpdr.c
@ -6,12 +6,103 @@
|
|||||||
#define IRP_MJ_WRITE 0x04
|
#define IRP_MJ_WRITE 0x04
|
||||||
#define IRP_MJ_DEVICE_CONTROL 0x0e
|
#define IRP_MJ_DEVICE_CONTROL 0x0e
|
||||||
|
|
||||||
|
#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_MN_QUERY_DIRECTORY 0x01
|
||||||
|
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
|
||||||
|
|
||||||
|
#define MAX_ASYNC_IO_REQUESTS 10
|
||||||
|
|
||||||
extern char hostname[16];
|
extern char hostname[16];
|
||||||
extern DEVICE_FNS serial_fns;
|
extern DEVICE_FNS serial_fns;
|
||||||
extern DEVICE_FNS printer_fns;
|
extern DEVICE_FNS printer_fns;
|
||||||
|
extern DEVICE_FNS parallel_fns;
|
||||||
|
extern DEVICE_FNS disk_fns;
|
||||||
|
|
||||||
|
|
||||||
static VCHANNEL *rdpdr_channel;
|
static VCHANNEL *rdpdr_channel;
|
||||||
|
|
||||||
|
/* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
|
||||||
|
HANDLE g_min_timeout_fd;
|
||||||
|
uint32 g_num_devices;
|
||||||
|
|
||||||
|
/* Table with information about rdpdr devices */
|
||||||
|
RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];
|
||||||
|
|
||||||
|
/* Used to store incoming io request, until they are ready to be completed */
|
||||||
|
struct async_iorequest
|
||||||
|
{
|
||||||
|
uint32 fd, major, minor, offset, device, id, length;
|
||||||
|
long timeout, /* Total timeout */
|
||||||
|
itv_timeout; /* Interval timeout (between serial characters) */
|
||||||
|
uint8 *buffer;
|
||||||
|
DEVICE_FNS *fns;
|
||||||
|
} g_iorequest[MAX_ASYNC_IO_REQUESTS];
|
||||||
|
|
||||||
|
/* Return device_id for a given handle */
|
||||||
|
int
|
||||||
|
get_device_index(HANDLE 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 */
|
||||||
|
void
|
||||||
|
convert_to_unix_filename(char *filename)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
while ((p = strchr(filename, '\\')))
|
||||||
|
{
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a new io request to the table containing pending io requests so it won't block rdesktop */
|
||||||
|
BOOL
|
||||||
|
add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
|
||||||
|
DEVICE_FNS * fns, long total_timeout, long interval_timeout, uint8 * buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct async_iorequest *iorq;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
|
||||||
|
{
|
||||||
|
iorq = &g_iorequest[i];
|
||||||
|
|
||||||
|
if (iorq->fd == 0)
|
||||||
|
{
|
||||||
|
iorq->device = device;
|
||||||
|
iorq->fd = file;
|
||||||
|
iorq->id = id;
|
||||||
|
iorq->major = major;
|
||||||
|
iorq->length = length;
|
||||||
|
iorq->fns = fns;
|
||||||
|
iorq->timeout = total_timeout;
|
||||||
|
iorq->itv_timeout = interval_timeout;
|
||||||
|
iorq->buffer = buffer;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("IO request table full. Increase MAX_ASYNC_IO_REQUESTS in rdpdr.c!\n");
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rdpdr_send_connect(void)
|
rdpdr_send_connect(void)
|
||||||
{
|
{
|
||||||
@ -27,6 +118,7 @@ rdpdr_send_connect(void)
|
|||||||
channel_send(s, rdpdr_channel);
|
channel_send(s, rdpdr_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rdpdr_send_name(void)
|
rdpdr_send_name(void)
|
||||||
{
|
{
|
||||||
@ -45,55 +137,79 @@ rdpdr_send_name(void)
|
|||||||
channel_send(s, rdpdr_channel);
|
channel_send(s, rdpdr_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the size of the payload of the announce packet */
|
||||||
|
int
|
||||||
|
announcedata_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;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rdpdr_send_available(void)
|
rdpdr_send_available(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8 magic[4] = "rDAD";
|
uint8 magic[4] = "rDAD";
|
||||||
char *driver = "Digital turbo PrintServer 20"; /* Fairly generic PostScript driver */
|
uint32 driverlen, printerlen, bloblen;
|
||||||
char *printer = "PostScript";
|
int i;
|
||||||
uint32 driverlen = (strlen(driver) + 1) * 2;
|
|
||||||
uint32 printerlen = (strlen(printer) + 1) * 2;
|
|
||||||
STREAM s;
|
STREAM s;
|
||||||
|
PRINTER *printerinfo;
|
||||||
|
|
||||||
s = channel_init(rdpdr_channel, 8 + 20);
|
s = channel_init(rdpdr_channel, announcedata_size());
|
||||||
out_uint8a(s, magic, 4);
|
out_uint8a(s, magic, 4);
|
||||||
out_uint32_le(s, 1); /* Number of devices */
|
out_uint32_le(s, g_num_devices);
|
||||||
|
|
||||||
#if 1
|
for (i = 0; i < g_num_devices; i++)
|
||||||
out_uint32_le(s, 0x1); /* Device type 0x1 - serial */
|
{
|
||||||
out_uint32_le(s, 0); /* Handle */
|
out_uint32_le(s, g_rdpdr_device[i].device_type);
|
||||||
out_uint8p(s, "COM2", 4);
|
out_uint32_le(s, i); /* RDP Device ID */
|
||||||
out_uint8s(s, 4); /* Pad to 8 */
|
out_uint8p(s, g_rdpdr_device[i].name, 8);
|
||||||
out_uint32(s, 0);
|
|
||||||
#endif
|
if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
|
||||||
#if 0
|
{
|
||||||
out_uint32_le(s, 0x2); /* Device type 0x2 - parallel */
|
printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
|
||||||
out_uint32_le(s, 0);
|
|
||||||
out_uint8p(s, "LPT2", 4);
|
driverlen = 2 * strlen(printerinfo->driver) + 2;
|
||||||
out_uint8s(s, 4);
|
printerlen = 2 * strlen(printerinfo->printer) + 2;
|
||||||
out_uint32(s, 0);
|
bloblen = printerinfo->bloblen;
|
||||||
#endif
|
|
||||||
#if 1
|
out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
|
||||||
out_uint32_le(s, 0x4); /* Device type 0x4 - printer */
|
out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
|
||||||
out_uint32_le(s, 1);
|
out_uint8s(s, 8); /* unknown */
|
||||||
out_uint8p(s, "PRN1", 4);
|
out_uint32_le(s, driverlen);
|
||||||
out_uint8s(s, 4);
|
out_uint32_le(s, printerlen);
|
||||||
out_uint32_le(s, 24 + driverlen + printerlen); /* length of extra info */
|
out_uint32_le(s, bloblen);
|
||||||
out_uint32_le(s, 2); /* unknown */
|
rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
|
||||||
out_uint8s(s, 8); /* unknown */
|
rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
|
||||||
out_uint32_le(s, driverlen); /* length of driver name */
|
out_uint8a(s, printerinfo->blob, bloblen);
|
||||||
out_uint32_le(s, printerlen); /* length of printer name */
|
|
||||||
out_uint32(s, 0); /* unknown */
|
xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
|
||||||
rdp_out_unistr(s, driver, driverlen - 2);
|
}
|
||||||
rdp_out_unistr(s, printer, printerlen - 2);
|
else
|
||||||
#endif
|
{
|
||||||
#if 0
|
out_uint32(s, 0);
|
||||||
out_uint32_le(s, 0x8); /* Device type 0x8 - disk */
|
}
|
||||||
out_uint32_le(s, 0);
|
}
|
||||||
out_uint8p(s, "Z:", 2);
|
|
||||||
out_uint8s(s, 6);
|
|
||||||
out_uint32(s, 0);
|
|
||||||
#endif
|
|
||||||
#if 0
|
#if 0
|
||||||
out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
|
out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
|
||||||
out_uint32_le(s, 0);
|
out_uint32_le(s, 0);
|
||||||
@ -121,20 +237,37 @@ rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, ui
|
|||||||
out_uint32_le(s, result);
|
out_uint32_le(s, result);
|
||||||
out_uint8p(s, buffer, length);
|
out_uint8p(s, buffer, length);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
|
/* JIF
|
||||||
|
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
|
||||||
channel_send(s, rdpdr_channel);
|
channel_send(s, rdpdr_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rdpdr_process_irp(STREAM s)
|
rdpdr_process_irp(STREAM s)
|
||||||
{
|
{
|
||||||
uint32 device, file, id, major, minor;
|
uint32 result = 0,
|
||||||
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
length = 0,
|
||||||
uint32 result = 0, length, request, bytes_in, bytes_out;
|
desired_access = 0,
|
||||||
uint8 buffer[256];
|
request,
|
||||||
uint32 buffer_len = 1;
|
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[256];
|
||||||
|
uint8 *buffer, *pst_buf;
|
||||||
struct stream out;
|
struct stream out;
|
||||||
DEVICE_FNS *fns;
|
DEVICE_FNS *fns;
|
||||||
|
BOOL rw_blocking = True;
|
||||||
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
in_uint32_le(s, device);
|
in_uint32_le(s, device);
|
||||||
in_uint32_le(s, file);
|
in_uint32_le(s, file);
|
||||||
@ -142,16 +275,38 @@ rdpdr_process_irp(STREAM s)
|
|||||||
in_uint32_le(s, major);
|
in_uint32_le(s, major);
|
||||||
in_uint32_le(s, minor);
|
in_uint32_le(s, minor);
|
||||||
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
buffer_len = 0;
|
||||||
|
buffer = (uint8 *) xmalloc(1024);
|
||||||
|
buffer[0] = 0;
|
||||||
|
|
||||||
/* FIXME: this should probably be a more dynamic mapping */
|
|
||||||
switch (device)
|
switch (g_rdpdr_device[device].device_type)
|
||||||
{
|
{
|
||||||
case 0:
|
case DEVICE_TYPE_SERIAL:
|
||||||
|
|
||||||
fns = &serial_fns;
|
fns = &serial_fns;
|
||||||
case 1:
|
rw_blocking = False;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_TYPE_PARALLEL:
|
||||||
|
|
||||||
|
fns = ¶llel_fns;
|
||||||
|
rw_blocking = False;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_TYPE_PRINTER:
|
||||||
|
|
||||||
fns = &printer_fns;
|
fns = &printer_fns;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_TYPE_DISK:
|
||||||
|
|
||||||
|
fns = &disk_fns;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_TYPE_SCARD:
|
||||||
default:
|
default:
|
||||||
|
|
||||||
error("IRP for bad device %ld\n", device);
|
error("IRP for bad device %ld\n", device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -159,42 +314,232 @@ rdpdr_process_irp(STREAM s)
|
|||||||
switch (major)
|
switch (major)
|
||||||
{
|
{
|
||||||
case IRP_MJ_CREATE:
|
case IRP_MJ_CREATE:
|
||||||
if (fns->create)
|
|
||||||
status = fns->create(&result);
|
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;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_CLOSE:
|
case IRP_MJ_CLOSE:
|
||||||
if (fns->close)
|
if (!fns->close)
|
||||||
status = fns->close(file);
|
{
|
||||||
|
status = STATUS_NOT_SUPPORTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fns->close(file);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_READ:
|
case IRP_MJ_READ:
|
||||||
if (fns->read)
|
|
||||||
|
if (!fns->read)
|
||||||
{
|
{
|
||||||
if (length > sizeof(buffer))
|
status = STATUS_NOT_SUPPORTED;
|
||||||
length = sizeof(buffer);
|
break;
|
||||||
status = fns->read(file, buffer, length, &result);
|
|
||||||
buffer_len = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (rw_blocking) // Complete read immediately
|
||||||
|
{
|
||||||
|
buffer = (uint8 *) xrealloc((void *) buffer, length);
|
||||||
|
status = fns->read(file, buffer, length, offset, &result);
|
||||||
|
buffer_len = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add request to table
|
||||||
|
pst_buf = (uint8 *) xmalloc(length);
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
status = STATUS_PENDING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = STATUS_CANCELLED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_WRITE:
|
case IRP_MJ_WRITE:
|
||||||
if (fns->write)
|
|
||||||
status = fns->write(file, s->p, length, &result);
|
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 (rw_blocking) // Complete immediately
|
||||||
|
{
|
||||||
|
status = fns->write(file, s->p, length, offset, &result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to table
|
||||||
|
pst_buf = (uint8 *) xmalloc(length);
|
||||||
|
in_uint8a(s, pst_buf, length);
|
||||||
|
|
||||||
|
if (add_async_iorequest
|
||||||
|
(device, file, id, major, length, fns, 0, 0, pst_buf))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
case IRP_MN_QUERY_DIRECTORY:
|
||||||
|
|
||||||
|
in_uint32_le(s, info_level);
|
||||||
|
in_uint8s(s, 1);
|
||||||
|
in_uint32_le(s, length);
|
||||||
|
in_uint8s(s, 0x17);
|
||||||
|
if (length && length < 2 * 255)
|
||||||
|
{
|
||||||
|
rdp_in_unistr(s, filename, length);
|
||||||
|
convert_to_unix_filename(filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename[0] = 0;
|
||||||
|
}
|
||||||
|
out.data = out.p = buffer;
|
||||||
|
out.size = sizeof(buffer);
|
||||||
|
status = disk_query_directory(file, info_level, filename,
|
||||||
|
&out);
|
||||||
|
result = buffer_len = out.p - out.data;
|
||||||
|
if (!buffer_len)
|
||||||
|
buffer_len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
|
||||||
|
|
||||||
|
/* JIF
|
||||||
|
unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
|
||||||
|
status = STATUS_PENDING; // Don't send completion packet
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
status = STATUS_INVALID_PARAMETER;
|
||||||
|
/* JIF
|
||||||
|
unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_DEVICE_CONTROL:
|
case IRP_MJ_DEVICE_CONTROL:
|
||||||
if (fns->device_control)
|
|
||||||
|
if (!fns->device_control)
|
||||||
{
|
{
|
||||||
in_uint32_le(s, bytes_out);
|
status = STATUS_NOT_SUPPORTED;
|
||||||
in_uint32_le(s, bytes_in);
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in_uint32_le(s, bytes_out);
|
||||||
|
in_uint32_le(s, bytes_in);
|
||||||
|
in_uint32_le(s, request);
|
||||||
|
in_uint8s(s, 0x14);
|
||||||
|
|
||||||
|
buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -202,7 +547,52 @@ rdpdr_process_irp(STREAM s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
|
if (status != STATUS_PENDING)
|
||||||
|
{
|
||||||
|
rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
|
||||||
|
}
|
||||||
|
xfree(buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdpdr_send_clientcapabilty(void)
|
||||||
|
{
|
||||||
|
uint8 magic[4] = "rDPC";
|
||||||
|
STREAM s;
|
||||||
|
|
||||||
|
s = channel_init(rdpdr_channel, 0x50);
|
||||||
|
out_uint8a(s, magic, 4);
|
||||||
|
out_uint32_le(s, 5); /* count */
|
||||||
|
out_uint16_le(s, 1); /* first */
|
||||||
|
out_uint16_le(s, 0x28); /* length */
|
||||||
|
out_uint32_le(s, 1);
|
||||||
|
out_uint32_le(s, 2);
|
||||||
|
out_uint16_le(s, 2);
|
||||||
|
out_uint16_le(s, 5);
|
||||||
|
out_uint16_le(s, 1);
|
||||||
|
out_uint16_le(s, 5);
|
||||||
|
out_uint16_le(s, 0xFFFF);
|
||||||
|
out_uint16_le(s, 0);
|
||||||
|
out_uint32_le(s, 0);
|
||||||
|
out_uint32_le(s, 3);
|
||||||
|
out_uint32_le(s, 0);
|
||||||
|
out_uint32_le(s, 0);
|
||||||
|
out_uint16_le(s, 2); /* second */
|
||||||
|
out_uint16_le(s, 8); /* length */
|
||||||
|
out_uint32_le(s, 1);
|
||||||
|
out_uint16_le(s, 3); /* third */
|
||||||
|
out_uint16_le(s, 8); /* length */
|
||||||
|
out_uint32_le(s, 1);
|
||||||
|
out_uint16_le(s, 4); /* fourth */
|
||||||
|
out_uint16_le(s, 8); /* length */
|
||||||
|
out_uint32_le(s, 1);
|
||||||
|
out_uint16_le(s, 5); /* fifth */
|
||||||
|
out_uint16_le(s, 8); /* length */
|
||||||
|
out_uint32_le(s, 1);
|
||||||
|
|
||||||
|
s_mark_end(s);
|
||||||
|
channel_send(s, rdpdr_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -211,8 +601,10 @@ rdpdr_process(STREAM s)
|
|||||||
uint32 handle;
|
uint32 handle;
|
||||||
uint8 *magic;
|
uint8 *magic;
|
||||||
|
|
||||||
printf("rdpdr_process\n");
|
#if WITH_DEBUG_RDP5
|
||||||
|
printf("--- rdpdr_process ---\n");
|
||||||
hexdump(s->p, s->end - s->p);
|
hexdump(s->p, s->end - s->p);
|
||||||
|
#endif
|
||||||
in_uint8p(s, magic, 4);
|
in_uint8p(s, magic, 4);
|
||||||
|
|
||||||
if ((magic[0] == 'r') && (magic[1] == 'D'))
|
if ((magic[0] == 'r') && (magic[1] == 'D'))
|
||||||
@ -226,19 +618,35 @@ rdpdr_process(STREAM s)
|
|||||||
{
|
{
|
||||||
rdpdr_send_connect();
|
rdpdr_send_connect();
|
||||||
rdpdr_send_name();
|
rdpdr_send_name();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((magic[2] == 'C') && (magic[3] == 'C'))
|
||||||
|
{
|
||||||
|
/* connect from server */
|
||||||
|
rdpdr_send_clientcapabilty();
|
||||||
rdpdr_send_available();
|
rdpdr_send_available();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ((magic[2] == 'C') && (magic[3] == 'C'))
|
if ((magic[2] == 'r') && (magic[3] == 'd'))
|
||||||
{
|
|
||||||
/* connect from server */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ((magic[2] == 'r') && (magic[3] == 'd'))
|
|
||||||
{
|
{
|
||||||
/* connect to a specific resource */
|
/* connect to a specific resource */
|
||||||
in_uint32(s, handle);
|
in_uint32(s, handle);
|
||||||
printf("Server connected to resource %d\n", handle);
|
#if WITH_DEBUG_RDP5
|
||||||
|
DEBUG(("RDPDR: Server connected to resource %d\n", handle));
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((magic[2] == 'P') && (magic[3] == 'S'))
|
||||||
|
{
|
||||||
|
/* server capability */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((magic[0] == 'R') && (magic[1] == 'P'))
|
||||||
|
{
|
||||||
|
if ((magic[2] == 'C') && (magic[3] == 'P'))
|
||||||
|
{
|
||||||
|
printercache_process(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,10 +654,150 @@ rdpdr_process(STREAM s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
rdpdr_init(void)
|
rdpdr_init()
|
||||||
{
|
{
|
||||||
rdpdr_channel =
|
if (g_num_devices > 0)
|
||||||
channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
|
{
|
||||||
rdpdr_process);
|
rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process);
|
||||||
|
}
|
||||||
|
|
||||||
return (rdpdr_channel != NULL);
|
return (rdpdr_channel != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add file descriptors of pending io request to select() */
|
||||||
|
void
|
||||||
|
rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
long select_timeout = 0; // Timeout value to be used for select() (in millisecons).
|
||||||
|
struct async_iorequest *iorq;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
|
||||||
|
{
|
||||||
|
iorq = &g_iorequest[i];
|
||||||
|
|
||||||
|
if (iorq->fd != 0) // Found a pending io request
|
||||||
|
{
|
||||||
|
switch (iorq->major)
|
||||||
|
{
|
||||||
|
case IRP_MJ_READ:
|
||||||
|
|
||||||
|
FD_SET(iorq->fd, rfds);
|
||||||
|
|
||||||
|
// Check if io request timeout is smaller than current (but not 0).
|
||||||
|
if (iorq->timeout
|
||||||
|
&& (select_timeout == 0
|
||||||
|
|| iorq->timeout < select_timeout))
|
||||||
|
{
|
||||||
|
// Set new timeout
|
||||||
|
select_timeout = iorq->timeout;
|
||||||
|
g_min_timeout_fd = iorq->fd; /* Remember fd */
|
||||||
|
tv->tv_sec = select_timeout / 1000;
|
||||||
|
tv->tv_usec = (select_timeout % 1000) * 1000;
|
||||||
|
*timeout = True;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IRP_MJ_WRITE:
|
||||||
|
|
||||||
|
FD_SET(iorq->fd, wfds);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
*n = MAX(*n, iorq->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
|
||||||
|
void
|
||||||
|
rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
NTSTATUS status;
|
||||||
|
uint32 result = 0, buffer_len = 0;
|
||||||
|
DEVICE_FNS *fns;
|
||||||
|
struct async_iorequest *iorq;
|
||||||
|
|
||||||
|
if (timed_out)
|
||||||
|
{
|
||||||
|
rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through array of pending io_rq's
|
||||||
|
for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
|
||||||
|
{
|
||||||
|
iorq = &g_iorequest[i];
|
||||||
|
|
||||||
|
if (iorq->fd != 0)
|
||||||
|
{
|
||||||
|
switch (iorq->major)
|
||||||
|
{
|
||||||
|
|
||||||
|
case IRP_MJ_READ:
|
||||||
|
|
||||||
|
if (FD_ISSET(iorq->fd, rfds))
|
||||||
|
{
|
||||||
|
// Read, and send data.
|
||||||
|
fns = iorq->fns;
|
||||||
|
status = fns->read(iorq->fd, iorq->buffer,
|
||||||
|
iorq->length, 0, &result);
|
||||||
|
buffer_len = result;
|
||||||
|
|
||||||
|
rdpdr_send_completion(iorq->device, iorq->id,
|
||||||
|
status, result, iorq->buffer,
|
||||||
|
buffer_len);
|
||||||
|
#if WITH_DEBUG_RDP5
|
||||||
|
DEBUG(("RDPDR: %d bytes of data read\n", result));
|
||||||
|
#endif
|
||||||
|
xfree(iorq->buffer);
|
||||||
|
iorq->fd = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IRP_MJ_WRITE:
|
||||||
|
|
||||||
|
if (FD_ISSET(iorq->fd, wfds))
|
||||||
|
{
|
||||||
|
// Write data and send completion.
|
||||||
|
fns = iorq->fns;
|
||||||
|
status = fns->write(iorq->fd, iorq->buffer,
|
||||||
|
iorq->length, 0, &result);
|
||||||
|
rdpdr_send_completion(iorq->device, iorq->id,
|
||||||
|
status, result, "", 1);
|
||||||
|
|
||||||
|
xfree(iorq->buffer);
|
||||||
|
iorq->fd = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abort a pending io request for a given handle and major */
|
||||||
|
BOOL
|
||||||
|
rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
|
||||||
|
{
|
||||||
|
uint32 result;
|
||||||
|
int i;
|
||||||
|
struct async_iorequest *iorq;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
|
||||||
|
{
|
||||||
|
iorq = &g_iorequest[i];
|
||||||
|
|
||||||
|
// Only remove from table when major is not set, or when correct major is supplied.
|
||||||
|
// Abort read should not abort a write io request.
|
||||||
|
if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
rdpdr_send_completion(iorq->device, iorq->id, status, result, "", 1);
|
||||||
|
xfree(iorq->buffer);
|
||||||
|
iorq->fd = 0;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
436
serial.c
436
serial.c
@ -52,6 +52,8 @@
|
|||||||
#define ODD_PARITY 1
|
#define ODD_PARITY 1
|
||||||
#define EVEN_PARITY 2
|
#define EVEN_PARITY 2
|
||||||
|
|
||||||
|
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||||
|
|
||||||
int serial_fd;
|
int serial_fd;
|
||||||
struct termios termios;
|
struct termios termios;
|
||||||
|
|
||||||
@ -61,121 +63,95 @@ uint32 queue_in_size, queue_out_size;
|
|||||||
uint32 wait_mask;
|
uint32 wait_mask;
|
||||||
uint8 stop_bits, parity, word_length;
|
uint8 stop_bits, parity, word_length;
|
||||||
|
|
||||||
static BOOL
|
SERIAL_DEVICE
|
||||||
get_termios(void)
|
*get_serial_info(HANDLE handle)
|
||||||
{
|
{
|
||||||
speed_t speed;
|
int index;
|
||||||
|
|
||||||
if (tcgetattr(serial_fd, &termios) == -1)
|
for (index = 0; index < RDPDR_MAX_DEVICES; index++)
|
||||||
return False;
|
{
|
||||||
|
if (handle == g_rdpdr_device[index].handle)
|
||||||
|
return (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
speed = cfgetispeed(&termios);
|
BOOL
|
||||||
switch (speed)
|
get_termios(SERIAL_DEVICE *pser_inf, HANDLE serial_fd)
|
||||||
{
|
{
|
||||||
|
speed_t speed;
|
||||||
|
struct termios *ptermios;
|
||||||
|
|
||||||
|
ptermios = pser_inf->ptermios;
|
||||||
|
|
||||||
|
if (tcgetattr(serial_fd, ptermios) == -1)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
speed = cfgetispeed(ptermios);
|
||||||
|
switch (speed)
|
||||||
|
{
|
||||||
#ifdef B75
|
#ifdef B75
|
||||||
case B75:
|
case B75: pser_inf->baud_rate = 75; break;
|
||||||
baud_rate = 75;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B110
|
#ifdef B110
|
||||||
case B110:
|
case B110: pser_inf->baud_rate = 110; break;
|
||||||
baud_rate = 110;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B134
|
#ifdef B134
|
||||||
case B134:
|
case B134: pser_inf->baud_rate = 134; break;
|
||||||
baud_rate = 134;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B150
|
#ifdef B150
|
||||||
case B150:
|
case B150: pser_inf->baud_rate = 150; break;
|
||||||
baud_rate = 150;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B300
|
#ifdef B300
|
||||||
case B300:
|
case B300: pser_inf->baud_rate = 300; break;
|
||||||
baud_rate = 300;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B600
|
#ifdef B600
|
||||||
case B600:
|
case B600: pser_inf->baud_rate = 600; break;
|
||||||
baud_rate = 600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B1200
|
#ifdef B1200
|
||||||
case B1200:
|
case B1200: pser_inf->baud_rate = 1200; break;
|
||||||
baud_rate = 1200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B1800
|
#ifdef B1800
|
||||||
case B1800:
|
case B1800: pser_inf->baud_rate = 1800; break;
|
||||||
baud_rate = 1800;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B2400
|
#ifdef B2400
|
||||||
case B2400:
|
case B2400: pser_inf->baud_rate = 2400; break;
|
||||||
baud_rate = 2400;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B4800
|
#ifdef B4800
|
||||||
case B4800:
|
case B4800: pser_inf->baud_rate = 4800; break;
|
||||||
baud_rate = 4800;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B9600
|
#ifdef B9600
|
||||||
case B9600:
|
case B9600: pser_inf->baud_rate = 9600; break;
|
||||||
baud_rate = 9600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B19200
|
#ifdef B19200
|
||||||
case B19200:
|
case B19200: pser_inf->baud_rate = 19200; break;
|
||||||
baud_rate = 19200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B38400
|
#ifdef B38400
|
||||||
case B38400:
|
case B38400: pser_inf->baud_rate = 38400; break;
|
||||||
baud_rate = 38400;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B57600
|
#ifdef B57600
|
||||||
case B57600:
|
case B57600: pser_inf->baud_rate = 57600; break;
|
||||||
baud_rate = 57600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B115200
|
#ifdef B115200
|
||||||
case B115200:
|
case B115200: pser_inf->baud_rate = 115200; break;
|
||||||
baud_rate = 115200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default: pser_inf->baud_rate = 0; break;
|
||||||
baud_rate = 0;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
speed = cfgetospeed(&termios);
|
speed = cfgetospeed(ptermios);
|
||||||
dtr = (speed == B0) ? 0 : 1;
|
pser_inf->dtr = (speed == B0) ? 0 : 1;
|
||||||
|
|
||||||
stop_bits = (termios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1;
|
pser_inf->stop_bits = (ptermios->c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1;
|
||||||
parity = (termios.
|
pser_inf->parity = (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY;
|
||||||
c_cflag & PARENB) ? ((termios.
|
switch (ptermios->c_cflag & CSIZE)
|
||||||
c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY;
|
{
|
||||||
switch (termios.c_cflag & CSIZE)
|
case CS5: pser_inf->word_length = 5; break;
|
||||||
{
|
case CS6: pser_inf->word_length = 6; break;
|
||||||
case CS5:
|
case CS7: pser_inf->word_length = 7; break;
|
||||||
word_length = 5;
|
default: pser_inf->word_length = 8; break;
|
||||||
break;
|
}
|
||||||
case CS6:
|
|
||||||
word_length = 6;
|
|
||||||
break;
|
|
||||||
case CS7:
|
|
||||||
word_length = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
word_length = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -186,83 +162,51 @@ set_termios(void)
|
|||||||
switch (baud_rate)
|
switch (baud_rate)
|
||||||
{
|
{
|
||||||
#ifdef B75
|
#ifdef B75
|
||||||
case 75:
|
case 75: speed = B75;break;
|
||||||
speed = B75;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B110
|
#ifdef B110
|
||||||
case 110:
|
case 110: speed = B110;break;
|
||||||
speed = B110;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B134
|
#ifdef B134
|
||||||
case 134:
|
case 134: speed = B134;break;
|
||||||
speed = B134;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B150
|
#ifdef B150
|
||||||
case 150:
|
case 150: speed = B150;break;
|
||||||
speed = B150;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B300
|
#ifdef B300
|
||||||
case 300:
|
case 300: speed = B300;break;
|
||||||
speed = B300;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B600
|
#ifdef B600
|
||||||
case 600:
|
case 600: speed = B600;break;
|
||||||
speed = B600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B1200
|
#ifdef B1200
|
||||||
case 1200:
|
case 1200: speed = B1200;break;
|
||||||
speed = B1200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B1800
|
#ifdef B1800
|
||||||
case 1800:
|
case 1800: speed = B1800;break;
|
||||||
speed = B1800;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B2400
|
#ifdef B2400
|
||||||
case 2400:
|
case 2400: speed = B2400;break;
|
||||||
speed = B2400;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B4800
|
#ifdef B4800
|
||||||
case 4800:
|
case 4800: speed = B4800;break;
|
||||||
speed = B4800;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B9600
|
#ifdef B9600
|
||||||
case 9600:
|
case 9600: speed = B9600;break;
|
||||||
speed = B9600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B19200
|
#ifdef B19200
|
||||||
case 19200:
|
case 19200: speed = B19200;break;
|
||||||
speed = B19200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B38400
|
#ifdef B38400
|
||||||
case 38400:
|
case 38400: speed = B38400;break;
|
||||||
speed = B38400;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B57600
|
#ifdef B57600
|
||||||
case 57600:
|
case 57600: speed = B57600;break;
|
||||||
speed = B57600;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef B115200
|
#ifdef B115200
|
||||||
case 115200:
|
case 115200: speed = B115200;break;
|
||||||
speed = B115200;
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default: speed = B0;break;
|
||||||
speed = B0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* on systems with separate ispeed and ospeed, we can remember the speed
|
/* on systems with separate ispeed and ospeed, we can remember the speed
|
||||||
@ -305,19 +249,151 @@ set_termios(void)
|
|||||||
tcsetattr(serial_fd, TCSANOW, &termios);
|
tcsetattr(serial_fd, TCSANOW, &termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
/* Enumeration of devices from rdesktop.c */
|
||||||
serial_create(HANDLE * handle)
|
/* returns numer of units found and initialized. */
|
||||||
|
/* optarg looks like ':com1=/dev/ttyS0' */
|
||||||
|
/* when it arrives to this function. */
|
||||||
|
/* windev u*dev baud, parity, stop bits, wordlength */
|
||||||
|
/* :com1=/dev/ttyS0:9600,0|1|2,0|2,5|6|7|8:dtr */
|
||||||
|
int
|
||||||
|
serial_enum_devices(int *id, char* optarg)
|
||||||
{
|
{
|
||||||
/* XXX do we have to handle concurrent open attempts? */
|
SERIAL_DEVICE* pser_inf;
|
||||||
serial_fd = open("/dev/ttyS0", O_RDWR);
|
|
||||||
if (serial_fd == -1)
|
|
||||||
return STATUS_ACCESS_DENIED;
|
|
||||||
|
|
||||||
if (!get_termios())
|
int argcount=0;
|
||||||
return STATUS_ACCESS_DENIED;
|
char* pos = optarg;
|
||||||
|
char* pos2;
|
||||||
|
char* pos3;
|
||||||
|
|
||||||
*handle = 0;
|
if(*id<RDPDR_MAX_DEVICES){
|
||||||
return STATUS_SUCCESS;
|
// Init data structures for device
|
||||||
|
pser_inf = (SERIAL_DEVICE *) xmalloc(sizeof(SERIAL_DEVICE));
|
||||||
|
pser_inf->ptermios = (struct termios *) xmalloc(sizeof(struct termios));
|
||||||
|
pser_inf->pold_termios = (struct termios *) xmalloc(sizeof(struct termios));
|
||||||
|
|
||||||
|
// skip the first colon
|
||||||
|
optarg++;
|
||||||
|
while( (pos = next_arg( optarg, ':')) ){
|
||||||
|
|
||||||
|
switch(argcount){
|
||||||
|
/* com1=/dev/ttyS0 */
|
||||||
|
case 0:
|
||||||
|
pos2 = next_arg(optarg,'=');
|
||||||
|
if( !pos2 || *pos2 == (char)0x00 ){
|
||||||
|
error("-r comport arguments should look like: -r comport:com1=/dev/ttyS0\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* optarg = com1, pos2 = /dev/ttyS0 */
|
||||||
|
strcpy(g_rdpdr_device[*id].name,optarg);
|
||||||
|
|
||||||
|
toupper(g_rdpdr_device[*id].name);
|
||||||
|
|
||||||
|
g_rdpdr_device[*id].local_path = xmalloc( strlen(pos2) + 1 );
|
||||||
|
strcpy(g_rdpdr_device[*id].local_path,pos2);
|
||||||
|
break;
|
||||||
|
/* 9600,0|1|2,O|2,5|6|7|8 */
|
||||||
|
/* TODO: values should be set in serial_create()... ??? */
|
||||||
|
case 1:
|
||||||
|
pos2 = next_arg(optarg,',');
|
||||||
|
/*optarg=9600*/
|
||||||
|
pser_inf->baud_rate = atoi(optarg);
|
||||||
|
if( !pos2 || *pos2 == (char)0x00 )
|
||||||
|
break;
|
||||||
|
pos3 = next_arg(pos2,',');
|
||||||
|
/* pos2 = 0|1|2 */
|
||||||
|
pser_inf->parity = atoi(pos2);
|
||||||
|
/* pos3 = 0|2,5|6|7|8*/
|
||||||
|
pos2 = next_arg(pos3,',');
|
||||||
|
if( !pos3 || *pos3 == (char)0x00 )
|
||||||
|
break;
|
||||||
|
pser_inf->stop_bits = atoi(pos3);
|
||||||
|
/* pos2 = 5|6|7|8 */
|
||||||
|
if( !pos2 || *pos2 == (char)0x00 )
|
||||||
|
break;
|
||||||
|
pser_inf->word_length = atoi(pos2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if( (*optarg != (char)0x00) && (strcmp( optarg, "dtr" ) == 0) ){
|
||||||
|
pser_inf->dtr = 1;
|
||||||
|
}
|
||||||
|
/* TODO: add more switches here, like xon, xoff. they will be separated by colon
|
||||||
|
if( (*optarg != (char)0x00) && (strcmp( optarg, "xon" ) == 0) ){
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
argcount++;
|
||||||
|
optarg=pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("SERIAL %s to %s", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path );
|
||||||
|
if( pser_inf->baud_rate != 0 ){
|
||||||
|
printf(" with baud: %u, parity: %u, stop bits: %u word length: %u", pser_inf->baud_rate, pser_inf->parity, pser_inf->stop_bits, pser_inf->word_length );
|
||||||
|
if( pser_inf->dtr )
|
||||||
|
printf( " dtr set\n");
|
||||||
|
else
|
||||||
|
printf( "\n" );
|
||||||
|
}else
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// set device type
|
||||||
|
g_rdpdr_device[*id].device_type = DEVICE_TYPE_SERIAL;
|
||||||
|
g_rdpdr_device[*id].pdevice_data = (void *) pser_inf;
|
||||||
|
(*id)++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
serial_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags_and_attributes, char *filename, HANDLE *handle)
|
||||||
|
{
|
||||||
|
HANDLE serial_fd;
|
||||||
|
SERIAL_DEVICE *pser_inf;
|
||||||
|
struct termios *ptermios;
|
||||||
|
SERIAL_DEVICE tmp_inf;
|
||||||
|
|
||||||
|
pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[device_id].pdevice_data;
|
||||||
|
ptermios = pser_inf->ptermios;
|
||||||
|
serial_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY);
|
||||||
|
|
||||||
|
if (serial_fd == -1)
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
// before we clog the user inserted args store them locally
|
||||||
|
//
|
||||||
|
memcpy(&tmp_inf,pser_inf, sizeof(pser_inf) );
|
||||||
|
|
||||||
|
if (!get_termios(pser_inf, serial_fd))
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
|
// Store handle for later use
|
||||||
|
g_rdpdr_device[device_id].handle = serial_fd;
|
||||||
|
tcgetattr(serial_fd, pser_inf->pold_termios); // Backup original settings
|
||||||
|
|
||||||
|
// Initial configuration.
|
||||||
|
bzero(ptermios, sizeof(ptermios));
|
||||||
|
ptermios->c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
|
||||||
|
ptermios->c_iflag = IGNPAR;
|
||||||
|
ptermios->c_oflag = 0;
|
||||||
|
ptermios->c_lflag = 0; //non-canonical, no echo
|
||||||
|
ptermios->c_cc[VTIME] = 0;
|
||||||
|
tcsetattr(serial_fd, TCSANOW, ptermios);
|
||||||
|
|
||||||
|
// overload with user settings
|
||||||
|
// -- if there are any
|
||||||
|
if( tmp_inf.baud_rate != 0 ){
|
||||||
|
dtr = tmp_inf.dtr;
|
||||||
|
baud_rate = tmp_inf.baud_rate;
|
||||||
|
parity = tmp_inf.parity;
|
||||||
|
stop_bits = tmp_inf.stop_bits;
|
||||||
|
word_length = tmp_inf.word_length;
|
||||||
|
set_termios();
|
||||||
|
}
|
||||||
|
|
||||||
|
*handle = serial_fd;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
@ -327,18 +403,52 @@ serial_close(HANDLE handle)
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
NTSTATUS
|
||||||
serial_read(HANDLE handle, uint8 * data, uint32 length, uint32 * result)
|
serial_read(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result)
|
||||||
{
|
{
|
||||||
*result = read(serial_fd, data, length);
|
long timeout;
|
||||||
return STATUS_SUCCESS;
|
SERIAL_DEVICE *pser_inf;
|
||||||
|
struct termios *ptermios;
|
||||||
|
|
||||||
|
timeout = 0;
|
||||||
|
pser_inf = get_serial_info(handle);
|
||||||
|
ptermios = pser_inf->ptermios;
|
||||||
|
|
||||||
|
// Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
|
||||||
|
// with requested read size
|
||||||
|
if (pser_inf->read_total_timeout_multiplier | pser_inf->read_total_timeout_constant)
|
||||||
|
{
|
||||||
|
timeout = (pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant + 99) / 100;
|
||||||
|
}
|
||||||
|
else if (pser_inf->read_interval_timeout)
|
||||||
|
{
|
||||||
|
timeout = (pser_inf->read_interval_timeout * length + 99) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a timeout is set, do a blocking read, which times out after some time.
|
||||||
|
// It will make rdesktop less responsive, but it will improve serial performance, by not
|
||||||
|
// reading one character at a time.
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
|
ptermios->c_cc[VTIME] = 0;
|
||||||
|
ptermios->c_cc[VMIN] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptermios->c_cc[VTIME] = timeout;
|
||||||
|
ptermios->c_cc[VMIN] = 1;
|
||||||
|
}
|
||||||
|
tcsetattr(handle, TCSANOW, ptermios);
|
||||||
|
|
||||||
|
*result = read(handle, data, length);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
NTSTATUS
|
||||||
serial_write(HANDLE handle, uint8 * data, uint32 length, uint32 * result)
|
serial_write(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result)
|
||||||
{
|
{
|
||||||
*result = write(serial_fd, data, length);
|
*result = write(handle, data, length);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
@ -382,7 +492,7 @@ serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
|
|||||||
break;
|
break;
|
||||||
case SERIAL_IMMEDIATE_CHAR:
|
case SERIAL_IMMEDIATE_CHAR:
|
||||||
in_uint8(in, immediate);
|
in_uint8(in, immediate);
|
||||||
serial_write(handle, &immediate, 1, &result);
|
serial_write(handle, &immediate, 1, 0, &result);
|
||||||
break;
|
break;
|
||||||
case SERIAL_CONFIG_SIZE:
|
case SERIAL_CONFIG_SIZE:
|
||||||
out_uint32_le(out, 0);
|
out_uint32_le(out, 0);
|
||||||
@ -430,9 +540,16 @@ serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
|
|||||||
tcsendbreak(serial_fd, 0);
|
tcsendbreak(serial_fd, 0);
|
||||||
break;
|
break;
|
||||||
case SERIAL_PURGE:
|
case SERIAL_PURGE:
|
||||||
in_uint32(purge_mask);
|
|
||||||
/* tcflush */
|
printf("SERIAL_PURGE\n");
|
||||||
break;
|
in_uint32(in, purge_mask);
|
||||||
|
if (purge_mask & 0x04) flush_mask |= TCOFLUSH;
|
||||||
|
if (purge_mask & 0x08) flush_mask |= TCIFLUSH;
|
||||||
|
if (flush_mask != 0) tcflush(handle, flush_mask);
|
||||||
|
if (purge_mask & 0x01) rdpdr_abort_io(handle, 4, STATUS_CANCELLED);
|
||||||
|
if (purge_mask & 0x02) rdpdr_abort_io(handle, 3, STATUS_CANCELLED);
|
||||||
|
break;
|
||||||
|
|
||||||
case SERIAL_RESET_DEVICE:
|
case SERIAL_RESET_DEVICE:
|
||||||
case SERIAL_SET_BREAK_OFF:
|
case SERIAL_SET_BREAK_OFF:
|
||||||
case SERIAL_SET_RTS:
|
case SERIAL_SET_RTS:
|
||||||
@ -451,6 +568,27 @@ serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read timeout for a given file descripter (device) when adding fd's to select() */
|
||||||
|
BOOL
|
||||||
|
serial_get_timeout(uint32 handle, uint32 length, uint32 *timeout, uint32 *itv_timeout)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
SERIAL_DEVICE *pser_inf;
|
||||||
|
|
||||||
|
index = get_device_index(handle);
|
||||||
|
|
||||||
|
if (g_rdpdr_device[index].device_type != DEVICE_TYPE_SERIAL)
|
||||||
|
{
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data;
|
||||||
|
|
||||||
|
*timeout = pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant;
|
||||||
|
*itv_timeout = pser_inf->read_interval_timeout;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
DEVICE_FNS serial_fns = {
|
DEVICE_FNS serial_fns = {
|
||||||
serial_create,
|
serial_create,
|
||||||
serial_close,
|
serial_close,
|
||||||
|
75
types.h
75
types.h
@ -7,7 +7,7 @@
|
|||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
@ -140,10 +140,73 @@ typedef uint32 HANDLE;
|
|||||||
|
|
||||||
typedef struct _DEVICE_FNS
|
typedef struct _DEVICE_FNS
|
||||||
{
|
{
|
||||||
NTSTATUS(*create) (HANDLE * handle);
|
NTSTATUS (*create)(uint32 device, uint32 desired_access, uint32 share_mode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, HANDLE *handle);
|
||||||
NTSTATUS(*close) (HANDLE handle);
|
NTSTATUS (*close)(HANDLE handle);
|
||||||
NTSTATUS(*read) (HANDLE handle, uint8 * data, uint32 length, uint32 * result);
|
NTSTATUS (*read)(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result);
|
||||||
NTSTATUS(*write) (HANDLE handle, uint8 * data, uint32 length, uint32 * result);
|
NTSTATUS (*write)(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result);
|
||||||
NTSTATUS(*device_control) (HANDLE handle, uint32 request, STREAM in, STREAM out);
|
NTSTATUS (*device_control)(HANDLE handle, uint32 request, STREAM in, STREAM out);
|
||||||
}
|
}
|
||||||
DEVICE_FNS;
|
DEVICE_FNS;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct rdpdr_device_info
|
||||||
|
{
|
||||||
|
uint32 device_type;
|
||||||
|
HANDLE handle;
|
||||||
|
char name[8];
|
||||||
|
char *local_path;
|
||||||
|
void *pdevice_data;
|
||||||
|
}
|
||||||
|
RDPDR_DEVICE;
|
||||||
|
|
||||||
|
typedef struct rdpdr_serial_device_info
|
||||||
|
{
|
||||||
|
int dtr;
|
||||||
|
uint32 baud_rate,
|
||||||
|
queue_in_size,
|
||||||
|
queue_out_size,
|
||||||
|
wait_mask,
|
||||||
|
read_interval_timeout,
|
||||||
|
read_total_timeout_multiplier,
|
||||||
|
read_total_timeout_constant,
|
||||||
|
write_total_timeout_multiplier,
|
||||||
|
write_total_timeout_constant,
|
||||||
|
posix_wait_mask;
|
||||||
|
uint8 stop_bits,
|
||||||
|
parity,
|
||||||
|
word_length;
|
||||||
|
struct termios *ptermios,
|
||||||
|
*pold_termios;
|
||||||
|
}
|
||||||
|
SERIAL_DEVICE;
|
||||||
|
|
||||||
|
typedef struct rdpdr_parallel_device_info
|
||||||
|
{
|
||||||
|
char *driver,
|
||||||
|
*printer;
|
||||||
|
uint32 queue_in_size,
|
||||||
|
queue_out_size,
|
||||||
|
wait_mask,
|
||||||
|
read_interval_timeout,
|
||||||
|
read_total_timeout_multiplier,
|
||||||
|
read_total_timeout_constant,
|
||||||
|
write_total_timeout_multiplier,
|
||||||
|
write_total_timeout_constant,
|
||||||
|
posix_wait_mask,
|
||||||
|
bloblen;
|
||||||
|
uint8 *blob;
|
||||||
|
}
|
||||||
|
PARALLEL_DEVICE;
|
||||||
|
|
||||||
|
typedef struct rdpdr_printer_info
|
||||||
|
{
|
||||||
|
FILE *printer_fp;
|
||||||
|
char *driver,
|
||||||
|
*printer;
|
||||||
|
uint32 bloblen;
|
||||||
|
uint8 *blob;
|
||||||
|
BOOL default_printer;
|
||||||
|
}
|
||||||
|
PRINTER;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user