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

691
ctrl.c
View File

@ -51,469 +51,432 @@ static struct _ctrl_slave_t *_ctrl_slaves;
typedef struct _ctrl_slave_t
{
struct _ctrl_slave_t *prev, *next;
int sock;
char linebuf[CTRL_LINEBUF_SIZE];
struct _ctrl_slave_t *prev, *next;
int sock;
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;
_ctrl_slave_t *it, *ns;
/* initialize new slave list item */
ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
memset(ns, 0, sizeof(_ctrl_slave_t));
ns->sock = sock;
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;
it = _ctrl_slaves;
/* find last element in list */
while (it && it->next)
it = it->next;
while (it && it->next)
it = it->next;
/* if last found append new */
if (it)
{
it->next = ns;
ns->prev = it;
}
else
{
/* no elements in list, lets add first */
_ctrl_slaves = ns;
}
if (it)
{
it->next = ns;
ns->prev = it;
}
else
{
_ctrl_slaves = ns;
}
}
static void
_ctrl_slave_disconnect(int sock)
static void _ctrl_slave_disconnect(int sock)
{
_ctrl_slave_t *it;
_ctrl_slave_t *it;
if (!_ctrl_slaves)
return;
if (!_ctrl_slaves)
return;
it = _ctrl_slaves;
it = _ctrl_slaves;
/* find slave with sock */
while (it->next && it->sock != sock)
it = it->next;
while (it->next && it->sock != sock)
it = it->next;
if (it->sock == sock)
{
/* shutdown socket */
shutdown(sock, SHUT_RDWR);
close(sock);
if (it->sock == sock)
{
shutdown(sock, SHUT_RDWR);
close(sock);
/* remove item from list */
if (it == _ctrl_slaves)
{
if (it->next)
_ctrl_slaves = it->next;
else
_ctrl_slaves = NULL;
}
if (it == _ctrl_slaves)
{
if (it->next)
_ctrl_slaves = it->next;
else
_ctrl_slaves = NULL;
}
if (it->prev)
{
(it->prev)->next = it->next;
if (it->next)
(it->next)->prev = it->prev;
}
else if (it->next)
(it->next)->prev = NULL;
if (it->prev)
{
(it->prev)->next = it->next;
if (it->next)
(it->next)->prev = it->prev;
}
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 };
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);
send(slave->sock, buf, strlen(buf), 0);
}
if (result == 0)
send(slave->sock, "OK\n", 3, 0);
else
{
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;
unsigned int res;
char *cmd, *p;
unsigned int res;
/* unescape linebuffer */
cmd = utils_string_unescape(slave->linebuf);
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;
else
p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
cmd = utils_string_unescape(slave->linebuf);
if (!cmd)
{
_ctrl_command_result(slave, ERR_RESULT_NO_SUCH_COMMAND);
return;
}
res = ERR_RESULT_OK;
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
{
p = strstr(cmd, "seamlessrdpshell.exe");
if (p)
p += strlen("seamlessrdpshell.exe") + 1;
else
p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
if (seamless_send_spawn(p) == (unsigned int) -1)
res = 1;
}
else
{
res = ERR_RESULT_NO_SUCH_COMMAND;
}
xfree(cmd);
res = ERR_RESULT_OK;
_ctrl_command_result(slave, res);
if (seamless_send_spawn(p) == (unsigned int)-1)
res = 1;
}
else
{
res = ERR_RESULT_NO_SUCH_COMMAND;
}
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;
struct sockaddr_un saun;
int s;
struct sockaddr_un saun;
socklen_t len;
memset(&saun, 0, sizeof(struct sockaddr_un));
memset(&saun, 0, sizeof(struct sockaddr_un));
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s",
strerror(errno));
exit(1);
}
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s",
strerror(errno));
exit(1);
}
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ctrlsock_name);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
saun.sun_family = AF_UNIX;
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)
return False;
if (connect(s, (struct sockaddr *)&saun, len) != 0)
{
close(s);
return False;
}
shutdown(s, SHUT_RDWR);
close(s);
return True;
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;
RDSSL_SHA1 sha1;
uint8 out[20], delim;
uint16 version;
uint32 flags;
/* version\0user\0domain\0host\0flags */
flags = 0;
delim = '\0';
version = 0x0100;
flags = 0;
delim = '\0';
version = 0x0100;
if (g_seamless_rdp)
flags = CTRL_HASH_FLAG_SEAMLESS;
if (g_seamless_rdp)
flags = CTRL_HASH_FLAG_SEAMLESS;
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version));
rdssl_sha1_update(&sha1, &delim, 1);
rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, (uint8 *)&version, sizeof(version));
rdssl_sha1_update(&sha1, &delim, 1);
if (user)
rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user));
rdssl_sha1_update(&sha1, &delim, 1);
if (user)
rdssl_sha1_update(&sha1, (uint8 *)user, strlen(user));
rdssl_sha1_update(&sha1, &delim, 1);
if (domain)
rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain));
rdssl_sha1_update(&sha1, &delim, 1);
if (domain)
rdssl_sha1_update(&sha1, (uint8 *)domain, strlen(domain));
rdssl_sha1_update(&sha1, &delim, 1);
if (host)
rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host));
rdssl_sha1_update(&sha1, &delim, 1);
if (host)
rdssl_sha1_update(&sha1, (uint8 *)host, strlen(host));
rdssl_sha1_update(&sha1, &delim, 1);
rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags));
rdssl_sha1_final(&sha1, out);
rdssl_sha1_update(&sha1, (uint8 *)&flags, sizeof(flags));
rdssl_sha1_final(&sha1, out);
sec_hash_to_string(hash, hsize, out, sizeof(out));
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;
struct stat st;
struct sockaddr_un saun;
char hash[41], path[PATH_MAX];
const char *home;
/* check if ctrl already initialized */
if (ctrlsock != 0 || _ctrl_is_slave)
return 0;
if (ctrlsock != 0 || _ctrl_is_slave)
return 0;
home = getenv("HOME");
if (home == NULL)
{
return -1;
}
home = getenv("HOME");
if (home == NULL)
{
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';
if (utils_mkdir_p(path, 0700) == -1)
{
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
return -1;
}
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;
return 1;
}
else
{
unlink(ctrlsock_name);
}
}
if (stat(ctrlsock_name, &st) == 0)
{
if (_ctrl_verify_unix_socket() == True)
{
_ctrl_is_slave = True;
return 1;
}
else
{
unlink(ctrlsock_name);
}
}
/* 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);
}
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));
if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0)
{
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
exit(1);
}
memset(&saun, 0, sizeof(struct sockaddr_un));
saun.sun_family = AF_UNIX;
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));
exit(1);
}
if (listen(ctrlsock, 5) < 0)
{
logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno));
exit(1);
}
if (listen(ctrlsock, 5) < 0)
{
logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno));
exit(1);
}
/* add ctrl cleanup func to exit hooks */
atexit(ctrl_cleanup);
atexit(ctrl_cleanup);
return 0;
return 0;
}
void
ctrl_cleanup()
void ctrl_cleanup(void)
{
if (ctrlsock)
{
close(ctrlsock);
unlink(ctrlsock_name);
}
if (ctrlsock)
{
close(ctrlsock);
unlink(ctrlsock_name);
}
}
RD_BOOL
ctrl_is_slave()
RD_BOOL ctrl_is_slave(void)
{
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;
if (ctrlsock == 0)
return;
_ctrl_slave_t *it;
if (ctrlsock == 0)
return;
FD_SET(ctrlsock, rfds);
*n = MAX(*n, ctrlsock);
FD_SET(ctrlsock, rfds);
*n = MAX(*n, ctrlsock);
/* add connected slaves to fd set */
it = _ctrl_slaves;
while (it)
{
FD_SET(it->sock, rfds);
*n = MAX(*n, it->sock);
it = it->next;
}
it = _ctrl_slaves;
while (it)
{
FD_SET(it->sock, rfds);
*n = MAX(*n, it->sock);
it = it->next;
}
}
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;
struct sockaddr_un fsaun;
socklen_t fromlen;
_ctrl_slave_t *it;
UNUSED(wfds);
int ns, res, offs;
struct sockaddr_un fsaun;
socklen_t fromlen;
_ctrl_slave_t *it;
if (ctrlsock == 0)
return;
if (ctrlsock == 0)
return;
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))
{
FD_CLR(ctrlsock, rfds);
fromlen = sizeof(fsaun);
ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen);
if (ns < 0)
{
logger(Core, Error, "ctrl_check_fds(), accept() failed: %s",
strerror(errno));
exit(1);
}
if (FD_ISSET(ctrlsock, rfds))
{
FD_CLR(ctrlsock, rfds);
fromlen = sizeof(fsaun);
ns = accept(ctrlsock, (struct sockaddr *)&fsaun, &fromlen);
if (ns < 0)
{
logger(Core, Error, "ctrl_check_fds(), accept() failed: %s",
strerror(errno));
exit(1);
}
_ctrl_slave_new(ns);
return;
}
_ctrl_slave_new(ns);
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);
FD_CLR(it->sock, rfds);
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 - 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')
{
_ctrl_slave_disconnect(it->sock);
break;
}
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
{
_ctrl_slave_disconnect(it->sock);
break;
}
if (res > 0)
{
/* Check if we got full command line */
char *p;
if ((p = strchr(it->linebuf, '\n')) == NULL)
continue;
if (res > 0)
{
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');
}
while (p)
{
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;
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;
}
}
it = it->next;
}
*p = '\0';
_ctrl_dispatch_command(it);
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
}
else
{
_ctrl_slave_disconnect(it->sock);
break;
}
}
it = it->next;
}
}
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;
int s, len, index, ret;
char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
char result[CTRL_RESULT_SIZE], c, *escaped;
FILE *fp;
struct sockaddr_un saun;
int s, len, index, ret;
char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
char result[CTRL_RESULT_SIZE], c, *escaped;
escaped = NULL;
escaped = NULL;
if (!_ctrl_is_slave)
return -1;
if (!_ctrl_is_slave)
return -1;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno));
exit(1);
}
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno));
exit(1);
}
memset(&saun, 0, sizeof(struct sockaddr_un));
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ctrlsock_name);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
memset(&saun, 0, sizeof(struct sockaddr_un));
saun.sun_family = AF_UNIX;
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)
{
logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno));
exit(1);
}
if (connect(s, (struct sockaddr *)&saun, len) < 0)
{
logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno));
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;
if (ret != 0)
goto bail_out;
/* escape the UTF-8 string */
escaped = utils_string_escape(tmp);
if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1)
goto bail_out;
escaped = utils_string_escape(tmp);
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);
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')
{
result[index] = c;
index++;
}
result[index - 1] = '\0';
fp = fdopen(s, "r");
index = 0;
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
{
result[index] = c;
index++;
}
result[index - 1] = '\0';
if (strncmp(result, "ERROR ", 6) == 0)
{
if (sscanf(result, "ERROR %d", &ret) != 1)
ret = -1;
}
if (strncmp(result, "ERROR ", 6) == 0)
{
if (sscanf(result, "ERROR %d", &ret) != 1)
ret = -1;
}
bail_out:
xfree(escaped);
shutdown(s, SHUT_RDWR);
close(s);
bail_out:
free(escaped);
shutdown(s, SHUT_RDWR);
close(s);
return ret;
return ret;
}

2018
disk.c

File diff suppressed because it is too large Load Diff

224
disk.h
View File

@ -18,123 +18,137 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
#define FILE_ATTRIBUTE_OFFLINE 0x00001000
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#ifndef DISK_REDIRECTION_DEFINITIONS_H
#define DISK_REDIRECTION_DEFINITIONS_H
#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_DELETE_ON_CLOSE 0x04000000
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
#define FILE_FLAG_NO_BUFFERING 0x20000000
#define FILE_FLAG_OVERLAPPED 0x40000000
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#include <windows.h>
#define FILE_SHARE_READ 0x01
#define FILE_SHARE_WRITE 0x02
#define FILE_SHARE_DELETE 0x04
// 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_NORMAL 0x00000080
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
#define FILE_ATTRIBUTE_OFFLINE 0x00001000
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#define FILE_BASIC_INFORMATION 0x04
#define FILE_STANDARD_INFORMATION 0x05
// 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
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
#define FILE_FLAG_NO_BUFFERING 0x20000000
#define FILE_FLAG_OVERLAPPED 0x40000000
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#define FS_CASE_SENSITIVE 0x00000001
#define FS_CASE_IS_PRESERVED 0x00000002
#define FS_UNICODE_STORED_ON_DISK 0x00000004
#define FS_PERSISTENT_ACLS 0x00000008
#define FS_FILE_COMPRESSION 0x00000010
#define FS_VOLUME_QUOTAS 0x00000020
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
#define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
#define FS_VOL_IS_COMPRESSED 0x00008000
#define FILE_READ_ONLY_VOLUME 0x00080000
// File share mode constants
#define FILE_SHARE_READ 0x00000001
#define FILE_SHARE_WRITE 0x00000002
#define FILE_SHARE_DELETE 0x00000004
#define OPEN_EXISTING 1
#define CREATE_NEW 2
#define OPEN_ALWAYS 3
#define TRUNCATE_EXISTING 4
#define CREATE_ALWAYS 5
// File information constants
#define FILE_BASIC_INFORMATION 0x00000004
#define FILE_STANDARD_INFORMATION 0x00000005
#define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000
#define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000
// File system attribute constants
#define FS_CASE_SENSITIVE 0x00000001
#define FS_CASE_IS_PRESERVED 0x00000002
#define FS_UNICODE_STORED_ON_DISK 0x00000004
#define FS_PERSISTENT_ACLS 0x00000008
#define FS_FILE_COMPRESSION 0x00000010
#define FS_VOLUME_QUOTAS 0x00000020
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
#define FS_SUPPORTS_REMOTE_STORAGE 0x00000100
#define FS_VOL_IS_COMPRESSED 0x00008000
#define FILE_READ_ONLY_VOLUME 0x00080000
#define ERROR_FILE_NOT_FOUND 2L
#define ERROR_ALREADY_EXISTS 183L
// File creation disposition constants
#define OPEN_EXISTING 3
#define CREATE_NEW 1
#define OPEN_ALWAYS 4
#define TRUNCATE_EXISTING 5
#define CREATE_ALWAYS 2
#define MAX_OPEN_FILES 0x100
// 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 256
typedef enum _FILE_INFORMATION_CLASS
{
FileDirectoryInformation = 1,
FileFullDirectoryInformation,
FileBothDirectoryInformation,
FileBasicInformation,
FileStandardInformation,
FileInternalInformation,
FileEaInformation,
FileAccessInformation,
FileNameInformation,
FileRenameInformation,
FileLinkInformation,
FileNamesInformation,
FileDispositionInformation,
FilePositionInformation,
FileFullEaInformation,
FileModeInformation,
FileAlignmentInformation,
FileAllInformation,
FileAllocationInformation,
FileEndOfFileInformation,
FileAlternateNameInformation,
FileStreamInformation,
FilePipeInformation,
FilePipeLocalInformation,
FilePipeRemoteInformation,
FileMailslotQueryInformation,
FileMailslotSetInformation,
FileCompressionInformation,
FileCopyOnWriteInformation,
FileCompletionInformation,
FileMoveClusterInformation,
FileOleClassIdInformation,
FileOleStateBitsInformation,
FileNetworkOpenInformation,
FileObjectIdInformation,
FileOleAllInformation,
FileOleDirectoryInformation,
FileContentIndexInformation,
FileInheritContentIndexInformation,
FileOleInformation,
FileMaximumInformation
FileDirectoryInformation = 1,
FileFullDirectoryInformation,
FileBothDirectoryInformation,
FileBasicInformation,
FileStandardInformation,
FileInternalInformation,
FileEaInformation,
FileAccessInformation,
FileNameInformation,
FileRenameInformation,
FileLinkInformation,
FileNamesInformation,
FileDispositionInformation,
FilePositionInformation,
FileFullEaInformation,
FileModeInformation,
FileAlignmentInformation,
FileAllInformation,
FileAllocationInformation,
FileEndOfFileInformation,
FileAlternateNameInformation,
FileStreamInformation,
FilePipeInformation,
FilePipeLocalInformation,
FilePipeRemoteInformation,
FileMailslotQueryInformation,
FileMailslotSetInformation,
FileCompressionInformation,
FileCopyOnWriteInformation,
FileCompletionInformation,
FileMoveClusterInformation,
FileOleClassIdInformation,
FileOleStateBitsInformation,
FileNetworkOpenInformation,
FileObjectIdInformation,
FileOleAllInformation,
FileOleDirectoryInformation,
FileContentIndexInformation,
FileInheritContentIndexInformation,
FileOleInformation,
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef enum _FSINFOCLASS
typedef enum _FS_INFORMATION_CLASS
{
FileFsVolumeInformation = 1,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsMaximumInformation
FileFsVolumeInformation = 1,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
#endif // DISK_REDIRECTION_DEFINITIONS_H

614
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,451 +20,320 @@
*/
#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
#define DYNVC_DATA 0x03
#define DYNVC_CLOSE 0x04
#define DYNVC_CAPABILITIES 0x05
#define DYNVC_DATA_FIRST_COMPRESSED 0x06
#define DYNVC_DATA_COMPRESSED 0x07
#define DYNVC_SOFT_SYNC_REQUEST 0x08
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
#define DYNVC_CREATE_REQ 0x01
#define DYNVC_DATA_FIRST 0x02
#define DYNVC_DATA 0x03
#define DYNVC_CLOSE 0x04
#define DYNVC_CAPABILITIES 0x05
#define DYNVC_DATA_FIRST_COMPRESSED 0x06
#define DYNVC_DATA_COMPRESSED 0x07
#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;
} hdr;
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;
dvc_channel_process_fn handler;
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++)
{
if (channels[i].hash == hash)
return True;
}
return False;
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 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)
{
return &channels[i];
}
}
return NULL;
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)
{
return channels[i].channel_id;
}
}
return INVALID_CHANNEL;
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)
{
memset(&channels[i], 0, sizeof(dvc_channel_t));
return True;
}
}
return False;
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 false;
}
static RD_BOOL
dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id)
{
int i;
uint32 hash;
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;
}
if (dvc_channels_exists(name) == True)
{
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
name);
return False;
}
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",
hash, channel_id, name, handler);
return true;
}
}
for (i = 0; i < MAX_DVC_CHANNELS; i++)
{
if (channels[i].hash == 0)
{
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",
hash, channel_id, name, handler);
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);
channels[i].channel_id = channel_id;
return 0;
}
}
return -1;
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)
{
return (channels[i].channel_id != INVALID_CHANNEL);
}
}
return False;
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;
}
RD_BOOL
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
{
return dvc_channels_add(name, handler, INVALID_CHANNEL);
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_t channelid, size_t length) {
STREAM s;
length += 1; // add 1 byte hdr
static STREAM
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
{
STREAM s;
if (channelid != INVALID_CHANNEL) {
if (hdr.hdr.cbid == 0)
length += 1;
else if (hdr.hdr.cbid == 1)
length += 2;
else if (hdr.hdr.cbid == 2)
length += 4;
}
length += 1; /* add 1 byte hdr */
s = channel_init(dvc_channel, length);
out_uint8(s, hdr.data); // DVC header
if (channelid != INVALID_CHANNEL)
{
if (hdr.hdr.cbid == 0)
length += 1;
else if (hdr.hdr.cbid == 1)
length += 2;
else if (hdr.hdr.cbid == 2)
length += 4;
}
if (channelid != INVALID_CHANNEL) {
if (hdr.hdr.cbid == 0) {
out_uint8(s, channelid);
} else if (hdr.hdr.cbid == 1) {
out_uint16_le(s, channelid);
} else if (hdr.hdr.cbid == 2) {
out_uint32_le(s, channelid);
}
}
s = channel_init(dvc_channel, length);
out_uint8(s, hdr.data); /* DVC header */
if (channelid != INVALID_CHANNEL)
{
if (hdr.hdr.cbid == 0)
{
out_uint8(s, channelid);
}
else if (hdr.hdr.cbid == 1)
{
out_uint16_le(s, channelid);
}
else if (hdr.hdr.cbid == 2)
{
out_uint32_le(s, channelid);
}
}
return s;
return s;
}
void
dvc_send(const char *name, STREAM s)
{
STREAM ls;
dvc_hdr_t hdr;
uint32 channel_id;
void dvc_send(const char *name, STREAM s) {
STREAM ls;
dvc_hdr_t hdr;
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);
return;
}
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;
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);
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() {
STREAM s;
dvc_hdr_t hdr;
uint16_t supportedversion = 0x01;
static void
dvc_send_capabilities_response()
{
STREAM s;
dvc_hdr_t hdr;
uint16 supportedversion = 0x01;
hdr.hdr.cbid = 0x00;
hdr.hdr.sp = 0x00;
hdr.hdr.cmd = DYNVC_CAPABILITIES;
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);
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 */
s_mark_end(s);
channel_send(s, dvc_channel);
s_free(s);
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);
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
dvc_send_capabilities_response();
dvc_send_capabilities_response();
}
static void
dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
{
STREAM s;
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);
s_mark_end(s);
channel_send(s, dvc_channel);
s_free(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 : (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)
{
char name[512];
uint32 channelid;
static void dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) {
char name[512];
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'",
channelid, 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);
}
else
{
dvc_send_create_response(False, hdr, channelid);
}
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", channelid, 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);
} else {
dvc_send_create_response(false, hdr, channelid);
}
}
static uint32
dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
{
uint32 id;
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr) {
uint32_t id = (uint32_t)-1;
id = (uint32) - 1;
switch (hdr.hdr.cbid)
{
case 0:
in_uint8(s, id);
break;
case 1:
in_uint16_le(s, id);
break;
case 2:
in_uint32_le(s, id);
break;
}
return id;
switch (hdr.hdr.cbid) {
case 0:
in_uint8(s, id);
break;
case 1:
in_uint16_le(s, id);
break;
case 2:
in_uint32_le(s, id);
break;
}
return id;
}
static void
dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
{
const dvc_channel_t *ch;
uint32 channelid;
static void dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) {
const dvc_channel_t *ch;
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);
return;
}
ch = dvc_channels_get_by_id(channelid);
if (ch == NULL) {
logger(Protocol, Warning, "dvc_process_data(), Received data on unregistered channel %d", channelid);
return;
}
/* dispatch packet to channel handler */
ch->handler(s);
// Dispatch packet to channel handler
ch->handler(s);
}
static void
dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr)
{
uint32 channelid;
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);
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) {
dvc_hdr_t hdr;
static void
dvc_process_pdu(STREAM s)
{
dvc_hdr_t hdr;
in_uint8(s, hdr.data);
in_uint8(s, hdr.data);
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 */
case DYNVC_DATA_FIRST:
break;
case DYNVC_DATA_FIRST_COMPRESSED:
break;
case DYNVC_DATA_COMPRESSED:
break;
case DYNVC_SOFT_SYNC_REQUEST:
break;
case DYNVC_SOFT_SYNC_RESPONSE:
break;
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
case DYNVC_DATA_FIRST:
break;
case DYNVC_DATA_FIRST_COMPRESSED:
break;
case DYNVC_DATA_COMPRESSED:
break;
case DYNVC_SOFT_SYNC_REQUEST:
break;
case DYNVC_SOFT_SYNC_RESPONSE:
break;
#endif
default:
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x",
hdr.hdr.cmd);
break;
}
default:
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", hdr.hdr.cmd);
break;
}
}
RD_BOOL
dvc_init()
{
memset(channels, 0, sizeof(channels));
dvc_channel = channel_register("drdynvc",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
dvc_process_pdu);
return (dvc_channel != NULL);
bool dvc_init() {
memset(channels, 0, sizeof(channels));
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,7 +59,8 @@ get_property_value(Window wnd, char *propname, long max_length,
property = XInternAtom(g_display, propname, True);
if (property == None)
{
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
if (!nowarn)
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
return (-1);
}
@ -71,7 +74,8 @@ get_property_value(Window wnd, char *propname, long max_length,
if (result != Success)
{
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
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;