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 typedef struct _ctrl_slave_t
{ {
struct _ctrl_slave_t *prev, *next; struct _ctrl_slave_t *prev, *next;
int sock; int sock;
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)
memset(ns, 0, sizeof(_ctrl_slave_t)); {
ns->sock = sock; 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)
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; ns->prev = it;
ns->prev = it; }
} else
else {
{ _ctrl_slaves = ns;
/* no elements in list, lets add first */ }
_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;
if (!_ctrl_slaves) if (!_ctrl_slaves)
return; return;
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) _ctrl_slaves = it->next;
_ctrl_slaves = it->next; else
else _ctrl_slaves = NULL;
_ctrl_slaves = NULL; }
}
if (it->prev) if (it->prev)
{ {
(it->prev)->next = it->next; (it->prev)->next = it->next;
if (it->next) if (it->next)
(it->next)->prev = it->prev; (it->next)->prev = it->prev;
} }
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, sizeof(buf), "ERROR %x\n", result);
snprintf(buf, 64, "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)
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0) {
{ _ctrl_command_result(slave, ERR_RESULT_NO_SUCH_COMMAND);
/* process seamless spawn request */ return;
p = strstr(cmd, "seamlessrdpshell.exe"); }
if (p)
p += strlen("seamlessrdpshell.exe") + 1;
else
p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
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 = ERR_RESULT_OK;
res = 1;
}
else
{
res = ERR_RESULT_NO_SUCH_COMMAND;
}
xfree(cmd);
_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 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));
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{ {
logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s", logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s",
strerror(errno)); strerror(errno));
exit(1); exit(1);
} }
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) {
return False; close(s);
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;
if (g_seamless_rdp) if (g_seamless_rdp)
flags = CTRL_HASH_FLAG_SEAMLESS; flags = CTRL_HASH_FLAG_SEAMLESS;
rdssl_sha1_init(&sha1); rdssl_sha1_init(&sha1);
rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version)); rdssl_sha1_update(&sha1, (uint8 *)&version, sizeof(version));
rdssl_sha1_update(&sha1, &delim, 1); rdssl_sha1_update(&sha1, &delim, 1);
if (user) if (user)
rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user)); rdssl_sha1_update(&sha1, (uint8 *)user, strlen(user));
rdssl_sha1_update(&sha1, &delim, 1); rdssl_sha1_update(&sha1, &delim, 1);
if (domain) if (domain)
rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain)); rdssl_sha1_update(&sha1, (uint8 *)domain, strlen(domain));
rdssl_sha1_update(&sha1, &delim, 1); rdssl_sha1_update(&sha1, &delim, 1);
if (host) if (host)
rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host)); rdssl_sha1_update(&sha1, (uint8 *)host, strlen(host));
rdssl_sha1_update(&sha1, &delim, 1); rdssl_sha1_update(&sha1, &delim, 1);
rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags)); rdssl_sha1_update(&sha1, (uint8 *)&flags, sizeof(flags));
rdssl_sha1_final(&sha1, out); rdssl_sha1_final(&sha1, out);
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;
home = getenv("HOME"); home = getenv("HOME");
if (home == NULL) if (home == NULL)
{ {
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); if (utils_mkdir_p(path, 0700) == -1)
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;
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)
if (stat(ctrlsock_name, &st) == 0) {
{ if (_ctrl_verify_unix_socket() == True)
/* verify that unix socket is not stale */ {
if (_ctrl_verify_unix_socket() == True) _ctrl_is_slave = True;
{ return 1;
_ctrl_is_slave = True; }
return 1; else
} {
else unlink(ctrlsock_name);
{ }
unlink(ctrlsock_name); }
}
}
/* 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) - 1);
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path)); 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)); exit(1);
exit(1); }
}
if (listen(ctrlsock, 5) < 0) if (listen(ctrlsock, 5) < 0)
{ {
logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno)); logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno));
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)
{ {
close(ctrlsock); close(ctrlsock);
unlink(ctrlsock_name); unlink(ctrlsock_name);
} }
} }
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)
return; return;
FD_SET(ctrlsock, rfds); FD_SET(ctrlsock, rfds);
*n = MAX(*n, ctrlsock); *n = MAX(*n, ctrlsock);
it = _ctrl_slaves;
/* add connected slaves to fd set */ while (it)
it = _ctrl_slaves; {
while (it) FD_SET(it->sock, rfds);
{ *n = MAX(*n, it->sock);
FD_SET(it->sock, rfds); it = it->next;
*n = MAX(*n, it->sock); }
it = it->next;
}
} }
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;
struct sockaddr_un fsaun; struct sockaddr_un fsaun;
socklen_t fromlen; socklen_t fromlen;
_ctrl_slave_t *it; _ctrl_slave_t *it;
if (ctrlsock == 0) if (ctrlsock == 0)
return; 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))
if (FD_ISSET(ctrlsock, rfds)) {
{ FD_CLR(ctrlsock, rfds);
FD_CLR(ctrlsock, rfds); fromlen = sizeof(fsaun);
fromlen = sizeof(fsaun); ns = accept(ctrlsock, (struct sockaddr *)&fsaun, &fromlen);
ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen); if (ns < 0)
if (ns < 0) {
{ logger(Core, Error, "ctrl_check_fds(), accept() failed: %s",
logger(Core, Error, "ctrl_check_fds(), accept() failed: %s", strerror(errno));
strerror(errno)); exit(1);
exit(1); }
}
_ctrl_slave_new(ns); _ctrl_slave_new(ns);
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 - 1, 0);
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 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') {
{ _ctrl_slave_disconnect(it->sock);
_ctrl_slave_disconnect(it->sock); break;
break; }
}
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) {
{ if (p > it->linebuf && *(p - 1) != '\\')
/* Check if newline is escaped */ break;
if (p > it->linebuf && *(p - 1) != '\\') p = strchr(p + 1, '\n');
break; }
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 {
{ _ctrl_slave_disconnect(it->sock);
/* Peer disconnected or socket error */ break;
_ctrl_slave_disconnect(it->sock); }
break; }
} it = it->next;
} }
it = it->next;
}
} }
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;
int s, len, index, ret; int s, len, index, ret;
char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE]; char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
char result[CTRL_RESULT_SIZE], c, *escaped; char result[CTRL_RESULT_SIZE], c, *escaped;
escaped = NULL; escaped = NULL;
if (!_ctrl_is_slave) if (!_ctrl_is_slave)
return -1; return -1;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{ {
logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno)); logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno));
exit(1); exit(1);
} }
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)
{ {
logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno)); logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno));
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) > sizeof(data) - 1)
if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 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') {
{ result[index] = c;
result[index] = c; index++;
index++; }
} result[index - 1] = '\0';
result[index - 1] = '\0';
if (strncmp(result, "ERROR ", 6) == 0) if (strncmp(result, "ERROR ", 6) == 0)
{ {
if (sscanf(result, "ERROR %d", &ret) != 1) if (sscanf(result, "ERROR %d", &ret) != 1)
ret = -1; ret = -1;
} }
bail_out: bail_out:
xfree(escaped); free(escaped);
shutdown(s, SHUT_RDWR); shutdown(s, SHUT_RDWR);
close(s); 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define FILE_ATTRIBUTE_READONLY 0x00000001 #ifndef DISK_REDIRECTION_DEFINITIONS_H
#define FILE_ATTRIBUTE_HIDDEN 0x00000002 #define DISK_REDIRECTION_DEFINITIONS_H
#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
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000 #include <windows.h>
#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
#define FILE_SHARE_READ 0x01 // File attribute constants
#define FILE_SHARE_WRITE 0x02 #define FILE_ATTRIBUTE_READONLY 0x00000001
#define FILE_SHARE_DELETE 0x04 #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 // File flag constants
#define FILE_STANDARD_INFORMATION 0x05 #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 // File share mode constants
#define FS_CASE_IS_PRESERVED 0x00000002 #define FILE_SHARE_READ 0x00000001
#define FS_UNICODE_STORED_ON_DISK 0x00000004 #define FILE_SHARE_WRITE 0x00000002
#define FS_PERSISTENT_ACLS 0x00000008 #define FILE_SHARE_DELETE 0x00000004
#define FS_FILE_COMPRESSION 0x00000010
#define FS_VOLUME_QUOTAS 0x00000020
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
#define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
#define FS_VOL_IS_COMPRESSED 0x00008000
#define FILE_READ_ONLY_VOLUME 0x00080000
#define OPEN_EXISTING 1 // File information constants
#define CREATE_NEW 2 #define FILE_BASIC_INFORMATION 0x00000004
#define OPEN_ALWAYS 3 #define FILE_STANDARD_INFORMATION 0x00000005
#define TRUNCATE_EXISTING 4
#define CREATE_ALWAYS 5
#define GENERIC_READ 0x80000000 // File system attribute constants
#define GENERIC_WRITE 0x40000000 #define FS_CASE_SENSITIVE 0x00000001
#define GENERIC_EXECUTE 0x20000000 #define FS_CASE_IS_PRESERVED 0x00000002
#define GENERIC_ALL 0x10000000 #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 // File creation disposition constants
#define ERROR_ALREADY_EXISTS 183L #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 typedef enum _FILE_INFORMATION_CLASS
{ {
FileDirectoryInformation = 1, FileDirectoryInformation = 1,
FileFullDirectoryInformation, FileFullDirectoryInformation,
FileBothDirectoryInformation, FileBothDirectoryInformation,
FileBasicInformation, FileBasicInformation,
FileStandardInformation, FileStandardInformation,
FileInternalInformation, FileInternalInformation,
FileEaInformation, FileEaInformation,
FileAccessInformation, FileAccessInformation,
FileNameInformation, FileNameInformation,
FileRenameInformation, FileRenameInformation,
FileLinkInformation, FileLinkInformation,
FileNamesInformation, FileNamesInformation,
FileDispositionInformation, FileDispositionInformation,
FilePositionInformation, FilePositionInformation,
FileFullEaInformation, FileFullEaInformation,
FileModeInformation, FileModeInformation,
FileAlignmentInformation, FileAlignmentInformation,
FileAllInformation, FileAllInformation,
FileAllocationInformation, FileAllocationInformation,
FileEndOfFileInformation, FileEndOfFileInformation,
FileAlternateNameInformation, FileAlternateNameInformation,
FileStreamInformation, FileStreamInformation,
FilePipeInformation, FilePipeInformation,
FilePipeLocalInformation, FilePipeLocalInformation,
FilePipeRemoteInformation, FilePipeRemoteInformation,
FileMailslotQueryInformation, FileMailslotQueryInformation,
FileMailslotSetInformation, FileMailslotSetInformation,
FileCompressionInformation, FileCompressionInformation,
FileCopyOnWriteInformation, FileCopyOnWriteInformation,
FileCompletionInformation, FileCompletionInformation,
FileMoveClusterInformation, FileMoveClusterInformation,
FileOleClassIdInformation, FileOleClassIdInformation,
FileOleStateBitsInformation, FileOleStateBitsInformation,
FileNetworkOpenInformation, FileNetworkOpenInformation,
FileObjectIdInformation, FileObjectIdInformation,
FileOleAllInformation, FileOleAllInformation,
FileOleDirectoryInformation, FileOleDirectoryInformation,
FileContentIndexInformation, FileContentIndexInformation,
FileInheritContentIndexInformation, FileInheritContentIndexInformation,
FileOleInformation, FileOleInformation,
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,
FileFsSizeInformation, FileFsSizeInformation,
FileFsDeviceInformation, FileFsDeviceInformation,
FileFsAttributeInformation, FileFsAttributeInformation,
FileFsControlInformation, FileFsControlInformation,
FileFsFullSizeInformation, FileFsFullSizeInformation,
FileFsObjectIdInformation, FileFsObjectIdInformation,
FileFsDriverPathInformation, FileFsDriverPathInformation,
FileFsMaximumInformation FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; } 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. 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,451 +20,320 @@
*/ */
#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
#define DYNVC_DATA 0x03 #define DYNVC_DATA 0x03
#define DYNVC_CLOSE 0x04 #define DYNVC_CLOSE 0x04
#define DYNVC_CAPABILITIES 0x05 #define DYNVC_CAPABILITIES 0x05
#define DYNVC_DATA_FIRST_COMPRESSED 0x06 #define DYNVC_DATA_FIRST_COMPRESSED 0x06
#define DYNVC_DATA_COMPRESSED 0x07 #define DYNVC_DATA_COMPRESSED 0x07
#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; } hdr;
uint8 cmd:4;
} 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; if (channels[i].hash == hash)
uint32 hash; return true;
hash = utils_djb2_hash(name); }
for (i = 0; i < MAX_DVC_CHANNELS; i++) return false;
{
if (channels[i].hash == hash)
return True;
}
return False;
} }
static const dvc_channel_t * static const dvc_channel_t *dvc_channels_get_by_id(uint32_t id) {
dvc_channels_get_by_id(uint32 id) for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
{ if (channels[i].channel_id == id) {
int i; return &channels[i];
}
for (i = 0; i < MAX_DVC_CHANNELS; i++) }
{ return NULL;
if (channels[i].channel_id == id)
{
return &channels[i];
}
}
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; return channels[i].channel_id;
hash = utils_djb2_hash(name); }
}
for (i = 0; i < MAX_DVC_CHANNELS; i++) return INVALID_CHANNEL;
{
if (channels[i].hash == hash)
{
return channels[i].channel_id;
}
}
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; memset(&channels[i], 0, sizeof(dvc_channel_t));
return true;
for (i = 0; i < MAX_DVC_CHANNELS; i++) }
{ }
if (channels[i].channel_id == channelid) return false;
{
memset(&channels[i], 0, sizeof(dvc_channel_t));
return True;
}
}
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) for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
{ if (channels[i].hash == 0) {
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", uint32_t hash = utils_djb2_hash(name);
name); channels[i].hash = hash;
return False; 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++) logger(Core, Warning, "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
{ return false;
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;
} }
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);
channels[i].channel_id = channel_id;
hash = utils_djb2_hash(name); return 0;
}
for (i = 0; i < MAX_DVC_CHANNELS; i++) }
{ return -1;
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 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; return (channels[i].channel_id != INVALID_CHANNEL);
hash = utils_djb2_hash(name); }
}
for (i = 0; i < MAX_DVC_CHANNELS; i++) return false;
{
if (channels[i].hash == hash)
{
return (channels[i].channel_id != INVALID_CHANNEL);
}
}
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) {
STREAM s;
length += 1; // add 1 byte hdr
static STREAM if (channelid != INVALID_CHANNEL) {
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length) if (hdr.hdr.cbid == 0)
{ length += 1;
STREAM s; 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 (channelid != INVALID_CHANNEL) {
{ if (hdr.hdr.cbid == 0) {
if (hdr.hdr.cbid == 0) out_uint8(s, channelid);
length += 1; } else if (hdr.hdr.cbid == 1) {
else if (hdr.hdr.cbid == 1) out_uint16_le(s, channelid);
length += 2; } else if (hdr.hdr.cbid == 2) {
else if (hdr.hdr.cbid == 2) out_uint32_le(s, channelid);
length += 4; }
} }
s = channel_init(dvc_channel, length); return s;
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;
} }
void void dvc_send(const char *name, STREAM s) {
dvc_send(const char *name, STREAM s) STREAM ls;
{ dvc_hdr_t hdr;
STREAM ls; uint32_t channel_id = dvc_channels_get_id(name);
dvc_hdr_t hdr;
uint32 channel_id;
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);
{ return;
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; ls = dvc_init_packet(hdr, channel_id, s_length(s));
hdr.hdr.cbid = 2; out_stream(ls, s);
hdr.hdr.sp = 0; s_mark_end(ls);
channel_send(ls, dvc_channel);
ls = dvc_init_packet(hdr, channel_id, s_length(s)); s_free(ls);
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 hdr.hdr.cbid = 0x00;
dvc_send_capabilities_response() hdr.hdr.sp = 0x00;
{ hdr.hdr.cmd = DYNVC_CAPABILITIES;
STREAM s;
dvc_hdr_t hdr;
uint16 supportedversion = 0x01;
hdr.hdr.cbid = 0x00; logger(Protocol, Debug, "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
hdr.hdr.sp = 0x00;
hdr.hdr.cmd = DYNVC_CAPABILITIES;
logger(Protocol, Debug, s = dvc_init_packet(hdr, (uint32_t)-1, 3);
"dvc_send_capabilities_response(), offering support for dvc %d", supportedversion); out_uint8(s, 0x00); // pad
out_uint16_le(s, supportedversion); // version
s = dvc_init_packet(hdr, -1, 3); s_mark_end(s);
out_uint8(s, 0x00); /* pad */ channel_send(s, dvc_channel);
out_uint16_le(s, supportedversion); /* version */ s_free(s);
s_mark_end(s);
channel_send(s, dvc_channel);
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];
{ uint32_t channelid;
char name[512];
uint32 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);
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);
}
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 static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr) {
dvc_in_channelid(STREAM s, dvc_hdr_t hdr) uint32_t id = (uint32_t)-1;
{
uint32 id;
id = (uint32) - 1; switch (hdr.hdr.cbid) {
case 0:
switch (hdr.hdr.cbid) in_uint8(s, id);
{ break;
case 0: case 1:
in_uint8(s, id); in_uint16_le(s, id);
break; break;
case 1: case 2:
in_uint16_le(s, id); in_uint32_le(s, id);
break; break;
case 2: }
in_uint32_le(s, id); return id;
break;
}
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;
{ uint32_t channelid = dvc_in_channelid(s, hdr);
const dvc_channel_t *ch;
uint32 channelid;
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);
{ return;
logger(Protocol, Warning, }
"dvc_process_data(), Received data on unregistered channel %d", channelid);
return;
}
/* dispatch packet to channel handler */ // Dispatch packet to channel handler
ch->handler(s); 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);
{ logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
uint32 channelid;
channelid = dvc_in_channelid(s, hdr); if (!dvc_channels_remove_by_id(channelid)) {
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid); logger(Protocol, Warning, "dvc_process_close_pdu(), Received close request for unregistered 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;
}
} }
static void dvc_process_pdu(STREAM s) {
dvc_hdr_t hdr;
static void in_uint8(s, hdr.data);
dvc_process_pdu(STREAM s)
{
dvc_hdr_t hdr;
in_uint8(s, hdr.data); switch (hdr.hdr.cmd) {
case DYNVC_CAPABILITIES:
switch (hdr.hdr.cmd) dvc_process_caps_pdu(s);
{ break;
case DYNVC_CAPABILITIES: case DYNVC_CREATE_REQ:
dvc_process_caps_pdu(s); dvc_process_create_pdu(s, hdr);
break; break;
case DYNVC_CREATE_REQ: case DYNVC_DATA:
dvc_process_create_pdu(s, hdr); dvc_process_data_pdu(s, hdr);
break; break;
case DYNVC_CLOSE:
case DYNVC_DATA: dvc_process_close_pdu(s, hdr);
dvc_process_data_pdu(s, hdr); break;
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;
#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 #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));
{ dvc_channel = channel_register("drdynvc", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, dvc_process_pdu);
memset(channels, 0, sizeof(channels)); return (dvc_channel != NULL);
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/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,7 +59,8 @@ 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)
{ {
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); return (-1);
} }
@ -71,7 +74,8 @@ get_property_value(Window wnd, char *propname, long max_length,
if (result != Success) if (result != Success)
{ {
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed"); if (!nowarn)
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;