Third Batch: Update files using ChatGPT 4o
This commit is contained in:
parent
669e3a9e11
commit
867c553378
163
ctrl.c
163
ctrl.c
@ -56,25 +56,31 @@ typedef struct _ctrl_slave_t
|
|||||||
char linebuf[CTRL_LINEBUF_SIZE];
|
char linebuf[CTRL_LINEBUF_SIZE];
|
||||||
} _ctrl_slave_t;
|
} _ctrl_slave_t;
|
||||||
|
|
||||||
|
static void _ctrl_slave_new(int sock);
|
||||||
|
static void _ctrl_slave_disconnect(int sock);
|
||||||
|
static void _ctrl_command_result(_ctrl_slave_t *slave, int result);
|
||||||
|
static void _ctrl_dispatch_command(_ctrl_slave_t *slave);
|
||||||
|
static RD_BOOL _ctrl_verify_unix_socket(void);
|
||||||
|
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize);
|
||||||
|
|
||||||
static void
|
static void _ctrl_slave_new(int sock)
|
||||||
_ctrl_slave_new(int sock)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it, *ns;
|
_ctrl_slave_t *it, *ns;
|
||||||
|
|
||||||
/* initialize new slave list item */
|
ns = (_ctrl_slave_t *)malloc(sizeof(_ctrl_slave_t));
|
||||||
ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
|
if (!ns)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "_ctrl_slave_new(), malloc() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
memset(ns, 0, sizeof(_ctrl_slave_t));
|
memset(ns, 0, sizeof(_ctrl_slave_t));
|
||||||
ns->sock = sock;
|
ns->sock = sock;
|
||||||
|
|
||||||
/* append new slave to end of list */
|
|
||||||
it = _ctrl_slaves;
|
it = _ctrl_slaves;
|
||||||
|
|
||||||
/* find last element in list */
|
|
||||||
while (it && it->next)
|
while (it && it->next)
|
||||||
it = it->next;
|
it = it->next;
|
||||||
|
|
||||||
/* if last found append new */
|
|
||||||
if (it)
|
if (it)
|
||||||
{
|
{
|
||||||
it->next = ns;
|
it->next = ns;
|
||||||
@ -82,13 +88,11 @@ _ctrl_slave_new(int sock)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no elements in list, lets add first */
|
|
||||||
_ctrl_slaves = ns;
|
_ctrl_slaves = ns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_slave_disconnect(int sock)
|
||||||
_ctrl_slave_disconnect(int sock)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it;
|
_ctrl_slave_t *it;
|
||||||
|
|
||||||
@ -97,17 +101,14 @@ _ctrl_slave_disconnect(int sock)
|
|||||||
|
|
||||||
it = _ctrl_slaves;
|
it = _ctrl_slaves;
|
||||||
|
|
||||||
/* find slave with sock */
|
|
||||||
while (it->next && it->sock != sock)
|
while (it->next && it->sock != sock)
|
||||||
it = it->next;
|
it = it->next;
|
||||||
|
|
||||||
if (it->sock == sock)
|
if (it->sock == sock)
|
||||||
{
|
{
|
||||||
/* shutdown socket */
|
|
||||||
shutdown(sock, SHUT_RDWR);
|
shutdown(sock, SHUT_RDWR);
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
/* remove item from list */
|
|
||||||
if (it == _ctrl_slaves)
|
if (it == _ctrl_slaves)
|
||||||
{
|
{
|
||||||
if (it->next)
|
if (it->next)
|
||||||
@ -125,38 +126,37 @@ _ctrl_slave_disconnect(int sock)
|
|||||||
else if (it->next)
|
else if (it->next)
|
||||||
(it->next)->prev = NULL;
|
(it->next)->prev = NULL;
|
||||||
|
|
||||||
xfree(it);
|
free(it);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_command_result(_ctrl_slave_t *slave, int result)
|
||||||
_ctrl_command_result(_ctrl_slave_t * slave, int result)
|
|
||||||
{
|
{
|
||||||
char buf[64] = { 0 };
|
char buf[64] = {0};
|
||||||
|
|
||||||
/* translate and send result code back to client */
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
send(slave->sock, "OK\n", 3, 0);
|
send(slave->sock, "OK\n", 3, 0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(buf, 64, "ERROR %x\n", result);
|
snprintf(buf, sizeof(buf), "ERROR %x\n", result);
|
||||||
send(slave->sock, buf, strlen(buf), 0);
|
send(slave->sock, buf, strlen(buf), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void _ctrl_dispatch_command(_ctrl_slave_t *slave)
|
||||||
_ctrl_dispatch_command(_ctrl_slave_t * slave)
|
|
||||||
{
|
{
|
||||||
char *p;
|
char *cmd, *p;
|
||||||
char *cmd;
|
|
||||||
unsigned int res;
|
unsigned int res;
|
||||||
|
|
||||||
/* unescape linebuffer */
|
|
||||||
cmd = utils_string_unescape(slave->linebuf);
|
cmd = utils_string_unescape(slave->linebuf);
|
||||||
|
if (!cmd)
|
||||||
|
{
|
||||||
|
_ctrl_command_result(slave, ERR_RESULT_NO_SUCH_COMMAND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
|
if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
|
||||||
{
|
{
|
||||||
/* process seamless spawn request */
|
|
||||||
p = strstr(cmd, "seamlessrdpshell.exe");
|
p = strstr(cmd, "seamlessrdpshell.exe");
|
||||||
if (p)
|
if (p)
|
||||||
p += strlen("seamlessrdpshell.exe") + 1;
|
p += strlen("seamlessrdpshell.exe") + 1;
|
||||||
@ -165,23 +165,23 @@ _ctrl_dispatch_command(_ctrl_slave_t * slave)
|
|||||||
|
|
||||||
res = ERR_RESULT_OK;
|
res = ERR_RESULT_OK;
|
||||||
|
|
||||||
if (seamless_send_spawn(p) == (unsigned int) -1)
|
if (seamless_send_spawn(p) == (unsigned int)-1)
|
||||||
res = 1;
|
res = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = ERR_RESULT_NO_SUCH_COMMAND;
|
res = ERR_RESULT_NO_SUCH_COMMAND;
|
||||||
}
|
}
|
||||||
xfree(cmd);
|
free(cmd);
|
||||||
|
|
||||||
_ctrl_command_result(slave, res);
|
_ctrl_command_result(slave, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static RD_BOOL _ctrl_verify_unix_socket(void)
|
||||||
_ctrl_verify_unix_socket()
|
|
||||||
{
|
{
|
||||||
int s, len;
|
int s;
|
||||||
struct sockaddr_un saun;
|
struct sockaddr_un saun;
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
@ -193,28 +193,27 @@ _ctrl_verify_unix_socket()
|
|||||||
}
|
}
|
||||||
|
|
||||||
saun.sun_family = AF_UNIX;
|
saun.sun_family = AF_UNIX;
|
||||||
strcpy(saun.sun_path, ctrlsock_name);
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
||||||
|
|
||||||
/* test connection */
|
if (connect(s, (struct sockaddr *)&saun, len) != 0)
|
||||||
if (connect(s, (struct sockaddr *) &saun, len) != 0)
|
{
|
||||||
|
close(s);
|
||||||
return False;
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
shutdown(s, SHUT_RDWR);
|
shutdown(s, SHUT_RDWR);
|
||||||
close(s);
|
close(s);
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
|
||||||
static void
|
|
||||||
_ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
|
|
||||||
{
|
{
|
||||||
RDSSL_SHA1 sha1;
|
RDSSL_SHA1 sha1;
|
||||||
uint8 out[20], delim;
|
uint8 out[20], delim;
|
||||||
uint16 version;
|
uint16 version;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
|
||||||
/* version\0user\0domain\0host\0flags */
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
delim = '\0';
|
delim = '\0';
|
||||||
version = 0x0100;
|
version = 0x0100;
|
||||||
@ -223,40 +222,34 @@ _ctrl_create_hash(const char *user, const char *domain, const char *host, char *
|
|||||||
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;
|
||||||
|
|
||||||
@ -266,24 +259,18 @@ ctrl_init(const char *user, const char *domain, const char *host)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get uniq hash for ctrlsock name */
|
_ctrl_create_hash(user, domain, host, hash, sizeof(hash));
|
||||||
_ctrl_create_hash(user, domain, host, hash, 41);
|
snprintf(ctrlsock_name, sizeof(ctrlsock_name), "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
|
||||||
snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
|
|
||||||
ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0';
|
|
||||||
|
|
||||||
/* make sure that ctrlsock store path exists */
|
snprintf(path, sizeof(path), "%s" RDESKTOP_CTRLSOCK_STORE, home);
|
||||||
snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home);
|
|
||||||
path[sizeof(path) - 1] = '\0';
|
|
||||||
if (utils_mkdir_p(path, 0700) == -1)
|
if (utils_mkdir_p(path, 0700) == -1)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if ctrl socket already exist then this process becomes a client */
|
|
||||||
if (stat(ctrlsock_name, &st) == 0)
|
if (stat(ctrlsock_name, &st) == 0)
|
||||||
{
|
{
|
||||||
/* verify that unix socket is not stale */
|
|
||||||
if (_ctrl_verify_unix_socket() == True)
|
if (_ctrl_verify_unix_socket() == True)
|
||||||
{
|
{
|
||||||
_ctrl_is_slave = True;
|
_ctrl_is_slave = True;
|
||||||
@ -295,18 +282,16 @@ ctrl_init(const char *user, const char *domain, const char *host)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup ctrl socket and start listening for connections */
|
|
||||||
if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bind and start listening on server socket */
|
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
saun.sun_family = AF_UNIX;
|
saun.sun_family = AF_UNIX;
|
||||||
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path));
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0)
|
if (bind(ctrlsock, (struct sockaddr *)&saun, sizeof(struct sockaddr_un)) < 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
|
logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -318,14 +303,12 @@ ctrl_init(const char *user, const char *domain, const char *host)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add ctrl cleanup func to exit hooks */
|
|
||||||
atexit(ctrl_cleanup);
|
atexit(ctrl_cleanup);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ctrl_cleanup(void)
|
||||||
ctrl_cleanup()
|
|
||||||
{
|
{
|
||||||
if (ctrlsock)
|
if (ctrlsock)
|
||||||
{
|
{
|
||||||
@ -334,15 +317,12 @@ ctrl_cleanup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
RD_BOOL ctrl_is_slave(void)
|
||||||
ctrl_is_slave()
|
|
||||||
{
|
{
|
||||||
return _ctrl_is_slave;
|
return _ctrl_is_slave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctrl_add_fds(int *n, fd_set *rfds)
|
||||||
void
|
|
||||||
ctrl_add_fds(int *n, fd_set * rfds)
|
|
||||||
{
|
{
|
||||||
_ctrl_slave_t *it;
|
_ctrl_slave_t *it;
|
||||||
if (ctrlsock == 0)
|
if (ctrlsock == 0)
|
||||||
@ -351,8 +331,6 @@ ctrl_add_fds(int *n, fd_set * rfds)
|
|||||||
FD_SET(ctrlsock, rfds);
|
FD_SET(ctrlsock, rfds);
|
||||||
*n = MAX(*n, ctrlsock);
|
*n = MAX(*n, ctrlsock);
|
||||||
|
|
||||||
|
|
||||||
/* add connected slaves to fd set */
|
|
||||||
it = _ctrl_slaves;
|
it = _ctrl_slaves;
|
||||||
while (it)
|
while (it)
|
||||||
{
|
{
|
||||||
@ -362,8 +340,7 @@ ctrl_add_fds(int *n, fd_set * rfds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ctrl_check_fds(fd_set *rfds, fd_set *wfds)
|
||||||
ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|
||||||
{
|
{
|
||||||
UNUSED(wfds);
|
UNUSED(wfds);
|
||||||
int ns, res, offs;
|
int ns, res, offs;
|
||||||
@ -376,12 +353,11 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|||||||
|
|
||||||
memset(&fsaun, 0, sizeof(struct sockaddr_un));
|
memset(&fsaun, 0, sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
/* check if we got any connections on server socket */
|
|
||||||
if (FD_ISSET(ctrlsock, rfds))
|
if (FD_ISSET(ctrlsock, rfds))
|
||||||
{
|
{
|
||||||
FD_CLR(ctrlsock, rfds);
|
FD_CLR(ctrlsock, rfds);
|
||||||
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",
|
||||||
@ -393,17 +369,15 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if any of our slaves fds has data */
|
|
||||||
it = _ctrl_slaves;
|
it = _ctrl_slaves;
|
||||||
while (it)
|
while (it)
|
||||||
{
|
{
|
||||||
if (FD_ISSET(it->sock, rfds))
|
if (FD_ISSET(it->sock, rfds))
|
||||||
{
|
{
|
||||||
offs = strlen(it->linebuf);
|
offs = strlen(it->linebuf);
|
||||||
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0);
|
res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs - 1, 0);
|
||||||
FD_CLR(it->sock, rfds);
|
FD_CLR(it->sock, rfds);
|
||||||
|
|
||||||
/* linebuffer full let's disconnect slave */
|
|
||||||
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
|
if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
|
||||||
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
|
it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
|
||||||
{
|
{
|
||||||
@ -413,32 +387,26 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|||||||
|
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
{
|
{
|
||||||
/* Check if we got full command line */
|
|
||||||
char *p;
|
char *p;
|
||||||
if ((p = strchr(it->linebuf, '\n')) == NULL)
|
if ((p = strchr(it->linebuf, '\n')) == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* iterate over string and check against escaped \n */
|
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
/* Check if newline is escaped */
|
|
||||||
if (p > it->linebuf && *(p - 1) != '\\')
|
if (p > it->linebuf && *(p - 1) != '\\')
|
||||||
break;
|
break;
|
||||||
p = strchr(p + 1, '\n');
|
p = strchr(p + 1, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we haven't found a nonescaped \n we need more data */
|
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* strip new linebuf and dispatch command */
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
_ctrl_dispatch_command(it);
|
_ctrl_dispatch_command(it);
|
||||||
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
|
memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Peer disconnected or socket error */
|
|
||||||
_ctrl_slave_disconnect(it->sock);
|
_ctrl_slave_disconnect(it->sock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -447,8 +415,7 @@ ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int ctrl_send_command(const char *cmd, const char *arg)
|
||||||
ctrl_send_command(const char *cmd, const char *arg)
|
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct sockaddr_un saun;
|
struct sockaddr_un saun;
|
||||||
@ -469,32 +436,28 @@ ctrl_send_command(const char *cmd, const char *arg)
|
|||||||
|
|
||||||
memset(&saun, 0, sizeof(struct sockaddr_un));
|
memset(&saun, 0, sizeof(struct sockaddr_un));
|
||||||
saun.sun_family = AF_UNIX;
|
saun.sun_family = AF_UNIX;
|
||||||
strcpy(saun.sun_path, ctrlsock_name);
|
strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path) - 1);
|
||||||
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
|
||||||
|
|
||||||
if (connect(s, (struct sockaddr *) &saun, len) < 0)
|
if (connect(s, (struct sockaddr *)&saun, len) < 0)
|
||||||
{
|
{
|
||||||
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) > CTRL_LINEBUF_SIZE - 1)
|
if ((strlen(escaped) + 1) > sizeof(data) - 1)
|
||||||
goto bail_out;
|
goto bail_out;
|
||||||
|
|
||||||
/* send escaped UTF-8 command to master */
|
|
||||||
send(s, escaped, strlen(escaped), 0);
|
send(s, escaped, strlen(escaped), 0);
|
||||||
send(s, "\n", 1, 0);
|
send(s, "\n", 1, 0);
|
||||||
|
|
||||||
/* read result from master */
|
|
||||||
fp = fdopen(s, "r");
|
fp = fdopen(s, "r");
|
||||||
index = 0;
|
index = 0;
|
||||||
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
|
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
|
||||||
@ -510,8 +473,8 @@ ctrl_send_command(const char *cmd, const char *arg)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bail_out:
|
bail_out:
|
||||||
xfree(escaped);
|
free(escaped);
|
||||||
shutdown(s, SHUT_RDWR);
|
shutdown(s, SHUT_RDWR);
|
||||||
close(s);
|
close(s);
|
||||||
|
|
||||||
|
258
disk.c
258
disk.c
@ -31,9 +31,10 @@
|
|||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <errno.h> /* errno */
|
#include <errno.h> /* errno */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <time.h> /* ctime */
|
#include <time.h> /* ctime */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))
|
#if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1))
|
||||||
#define DIRFD(a) (dirfd(a))
|
#define DIRFD(a) (dirfd(a))
|
||||||
@ -125,8 +126,7 @@ struct dummy_statfs_t
|
|||||||
int f_namemax;
|
int f_namemax;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int dummy_statfs(struct dummy_statfs_t *buf)
|
||||||
dummy_statfs(struct dummy_statfs_t *buf)
|
|
||||||
{
|
{
|
||||||
buf->f_blocks = 262144;
|
buf->f_blocks = 262144;
|
||||||
buf->f_bfree = 131072;
|
buf->f_bfree = 131072;
|
||||||
@ -155,54 +155,49 @@ typedef struct
|
|||||||
char type[PATH_MAX];
|
char type[PATH_MAX];
|
||||||
} FsInfoType;
|
} FsInfoType;
|
||||||
|
|
||||||
static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p);
|
static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY *p);
|
||||||
|
|
||||||
static time_t
|
static time_t get_create_time(struct stat *filestat)
|
||||||
get_create_time(struct stat *filestat)
|
|
||||||
{
|
{
|
||||||
time_t ret, ret1;
|
time_t ret, ret1;
|
||||||
|
|
||||||
ret = MIN(filestat->st_ctime, filestat->st_mtime);
|
ret = MIN(filestat->st_ctime, filestat->st_mtime);
|
||||||
ret1 = MIN(ret, filestat->st_atime);
|
ret1 = MIN(ret, filestat->st_atime);
|
||||||
|
|
||||||
if (ret1 != (time_t) 0)
|
if (ret1 != (time_t)0)
|
||||||
return ret1;
|
return ret1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert seconds since 1970 to a filetime */
|
/* Convert seconds since 1970 to a filetime */
|
||||||
static void
|
static void seconds_since_1970_to_filetime(time_t seconds, uint32 *high, uint32 *low)
|
||||||
seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low)
|
|
||||||
{
|
{
|
||||||
unsigned long long ticks;
|
unsigned long long ticks;
|
||||||
|
|
||||||
ticks = (seconds + 11644473600LL) * 10000000;
|
ticks = (seconds + 11644473600LL) * 10000000;
|
||||||
*low = (uint32) ticks;
|
*low = (uint32)ticks;
|
||||||
*high = (uint32) (ticks >> 32);
|
*high = (uint32)(ticks >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert seconds since 1970 back to filetime */
|
/* Convert seconds since 1970 back to filetime */
|
||||||
static time_t
|
static time_t convert_1970_to_filetime(uint32 high, uint32 low)
|
||||||
convert_1970_to_filetime(uint32 high, uint32 low)
|
|
||||||
{
|
{
|
||||||
unsigned long long ticks;
|
unsigned long long ticks;
|
||||||
time_t val;
|
time_t val;
|
||||||
|
|
||||||
ticks = low + (((unsigned long long) high) << 32);
|
ticks = low + (((unsigned long long)high) << 32);
|
||||||
ticks /= 10000000;
|
ticks /= 10000000;
|
||||||
ticks -= 11644473600LL;
|
ticks -= 11644473600LL;
|
||||||
|
|
||||||
val = (time_t) ticks;
|
val = (time_t)ticks;
|
||||||
return (val);
|
return (val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A wrapper for ftruncate which supports growing files, even if the
|
/* A wrapper for ftruncate which supports growing files, even if the
|
||||||
native ftruncate doesn't. This is needed on Linux FAT filesystems,
|
native ftruncate doesn't. This is needed on Linux FAT filesystems,
|
||||||
for example. */
|
for example. */
|
||||||
static int
|
static int ftruncate_growable(int fd, off_t length)
|
||||||
ftruncate_growable(int fd, off_t length)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
off_t pos;
|
off_t pos;
|
||||||
@ -243,8 +238,7 @@ ftruncate_growable(int fd, off_t length)
|
|||||||
/* Truncate. This shouldn't fail. */
|
/* Truncate. This shouldn't fail. */
|
||||||
if (ftruncate(fd, length) == -1)
|
if (ftruncate(fd, length) == -1)
|
||||||
{
|
{
|
||||||
logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s",
|
logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,14 +252,10 @@ ftruncate_growable(int fd, off_t length)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just like open(2), but if a open with O_EXCL fails, retry with
|
/* Just like open(2), but if an open with O_EXCL fails due to unsupported
|
||||||
GUARDED semantics. This might be necessary because some filesystems
|
behavior by some filesystems (like NFS), retry without O_EXCL.
|
||||||
(such as NFS filesystems mounted from a unfsd server) doesn't
|
This ensures compatibility with filesystems that do not support O_EXCL. */
|
||||||
support O_EXCL. GUARDED semantics are subject to race conditions,
|
static int open_weak_exclusive(const char *pathname, int flags, mode_t mode)
|
||||||
but we can live with that.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
open_weak_exclusive(const char *pathname, int flags, mode_t mode)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stat filestat;
|
struct stat filestat;
|
||||||
@ -277,12 +267,8 @@ open_weak_exclusive(const char *pathname, int flags, mode_t mode)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* An error occurred, and we are using O_EXCL. In case the FS
|
/* An error occurred, and we are using O_EXCL.
|
||||||
doesn't support O_EXCL, some kind of error will be
|
Handle specific known errors directly. */
|
||||||
returned. Unfortunately, we don't know which one. Linux
|
|
||||||
2.6.8 seems to return 524, but I cannot find a documented
|
|
||||||
#define for this case. So, we'll return only on errors that
|
|
||||||
we know aren't related to O_EXCL. */
|
|
||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
case EACCES:
|
case EACCES:
|
||||||
@ -296,25 +282,32 @@ open_weak_exclusive(const char *pathname, int flags, mode_t mode)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retry with GUARDED semantics */
|
/* For other errors, assume it's due to O_EXCL not being supported
|
||||||
if (stat(pathname, &filestat) != -1)
|
by the filesystem and retry without O_EXCL. */
|
||||||
|
if (stat(pathname, &filestat) == 0)
|
||||||
{
|
{
|
||||||
/* File exists */
|
/* File exists */
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
else if (errno == ENOENT)
|
||||||
|
{
|
||||||
|
/* File does not exist, retry without O_EXCL */
|
||||||
|
return open(pathname, flags & ~O_EXCL, mode);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return open(pathname, flags & ~O_EXCL, mode);
|
/* Some other error occurred */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enumeration of devices from rdesktop.c */
|
/* Enumeration of devices from rdesktop.c
|
||||||
/* returns number of units found and initialized. */
|
* returns number of units found and initialized.
|
||||||
/* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */
|
* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1'
|
||||||
/* when it arrives to this function. */
|
* when it arrives at this function.
|
||||||
int
|
*/
|
||||||
disk_enum_devices(uint32 * id, char *optarg)
|
int disk_enum_devices(uint32 *id, char *optarg)
|
||||||
{
|
{
|
||||||
char *pos = optarg;
|
char *pos = optarg;
|
||||||
char *pos2;
|
char *pos2;
|
||||||
@ -327,15 +320,15 @@ disk_enum_devices(uint32 * id, char *optarg)
|
|||||||
{
|
{
|
||||||
pos2 = next_arg(optarg, '=');
|
pos2 = next_arg(optarg, '=');
|
||||||
|
|
||||||
pdisk_data = (DISK_DEVICE *) xmalloc(sizeof(DISK_DEVICE));
|
pdisk_data = (DISK_DEVICE *)xmalloc(sizeof(DISK_DEVICE));
|
||||||
memset(pdisk_data, 0, sizeof(DISK_DEVICE));
|
memset(pdisk_data, 0, sizeof(DISK_DEVICE));
|
||||||
strncpy(pdisk_data->name, optarg, sizeof(pdisk_data->name) - 1);
|
strncpy(pdisk_data->name, optarg, sizeof(pdisk_data->name) - 1);
|
||||||
strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1);
|
strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1);
|
||||||
|
|
||||||
g_rdpdr_device[*id].local_path = (char *) xmalloc(strlen(pos2) + 1);
|
g_rdpdr_device[*id].local_path = (char *)xmalloc(strlen(pos2) + 1);
|
||||||
strcpy(g_rdpdr_device[*id].local_path, pos2);
|
strcpy(g_rdpdr_device[*id].local_path, pos2);
|
||||||
g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK;
|
g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK;
|
||||||
g_rdpdr_device[*id].pdevice_data = (void *) pdisk_data;
|
g_rdpdr_device[*id].pdevice_data = (void *)pdisk_data;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
(*id)++;
|
(*id)++;
|
||||||
@ -346,9 +339,9 @@ disk_enum_devices(uint32 * id, char *optarg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Opens or creates a file or directory */
|
/* Opens or creates a file or directory */
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode,
|
||||||
disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition,
|
uint32 create_disposition, uint32 flags_and_attributes,
|
||||||
uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle)
|
char *filename, RD_NTHANDLE *phandle)
|
||||||
{
|
{
|
||||||
int handle;
|
int handle;
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
@ -357,8 +350,8 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
struct stat filestat;
|
struct stat filestat;
|
||||||
|
|
||||||
logger(Disk, Debug, "disk_create(device_id=0x%x, accessmask=0x%x, sharemode=0x%x, "
|
logger(Disk, Debug, "disk_create(device_id=0x%x, accessmask=0x%x, sharemode=0x%x, "
|
||||||
"create_disp=%d, flags=0x%x, fname=%s, ...)", device_id, accessmask,
|
"create_disp=%d, flags=0x%x, fname=%s, ...)",
|
||||||
sharemode, create_disposition, flags_and_attributes, filename);
|
device_id, accessmask, sharemode, create_disposition, flags_and_attributes, filename);
|
||||||
handle = 0;
|
handle = 0;
|
||||||
dirp = NULL;
|
dirp = NULL;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
@ -367,7 +360,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
if (filename && *filename && filename[strlen(filename) - 1] == '/')
|
if (filename && *filename && filename[strlen(filename) - 1] == '/')
|
||||||
filename[strlen(filename) - 1] = 0;
|
filename[strlen(filename) - 1] = 0;
|
||||||
|
|
||||||
sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : "");
|
snprintf(path, sizeof(path), "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : "");
|
||||||
|
|
||||||
/* Protect against malicious servers:
|
/* Protect against malicious servers:
|
||||||
somelongpath/.. not allowed
|
somelongpath/.. not allowed
|
||||||
@ -385,31 +378,26 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
switch (create_disposition)
|
switch (create_disposition)
|
||||||
{
|
{
|
||||||
case CREATE_ALWAYS:
|
case CREATE_ALWAYS:
|
||||||
|
|
||||||
/* Delete existing file/link. */
|
/* Delete existing file/link. */
|
||||||
unlink(path);
|
unlink(path);
|
||||||
flags |= O_CREAT;
|
flags |= O_CREAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CREATE_NEW:
|
case CREATE_NEW:
|
||||||
|
|
||||||
/* If the file already exists, then fail. */
|
/* If the file already exists, then fail. */
|
||||||
flags |= O_CREAT | O_EXCL;
|
flags |= O_CREAT | O_EXCL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPEN_ALWAYS:
|
case OPEN_ALWAYS:
|
||||||
|
|
||||||
/* Create if not already exists. */
|
/* Create if not already exists. */
|
||||||
flags |= O_CREAT;
|
flags |= O_CREAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPEN_EXISTING:
|
case OPEN_EXISTING:
|
||||||
|
|
||||||
/* Default behaviour */
|
/* Default behaviour */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRUNCATE_EXISTING:
|
case TRUNCATE_EXISTING:
|
||||||
|
|
||||||
/* If the file does not exist, then fail. */
|
/* If the file does not exist, then fail. */
|
||||||
flags |= O_TRUNC;
|
flags |= O_TRUNC;
|
||||||
break;
|
break;
|
||||||
@ -439,16 +427,13 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
case EACCES:
|
case EACCES:
|
||||||
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
|
|
||||||
return RD_STATUS_NO_SUCH_FILE;
|
return RD_STATUS_NO_SUCH_FILE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(Disk, Error, "disk_create(), opendir() failed: %s",
|
logger(Disk, Error, "disk_create(), opendir() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_NO_SUCH_FILE;
|
return RD_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,9 +441,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (accessmask & GENERIC_ALL || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
|
||||||
if (accessmask & GENERIC_ALL
|
|
||||||
|| (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE))
|
|
||||||
{
|
{
|
||||||
flags |= O_RDWR;
|
flags |= O_RDWR;
|
||||||
}
|
}
|
||||||
@ -477,30 +460,24 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
case EISDIR:
|
case EISDIR:
|
||||||
|
|
||||||
return RD_STATUS_FILE_IS_A_DIRECTORY;
|
return RD_STATUS_FILE_IS_A_DIRECTORY;
|
||||||
|
|
||||||
case EACCES:
|
case EACCES:
|
||||||
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
|
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
|
|
||||||
return RD_STATUS_NO_SUCH_FILE;
|
return RD_STATUS_NO_SUCH_FILE;
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
|
|
||||||
return RD_STATUS_OBJECT_NAME_COLLISION;
|
return RD_STATUS_OBJECT_NAME_COLLISION;
|
||||||
default:
|
default:
|
||||||
logger(Disk, Error, "disk_create(), open() failed: %s",
|
logger(Disk, Error, "disk_create(), open() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_NO_SUCH_FILE;
|
return RD_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all read and writes of files should be non blocking */
|
/* all read and writes of files should be non-blocking */
|
||||||
if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
|
if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1)
|
||||||
logger(Disk, Error, "disk_create(), fcntl() failed: %s", strerror(errno));
|
logger(Disk, Error, "disk_create(), fcntl() failed: %s", strerror(errno));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle >= MAX_OPEN_FILES)
|
if (handle >= MAX_OPEN_FILES)
|
||||||
@ -529,8 +506,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS disk_close(RD_NTHANDLE handle)
|
||||||
disk_close(RD_NTHANDLE handle)
|
|
||||||
{
|
{
|
||||||
struct fileinfo *pfinfo;
|
struct fileinfo *pfinfo;
|
||||||
|
|
||||||
@ -554,8 +530,7 @@ disk_close(RD_NTHANDLE handle)
|
|||||||
if (pfinfo->delete_on_close)
|
if (pfinfo->delete_on_close)
|
||||||
if (rmdir(pfinfo->path) < 0)
|
if (rmdir(pfinfo->path) < 0)
|
||||||
{
|
{
|
||||||
logger(Disk, Error, "disk_close(), rmdir() failed: %s",
|
logger(Disk, Error, "disk_close(), rmdir() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
pfinfo->delete_on_close = False;
|
pfinfo->delete_on_close = False;
|
||||||
@ -570,8 +545,7 @@ disk_close(RD_NTHANDLE handle)
|
|||||||
if (pfinfo->delete_on_close)
|
if (pfinfo->delete_on_close)
|
||||||
if (unlink(pfinfo->path) < 0)
|
if (unlink(pfinfo->path) < 0)
|
||||||
{
|
{
|
||||||
logger(Disk, Error, "disk_close(), unlink() failed: %s",
|
logger(Disk, Error, "disk_close(), unlink() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,8 +555,7 @@ disk_close(RD_NTHANDLE handle)
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS disk_read(RD_NTHANDLE handle, uint8 *data, uint32 length, uint64 offset, uint32 *result)
|
||||||
disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@ -611,8 +584,7 @@ disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32
|
|||||||
/* return STATUS_FILE_IS_A_DIRECTORY; */
|
/* return STATUS_FILE_IS_A_DIRECTORY; */
|
||||||
return RD_STATUS_NOT_IMPLEMENTED;
|
return RD_STATUS_NOT_IMPLEMENTED;
|
||||||
default:
|
default:
|
||||||
logger(Disk, Error, "disk_read(), read failed: %s",
|
logger(Disk, Error, "disk_read(), read failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_INVALID_PARAMETER;
|
return RD_STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,8 +594,7 @@ disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS disk_write(RD_NTHANDLE handle, uint8 *data, uint32 length, uint64 offset, uint32 *result)
|
||||||
disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@ -649,16 +620,14 @@ disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint3
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Btw, all used Flie* structures are described in [MS-FSCC] */
|
/* Btw, all used File* structures are described in [MS-FSCC] */
|
||||||
RD_NTSTATUS
|
RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
||||||
disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|
||||||
{
|
{
|
||||||
uint32 file_attributes, ft_high, ft_low;
|
uint32 file_attributes, ft_high, ft_low;
|
||||||
struct stat filestat;
|
struct stat filestat;
|
||||||
char *path, *filename;
|
char *path, *filename;
|
||||||
|
|
||||||
logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle,
|
logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle, info_class);
|
||||||
info_class);
|
|
||||||
|
|
||||||
path = g_fileinfo[handle].path;
|
path = g_fileinfo[handle].path;
|
||||||
|
|
||||||
@ -692,8 +661,7 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
switch (info_class)
|
switch (info_class)
|
||||||
{
|
{
|
||||||
case FileBasicInformation:
|
case FileBasicInformation:
|
||||||
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
|
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
|
||||||
&ft_low);
|
|
||||||
out_uint32_le(out, ft_low); /* create_access_time */
|
out_uint32_le(out, ft_low); /* create_access_time */
|
||||||
out_uint32_le(out, ft_high);
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
@ -713,7 +681,6 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FileStandardInformation:
|
case FileStandardInformation:
|
||||||
|
|
||||||
out_uint64_le(out, filestat.st_size); /* Allocation size */
|
out_uint64_le(out, filestat.st_size); /* Allocation size */
|
||||||
out_uint64_le(out, filestat.st_size); /* End of file */
|
out_uint64_le(out, filestat.st_size); /* End of file */
|
||||||
|
|
||||||
@ -723,7 +690,6 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FileObjectIdInformation:
|
case FileObjectIdInformation:
|
||||||
|
|
||||||
out_uint32_le(out, file_attributes); /* File Attributes */
|
out_uint32_le(out, file_attributes); /* File Attributes */
|
||||||
out_uint32_le(out, 0); /* Reparse Tag */
|
out_uint32_le(out, 0); /* Reparse Tag */
|
||||||
break;
|
break;
|
||||||
@ -738,8 +704,7 @@ disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 2.2.3.3.9 [MS-RDPEFS] */
|
/* 2.2.3.3.9 [MS-RDPEFS] */
|
||||||
RD_NTSTATUS
|
RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||||
disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
|
||||||
{
|
{
|
||||||
UNUSED(out);
|
UNUSED(out);
|
||||||
uint32 length, file_attributes, ft_high, ft_low;
|
uint32 length, file_attributes, ft_high, ft_low;
|
||||||
@ -751,8 +716,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
struct utimbuf tvs;
|
struct utimbuf tvs;
|
||||||
struct STATFS_T stat_fs;
|
struct STATFS_T stat_fs;
|
||||||
|
|
||||||
logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle,
|
logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle, info_class);
|
||||||
info_class);
|
|
||||||
|
|
||||||
pfinfo = &(g_fileinfo[handle]);
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
g_notify_stamp = True;
|
g_notify_stamp = True;
|
||||||
@ -798,7 +762,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
if (access_time)
|
if (access_time)
|
||||||
tvs.actime = access_time;
|
tvs.actime = access_time;
|
||||||
|
|
||||||
|
|
||||||
if (write_time || change_time)
|
if (write_time || change_time)
|
||||||
mod_time = MIN(write_time, change_time);
|
mod_time = MIN(write_time, change_time);
|
||||||
else
|
else
|
||||||
@ -807,7 +770,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
if (mod_time)
|
if (mod_time)
|
||||||
tvs.modtime = mod_time;
|
tvs.modtime = mod_time;
|
||||||
|
|
||||||
|
|
||||||
if (access_time || write_time || change_time)
|
if (access_time || write_time || change_time)
|
||||||
{
|
{
|
||||||
logger(Disk, Debug,
|
logger(Disk, Debug,
|
||||||
@ -837,7 +799,6 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FileRenameInformation:
|
case FileRenameInformation:
|
||||||
|
|
||||||
in_uint8s(in, 4); /* Handle of root dir? */
|
in_uint8s(in, 4); /* Handle of root dir? */
|
||||||
in_uint8s(in, 0x1a); /* unknown */
|
in_uint8s(in, 0x1a); /* unknown */
|
||||||
in_uint32_le(in, length);
|
in_uint32_le(in, length);
|
||||||
@ -851,15 +812,13 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
|
|
||||||
convert_to_unix_filename(newname);
|
convert_to_unix_filename(newname);
|
||||||
|
|
||||||
sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path,
|
snprintf(fullpath, sizeof(fullpath), "%s%s", g_rdpdr_device[pfinfo->device_id].local_path, newname);
|
||||||
newname);
|
|
||||||
|
|
||||||
free(newname);
|
free(newname);
|
||||||
|
|
||||||
if (rename(pfinfo->path, fullpath) != 0)
|
if (rename(pfinfo->path, fullpath) != 0)
|
||||||
{
|
{
|
||||||
logger(Disk, Error, "disk_set_information(), rename() failed: %s",
|
logger(Disk, Error, "disk_set_information(), rename() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -879,15 +838,18 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
Length is always set to zero.
|
Length is always set to zero.
|
||||||
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
|
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
|
||||||
- 2.2.3.3.9 Server Drive Set Information Request
|
- 2.2.3.3.9 Server Drive Set Information Request
|
||||||
|
- 2.2.3.4.9 Client Drive Set Information Response
|
||||||
|
[MS-FSCC] http://msdn.microsoft.com/en-us/library/cc231987%28PROT.10%29.aspx
|
||||||
|
- 2.4.11 FileDispositionInformation
|
||||||
|
[FSBO] http://msdn.microsoft.com/en-us/library/cc246487%28PROT.13%29.aspx
|
||||||
|
- 4.3.2 Set Delete-on-close using FileDispositionInformation Information Class (IRP_MJ_SET_INFORMATION)
|
||||||
*/
|
*/
|
||||||
in_uint8s(in, 4); /* length of SetBuffer */
|
in_uint8s(in, 4); /* length of SetBuffer */
|
||||||
in_uint8s(in, 24); /* padding */
|
in_uint8s(in, 24); /* padding */
|
||||||
|
|
||||||
|
if ((pfinfo->accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
|
||||||
if ((pfinfo->accessmask &
|
|
||||||
(FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
|
|
||||||
{
|
{
|
||||||
/* if file exists in directory , necessary to return RD_STATUS_DIRECTORY_NOT_EMPTY with win2008
|
/* if file exists in directory, necessary to return RD_STATUS_DIRECTORY_NOT_EMPTY with win2008
|
||||||
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
|
[MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx
|
||||||
- 2.2.3.3.9 Server Drive Set Information Request
|
- 2.2.3.3.9 Server Drive Set Information Request
|
||||||
- 2.2.3.4.9 Client Drive Set Information Response
|
- 2.2.3.4.9 Client Drive Set Information Response
|
||||||
@ -903,8 +865,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
|
|
||||||
while ((dir = readdir(dp)) != NULL)
|
while ((dir = readdir(dp)) != NULL)
|
||||||
{
|
{
|
||||||
if (strcmp(dir->d_name, ".") != 0
|
if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
|
||||||
&& strcmp(dir->d_name, "..") != 0)
|
|
||||||
{
|
{
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
return RD_STATUS_DIRECTORY_NOT_EMPTY;
|
return RD_STATUS_DIRECTORY_NOT_EMPTY;
|
||||||
@ -949,8 +910,7 @@ disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM ou
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_NTSTATUS
|
RD_NTSTATUS disk_check_notify(RD_NTHANDLE handle)
|
||||||
disk_check_notify(RD_NTHANDLE handle)
|
|
||||||
{
|
{
|
||||||
struct fileinfo *pfinfo;
|
struct fileinfo *pfinfo;
|
||||||
RD_NTSTATUS status = RD_STATUS_PENDING;
|
RD_NTSTATUS status = RD_STATUS_PENDING;
|
||||||
@ -962,8 +922,6 @@ disk_check_notify(RD_NTHANDLE handle)
|
|||||||
if (!pfinfo->pdir)
|
if (!pfinfo->pdir)
|
||||||
return RD_STATUS_INVALID_DEVICE_REQUEST;
|
return RD_STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
status = NotifyInfo(handle, pfinfo->info_class, ¬ify);
|
status = NotifyInfo(handle, pfinfo->info_class, ¬ify);
|
||||||
|
|
||||||
if (status != RD_STATUS_PENDING)
|
if (status != RD_STATUS_PENDING)
|
||||||
@ -977,12 +935,9 @@ disk_check_notify(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_NTSTATUS
|
RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
|
||||||
disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
|
|
||||||
{
|
{
|
||||||
struct fileinfo *pfinfo;
|
struct fileinfo *pfinfo;
|
||||||
RD_NTSTATUS ret = RD_STATUS_PENDING;
|
RD_NTSTATUS ret = RD_STATUS_PENDING;
|
||||||
@ -1002,13 +957,10 @@ disk_create_notify(RD_NTHANDLE handle, uint32 info_class)
|
|||||||
|
|
||||||
/* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
|
/* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY *p)
|
||||||
NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
|
|
||||||
{
|
{
|
||||||
UNUSED(info_class);
|
UNUSED(info_class);
|
||||||
struct fileinfo *pfinfo;
|
struct fileinfo *pfinfo;
|
||||||
@ -1028,7 +980,6 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
|
|||||||
p->num_entries = 0;
|
p->num_entries = 0;
|
||||||
p->total_time = 0;
|
p->total_time = 0;
|
||||||
|
|
||||||
|
|
||||||
dpr = opendir(pfinfo->path);
|
dpr = opendir(pfinfo->path);
|
||||||
if (!dpr)
|
if (!dpr)
|
||||||
{
|
{
|
||||||
@ -1036,13 +987,12 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
|
|||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while ((dp = readdir(dpr)))
|
while ((dp = readdir(dpr)))
|
||||||
{
|
{
|
||||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
p->num_entries++;
|
p->num_entries++;
|
||||||
fullname = (char *) xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2);
|
fullname = (char *)xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2);
|
||||||
sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name);
|
sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name);
|
||||||
|
|
||||||
if (!stat(fullname, &filestat))
|
if (!stat(fullname, &filestat))
|
||||||
@ -1057,10 +1007,8 @@ NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p)
|
|||||||
return RD_STATUS_PENDING;
|
return RD_STATUS_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FsInfoType *
|
static FsInfoType *FsVolumeInfo(char *fpath)
|
||||||
FsVolumeInfo(char *fpath)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
static FsInfoType info;
|
static FsInfoType info;
|
||||||
#ifdef USE_SETMNTENT
|
#ifdef USE_SETMNTENT
|
||||||
FILE *fdfs;
|
FILE *fdfs;
|
||||||
@ -1091,20 +1039,18 @@ FsVolumeInfo(char *fpath)
|
|||||||
unsigned char buf[512];
|
unsigned char buf[512];
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
if (strstr(e->mnt_opts, "vfat"))
|
if (strstr(e->mnt_opts, "vfat"))
|
||||||
/*FAT*/
|
|
||||||
{
|
{
|
||||||
|
/*FAT*/
|
||||||
strcpy(info.type, "vfat");
|
strcpy(info.type, "vfat");
|
||||||
read(fd, buf, sizeof(buf));
|
read(fd, buf, sizeof(buf));
|
||||||
info.serial =
|
info.serial = (buf[42] << 24) + (buf[41] << 16) + (buf[40] << 8) + buf[39];
|
||||||
(buf[42] << 24) + (buf[41] << 16) +
|
strncpy(info.label, (char *)buf + 43, 10);
|
||||||
(buf[40] << 8) + buf[39];
|
|
||||||
strncpy(info.label, (char *) buf + 43, 10);
|
|
||||||
info.label[10] = '\0';
|
info.label[10] = '\0';
|
||||||
}
|
}
|
||||||
else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */
|
else if (lseek(fd, 32767, SEEK_SET) >= 0)
|
||||||
{
|
{ /* ISO9660 */
|
||||||
read(fd, buf, sizeof(buf));
|
read(fd, buf, sizeof(buf));
|
||||||
strncpy(info.label, (char *) buf + 41, 32);
|
strncpy(info.label, (char *)buf + 41, 32);
|
||||||
info.label[32] = '\0';
|
info.label[32] = '\0';
|
||||||
/* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */
|
/* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */
|
||||||
}
|
}
|
||||||
@ -1124,24 +1070,20 @@ FsVolumeInfo(char *fpath)
|
|||||||
return &info;
|
return &info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RD_NTSTATUS disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
||||||
RD_NTSTATUS
|
|
||||||
disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|
||||||
{
|
{
|
||||||
struct STATFS_T stat_fs;
|
struct STATFS_T stat_fs;
|
||||||
struct fileinfo *pfinfo;
|
struct fileinfo *pfinfo;
|
||||||
FsInfoType *fsinfo;
|
FsInfoType *fsinfo;
|
||||||
STREAM stmp;
|
STREAM stmp;
|
||||||
|
|
||||||
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle,
|
logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle, info_class);
|
||||||
info_class);
|
|
||||||
|
|
||||||
pfinfo = &(g_fileinfo[handle]);
|
pfinfo = &(g_fileinfo[handle]);
|
||||||
|
|
||||||
if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
|
if (STATFS_FN(pfinfo->path, &stat_fs) != 0)
|
||||||
{
|
{
|
||||||
logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s",
|
logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
return RD_STATUS_ACCESS_DENIED;
|
return RD_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,7 +1106,6 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FileFsSizeInformation:
|
case FileFsSizeInformation:
|
||||||
|
|
||||||
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
|
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
|
||||||
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
|
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
|
||||||
out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
|
out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */
|
||||||
@ -1172,7 +1113,6 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FileFsFullSizeInformation:
|
case FileFsFullSizeInformation:
|
||||||
|
|
||||||
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
|
out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */
|
||||||
out_uint64_le(out, stat_fs.f_bavail); /* Caller allocation units */
|
out_uint64_le(out, stat_fs.f_bavail); /* Caller allocation units */
|
||||||
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
|
out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */
|
||||||
@ -1208,8 +1148,7 @@ disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out)
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_NTSTATUS
|
RD_NTSTATUS disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
|
||||||
disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out)
|
|
||||||
{
|
{
|
||||||
uint32 file_attributes, ft_low, ft_high;
|
uint32 file_attributes, ft_low, ft_high;
|
||||||
char *dirname, fullpath[PATH_MAX];
|
char *dirname, fullpath[PATH_MAX];
|
||||||
@ -1233,7 +1172,6 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
case FileDirectoryInformation:
|
case FileDirectoryInformation:
|
||||||
case FileFullDirectoryInformation:
|
case FileFullDirectoryInformation:
|
||||||
case FileNamesInformation:
|
case FileNamesInformation:
|
||||||
|
|
||||||
/* If a search pattern is received, remember this pattern, and restart search */
|
/* If a search pattern is received, remember this pattern, and restart search */
|
||||||
if (pattern != NULL && pattern[0] != 0)
|
if (pattern != NULL && pattern[0] != 0)
|
||||||
{
|
{
|
||||||
@ -1250,7 +1188,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
return RD_STATUS_NO_MORE_FILES;
|
return RD_STATUS_NO_MORE_FILES;
|
||||||
|
|
||||||
/* Get information for directory entry */
|
/* Get information for directory entry */
|
||||||
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
|
snprintf(fullpath, sizeof(fullpath), "%s/%s", dirname, pdirent->d_name);
|
||||||
|
|
||||||
if (stat(fullpath, &filestat))
|
if (stat(fullpath, &filestat))
|
||||||
{
|
{
|
||||||
@ -1302,9 +1240,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
switch (info_class)
|
switch (info_class)
|
||||||
{
|
{
|
||||||
case FileBothDirectoryInformation:
|
case FileBothDirectoryInformation:
|
||||||
|
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
|
||||||
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
|
|
||||||
&ft_low);
|
|
||||||
out_uint32_le(out, ft_low); /* create time */
|
out_uint32_le(out, ft_low); /* create time */
|
||||||
out_uint32_le(out, ft_high);
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
@ -1330,11 +1266,8 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
out_stream(out, stmp); /* dir entry name string */
|
out_stream(out, stmp); /* dir entry name string */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case FileDirectoryInformation:
|
case FileDirectoryInformation:
|
||||||
|
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
|
||||||
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
|
|
||||||
&ft_low);
|
|
||||||
out_uint32_le(out, ft_low); /* create time */
|
out_uint32_le(out, ft_low); /* create time */
|
||||||
out_uint32_le(out, ft_high);
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
@ -1357,11 +1290,8 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
out_stream(out, stmp); /* dir entry name */
|
out_stream(out, stmp); /* dir entry name */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case FileFullDirectoryInformation:
|
case FileFullDirectoryInformation:
|
||||||
|
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low);
|
||||||
seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high,
|
|
||||||
&ft_low);
|
|
||||||
out_uint32_le(out, ft_low); /* create time */
|
out_uint32_le(out, ft_low); /* create time */
|
||||||
out_uint32_le(out, ft_high);
|
out_uint32_le(out, ft_high);
|
||||||
|
|
||||||
@ -1385,14 +1315,11 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
out_stream(out, stmp); /* dir entry name */
|
out_stream(out, stmp); /* dir entry name */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case FileNamesInformation:
|
case FileNamesInformation:
|
||||||
|
|
||||||
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
|
out_uint32_le(out, s_length(stmp)); /* dir entry name string length */
|
||||||
out_stream(out, stmp); /* dir entry name */
|
out_stream(out, stmp); /* dir entry name */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(Disk, Warning,
|
logger(Disk, Warning,
|
||||||
"disk_query_directory(), unhandled directory info class 0x%x",
|
"disk_query_directory(), unhandled directory info class 0x%x",
|
||||||
@ -1406,10 +1333,7 @@ disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREA
|
|||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RD_NTSTATUS disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||||
|
|
||||||
static RD_NTSTATUS
|
|
||||||
disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
|
||||||
{
|
{
|
||||||
UNUSED(in);
|
UNUSED(in);
|
||||||
UNUSED(out);
|
UNUSED(out);
|
||||||
|
44
disk.h
44
disk.h
@ -18,13 +18,18 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef DISK_REDIRECTION_DEFINITIONS_H
|
||||||
|
#define DISK_REDIRECTION_DEFINITIONS_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// File attribute constants
|
||||||
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
||||||
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
||||||
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
||||||
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||||
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
|
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
|
||||||
#define FILE_ATTRIBUTE_DEVICE 0x00000040
|
#define FILE_ATTRIBUTE_DEVICE 0x00000040
|
||||||
#define FILE_ATTRIBUTE_UNKNOWNXXX0 0x00000060 /* ??? ACTION i.e. 0x860 == compress this file ? */
|
|
||||||
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||||
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
|
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
|
||||||
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
|
#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
|
||||||
@ -34,10 +39,11 @@
|
|||||||
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
|
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
|
||||||
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
|
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
|
||||||
|
|
||||||
|
// File flag constants
|
||||||
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
|
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
|
||||||
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
|
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
|
||||||
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
|
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
|
||||||
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 /* sometimes used to create a directory */
|
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
|
||||||
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
|
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
|
||||||
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
|
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
|
||||||
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
|
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
|
||||||
@ -45,13 +51,16 @@
|
|||||||
#define FILE_FLAG_OVERLAPPED 0x40000000
|
#define FILE_FLAG_OVERLAPPED 0x40000000
|
||||||
#define FILE_FLAG_WRITE_THROUGH 0x80000000
|
#define FILE_FLAG_WRITE_THROUGH 0x80000000
|
||||||
|
|
||||||
#define FILE_SHARE_READ 0x01
|
// File share mode constants
|
||||||
#define FILE_SHARE_WRITE 0x02
|
#define FILE_SHARE_READ 0x00000001
|
||||||
#define FILE_SHARE_DELETE 0x04
|
#define FILE_SHARE_WRITE 0x00000002
|
||||||
|
#define FILE_SHARE_DELETE 0x00000004
|
||||||
|
|
||||||
#define FILE_BASIC_INFORMATION 0x04
|
// File information constants
|
||||||
#define FILE_STANDARD_INFORMATION 0x05
|
#define FILE_BASIC_INFORMATION 0x00000004
|
||||||
|
#define FILE_STANDARD_INFORMATION 0x00000005
|
||||||
|
|
||||||
|
// File system attribute constants
|
||||||
#define FS_CASE_SENSITIVE 0x00000001
|
#define FS_CASE_SENSITIVE 0x00000001
|
||||||
#define FS_CASE_IS_PRESERVED 0x00000002
|
#define FS_CASE_IS_PRESERVED 0x00000002
|
||||||
#define FS_UNICODE_STORED_ON_DISK 0x00000004
|
#define FS_UNICODE_STORED_ON_DISK 0x00000004
|
||||||
@ -60,25 +69,28 @@
|
|||||||
#define FS_VOLUME_QUOTAS 0x00000020
|
#define FS_VOLUME_QUOTAS 0x00000020
|
||||||
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
|
#define FS_SUPPORTS_SPARSE_FILES 0x00000040
|
||||||
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
|
#define FS_SUPPORTS_REPARSE_POINTS 0x00000080
|
||||||
#define FS_SUPPORTS_REMOTE_STORAGE 0X00000100
|
#define FS_SUPPORTS_REMOTE_STORAGE 0x00000100
|
||||||
#define FS_VOL_IS_COMPRESSED 0x00008000
|
#define FS_VOL_IS_COMPRESSED 0x00008000
|
||||||
#define FILE_READ_ONLY_VOLUME 0x00080000
|
#define FILE_READ_ONLY_VOLUME 0x00080000
|
||||||
|
|
||||||
#define OPEN_EXISTING 1
|
// File creation disposition constants
|
||||||
#define CREATE_NEW 2
|
#define OPEN_EXISTING 3
|
||||||
#define OPEN_ALWAYS 3
|
#define CREATE_NEW 1
|
||||||
#define TRUNCATE_EXISTING 4
|
#define OPEN_ALWAYS 4
|
||||||
#define CREATE_ALWAYS 5
|
#define TRUNCATE_EXISTING 5
|
||||||
|
#define CREATE_ALWAYS 2
|
||||||
|
|
||||||
|
// Generic access rights constants
|
||||||
#define GENERIC_READ 0x80000000
|
#define GENERIC_READ 0x80000000
|
||||||
#define GENERIC_WRITE 0x40000000
|
#define GENERIC_WRITE 0x40000000
|
||||||
#define GENERIC_EXECUTE 0x20000000
|
#define GENERIC_EXECUTE 0x20000000
|
||||||
#define GENERIC_ALL 0x10000000
|
#define GENERIC_ALL 0x10000000
|
||||||
|
|
||||||
|
// Error codes
|
||||||
#define ERROR_FILE_NOT_FOUND 2L
|
#define ERROR_FILE_NOT_FOUND 2L
|
||||||
#define ERROR_ALREADY_EXISTS 183L
|
#define ERROR_ALREADY_EXISTS 183L
|
||||||
|
|
||||||
#define MAX_OPEN_FILES 0x100
|
#define MAX_OPEN_FILES 256
|
||||||
|
|
||||||
typedef enum _FILE_INFORMATION_CLASS
|
typedef enum _FILE_INFORMATION_CLASS
|
||||||
{
|
{
|
||||||
@ -125,7 +137,7 @@ typedef enum _FILE_INFORMATION_CLASS
|
|||||||
FileMaximumInformation
|
FileMaximumInformation
|
||||||
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
typedef enum _FSINFOCLASS
|
typedef enum _FS_INFORMATION_CLASS
|
||||||
{
|
{
|
||||||
FileFsVolumeInformation = 1,
|
FileFsVolumeInformation = 1,
|
||||||
FileFsLabelInformation,
|
FileFsLabelInformation,
|
||||||
@ -138,3 +150,5 @@ typedef enum _FSINFOCLASS
|
|||||||
FileFsDriverPathInformation,
|
FileFsDriverPathInformation,
|
||||||
FileFsMaximumInformation
|
FileFsMaximumInformation
|
||||||
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
|
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
#endif // DISK_REDIRECTION_DEFINITIONS_H
|
||||||
|
340
dvc.c
340
dvc.c
@ -1,4 +1,5 @@
|
|||||||
/* -*- c-basic-offset: 8 -*-
|
/*
|
||||||
|
-*- c-basic-offset: 8 -*-
|
||||||
rdesktop: A Remote Desktop Protocol client.
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
Dynamic Channel Virtual Channel Extension.
|
Dynamic Channel Virtual Channel Extension.
|
||||||
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
|
Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB
|
||||||
@ -19,9 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define MAX_DVC_CHANNELS 20
|
#define MAX_DVC_CHANNELS 20
|
||||||
#define INVALID_CHANNEL ((uint32)-1)
|
#define INVALID_CHANNEL ((uint32_t)-1)
|
||||||
|
|
||||||
#define DYNVC_CREATE_REQ 0x01
|
#define DYNVC_CREATE_REQ 0x01
|
||||||
#define DYNVC_DATA_FIRST 0x02
|
#define DYNVC_DATA_FIRST 0x02
|
||||||
@ -33,183 +37,117 @@
|
|||||||
#define DYNVC_SOFT_SYNC_REQUEST 0x08
|
#define DYNVC_SOFT_SYNC_REQUEST 0x08
|
||||||
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
|
#define DYNVC_SOFT_SYNC_RESPONSE 0x09
|
||||||
|
|
||||||
typedef union dvc_hdr_t
|
typedef union {
|
||||||
{
|
uint8_t data;
|
||||||
uint8 data;
|
struct {
|
||||||
struct
|
uint8_t cbid : 2;
|
||||||
{
|
uint8_t sp : 2;
|
||||||
uint8 cbid:2;
|
uint8_t cmd : 4;
|
||||||
uint8 sp:2;
|
|
||||||
uint8 cmd:4;
|
|
||||||
} hdr;
|
} hdr;
|
||||||
} dvc_hdr_t;
|
} dvc_hdr_t;
|
||||||
|
|
||||||
typedef struct dvc_channel_t
|
typedef struct {
|
||||||
{
|
uint32_t hash;
|
||||||
uint32 hash;
|
uint32_t channel_id;
|
||||||
uint32 channel_id;
|
|
||||||
dvc_channel_process_fn handler;
|
dvc_channel_process_fn handler;
|
||||||
} dvc_channel_t;
|
} dvc_channel_t;
|
||||||
|
|
||||||
static VCHANNEL *dvc_channel;
|
static VCHANNEL *dvc_channel;
|
||||||
static dvc_channel_t channels[MAX_DVC_CHANNELS];
|
static dvc_channel_t channels[MAX_DVC_CHANNELS];
|
||||||
|
|
||||||
static uint32 dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
|
static uint32_t dvc_in_channelid(STREAM s, dvc_hdr_t hdr);
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_exists(const char *name) {
|
||||||
dvc_channels_exists(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
|
||||||
uint32 hash;
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
if (channels[i].hash == hash)
|
||||||
return True;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const dvc_channel_t *
|
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;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].channel_id == id)
|
|
||||||
{
|
|
||||||
return &channels[i];
|
return &channels[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32
|
static uint32_t dvc_channels_get_id(const char *name) {
|
||||||
dvc_channels_get_id(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
return channels[i].channel_id;
|
return channels[i].channel_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_CHANNEL;
|
return INVALID_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_remove_by_id(uint32_t channelid) {
|
||||||
dvc_channels_remove_by_id(uint32 channelid)
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
{
|
if (channels[i].channel_id == channelid) {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].channel_id == channelid)
|
|
||||||
{
|
|
||||||
memset(&channels[i], 0, sizeof(dvc_channel_t));
|
memset(&channels[i], 0, sizeof(dvc_channel_t));
|
||||||
return True;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return False;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
static bool dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32_t channel_id) {
|
||||||
dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id)
|
if (dvc_channels_exists(name)) {
|
||||||
{
|
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", name);
|
||||||
int i;
|
return false;
|
||||||
uint32 hash;
|
|
||||||
|
|
||||||
if (dvc_channels_exists(name) == True)
|
|
||||||
{
|
|
||||||
logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists",
|
|
||||||
name);
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
{
|
if (channels[i].hash == 0) {
|
||||||
if (channels[i].hash == 0)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
channels[i].hash = hash;
|
channels[i].hash = hash;
|
||||||
channels[i].handler = handler;
|
channels[i].handler = handler;
|
||||||
channels[i].channel_id = channel_id;
|
channels[i].channel_id = channel_id;
|
||||||
logger(Core, Debug,
|
logger(Core, Debug, "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
|
||||||
"dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p",
|
|
||||||
hash, channel_id, name, handler);
|
hash, channel_id, name, handler);
|
||||||
return True;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(Core, Warning,
|
logger(Core, Warning, "dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
|
||||||
"dvc_channels_add(), Failed to add channel, maximum number of channels are being used");
|
return false;
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int dvc_channels_set_id(const char *name, uint32_t channel_id) {
|
||||||
dvc_channels_set_id(const char *name, uint32 channel_id)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d", name, channel_id);
|
||||||
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d",
|
|
||||||
name, channel_id);
|
|
||||||
channels[i].channel_id = channel_id;
|
channels[i].channel_id = channel_id;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_channels_is_available(const char *name) {
|
||||||
dvc_channels_is_available(const char *name)
|
uint32_t hash = utils_djb2_hash(name);
|
||||||
{
|
for (int i = 0; i < MAX_DVC_CHANNELS; i++) {
|
||||||
int i;
|
if (channels[i].hash == hash) {
|
||||||
uint32 hash;
|
|
||||||
hash = utils_djb2_hash(name);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].hash == hash)
|
|
||||||
{
|
|
||||||
return (channels[i].channel_id != INVALID_CHANNEL);
|
return (channels[i].channel_id != INVALID_CHANNEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_channels_register(const char *name, dvc_channel_process_fn handler) {
|
||||||
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
|
|
||||||
{
|
|
||||||
return dvc_channels_add(name, handler, INVALID_CHANNEL);
|
return dvc_channels_add(name, handler, INVALID_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static STREAM dvc_init_packet(dvc_hdr_t hdr, uint32_t channelid, size_t length) {
|
||||||
static STREAM
|
|
||||||
dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
|
|
||||||
{
|
|
||||||
STREAM s;
|
STREAM s;
|
||||||
|
length += 1; // add 1 byte hdr
|
||||||
|
|
||||||
length += 1; /* add 1 byte hdr */
|
if (channelid != INVALID_CHANNEL) {
|
||||||
|
|
||||||
if (channelid != INVALID_CHANNEL)
|
|
||||||
{
|
|
||||||
if (hdr.hdr.cbid == 0)
|
if (hdr.hdr.cbid == 0)
|
||||||
length += 1;
|
length += 1;
|
||||||
else if (hdr.hdr.cbid == 1)
|
else if (hdr.hdr.cbid == 1)
|
||||||
@ -219,20 +157,14 @@ dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s = channel_init(dvc_channel, length);
|
s = channel_init(dvc_channel, length);
|
||||||
out_uint8(s, hdr.data); /* DVC header */
|
out_uint8(s, hdr.data); // DVC header
|
||||||
|
|
||||||
if (channelid != INVALID_CHANNEL)
|
if (channelid != INVALID_CHANNEL) {
|
||||||
{
|
if (hdr.hdr.cbid == 0) {
|
||||||
if (hdr.hdr.cbid == 0)
|
|
||||||
{
|
|
||||||
out_uint8(s, channelid);
|
out_uint8(s, channelid);
|
||||||
}
|
} else if (hdr.hdr.cbid == 1) {
|
||||||
else if (hdr.hdr.cbid == 1)
|
|
||||||
{
|
|
||||||
out_uint16_le(s, channelid);
|
out_uint16_le(s, channelid);
|
||||||
}
|
} else if (hdr.hdr.cbid == 2) {
|
||||||
else if (hdr.hdr.cbid == 2)
|
|
||||||
{
|
|
||||||
out_uint32_le(s, channelid);
|
out_uint32_le(s, channelid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,127 +172,92 @@ dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void dvc_send(const char *name, STREAM s) {
|
||||||
dvc_send(const char *name, STREAM s)
|
|
||||||
{
|
|
||||||
STREAM ls;
|
STREAM ls;
|
||||||
dvc_hdr_t hdr;
|
dvc_hdr_t hdr;
|
||||||
uint32 channel_id;
|
uint32_t channel_id = dvc_channels_get_id(name);
|
||||||
|
|
||||||
channel_id = dvc_channels_get_id(name);
|
if (channel_id == INVALID_CHANNEL) {
|
||||||
if (channel_id == INVALID_CHANNEL)
|
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'", name);
|
||||||
{
|
|
||||||
logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'",
|
|
||||||
name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: we assume length is less than 1600 */
|
// FIXME: we assume length is less than 1600
|
||||||
|
|
||||||
hdr.hdr.cmd = DYNVC_DATA;
|
hdr.hdr.cmd = DYNVC_DATA;
|
||||||
hdr.hdr.cbid = 2;
|
hdr.hdr.cbid = 2;
|
||||||
hdr.hdr.sp = 0;
|
hdr.hdr.sp = 0;
|
||||||
|
|
||||||
ls = dvc_init_packet(hdr, channel_id, s_length(s));
|
ls = dvc_init_packet(hdr, channel_id, s_length(s));
|
||||||
|
|
||||||
out_stream(ls, s);
|
out_stream(ls, s);
|
||||||
|
|
||||||
s_mark_end(ls);
|
s_mark_end(ls);
|
||||||
|
|
||||||
channel_send(ls, dvc_channel);
|
channel_send(ls, dvc_channel);
|
||||||
s_free(ls);
|
s_free(ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dvc_send_capabilities_response() {
|
||||||
static void
|
|
||||||
dvc_send_capabilities_response()
|
|
||||||
{
|
|
||||||
STREAM s;
|
STREAM s;
|
||||||
dvc_hdr_t hdr;
|
dvc_hdr_t hdr;
|
||||||
uint16 supportedversion = 0x01;
|
uint16_t supportedversion = 0x01;
|
||||||
|
|
||||||
hdr.hdr.cbid = 0x00;
|
hdr.hdr.cbid = 0x00;
|
||||||
hdr.hdr.sp = 0x00;
|
hdr.hdr.sp = 0x00;
|
||||||
hdr.hdr.cmd = DYNVC_CAPABILITIES;
|
hdr.hdr.cmd = DYNVC_CAPABILITIES;
|
||||||
|
|
||||||
logger(Protocol, Debug,
|
logger(Protocol, Debug, "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
|
||||||
"dvc_send_capabilities_response(), offering support for dvc %d", supportedversion);
|
|
||||||
|
|
||||||
s = dvc_init_packet(hdr, -1, 3);
|
|
||||||
out_uint8(s, 0x00); /* pad */
|
|
||||||
out_uint16_le(s, supportedversion); /* version */
|
|
||||||
|
|
||||||
|
s = dvc_init_packet(hdr, (uint32_t)-1, 3);
|
||||||
|
out_uint8(s, 0x00); // pad
|
||||||
|
out_uint16_le(s, supportedversion); // version
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
|
|
||||||
channel_send(s, dvc_channel);
|
channel_send(s, dvc_channel);
|
||||||
s_free(s);
|
s_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_caps_pdu(STREAM s) {
|
||||||
dvc_process_caps_pdu(STREAM s)
|
uint16_t version;
|
||||||
{
|
|
||||||
uint16 version;
|
|
||||||
|
|
||||||
/* VERSION1 */
|
in_uint8s(s, 1); // pad
|
||||||
in_uint8s(s, 1); /* pad */
|
in_uint16_le(s, version); // version
|
||||||
in_uint16_le(s, version); /* version */
|
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
|
logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version);
|
||||||
|
|
||||||
dvc_send_capabilities_response();
|
dvc_send_capabilities_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_send_create_response(bool success, dvc_hdr_t hdr, uint32_t channelid) {
|
||||||
dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid)
|
|
||||||
{
|
|
||||||
STREAM s;
|
STREAM s;
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
|
logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d",
|
||||||
(success ? "granted" : "denied"), channelid);
|
(success ? "granted" : "denied"), channelid);
|
||||||
s = dvc_init_packet(hdr, channelid, 4);
|
s = dvc_init_packet(hdr, channelid, 4);
|
||||||
out_uint32_le(s, success ? 0 : -1);
|
out_uint32_le(s, success ? 0 : (uint32_t)-1);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
|
|
||||||
channel_send(s, dvc_channel);
|
channel_send(s, dvc_channel);
|
||||||
s_free(s);
|
s_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr)
|
|
||||||
{
|
|
||||||
char name[512];
|
char name[512];
|
||||||
uint32 channelid;
|
uint32_t channelid;
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
channelid = dvc_in_channelid(s, hdr);
|
||||||
|
|
||||||
in_ansi_string(s, name, sizeof(name));
|
in_ansi_string(s, name, sizeof(name));
|
||||||
|
|
||||||
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'",
|
logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", channelid, name);
|
||||||
channelid, name);
|
|
||||||
|
|
||||||
if (dvc_channels_exists(name))
|
if (dvc_channels_exists(name)) {
|
||||||
{
|
|
||||||
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
|
logger(Core, Verbose, "Established dynamic virtual channel '%s'", name);
|
||||||
|
|
||||||
dvc_channels_set_id(name, channelid);
|
dvc_channels_set_id(name, channelid);
|
||||||
dvc_send_create_response(True, hdr, channelid);
|
dvc_send_create_response(true, hdr, channelid);
|
||||||
|
} else {
|
||||||
|
dvc_send_create_response(false, hdr, channelid);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
dvc_send_create_response(False, hdr, channelid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32
|
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) {
|
||||||
|
|
||||||
switch (hdr.hdr.cbid)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
in_uint8(s, id);
|
in_uint8(s, id);
|
||||||
break;
|
break;
|
||||||
@ -374,69 +271,49 @@ dvc_in_channelid(STREAM s, dvc_hdr_t hdr)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr)
|
|
||||||
{
|
|
||||||
const dvc_channel_t *ch;
|
const dvc_channel_t *ch;
|
||||||
uint32 channelid;
|
uint32_t channelid = dvc_in_channelid(s, hdr);
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
|
||||||
ch = dvc_channels_get_by_id(channelid);
|
ch = dvc_channels_get_by_id(channelid);
|
||||||
if (ch == NULL)
|
if (ch == NULL) {
|
||||||
{
|
logger(Protocol, Warning, "dvc_process_data(), Received data on unregistered channel %d", channelid);
|
||||||
logger(Protocol, Warning,
|
|
||||||
"dvc_process_data(), Received data on unregistered channel %d", channelid);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dispatch packet to channel handler */
|
// Dispatch packet to channel handler
|
||||||
ch->handler(s);
|
ch->handler(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) {
|
||||||
dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr)
|
uint32_t channelid = dvc_in_channelid(s, hdr);
|
||||||
{
|
|
||||||
uint32 channelid;
|
|
||||||
|
|
||||||
channelid = dvc_in_channelid(s, hdr);
|
|
||||||
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
|
logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid);
|
||||||
|
|
||||||
if (!dvc_channels_remove_by_id(channelid))
|
if (!dvc_channels_remove_by_id(channelid)) {
|
||||||
{
|
logger(Protocol, Warning, "dvc_process_close_pdu(), Received close request for unregistered channel %d", channelid);
|
||||||
logger(Protocol, Warning,
|
|
||||||
"dvc_process_close_pdu(), Received close request for unregistered channel %d",
|
|
||||||
channelid);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dvc_process_pdu(STREAM s) {
|
||||||
static void
|
|
||||||
dvc_process_pdu(STREAM s)
|
|
||||||
{
|
|
||||||
dvc_hdr_t hdr;
|
dvc_hdr_t hdr;
|
||||||
|
|
||||||
in_uint8(s, hdr.data);
|
in_uint8(s, hdr.data);
|
||||||
|
|
||||||
switch (hdr.hdr.cmd)
|
switch (hdr.hdr.cmd) {
|
||||||
{
|
|
||||||
case DYNVC_CAPABILITIES:
|
case DYNVC_CAPABILITIES:
|
||||||
dvc_process_caps_pdu(s);
|
dvc_process_caps_pdu(s);
|
||||||
break;
|
break;
|
||||||
case DYNVC_CREATE_REQ:
|
case DYNVC_CREATE_REQ:
|
||||||
dvc_process_create_pdu(s, hdr);
|
dvc_process_create_pdu(s, hdr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DYNVC_DATA:
|
case DYNVC_DATA:
|
||||||
dvc_process_data_pdu(s, hdr);
|
dvc_process_data_pdu(s, hdr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DYNVC_CLOSE:
|
case DYNVC_CLOSE:
|
||||||
dvc_process_close_pdu(s, hdr);
|
dvc_process_close_pdu(s, hdr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0 /* Unimplemented */
|
#if 0 // Unimplemented
|
||||||
|
|
||||||
case DYNVC_DATA_FIRST:
|
case DYNVC_DATA_FIRST:
|
||||||
break;
|
break;
|
||||||
case DYNVC_DATA_FIRST_COMPRESSED:
|
case DYNVC_DATA_FIRST_COMPRESSED:
|
||||||
@ -447,23 +324,16 @@ dvc_process_pdu(STREAM s)
|
|||||||
break;
|
break;
|
||||||
case DYNVC_SOFT_SYNC_RESPONSE:
|
case DYNVC_SOFT_SYNC_RESPONSE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x",
|
logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", hdr.hdr.cmd);
|
||||||
hdr.hdr.cmd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
bool dvc_init() {
|
||||||
dvc_init()
|
|
||||||
{
|
|
||||||
memset(channels, 0, sizeof(channels));
|
memset(channels, 0, sizeof(channels));
|
||||||
dvc_channel = channel_register("drdynvc",
|
dvc_channel = channel_register("drdynvc", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, dvc_process_pdu);
|
||||||
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
|
|
||||||
dvc_process_pdu);
|
|
||||||
|
|
||||||
return (dvc_channel != NULL);
|
return (dvc_channel != NULL);
|
||||||
}
|
}
|
||||||
|
51
ewmhints.c
51
ewmhints.c
@ -25,6 +25,8 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
|
||||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||||
@ -45,7 +47,7 @@ Atom g_net_wm_state_atom, g_net_wm_desktop_atom, g_net_wm_ping_atom;
|
|||||||
Returns zero on success, -1 on error
|
Returns zero on success, -1 on error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
get_property_value(Window wnd, char *propname, long max_length,
|
get_property_value(Window wnd, const char *propname, long max_length,
|
||||||
unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
|
unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
@ -57,6 +59,7 @@ get_property_value(Window wnd, char *propname, long max_length,
|
|||||||
property = XInternAtom(g_display, propname, True);
|
property = XInternAtom(g_display, propname, True);
|
||||||
if (property == None)
|
if (property == None)
|
||||||
{
|
{
|
||||||
|
if (!nowarn)
|
||||||
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
|
logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -71,6 +74,7 @@ get_property_value(Window wnd, char *propname, long max_length,
|
|||||||
|
|
||||||
if (result != Success)
|
if (result != Success)
|
||||||
{
|
{
|
||||||
|
if (!nowarn)
|
||||||
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
|
logger(GUI, Error, "get_property_value(), XGetWindowProperty failed");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -106,7 +110,7 @@ static int
|
|||||||
get_current_desktop(void)
|
get_current_desktop(void)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
int current_desktop;
|
int current_desktop;
|
||||||
|
|
||||||
if (get_property_value
|
if (get_property_value
|
||||||
@ -117,6 +121,7 @@ get_current_desktop(void)
|
|||||||
if (nitems_return != 1)
|
if (nitems_return != 1)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length");
|
logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length");
|
||||||
|
if (prop_return) XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +140,7 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
|
|||||||
{
|
{
|
||||||
int current_desktop;
|
int current_desktop;
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
long *return_words;
|
long *return_words;
|
||||||
const uint32 net_workarea_x_offset = 0;
|
const uint32 net_workarea_x_offset = 0;
|
||||||
const uint32 net_workarea_y_offset = 1;
|
const uint32 net_workarea_y_offset = 1;
|
||||||
@ -151,13 +156,17 @@ get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
|
|||||||
if (nitems_return % 4)
|
if (nitems_return % 4)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length");
|
logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length");
|
||||||
|
XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_desktop = get_current_desktop();
|
current_desktop = get_current_desktop();
|
||||||
|
|
||||||
if (current_desktop < 0)
|
if (current_desktop < 0)
|
||||||
|
{
|
||||||
|
XFree(prop_return);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return_words = (long *) prop_return;
|
return_words = (long *) prop_return;
|
||||||
|
|
||||||
@ -206,7 +215,7 @@ int
|
|||||||
ewmh_get_window_state(Window w)
|
ewmh_get_window_state(Window w)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
unsigned long *return_words;
|
unsigned long *return_words;
|
||||||
unsigned long item;
|
unsigned long item;
|
||||||
RD_BOOL maximized_vert, maximized_horz, hidden;
|
RD_BOOL maximized_vert, maximized_horz, hidden;
|
||||||
@ -247,7 +256,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
|
|||||||
|
|
||||||
int result;
|
int result;
|
||||||
unsigned long i, nitems;
|
unsigned long i, nitems;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
uint32 state = WithdrawnState;
|
uint32 state = WithdrawnState;
|
||||||
|
|
||||||
/* The spec states that the window manager must respect any
|
/* The spec states that the window manager must respect any
|
||||||
@ -312,10 +321,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
|
|||||||
xevent.xclient.window = wnd;
|
xevent.xclient.window = wnd;
|
||||||
xevent.xclient.message_type = g_net_wm_state_atom;
|
xevent.xclient.message_type = g_net_wm_state_atom;
|
||||||
xevent.xclient.format = 32;
|
xevent.xclient.format = 32;
|
||||||
if (add)
|
xevent.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||||
xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
|
|
||||||
else
|
|
||||||
xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
|
|
||||||
xevent.xclient.data.l[1] = atom1;
|
xevent.xclient.data.l[1] = atom1;
|
||||||
xevent.xclient.data.l[2] = atom2;
|
xevent.xclient.data.l[2] = atom2;
|
||||||
xevent.xclient.data.l[3] = 0;
|
xevent.xclient.data.l[3] = 0;
|
||||||
@ -361,7 +367,7 @@ int
|
|||||||
ewmh_get_window_desktop(Window wnd)
|
ewmh_get_window_desktop(Window wnd)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
int desktop;
|
int desktop;
|
||||||
|
|
||||||
if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
|
if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
|
||||||
@ -370,6 +376,7 @@ ewmh_get_window_desktop(Window wnd)
|
|||||||
if (nitems_return != 1)
|
if (nitems_return != 1)
|
||||||
{
|
{
|
||||||
logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length");
|
logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length");
|
||||||
|
if (prop_return) XFree(prop_return);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +447,7 @@ void
|
|||||||
ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
||||||
{
|
{
|
||||||
unsigned long nitems, i;
|
unsigned long nitems, i;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
unsigned long *cur_set, *new_set;
|
unsigned long *cur_set, *new_set;
|
||||||
unsigned long *icon;
|
unsigned long *icon;
|
||||||
|
|
||||||
@ -463,7 +470,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
icon = cur_set + i;
|
icon = cur_set + i;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_set = xmalloc((nitems + width * height + 2) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((nitems + width * height + 2) * sizeof(unsigned long));
|
||||||
memcpy(new_set, cur_set, nitems * sizeof(unsigned long));
|
memcpy(new_set, cur_set, nitems * sizeof(unsigned long));
|
||||||
icon = new_set + nitems;
|
icon = new_set + nitems;
|
||||||
nitems += width * height + 2;
|
nitems += width * height + 2;
|
||||||
@ -471,7 +478,7 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_set = xmalloc((width * height + 2) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((width * height + 2) * sizeof(unsigned long));
|
||||||
icon = new_set;
|
icon = new_set;
|
||||||
nitems = width * height + 2;
|
nitems = width * height + 2;
|
||||||
}
|
}
|
||||||
@ -483,10 +490,10 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
for (i = 0; i < (width * height); i++)
|
for (i = 0; i < (width * height); i++)
|
||||||
{
|
{
|
||||||
icon[i + 2] =
|
icon[i + 2] =
|
||||||
rgba_data[i * 4 + 3] << 24 |
|
((unsigned char)rgba_data[i * 4 + 3] << 24) |
|
||||||
((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
|
(((unsigned char)rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
|
||||||
((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
|
(((unsigned char)rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
|
||||||
((rgba_data[i * 4 + 2] << 0) & 0x000000FF);
|
(((unsigned char)rgba_data[i * 4 + 2] << 0) & 0x000000FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||||
@ -495,14 +502,14 @@ ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data)
|
|||||||
if (cur_set)
|
if (cur_set)
|
||||||
XFree(cur_set);
|
XFree(cur_set);
|
||||||
if (new_set)
|
if (new_set)
|
||||||
xfree(new_set);
|
free(new_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
unsigned long nitems, i, icon_size;
|
unsigned long nitems, i, icon_size;
|
||||||
unsigned char *props;
|
unsigned char *props = NULL;
|
||||||
unsigned long *cur_set, *new_set;
|
unsigned long *cur_set, *new_set;
|
||||||
|
|
||||||
cur_set = NULL;
|
cur_set = NULL;
|
||||||
@ -525,7 +532,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
icon_size = width * height + 2;
|
icon_size = width * height + 2;
|
||||||
new_set = xmalloc((nitems - icon_size) * sizeof(unsigned long));
|
new_set = (unsigned long *)malloc((nitems - icon_size) * sizeof(unsigned long));
|
||||||
|
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
memcpy(new_set, cur_set, i * sizeof(unsigned long));
|
memcpy(new_set, cur_set, i * sizeof(unsigned long));
|
||||||
@ -538,7 +545,7 @@ ewmh_del_icon(Window wnd, uint32 width, uint32 height)
|
|||||||
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
|
||||||
PropModeReplace, (unsigned char *) new_set, nitems);
|
PropModeReplace, (unsigned char *) new_set, nitems);
|
||||||
|
|
||||||
xfree(new_set);
|
free(new_set);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
XFree(cur_set);
|
XFree(cur_set);
|
||||||
@ -556,7 +563,7 @@ RD_BOOL
|
|||||||
ewmh_is_window_above(Window w)
|
ewmh_is_window_above(Window w)
|
||||||
{
|
{
|
||||||
unsigned long nitems_return;
|
unsigned long nitems_return;
|
||||||
unsigned char *prop_return;
|
unsigned char *prop_return = NULL;
|
||||||
unsigned long *return_words;
|
unsigned long *return_words;
|
||||||
unsigned long item;
|
unsigned long item;
|
||||||
RD_BOOL above;
|
RD_BOOL above;
|
||||||
|
Loading…
Reference in New Issue
Block a user