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

232
disk.c
View File

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

44
disk.h
View File

@ -18,13 +18,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. 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_READONLY 0x00000001
#define FILE_ATTRIBUTE_HIDDEN 0x00000002 #define FILE_ATTRIBUTE_HIDDEN 0x00000002
#define FILE_ATTRIBUTE_SYSTEM 0x00000004 #define FILE_ATTRIBUTE_SYSTEM 0x00000004
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 #define FILE_ATTRIBUTE_ARCHIVE 0x00000020
#define FILE_ATTRIBUTE_DEVICE 0x00000040 #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_NORMAL 0x00000080
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 #define FILE_ATTRIBUTE_TEMPORARY 0x00000100
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
@ -34,10 +39,11 @@
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
// File flag constants
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000 #define FILE_FLAG_OPEN_NO_RECALL 0x00100000
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 #define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000 #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_DELETE_ON_CLOSE 0x04000000
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000 #define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
#define FILE_FLAG_RANDOM_ACCESS 0x10000000 #define FILE_FLAG_RANDOM_ACCESS 0x10000000
@ -45,13 +51,16 @@
#define FILE_FLAG_OVERLAPPED 0x40000000 #define FILE_FLAG_OVERLAPPED 0x40000000
#define FILE_FLAG_WRITE_THROUGH 0x80000000 #define FILE_FLAG_WRITE_THROUGH 0x80000000
#define FILE_SHARE_READ 0x01 // File share mode constants
#define FILE_SHARE_WRITE 0x02 #define FILE_SHARE_READ 0x00000001
#define FILE_SHARE_DELETE 0x04 #define FILE_SHARE_WRITE 0x00000002
#define FILE_SHARE_DELETE 0x00000004
#define FILE_BASIC_INFORMATION 0x04 // File information constants
#define FILE_STANDARD_INFORMATION 0x05 #define FILE_BASIC_INFORMATION 0x00000004
#define FILE_STANDARD_INFORMATION 0x00000005
// File system attribute constants
#define FS_CASE_SENSITIVE 0x00000001 #define FS_CASE_SENSITIVE 0x00000001
#define FS_CASE_IS_PRESERVED 0x00000002 #define FS_CASE_IS_PRESERVED 0x00000002
#define FS_UNICODE_STORED_ON_DISK 0x00000004 #define FS_UNICODE_STORED_ON_DISK 0x00000004
@ -60,25 +69,28 @@
#define FS_VOLUME_QUOTAS 0x00000020 #define FS_VOLUME_QUOTAS 0x00000020
#define FS_SUPPORTS_SPARSE_FILES 0x00000040 #define FS_SUPPORTS_SPARSE_FILES 0x00000040
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080 #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 FS_VOL_IS_COMPRESSED 0x00008000
#define FILE_READ_ONLY_VOLUME 0x00080000 #define FILE_READ_ONLY_VOLUME 0x00080000
#define OPEN_EXISTING 1 // File creation disposition constants
#define CREATE_NEW 2 #define OPEN_EXISTING 3
#define OPEN_ALWAYS 3 #define CREATE_NEW 1
#define TRUNCATE_EXISTING 4 #define OPEN_ALWAYS 4
#define CREATE_ALWAYS 5 #define TRUNCATE_EXISTING 5
#define CREATE_ALWAYS 2
// Generic access rights constants
#define GENERIC_READ 0x80000000 #define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000 #define GENERIC_WRITE 0x40000000
#define GENERIC_EXECUTE 0x20000000 #define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000 #define GENERIC_ALL 0x10000000
// Error codes
#define ERROR_FILE_NOT_FOUND 2L #define ERROR_FILE_NOT_FOUND 2L
#define ERROR_ALREADY_EXISTS 183L #define ERROR_ALREADY_EXISTS 183L
#define MAX_OPEN_FILES 0x100 #define MAX_OPEN_FILES 256
typedef enum _FILE_INFORMATION_CLASS typedef enum _FILE_INFORMATION_CLASS
{ {
@ -125,7 +137,7 @@ typedef enum _FILE_INFORMATION_CLASS
FileMaximumInformation FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef enum _FSINFOCLASS typedef enum _FS_INFORMATION_CLASS
{ {
FileFsVolumeInformation = 1, FileFsVolumeInformation = 1,
FileFsLabelInformation, FileFsLabelInformation,
@ -138,3 +150,5 @@ typedef enum _FSINFOCLASS
FileFsDriverPathInformation, FileFsDriverPathInformation,
FileFsMaximumInformation FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; } 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. rdesktop: A Remote Desktop Protocol client.
Dynamic Channel Virtual Channel Extension. Dynamic Channel Virtual Channel Extension.
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
@ -19,9 +20,12 @@
*/ */
#include "rdesktop.h" #include "rdesktop.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define MAX_DVC_CHANNELS 20 #define MAX_DVC_CHANNELS 20
#define INVALID_CHANNEL ((uint32)-1) #define INVALID_CHANNEL ((uint32_t)-1)
#define DYNVC_CREATE_REQ 0x01 #define DYNVC_CREATE_REQ 0x01
#define DYNVC_DATA_FIRST 0x02 #define DYNVC_DATA_FIRST 0x02
@ -33,183 +37,117 @@
#define DYNVC_SOFT_SYNC_REQUEST 0x08 #define DYNVC_SOFT_SYNC_REQUEST 0x08
#define DYNVC_SOFT_SYNC_RESPONSE 0x09 #define DYNVC_SOFT_SYNC_RESPONSE 0x09
typedef union dvc_hdr_t typedef union {
{ uint8_t data;
uint8 data; struct {
struct uint8_t cbid : 2;
{ uint8_t sp : 2;
uint8 cbid:2; uint8_t cmd : 4;
uint8 sp:2;
uint8 cmd:4;
} hdr; } hdr;
} dvc_hdr_t; } dvc_hdr_t;
typedef struct dvc_channel_t typedef struct {
{ uint32_t hash;
uint32 hash; uint32_t channel_id;
uint32 channel_id;
dvc_channel_process_fn handler; dvc_channel_process_fn handler;
} dvc_channel_t; } dvc_channel_t;
static VCHANNEL *dvc_channel; static VCHANNEL *dvc_channel;
static dvc_channel_t channels[MAX_DVC_CHANNELS]; 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 static bool dvc_channels_exists(const char *name) {
dvc_channels_exists(const char *name) uint32_t hash = utils_djb2_hash(name);
{ for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
int i;
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash) if (channels[i].hash == hash)
return True; return true;
}
return false;
} }
return False; 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) {
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)
{
return &channels[i]; return &channels[i];
} }
} }
return NULL; return NULL;
} }
static uint32 static uint32_t dvc_channels_get_id(const char *name) {
dvc_channels_get_id(const char *name) uint32_t hash = utils_djb2_hash(name);
{ for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
int i; if (channels[i].hash == hash) {
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash)
{
return channels[i].channel_id; return channels[i].channel_id;
} }
} }
return INVALID_CHANNEL; return INVALID_CHANNEL;
} }
static RD_BOOL static bool dvc_channels_remove_by_id(uint32_t channelid) {
dvc_channels_remove_by_id(uint32 channelid) for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
{ if (channels[i].channel_id == channelid) {
int i;
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].channel_id == channelid)
{
memset(&channels[i], 0, sizeof(dvc_channel_t)); memset(&channels[i], 0, sizeof(dvc_channel_t));
return True; return true;
} }
} }
return False; return false;
} }
static RD_BOOL static bool dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32_t channel_id) {
dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id) if (dvc_channels_exists(name)) {
{ logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", name);
int i; return false;
uint32 hash;
if (dvc_channels_exists(name) == True)
{
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
name);
return False;
} }
for (i = 0; i < MAX_DVC_CHANNELS; i++) for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
{ if (channels[i].hash == 0) {
if (channels[i].hash == 0) uint32_t hash = utils_djb2_hash(name);
{
hash = utils_djb2_hash(name);
channels[i].hash = hash; channels[i].hash = hash;
channels[i].handler = handler; channels[i].handler = handler;
channels[i].channel_id = channel_id; channels[i].channel_id = channel_id;
logger(Core, Debug, logger(Core, Debug, "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
"dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
hash, channel_id, name, handler); hash, channel_id, name, handler);
return True; return true;
} }
} }
logger(Core, Warning, logger(Core, Warning, "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
"dvc_channels_add(), Failed to add channel, maximum number of channels are being used"); return false;
return False;
} }
static int static int dvc_channels_set_id(const char *name, uint32_t channel_id) {
dvc_channels_set_id(const char *name, uint32 channel_id) uint32_t hash = utils_djb2_hash(name);
{ for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
int i; if (channels[i].hash == hash) {
uint32 hash; logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d", name, channel_id);
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);
channels[i].channel_id = channel_id; channels[i].channel_id = channel_id;
return 0; return 0;
} }
} }
return -1; return -1;
} }
RD_BOOL bool dvc_channels_is_available(const char *name) {
dvc_channels_is_available(const char *name) uint32_t hash = utils_djb2_hash(name);
{ for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
int i; if (channels[i].hash == hash) {
uint32 hash;
hash = utils_djb2_hash(name);
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == hash)
{
return (channels[i].channel_id != INVALID_CHANNEL); return (channels[i].channel_id != INVALID_CHANNEL);
} }
} }
return false;
return False;
} }
RD_BOOL bool dvc_channels_register(const char *name, dvc_channel_process_fn handler) {
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
{
return dvc_channels_add(name, handler, INVALID_CHANNEL); return dvc_channels_add(name, handler, INVALID_CHANNEL);
} }
static STREAM dvc_init_packet(dvc_hdr_t hdr, uint32_t channelid, size_t length) {
static STREAM
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
{
STREAM s; 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) if (hdr.hdr.cbid == 0)
length += 1; length += 1;
else if (hdr.hdr.cbid == 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); 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 (channelid != INVALID_CHANNEL) {
{ if (hdr.hdr.cbid == 0) {
if (hdr.hdr.cbid == 0)
{
out_uint8(s, channelid); out_uint8(s, channelid);
} } else if (hdr.hdr.cbid == 1) {
else if (hdr.hdr.cbid == 1)
{
out_uint16_le(s, channelid); out_uint16_le(s, channelid);
} } else if (hdr.hdr.cbid == 2) {
else if (hdr.hdr.cbid == 2)
{
out_uint32_le(s, channelid); out_uint32_le(s, channelid);
} }
} }
@ -240,127 +172,92 @@ dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
return s; return s;
} }
void void dvc_send(const char *name, STREAM s) {
dvc_send(const char *name, STREAM s)
{
STREAM ls; STREAM ls;
dvc_hdr_t hdr; 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) {
if (channel_id == INVALID_CHANNEL) logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'", name);
{
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'",
name);
return; return;
} }
/* FIXME: we assume length is less than 1600 */ // FIXME: we assume length is less than 1600
hdr.hdr.cmd = DYNVC_DATA; hdr.hdr.cmd = DYNVC_DATA;
hdr.hdr.cbid = 2; hdr.hdr.cbid = 2;
hdr.hdr.sp = 0; hdr.hdr.sp = 0;
ls = dvc_init_packet(hdr, channel_id, s_length(s)); ls = dvc_init_packet(hdr, channel_id, s_length(s));
out_stream(ls, s); out_stream(ls, s);
s_mark_end(ls); s_mark_end(ls);
channel_send(ls, dvc_channel); channel_send(ls, dvc_channel);
s_free(ls); s_free(ls);
} }
static void dvc_send_capabilities_response() {
static void
dvc_send_capabilities_response()
{
STREAM s; STREAM s;
dvc_hdr_t hdr; dvc_hdr_t hdr;
uint16 supportedversion = 0x01; uint16_t supportedversion = 0x01;
hdr.hdr.cbid = 0x00; hdr.hdr.cbid = 0x00;
hdr.hdr.sp = 0x00; hdr.hdr.sp = 0x00;
hdr.hdr.cmd = DYNVC_CAPABILITIES; hdr.hdr.cmd = DYNVC_CAPABILITIES;
logger(Protocol, Debug, logger(Protocol, Debug, "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
"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 */
s = dvc_init_packet(hdr, (uint32_t)-1, 3);
out_uint8(s, 0x00); // pad
out_uint16_le(s, supportedversion); // version
s_mark_end(s); s_mark_end(s);
channel_send(s, dvc_channel); channel_send(s, dvc_channel);
s_free(s); s_free(s);
} }
static void static void dvc_process_caps_pdu(STREAM s) {
dvc_process_caps_pdu(STREAM s) uint16_t version;
{
uint16 version;
/* VERSION1 */ in_uint8s(s, 1); // pad
in_uint8s(s, 1); /* pad */ in_uint16_le(s, version); // version
in_uint16_le(s, version); /* version */
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version); logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
dvc_send_capabilities_response(); dvc_send_capabilities_response();
} }
static void static void dvc_send_create_response(bool success, dvc_hdr_t hdr, uint32_t channelid) {
dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
{
STREAM s; STREAM s;
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d", logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
(success ? "granted" : "denied"), channelid); (success ? "granted" : "denied"), channelid);
s = dvc_init_packet(hdr, channelid, 4); 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); s_mark_end(s);
channel_send(s, dvc_channel); channel_send(s, dvc_channel);
s_free(s); s_free(s);
} }
static void static void dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) {
dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr)
{
char name[512]; char name[512];
uint32 channelid; uint32_t channelid;
channelid = dvc_in_channelid(s, hdr); channelid = dvc_in_channelid(s, hdr);
in_ansi_string(s, name, sizeof(name)); in_ansi_string(s, name, sizeof(name));
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", channelid, name);
channelid, name);
if (dvc_channels_exists(name)) if (dvc_channels_exists(name)) {
{
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name); logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
dvc_channels_set_id(name, channelid); 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 switch (hdr.hdr.cbid) {
dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
{
uint32 id;
id = (uint32) - 1;
switch (hdr.hdr.cbid)
{
case 0: case 0:
in_uint8(s, id); in_uint8(s, id);
break; break;
@ -374,69 +271,49 @@ dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
return id; return id;
} }
static void static void dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) {
dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
{
const dvc_channel_t *ch; 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); ch = dvc_channels_get_by_id(channelid);
if (ch == NULL) if (ch == NULL) {
{ logger(Protocol, Warning, "dvc_process_data(), Received data on unregistered channel %d", channelid);
logger(Protocol, Warning,
"dvc_process_data(), Received data on unregistered channel %d", channelid);
return; return;
} }
/* dispatch packet to channel handler */ // Dispatch packet to channel handler
ch->handler(s); ch->handler(s);
} }
static void static void dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) {
dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) uint32_t channelid = dvc_in_channelid(s, hdr);
{
uint32 channelid;
channelid = dvc_in_channelid(s, hdr);
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid); logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
if (!dvc_channels_remove_by_id(channelid)) if (!dvc_channels_remove_by_id(channelid)) {
{ logger(Protocol, Warning, "dvc_process_close_pdu(), Received close request for unregistered channel %d", channelid);
logger(Protocol, Warning,
"dvc_process_close_pdu(), Received close request for unregistered channel %d",
channelid);
return;
} }
} }
static void dvc_process_pdu(STREAM s) {
static void
dvc_process_pdu(STREAM s)
{
dvc_hdr_t hdr; dvc_hdr_t hdr;
in_uint8(s, hdr.data); in_uint8(s, hdr.data);
switch (hdr.hdr.cmd) switch (hdr.hdr.cmd) {
{
case DYNVC_CAPABILITIES: case DYNVC_CAPABILITIES:
dvc_process_caps_pdu(s); dvc_process_caps_pdu(s);
break; break;
case DYNVC_CREATE_REQ: case DYNVC_CREATE_REQ:
dvc_process_create_pdu(s, hdr); dvc_process_create_pdu(s, hdr);
break; break;
case DYNVC_DATA: case DYNVC_DATA:
dvc_process_data_pdu(s, hdr); dvc_process_data_pdu(s, hdr);
break; break;
case DYNVC_CLOSE: case DYNVC_CLOSE:
dvc_process_close_pdu(s, hdr); dvc_process_close_pdu(s, hdr);
break; break;
#if 0 /* Unimplemented */ #if 0 // Unimplemented
case DYNVC_DATA_FIRST: case DYNVC_DATA_FIRST:
break; break;
case DYNVC_DATA_FIRST_COMPRESSED: case DYNVC_DATA_FIRST_COMPRESSED:
@ -447,23 +324,16 @@ dvc_process_pdu(STREAM s)
break; break;
case DYNVC_SOFT_SYNC_RESPONSE: case DYNVC_SOFT_SYNC_RESPONSE:
break; break;
#endif #endif
default: default:
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", hdr.hdr.cmd);
hdr.hdr.cmd);
break; break;
} }
} }
RD_BOOL bool dvc_init() {
dvc_init()
{
memset(channels, 0, sizeof(channels)); memset(channels, 0, sizeof(channels));
dvc_channel = channel_register("drdynvc", dvc_channel = channel_register("drdynvc", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, dvc_process_pdu);
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
dvc_process_pdu);
return (dvc_channel != NULL); return (dvc_channel != NULL);
} }

View File

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