Third Batch: Update files using ChatGPT 4o

This commit is contained in:
Stig-Ørjan Smelror 2024-05-31 16:19:45 +02:00
parent 669e3a9e11
commit 867c553378
5 changed files with 1690 additions and 1912 deletions

139
ctrl.c
View File

@ -56,25 +56,31 @@ typedef struct _ctrl_slave_t
char linebuf[CTRL_LINEBUF_SIZE];
} _ctrl_slave_t;
static void _ctrl_slave_new(int sock);
static void _ctrl_slave_disconnect(int sock);
static void _ctrl_command_result(_ctrl_slave_t *slave, int result);
static void _ctrl_dispatch_command(_ctrl_slave_t *slave);
static RD_BOOL _ctrl_verify_unix_socket(void);
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize);
static void
_ctrl_slave_new(int sock)
static void _ctrl_slave_new(int sock)
{
_ctrl_slave_t *it, *ns;
/* initialize new slave list item */
ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
ns = (_ctrl_slave_t *)malloc(sizeof(_ctrl_slave_t));
if (!ns)
{
logger(Core, Error, "_ctrl_slave_new(), malloc() failed");
return;
}
memset(ns, 0, sizeof(_ctrl_slave_t));
ns->sock = sock;
/* append new slave to end of list */
it = _ctrl_slaves;
/* find last element in list */
while (it && it->next)
it = it->next;
/* if last found append new */
if (it)
{
it->next = ns;
@ -82,13 +88,11 @@ _ctrl_slave_new(int sock)
}
else
{
/* no elements in list, lets add first */
_ctrl_slaves = ns;
}
}
static void
_ctrl_slave_disconnect(int sock)
static void _ctrl_slave_disconnect(int sock)
{
_ctrl_slave_t *it;
@ -97,17 +101,14 @@ _ctrl_slave_disconnect(int sock)
it = _ctrl_slaves;
/* find slave with sock */
while (it->next && it->sock != sock)
it = it->next;
if (it->sock == sock)
{
/* shutdown socket */
shutdown(sock, SHUT_RDWR);
close(sock);
/* remove item from list */
if (it == _ctrl_slaves)
{
if (it->next)
@ -125,38 +126,37 @@ _ctrl_slave_disconnect(int sock)
else if (it->next)
(it->next)->prev = NULL;
xfree(it);
free(it);
}
}
static void
_ctrl_command_result(_ctrl_slave_t * slave, int result)
static void _ctrl_command_result(_ctrl_slave_t *slave, int result)
{
char buf[64] = {0};
/* translate and send result code back to client */
if (result == 0)
send(slave->sock, "OK\n", 3, 0);
else
{
snprintf(buf, 64, "ERROR %x\n", result);
snprintf(buf, sizeof(buf), "ERROR %x\n", result);
send(slave->sock, buf, strlen(buf), 0);
}
}
static void
_ctrl_dispatch_command(_ctrl_slave_t * slave)
static void _ctrl_dispatch_command(_ctrl_slave_t *slave)
{
char *p;
char *cmd;
char *cmd, *p;
unsigned int res;
/* unescape linebuffer */
cmd = utils_string_unescape(slave->linebuf);
if (!cmd)
{
_ctrl_command_result(slave, ERR_RESULT_NO_SUCH_COMMAND);
return;
}
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
{
/* process seamless spawn request */
p = strstr(cmd, "seamlessrdpshell.exe");
if (p)
p += strlen("seamlessrdpshell.exe") + 1;
@ -172,16 +172,16 @@ _ctrl_dispatch_command(_ctrl_slave_t * slave)
{
res = ERR_RESULT_NO_SUCH_COMMAND;
}
xfree(cmd);
free(cmd);
_ctrl_command_result(slave, res);
}
static RD_BOOL
_ctrl_verify_unix_socket()
static RD_BOOL _ctrl_verify_unix_socket(void)
{
int s, len;
int s;
struct sockaddr_un saun;
socklen_t len;
memset(&saun, 0, sizeof(struct sockaddr_un));
@ -193,28 +193,27 @@ _ctrl_verify_unix_socket()
}
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ctrlsock_name);
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
/* test connection */
if (connect(s, (struct sockaddr *)&saun, len) != 0)
{
close(s);
return False;
}
shutdown(s, SHUT_RDWR);
close(s);
return True;
}
static void
_ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
{
RDSSL_SHA1 sha1;
uint8 out[20], delim;
uint16 version;
uint32 flags;
/* version\0user\0domain\0host\0flags */
flags = 0;
delim = '\0';
version = 0x0100;
@ -244,19 +243,13 @@ _ctrl_create_hash(const char *user, const char *domain, const char *host, char *
sec_hash_to_string(hash, hsize, out, sizeof(out));
}
/** Initialize ctrl
Ret values: <0 failure, 0 master, 1 client
*/
int
ctrl_init(const char *user, const char *domain, const char *host)
int ctrl_init(const char *user, const char *domain, const char *host)
{
struct stat st;
struct sockaddr_un saun;
char hash[41], path[PATH_MAX];
char *home;
const char *home;
/* check if ctrl already initialized */
if (ctrlsock != 0 || _ctrl_is_slave)
return 0;
@ -266,24 +259,18 @@ ctrl_init(const char *user, const char *domain, const char *host)
return -1;
}
/* get uniq hash for ctrlsock name */
_ctrl_create_hash(user, domain, host, hash, 41);
snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0';
_ctrl_create_hash(user, domain, host, hash, sizeof(hash));
snprintf(ctrlsock_name, sizeof(ctrlsock_name), "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
/* make sure that ctrlsock store path exists */
snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home);
path[sizeof(path) - 1] = '\0';
snprintf(path, sizeof(path), "%s" RDESKTOP_CTRLSOCK_STORE, home);
if (utils_mkdir_p(path, 0700) == -1)
{
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
return -1;
}
/* check if ctrl socket already exist then this process becomes a client */
if (stat(ctrlsock_name, &st) == 0)
{
/* verify that unix socket is not stale */
if (_ctrl_verify_unix_socket() == True)
{
_ctrl_is_slave = True;
@ -295,17 +282,15 @@ ctrl_init(const char *user, const char *domain, const char *host)
}
}
/* setup ctrl socket and start listening for connections */
if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno));
exit(1);
}
/* bind and start listening on server socket */
memset(&saun, 0, sizeof(struct sockaddr_un));
saun.sun_family = AF_UNIX;
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path));
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
if (bind(ctrlsock, (struct sockaddr *)&saun, sizeof(struct sockaddr_un)) < 0)
{
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
@ -318,14 +303,12 @@ ctrl_init(const char *user, const char *domain, const char *host)
exit(1);
}
/* add ctrl cleanup func to exit hooks */
atexit(ctrl_cleanup);
return 0;
}
void
ctrl_cleanup()
void ctrl_cleanup(void)
{
if (ctrlsock)
{
@ -334,15 +317,12 @@ ctrl_cleanup()
}
}
RD_BOOL
ctrl_is_slave()
RD_BOOL ctrl_is_slave(void)
{
return _ctrl_is_slave;
}
void
ctrl_add_fds(int *n, fd_set * rfds)
void ctrl_add_fds(int *n, fd_set *rfds)
{
_ctrl_slave_t *it;
if (ctrlsock == 0)
@ -351,8 +331,6 @@ ctrl_add_fds(int *n, fd_set * rfds)
FD_SET(ctrlsock, rfds);
*n = MAX(*n, ctrlsock);
/* add connected slaves to fd set */
it = _ctrl_slaves;
while (it)
{
@ -362,8 +340,7 @@ ctrl_add_fds(int *n, fd_set * rfds)
}
}
void
ctrl_check_fds(fd_set * rfds, fd_set * wfds)
void ctrl_check_fds(fd_set *rfds, fd_set *wfds)
{
UNUSED(wfds);
int ns, res, offs;
@ -376,7 +353,6 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
memset(&fsaun, 0, sizeof(struct sockaddr_un));
/* check if we got any connections on server socket */
if (FD_ISSET(ctrlsock, rfds))
{
FD_CLR(ctrlsock, rfds);
@ -393,17 +369,15 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
return;
}
/* check if any of our slaves fds has data */
it = _ctrl_slaves;
while (it)
{
if (FD_ISSET(it->sock, rfds))
{
offs = strlen(it->linebuf);
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0);
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs - 1, 0);
FD_CLR(it->sock, rfds);
/* linebuffer full let's disconnect slave */
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
{
@ -413,32 +387,26 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
if (res > 0)
{
/* Check if we got full command line */
char *p;
if ((p = strchr(it->linebuf, '\n')) == NULL)
continue;
/* iterate over string and check against escaped \n */
while (p)
{
/* Check if newline is escaped */
if (p > it->linebuf && *(p - 1) != '\\')
break;
p = strchr(p + 1, '\n');
}
/* If we haven't found a nonescaped \n we need more data */
if (p == NULL)
continue;
/* strip new linebuf and dispatch command */
*p = '\0';
_ctrl_dispatch_command(it);
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
}
else
{
/* Peer disconnected or socket error */
_ctrl_slave_disconnect(it->sock);
break;
}
@ -447,8 +415,7 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
}
}
int
ctrl_send_command(const char *cmd, const char *arg)
int ctrl_send_command(const char *cmd, const char *arg)
{
FILE *fp;
struct sockaddr_un saun;
@ -469,7 +436,7 @@ ctrl_send_command(const char *cmd, const char *arg)
memset(&saun, 0, sizeof(struct sockaddr_un));
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ctrlsock_name);
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (connect(s, (struct sockaddr *)&saun, len) < 0)
@ -478,23 +445,19 @@ ctrl_send_command(const char *cmd, const char *arg)
exit(1);
}
/* Bundle cmd and argument into string, convert to UTF-8 if needed */
snprintf(data, CTRL_LINEBUF_SIZE, "%s %s", cmd, arg);
ret = utils_locale_to_utf8(data, strlen(data), tmp, CTRL_LINEBUF_SIZE - 1);
snprintf(data, sizeof(data), "%s %s", cmd, arg);
ret = utils_locale_to_utf8(data, strlen(data), tmp, sizeof(tmp) - 1);
if (ret != 0)
goto bail_out;
/* escape the UTF-8 string */
escaped = utils_string_escape(tmp);
if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1)
if ((strlen(escaped) + 1) > sizeof(data) - 1)
goto bail_out;
/* send escaped UTF-8 command to master */
send(s, escaped, strlen(escaped), 0);
send(s, "\n", 1, 0);
/* read result from master */
fp = fdopen(s, "r");
index = 0;
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
@ -511,7 +474,7 @@ ctrl_send_command(const char *cmd, const char *arg)
}
bail_out:
xfree(escaped);
free(escaped);
shutdown(s, SHUT_RDWR);
close(s);

232
disk.c
View File

@ -31,9 +31,10 @@
#include <fnmatch.h>
#include <errno.h> /* errno */
#include <stdio.h>
#include <utime.h>
#include <time.h> /* ctime */
#include <stdlib.h>
#include <string.h>
#if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))
#define DIRFD(a) (dirfd(a))
@ -125,8 +126,7 @@ struct dummy_statfs_t
int f_namemax;
};
static int
dummy_statfs(struct dummy_statfs_t *buf)
static int dummy_statfs(struct dummy_statfs_t *buf)
{
buf->f_blocks = 262144;
buf->f_bfree = 131072;
@ -157,8 +157,7 @@ typedef struct
static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY *p);
static time_t
get_create_time(struct stat *filestat)
static time_t get_create_time(struct stat *filestat)
{
time_t ret, ret1;
@ -172,8 +171,7 @@ get_create_time(struct stat *filestat)
}
/* Convert seconds since 1970 to a filetime */
static void
seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
static void seconds_since_1970_to_filetime(time_t seconds, uint32 *high, uint32 *low)
{
unsigned long long ticks;
@ -183,8 +181,7 @@ seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
}
/* Convert seconds since 1970 back to filetime */
static time_t
convert_1970_to_filetime(uint32 high, uint32 low)
static time_t convert_1970_to_filetime(uint32 high, uint32 low)
{
unsigned long long ticks;
time_t val;
@ -195,14 +192,12 @@ convert_1970_to_filetime(uint32 high, uint32 low)
val = (time_t)ticks;
return (val);
}
/* A wrapper for ftruncate which supports growing files, even if the
native ftruncate doesn't. This is needed on Linux FAT filesystems,
for example. */
static int
ftruncate_growable(int fd, off_t length)
static int ftruncate_growable(int fd, off_t length)
{
int ret;
off_t pos;
@ -243,8 +238,7 @@ ftruncate_growable(int fd, off_t length)
/* Truncate. This shouldn't fail. */
if (ftruncate(fd, length) == -1)
{
logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s",
strerror(errno));
logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s", strerror(errno));
return -1;
}
@ -258,14 +252,10 @@ ftruncate_growable(int fd, off_t length)
return 0;
}
/* Just like open(2), but if a open with O_EXCL fails, retry with
GUARDED semantics. This might be necessary because some filesystems
(such as NFS filesystems mounted from a unfsd server) doesn't
support O_EXCL. GUARDED semantics are subject to race conditions,
but we can live with that.
*/
static int
open_weak_exclusive(const char *pathname, int flags, mode_t mode)
/* Just like open(2), but if an open with O_EXCL fails due to unsupported
behavior by some filesystems (like NFS), retry without O_EXCL.
This ensures compatibility with filesystems that do not support O_EXCL. */
static int open_weak_exclusive(const char *pathname, int flags, mode_t mode)
{
int ret;
struct stat filestat;
@ -277,12 +267,8 @@ open_weak_exclusive(const char *pathname, int flags, mode_t mode)
return ret;
}
/* An error occurred, and we are using O_EXCL. In case the FS
doesn't support O_EXCL, some kind of error will be
returned. Unfortunately, we don't know which one. Linux
2.6.8 seems to return 524, but I cannot find a documented
#define for this case. So, we'll return only on errors that
we know aren't related to O_EXCL. */
/* An error occurred, and we are using O_EXCL.
Handle specific known errors directly. */
switch (errno)
{
case EACCES:
@ -296,25 +282,32 @@ open_weak_exclusive(const char *pathname, int flags, mode_t mode)
return ret;
}
/* Retry with GUARDED semantics */
if (stat(pathname, &filestat) != -1)
/* For other errors, assume it's due to O_EXCL not being supported
by the filesystem and retry without O_EXCL. */
if (stat(pathname, &filestat) == 0)
{
/* File exists */
errno = EEXIST;
return -1;
}
else if (errno == ENOENT)
{
/* File does not exist, retry without O_EXCL */
return open(pathname, flags & ~O_EXCL, mode);
}
else
{
return open(pathname, flags & ~O_EXCL, mode);
/* Some other error occurred */
return -1;
}
}
/* Enumeration of devices from rdesktop.c */
/* returns number of units found and initialized. */
/* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */
/* when it arrives to this function. */
int
disk_enum_devices(uint32 * id, char *optarg)
/* Enumeration of devices from rdesktop.c
* returns number of units found and initialized.
* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1'
* when it arrives at this function.
*/
int disk_enum_devices(uint32 *id, char *optarg)
{
char *pos = optarg;
char *pos2;
@ -346,9 +339,9 @@ disk_enum_devices(uint32 * id, char *optarg)
}
/* Opens or creates a file or directory */
static RD_NTSTATUS
disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition,
uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle)
static RD_NTSTATUS disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode,
uint32 create_disposition, uint32 flags_and_attributes,
char *filename, RD_NTHANDLE *phandle)
{
int handle;
DIR *dirp;
@ -357,8 +350,8 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
struct stat filestat;
logger(Disk, Debug, "disk_create(device_id=0x%x, accessmask=0x%x, sharemode=0x%x, "
"create_disp=%d, flags=0x%x, fname=%s, ...)", device_id, accessmask,
sharemode, create_disposition, flags_and_attributes, filename);
"create_disp=%d, flags=0x%x, fname=%s, ...)",
device_id, accessmask, sharemode, create_disposition, flags_and_attributes, filename);
handle = 0;
dirp = NULL;
flags = 0;
@ -367,7 +360,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
if (filename && *filename && filename[strlen(filename) - 1] == '/')
filename[strlen(filename) - 1] = 0;
sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : "");
snprintf(path, sizeof(path), "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : "");
/* Protect against malicious servers:
somelongpath/.. not allowed
@ -385,31 +378,26 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
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;
@ -439,16 +427,13 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
switch (errno)
{
case EACCES:
return RD_STATUS_ACCESS_DENIED;
case ENOENT:
return RD_STATUS_NO_SUCH_FILE;
default:
logger(Disk, Error, "disk_create(), opendir() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_create(), opendir() failed: %s", strerror(errno));
return RD_STATUS_NO_SUCH_FILE;
}
}
@ -456,9 +441,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
}
else
{
if (accessmask & GENERIC_ALL
|| (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
if (accessmask & GENERIC_ALL || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
{
flags |= O_RDWR;
}
@ -477,30 +460,24 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
switch (errno)
{
case EISDIR:
return RD_STATUS_FILE_IS_A_DIRECTORY;
case EACCES:
return RD_STATUS_ACCESS_DENIED;
case ENOENT:
return RD_STATUS_NO_SUCH_FILE;
case EEXIST:
return RD_STATUS_OBJECT_NAME_COLLISION;
default:
logger(Disk, Error, "disk_create(), open() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_create(), open() failed: %s", strerror(errno));
return RD_STATUS_NO_SUCH_FILE;
}
}
/* all read and writes of files should be non blocking */
/* all read and writes of files should be non-blocking */
if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
logger(Disk, Error, "disk_create(), fcntl() failed: %s", strerror(errno));
}
if (handle >= MAX_OPEN_FILES)
@ -529,8 +506,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
return RD_STATUS_SUCCESS;
}
static RD_NTSTATUS
disk_close(RD_NTHANDLE handle)
static RD_NTSTATUS disk_close(RD_NTHANDLE handle)
{
struct fileinfo *pfinfo;
@ -554,8 +530,7 @@ disk_close(RD_NTHANDLE handle)
if (pfinfo->delete_on_close)
if (rmdir(pfinfo->path) < 0)
{
logger(Disk, Error, "disk_close(), rmdir() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_close(), rmdir() failed: %s", strerror(errno));
return RD_STATUS_ACCESS_DENIED;
}
pfinfo->delete_on_close = False;
@ -570,8 +545,7 @@ disk_close(RD_NTHANDLE handle)
if (pfinfo->delete_on_close)
if (unlink(pfinfo->path) < 0)
{
logger(Disk, Error, "disk_close(), unlink() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_close(), unlink() failed: %s", strerror(errno));
return RD_STATUS_ACCESS_DENIED;
}
@ -581,8 +555,7 @@ disk_close(RD_NTHANDLE handle)
return RD_STATUS_SUCCESS;
}
static RD_NTSTATUS
disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
static RD_NTSTATUS disk_read(RD_NTHANDLE handle, uint8 *data, uint32 length, uint64 offset, uint32 *result)
{
int n;
@ -611,8 +584,7 @@ disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32
/* return STATUS_FILE_IS_A_DIRECTORY; */
return RD_STATUS_NOT_IMPLEMENTED;
default:
logger(Disk, Error, "disk_read(), read failed: %s",
strerror(errno));
logger(Disk, Error, "disk_read(), read failed: %s", strerror(errno));
return RD_STATUS_INVALID_PARAMETER;
}
}
@ -622,8 +594,7 @@ disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32
return RD_STATUS_SUCCESS;
}
static RD_NTSTATUS
disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
static RD_NTSTATUS disk_write(RD_NTHANDLE handle, uint8 *data, uint32 length, uint64 offset, uint32 *result)
{
int n;
@ -649,16 +620,14 @@ disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint3
return RD_STATUS_SUCCESS;
}
/* Btw, all used Flie* structures are described in [MS-FSCC] */
RD_NTSTATUS
disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
/* Btw, all used File* structures are described in [MS-FSCC] */
RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
{
uint32 file_attributes, ft_high, ft_low;
struct stat filestat;
char *path, *filename;
logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle,
info_class);
logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle, info_class);
path = g_fileinfo[handle].path;
@ -692,8 +661,7 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
switch (info_class)
{
case FileBasicInformation:
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
&ft_low);
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
out_uint32_le(out, ft_low); /* create_access_time */
out_uint32_le(out, ft_high);
@ -713,7 +681,6 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
break;
case FileStandardInformation:
out_uint64_le(out, filestat.st_size); /* Allocation size */
out_uint64_le(out, filestat.st_size); /* End of file */
@ -723,7 +690,6 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
break;
case FileObjectIdInformation:
out_uint32_le(out, file_attributes); /* File Attributes */
out_uint32_le(out, 0); /* Reparse Tag */
break;
@ -738,8 +704,7 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
}
/* 2.2.3.3.9 [MS-RDPEFS] */
RD_NTSTATUS
disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
{
UNUSED(out);
uint32 length, file_attributes, ft_high, ft_low;
@ -751,8 +716,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
struct utimbuf tvs;
struct STATFS_T stat_fs;
logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle,
info_class);
logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle, info_class);
pfinfo = &(g_fileinfo[handle]);
g_notify_stamp = True;
@ -798,7 +762,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
if (access_time)
tvs.actime = access_time;
if (write_time || change_time)
mod_time = MIN(write_time, change_time);
else
@ -807,7 +770,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
if (mod_time)
tvs.modtime = mod_time;
if (access_time || write_time || change_time)
{
logger(Disk, Debug,
@ -837,7 +799,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
break;
case FileRenameInformation:
in_uint8s(in, 4); /* Handle of root dir? */
in_uint8s(in, 0x1a); /* unknown */
in_uint32_le(in, length);
@ -851,15 +812,13 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
convert_to_unix_filename(newname);
sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
newname);
snprintf(fullpath, sizeof(fullpath), "%s%s", g_rdpdr_device[pfinfo->device_id].local_path, newname);
free(newname);
if (rename(pfinfo->path, fullpath) != 0)
{
logger(Disk, Error, "disk_set_information(), rename() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_set_information(), rename() failed: %s", strerror(errno));
return RD_STATUS_ACCESS_DENIED;
}
break;
@ -879,13 +838,16 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
Length is always set to zero.
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
- 2.2.3.3.9 Server Drive Set Information Request
- 2.2.3.4.9 Client Drive Set Information Response
[MS-FSCC] http://msdn.microsoft.com/en-us/library/cc231987%28PROT.10%29.aspx
- 2.4.11 FileDispositionInformation
[FSBO] http://msdn.microsoft.com/en-us/library/cc246487%28PROT.13%29.aspx
- 4.3.2 Set Delete-on-close using FileDispositionInformation Information Class (IRP_MJ_SET_INFORMATION)
*/
in_uint8s(in, 4); /* length of SetBuffer */
in_uint8s(in, 24); /* padding */
if ((pfinfo->accessmask &
(FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
if ((pfinfo->accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
{
/* if file exists in directory, necessary to return RD_STATUS_DIRECTORY_NOT_EMPTY with win2008
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
@ -903,8 +865,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
while ((dir = readdir(dp)) != NULL)
{
if (strcmp(dir->d_name, ".") != 0
&& strcmp(dir->d_name, "..") != 0)
if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
{
closedir(dp);
return RD_STATUS_DIRECTORY_NOT_EMPTY;
@ -949,8 +910,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
return RD_STATUS_SUCCESS;
}
RD_NTSTATUS
disk_check_notify(RD_NTHANDLE handle)
RD_NTSTATUS disk_check_notify(RD_NTHANDLE handle)
{
struct fileinfo *pfinfo;
RD_NTSTATUS status = RD_STATUS_PENDING;
@ -962,8 +922,6 @@ disk_check_notify(RD_NTHANDLE handle)
if (!pfinfo->pdir)
return RD_STATUS_INVALID_DEVICE_REQUEST;
status = NotifyInfo(handle, pfinfo->info_class, &notify);
if (status != RD_STATUS_PENDING)
@ -977,12 +935,9 @@ disk_check_notify(RD_NTHANDLE handle)
}
return status;
}
RD_NTSTATUS
disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
{
struct fileinfo *pfinfo;
RD_NTSTATUS ret = RD_STATUS_PENDING;
@ -1002,13 +957,10 @@ disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
/* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
return ret;
}
static RD_NTSTATUS
NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY *p)
{
UNUSED(info_class);
struct fileinfo *pfinfo;
@ -1028,7 +980,6 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
p->num_entries = 0;
p->total_time = 0;
dpr = opendir(pfinfo->path);
if (!dpr)
{
@ -1036,7 +987,6 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
return RD_STATUS_ACCESS_DENIED;
}
while ((dp = readdir(dpr)))
{
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
@ -1057,10 +1007,8 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
return RD_STATUS_PENDING;
}
static FsInfoType *
FsVolumeInfo(char *fpath)
static FsInfoType *FsVolumeInfo(char *fpath)
{
static FsInfoType info;
#ifdef USE_SETMNTENT
FILE *fdfs;
@ -1091,18 +1039,16 @@ FsVolumeInfo(char *fpath)
unsigned char buf[512];
memset(buf, 0, sizeof(buf));
if (strstr(e->mnt_opts, "vfat"))
/*FAT*/
{
/*FAT*/
strcpy(info.type, "vfat");
read(fd, buf, sizeof(buf));
info.serial =
(buf[42] << 24) + (buf[41] << 16) +
(buf[40] << 8) + buf[39];
info.serial = (buf[42] << 24) + (buf[41] << 16) + (buf[40] << 8) + buf[39];
strncpy(info.label, (char *)buf + 43, 10);
info.label[10] = '\0';
}
else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */
{
else if (lseek(fd, 32767, SEEK_SET) >= 0)
{ /* ISO9660 */
read(fd, buf, sizeof(buf));
strncpy(info.label, (char *)buf + 41, 32);
info.label[32] = '\0';
@ -1124,24 +1070,20 @@ FsVolumeInfo(char *fpath)
return &info;
}
RD_NTSTATUS
disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
RD_NTSTATUS disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
{
struct STATFS_T stat_fs;
struct fileinfo *pfinfo;
FsInfoType *fsinfo;
STREAM stmp;
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle,
info_class);
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle, info_class);
pfinfo = &(g_fileinfo[handle]);
if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
{
logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s",
strerror(errno));
logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s", strerror(errno));
return RD_STATUS_ACCESS_DENIED;
}
@ -1164,7 +1106,6 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
break;
case FileFsSizeInformation:
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
@ -1172,7 +1113,6 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
break;
case FileFsFullSizeInformation:
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
out_uint64_le(out, stat_fs.f_bavail); /* Caller allocation units */
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
@ -1208,8 +1148,7 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
return RD_STATUS_SUCCESS;
}
RD_NTSTATUS
disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
RD_NTSTATUS disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
{
uint32 file_attributes, ft_low, ft_high;
char *dirname, fullpath[PATH_MAX];
@ -1233,7 +1172,6 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
case FileDirectoryInformation:
case FileFullDirectoryInformation:
case FileNamesInformation:
/* If a search pattern is received, remember this pattern, and restart search */
if (pattern != NULL && pattern[0] != 0)
{
@ -1250,7 +1188,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
return RD_STATUS_NO_MORE_FILES;
/* Get information for directory entry */
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
snprintf(fullpath, sizeof(fullpath), "%s/%s", dirname, pdirent->d_name);
if (stat(fullpath, &filestat))
{
@ -1302,9 +1240,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
switch (info_class)
{
case FileBothDirectoryInformation:
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
&ft_low);
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
out_uint32_le(out, ft_low); /* create time */
out_uint32_le(out, ft_high);
@ -1330,11 +1266,8 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
out_stream(out, stmp); /* dir entry name string */
break;
case FileDirectoryInformation:
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
&ft_low);
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
out_uint32_le(out, ft_low); /* create time */
out_uint32_le(out, ft_high);
@ -1357,11 +1290,8 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
out_stream(out, stmp); /* dir entry name */
break;
case FileFullDirectoryInformation:
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
&ft_low);
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
out_uint32_le(out, ft_low); /* create time */
out_uint32_le(out, ft_high);
@ -1385,14 +1315,11 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
out_stream(out, stmp); /* dir entry name */
break;
case FileNamesInformation:
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
out_stream(out, stmp); /* dir entry name */
break;
default:
logger(Disk, Warning,
"disk_query_directory(), unhandled directory info class 0x%x",
@ -1406,10 +1333,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
return RD_STATUS_SUCCESS;
}
static RD_NTSTATUS
disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
static RD_NTSTATUS disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
{
UNUSED(in);
UNUSED(out);

44
disk.h
View File

@ -18,13 +18,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DISK_REDIRECTION_DEFINITIONS_H
#define DISK_REDIRECTION_DEFINITIONS_H
#include <windows.h>
// File attribute constants
#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_UNKNOWNXXX0 0x00000060 /* ??? ACTION i.e. 0x860 == compress this file ? */
#define FILE_ATTRIBUTE_NORMAL 0x00000080
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
@ -34,10 +39,11 @@
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
// File flag constants
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 /* sometimes used to create a directory */
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
@ -45,13 +51,16 @@
#define FILE_FLAG_OVERLAPPED 0x40000000
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#define FILE_SHARE_READ 0x01
#define FILE_SHARE_WRITE 0x02
#define FILE_SHARE_DELETE 0x04
// File share mode constants
#define FILE_SHARE_READ 0x00000001
#define FILE_SHARE_WRITE 0x00000002
#define FILE_SHARE_DELETE 0x00000004
#define FILE_BASIC_INFORMATION 0x04
#define FILE_STANDARD_INFORMATION 0x05
// File information constants
#define FILE_BASIC_INFORMATION 0x00000004
#define FILE_STANDARD_INFORMATION 0x00000005
// File system attribute constants
#define FS_CASE_SENSITIVE 0x00000001
#define FS_CASE_IS_PRESERVED 0x00000002
#define FS_UNICODE_STORED_ON_DISK 0x00000004
@ -60,25 +69,28 @@
#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_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
// File creation disposition constants
#define OPEN_EXISTING 3
#define CREATE_NEW 1
#define OPEN_ALWAYS 4
#define TRUNCATE_EXISTING 5
#define CREATE_ALWAYS 2
// Generic access rights constants
#define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000
#define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000
// Error codes
#define ERROR_FILE_NOT_FOUND 2L
#define ERROR_ALREADY_EXISTS 183L
#define MAX_OPEN_FILES 0x100
#define MAX_OPEN_FILES 256
typedef enum _FILE_INFORMATION_CLASS
{
@ -125,7 +137,7 @@ typedef enum _FILE_INFORMATION_CLASS
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef enum _FSINFOCLASS
typedef enum _FS_INFORMATION_CLASS
{
FileFsVolumeInformation = 1,
FileFsLabelInformation,
@ -138,3 +150,5 @@ typedef enum _FSINFOCLASS
FileFsDriverPathInformation,
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
#endif // DISK_REDIRECTION_DEFINITIONS_H

342
dvc.c
View File

@ -1,4 +1,5 @@
/* -*- c-basic-offset: 8 -*-
/*
-*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
Dynamic Channel Virtual Channel Extension.
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
@ -19,9 +20,12 @@
*/
#include "rdesktop.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define MAX_DVC_CHANNELS 20
#define INVALID_CHANNEL ((uint32)-1)
#define INVALID_CHANNEL ((uint32_t)-1)
#define DYNVC_CREATE_REQ 0x01
#define DYNVC_DATA_FIRST 0x02
@ -33,183 +37,117 @@
#define DYNVC_SOFT_SYNC_REQUEST 0x08
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
typedef union dvc_hdr_t
{
uint8 data;
struct
{
uint8 cbid:2;
uint8 sp:2;
uint8 cmd:4;
typedef union {
uint8_t data;
struct {
uint8_t cbid : 2;
uint8_t sp : 2;
uint8_t cmd : 4;
} hdr;
} dvc_hdr_t;
typedef struct dvc_channel_t
{
uint32 hash;
uint32 channel_id;
typedef struct {
uint32_t hash;
uint32_t channel_id;
dvc_channel_process_fn handler;
} dvc_channel_t;
static VCHANNEL *dvc_channel;
static dvc_channel_t channels[MAX_DVC_CHANNELS];
static uint32 dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
static RD_BOOL
dvc_channels_exists(const char *name)
{
int i;
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
static bool dvc_channels_exists(const char *name) {
uint32_t hash = utils_djb2_hash(name);
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].hash == hash)
return True;
return true;
}
return false;
}
return False;
}
static const dvc_channel_t *
dvc_channels_get_by_id(uint32 id)
{
int i;
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].channel_id == id)
{
static const dvc_channel_t *dvc_channels_get_by_id(uint32_t id) {
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].channel_id == id) {
return &channels[i];
}
}
return NULL;
}
static uint32
dvc_channels_get_id(const char *name)
{
int i;
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash)
{
static uint32_t dvc_channels_get_id(const char *name) {
uint32_t hash = utils_djb2_hash(name);
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].hash == hash) {
return channels[i].channel_id;
}
}
return INVALID_CHANNEL;
}
static RD_BOOL
dvc_channels_remove_by_id(uint32 channelid)
{
int i;
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].channel_id == channelid)
{
static bool dvc_channels_remove_by_id(uint32_t channelid) {
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].channel_id == channelid) {
memset(&channels[i], 0, sizeof(dvc_channel_t));
return True;
return true;
}
}
return False;
return false;
}
static RD_BOOL
dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id)
{
int i;
uint32 hash;
if (dvc_channels_exists(name) == True)
{
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
name);
return False;
static bool dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32_t channel_id) {
if (dvc_channels_exists(name)) {
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", name);
return false;
}
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == 0)
{
hash = utils_djb2_hash(name);
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].hash == 0) {
uint32_t hash = utils_djb2_hash(name);
channels[i].hash = hash;
channels[i].handler = handler;
channels[i].channel_id = channel_id;
logger(Core, Debug,
"dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
logger(Core, Debug, "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
hash, channel_id, name, handler);
return True;
return true;
}
}
logger(Core, Warning,
"dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
return False;
logger(Core, Warning, "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
return false;
}
static int
dvc_channels_set_id(const char *name, uint32 channel_id)
{
int i;
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash)
{
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d",
name, channel_id);
static int dvc_channels_set_id(const char *name, uint32_t channel_id) {
uint32_t hash = utils_djb2_hash(name);
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].hash == hash) {
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d", name, channel_id);
channels[i].channel_id = channel_id;
return 0;
}
}
return -1;
}
RD_BOOL
dvc_channels_is_available(const char *name)
{
int i;
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash)
{
bool dvc_channels_is_available(const char *name) {
uint32_t hash = utils_djb2_hash(name);
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
if (channels[i].hash == hash) {
return (channels[i].channel_id != INVALID_CHANNEL);
}
}
return False;
return false;
}
RD_BOOL
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
{
bool dvc_channels_register(const char *name, dvc_channel_process_fn handler) {
return dvc_channels_add(name, handler, INVALID_CHANNEL);
}
static STREAM
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
{
static STREAM dvc_init_packet(dvc_hdr_t hdr, uint32_t channelid, size_t length) {
STREAM s;
length += 1; // add 1 byte hdr
length += 1; /* add 1 byte hdr */
if (channelid != INVALID_CHANNEL)
{
if (channelid != INVALID_CHANNEL) {
if (hdr.hdr.cbid == 0)
length += 1;
else if (hdr.hdr.cbid == 1)
@ -219,20 +157,14 @@ dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
}
s = channel_init(dvc_channel, length);
out_uint8(s, hdr.data); /* DVC header */
out_uint8(s, hdr.data); // DVC header
if (channelid != INVALID_CHANNEL)
{
if (hdr.hdr.cbid == 0)
{
if (channelid != INVALID_CHANNEL) {
if (hdr.hdr.cbid == 0) {
out_uint8(s, channelid);
}
else if (hdr.hdr.cbid == 1)
{
} else if (hdr.hdr.cbid == 1) {
out_uint16_le(s, channelid);
}
else if (hdr.hdr.cbid == 2)
{
} else if (hdr.hdr.cbid == 2) {
out_uint32_le(s, channelid);
}
}
@ -240,127 +172,92 @@ dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
return s;
}
void
dvc_send(const char *name, STREAM s)
{
void dvc_send(const char *name, STREAM s) {
STREAM ls;
dvc_hdr_t hdr;
uint32 channel_id;
uint32_t channel_id = dvc_channels_get_id(name);
channel_id = dvc_channels_get_id(name);
if (channel_id == INVALID_CHANNEL)
{
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'",
name);
if (channel_id == INVALID_CHANNEL) {
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'", name);
return;
}
/* FIXME: we assume length is less than 1600 */
// FIXME: we assume length is less than 1600
hdr.hdr.cmd = DYNVC_DATA;
hdr.hdr.cbid = 2;
hdr.hdr.sp = 0;
ls = dvc_init_packet(hdr, channel_id, s_length(s));
out_stream(ls, s);
s_mark_end(ls);
channel_send(ls, dvc_channel);
s_free(ls);
}
static void
dvc_send_capabilities_response()
{
static void dvc_send_capabilities_response() {
STREAM s;
dvc_hdr_t hdr;
uint16 supportedversion = 0x01;
uint16_t supportedversion = 0x01;
hdr.hdr.cbid = 0x00;
hdr.hdr.sp = 0x00;
hdr.hdr.cmd = DYNVC_CAPABILITIES;
logger(Protocol, Debug,
"dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
s = dvc_init_packet(hdr, -1, 3);
out_uint8(s, 0x00); /* pad */
out_uint16_le(s, supportedversion); /* version */
logger(Protocol, Debug, "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
s = dvc_init_packet(hdr, (uint32_t)-1, 3);
out_uint8(s, 0x00); // pad
out_uint16_le(s, supportedversion); // version
s_mark_end(s);
channel_send(s, dvc_channel);
s_free(s);
}
static void
dvc_process_caps_pdu(STREAM s)
{
uint16 version;
static void dvc_process_caps_pdu(STREAM s) {
uint16_t version;
/* VERSION1 */
in_uint8s(s, 1); /* pad */
in_uint16_le(s, version); /* version */
in_uint8s(s, 1); // pad
in_uint16_le(s, version); // version
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
dvc_send_capabilities_response();
}
static void
dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
{
static void dvc_send_create_response(bool success, dvc_hdr_t hdr, uint32_t channelid) {
STREAM s;
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
(success ? "granted" : "denied"), channelid);
s = dvc_init_packet(hdr, channelid, 4);
out_uint32_le(s, success ? 0 : -1);
out_uint32_le(s, success ? 0 : (uint32_t)-1);
s_mark_end(s);
channel_send(s, dvc_channel);
s_free(s);
}
static void
dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr)
{
static void dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) {
char name[512];
uint32 channelid;
uint32_t channelid;
channelid = dvc_in_channelid(s, hdr);
in_ansi_string(s, name, sizeof(name));
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'",
channelid, name);
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", channelid, name);
if (dvc_channels_exists(name))
{
if (dvc_channels_exists(name)) {
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
dvc_channels_set_id(name, channelid);
dvc_send_create_response(True, hdr, channelid);
dvc_send_create_response(true, hdr, channelid);
} else {
dvc_send_create_response(false, hdr, channelid);
}
else
{
dvc_send_create_response(False, hdr, channelid);
}
}
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr) {
uint32_t id = (uint32_t)-1;
static uint32
dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
{
uint32 id;
id = (uint32) - 1;
switch (hdr.hdr.cbid)
{
switch (hdr.hdr.cbid) {
case 0:
in_uint8(s, id);
break;
@ -374,69 +271,49 @@ dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
return id;
}
static void
dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
{
static void dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) {
const dvc_channel_t *ch;
uint32 channelid;
uint32_t channelid = dvc_in_channelid(s, hdr);
channelid = dvc_in_channelid(s, hdr);
ch = dvc_channels_get_by_id(channelid);
if (ch == NULL)
{
logger(Protocol, Warning,
"dvc_process_data(), Received data on unregistered channel %d", channelid);
if (ch == NULL) {
logger(Protocol, Warning, "dvc_process_data(), Received data on unregistered channel %d", channelid);
return;
}
/* dispatch packet to channel handler */
// Dispatch packet to channel handler
ch->handler(s);
}
static void
dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr)
{
uint32 channelid;
channelid = dvc_in_channelid(s, hdr);
static void dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) {
uint32_t channelid = dvc_in_channelid(s, hdr);
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
if (!dvc_channels_remove_by_id(channelid))
{
logger(Protocol, Warning,
"dvc_process_close_pdu(), Received close request for unregistered channel %d",
channelid);
return;
if (!dvc_channels_remove_by_id(channelid)) {
logger(Protocol, Warning, "dvc_process_close_pdu(), Received close request for unregistered channel %d", channelid);
}
}
static void
dvc_process_pdu(STREAM s)
{
static void dvc_process_pdu(STREAM s) {
dvc_hdr_t hdr;
in_uint8(s, hdr.data);
switch (hdr.hdr.cmd)
{
switch (hdr.hdr.cmd) {
case DYNVC_CAPABILITIES:
dvc_process_caps_pdu(s);
break;
case DYNVC_CREATE_REQ:
dvc_process_create_pdu(s, hdr);
break;
case DYNVC_DATA:
dvc_process_data_pdu(s, hdr);
break;
case DYNVC_CLOSE:
dvc_process_close_pdu(s, hdr);
break;
#if 0 /* Unimplemented */
#if 0 // Unimplemented
case DYNVC_DATA_FIRST:
break;
case DYNVC_DATA_FIRST_COMPRESSED:
@ -447,23 +324,16 @@ dvc_process_pdu(STREAM s)
break;
case DYNVC_SOFT_SYNC_RESPONSE:
break;
#endif
default:
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x",
hdr.hdr.cmd);
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", hdr.hdr.cmd);
break;
}
}
RD_BOOL
dvc_init()
{
bool dvc_init() {
memset(channels, 0, sizeof(channels));
dvc_channel = channel_register("drdynvc",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
dvc_process_pdu);
dvc_channel = channel_register("drdynvc", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, dvc_process_pdu);
return (dvc_channel != NULL);
}

View File

@ -25,6 +25,8 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <string.h>
#include <stdlib.h>
#include "rdesktop.h"
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
@ -45,7 +47,7 @@ Atom g_net_wm_state_atom, g_net_wm_desktop_atom, g_net_wm_ping_atom;
Returns zero on success, -1 on error
*/
static int
get_property_value(Window wnd, char *propname, long max_length,
get_property_value(Window wnd, const char *propname, long max_length,
unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
{
int result;
@ -57,6 +59,7 @@ get_property_value(Window wnd, char *propname, long max_length,
property = XInternAtom(g_display, propname, True);
if (property == None)
{
if (!nowarn)
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
return (-1);
}
@ -71,6 +74,7 @@ get_property_value(Window wnd, char *propname, long max_length,
if (result != Success)
{
if (!nowarn)
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
return (-1);
}
@ -106,7 +110,7 @@ static int
get_current_desktop(void)
{
unsigned long nitems_return;
unsigned char *prop_return;
unsigned char *prop_return = NULL;
int current_desktop;
if (get_property_value
@ -117,6 +121,7 @@ get_current_desktop(void)
if (nitems_return != 1)
{
logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length");
if (prop_return) XFree(prop_return);
return (-1);
}
@ -135,7 +140,7 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
{
int current_desktop;
unsigned long nitems_return;
unsigned char *prop_return;
unsigned char *prop_return = NULL;
long *return_words;
const uint32 net_workarea_x_offset = 0;
const uint32 net_workarea_y_offset = 1;
@ -151,13 +156,17 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
if (nitems_return % 4)
{
logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length");
XFree(prop_return);
return (-1);
}
current_desktop = get_current_desktop();
if (current_desktop < 0)
{
XFree(prop_return);
return -1;
}
return_words = (long *) prop_return;
@ -206,7 +215,7 @@ int
ewmh_get_window_state(Window w)
{
unsigned long nitems_return;
unsigned char *prop_return;
unsigned char *prop_return = NULL;
unsigned long *return_words;
unsigned long item;
RD_BOOL maximized_vert, maximized_horz, hidden;
@ -247,7 +256,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
int result;
unsigned long i, nitems;
unsigned char *props;
unsigned char *props = NULL;
uint32 state = WithdrawnState;
/* The spec states that the window manager must respect any
@ -312,10 +321,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
xevent.xclient.window = wnd;
xevent.xclient.message_type = g_net_wm_state_atom;
xevent.xclient.format = 32;
if (add)
xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
else
xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
xevent.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
xevent.xclient.data.l[1] = atom1;
xevent.xclient.data.l[2] = atom2;
xevent.xclient.data.l[3] = 0;
@ -361,7 +367,7 @@ int
ewmh_get_window_desktop(Window wnd)
{
unsigned long nitems_return;
unsigned char *prop_return;
unsigned char *prop_return = NULL;
int desktop;
if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
@ -370,6 +376,7 @@ ewmh_get_window_desktop(Window wnd)
if (nitems_return != 1)
{
logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length");
if (prop_return) XFree(prop_return);
return (-1);
}
@ -440,7 +447,7 @@ void
ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
{
unsigned long nitems, i;
unsigned char *props;
unsigned char *props = NULL;
unsigned long *cur_set, *new_set;
unsigned long *icon;
@ -463,7 +470,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
icon = cur_set + i;
else
{
new_set = xmalloc((nitems + width * height + 2) * sizeof(unsigned long));
new_set = (unsigned long *)malloc((nitems + width * height + 2) * sizeof(unsigned long));
memcpy(new_set, cur_set, nitems * sizeof(unsigned long));
icon = new_set + nitems;
nitems += width * height + 2;
@ -471,7 +478,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
}
else
{
new_set = xmalloc((width * height + 2) * sizeof(unsigned long));
new_set = (unsigned long *)malloc((width * height + 2) * sizeof(unsigned long));
icon = new_set;
nitems = width * height + 2;
}
@ -483,10 +490,10 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
for (i = 0; i < (width * height); i++)
{
icon[i + 2] =
rgba_data[i * 4 + 3] << 24 |
((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
((rgba_data[i * 4 + 2] << 0) & 0x000000FF);
((unsigned char)rgba_data[i * 4 + 3] << 24) |
(((unsigned char)rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
(((unsigned char)rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
(((unsigned char)rgba_data[i * 4 + 2] << 0) & 0x000000FF);
}
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
@ -495,14 +502,14 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
if (cur_set)
XFree(cur_set);
if (new_set)
xfree(new_set);
free(new_set);
}
void
ewmh_del_icon(Window wnd, uint32 width, uint32 height)
{
unsigned long nitems, i, icon_size;
unsigned char *props;
unsigned char *props = NULL;
unsigned long *cur_set, *new_set;
cur_set = NULL;
@ -525,7 +532,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
goto out;
icon_size = width * height + 2;
new_set = xmalloc((nitems - icon_size) * sizeof(unsigned long));
new_set = (unsigned long *)malloc((nitems - icon_size) * sizeof(unsigned long));
if (i != 0)
memcpy(new_set, cur_set, i * sizeof(unsigned long));
@ -538,7 +545,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *) new_set, nitems);
xfree(new_set);
free(new_set);
out:
XFree(cur_set);
@ -556,7 +563,7 @@ RD_BOOL
ewmh_is_window_above(Window w)
{
unsigned long nitems_return;
unsigned char *prop_return;
unsigned char *prop_return = NULL;
unsigned long *return_words;
unsigned long item;
RD_BOOL above;