2011-03-10 16:50:40 +01:00
|
|
|
#include <sys/stat.h>
|
2011-12-27 17:04:30 +01:00
|
|
|
#include <sys/wait.h>
|
2013-12-29 14:05:44 +01:00
|
|
|
#include <sys/time.h>
|
2011-03-10 16:50:40 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2013-12-29 13:45:51 +01:00
|
|
|
#include <errno.h>
|
2014-01-06 18:31:12 +01:00
|
|
|
#include <libqubes-rpc-filecopy.h>
|
2011-03-10 16:50:40 +01:00
|
|
|
#include "dvm2.h"
|
|
|
|
|
2013-11-14 21:38:27 +01:00
|
|
|
#define USER_HOME "/home/user"
|
2013-12-29 13:45:51 +01:00
|
|
|
#define TMP_LOC "/tmp/qopen/"
|
2016-03-05 00:38:56 +01:00
|
|
|
// #define DEBUG
|
2013-11-14 21:38:27 +01:00
|
|
|
|
2014-05-04 19:16:30 +02:00
|
|
|
static const char *cleanup_filename = NULL;
|
2017-10-19 15:18:20 +02:00
|
|
|
static const char *cleanup_dirname = NULL;
|
2014-05-04 19:16:30 +02:00
|
|
|
|
|
|
|
static void cleanup_file(void)
|
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
if (cleanup_filename) {
|
|
|
|
if (unlink(cleanup_filename) < 0)
|
|
|
|
fprintf(stderr, "Failed to remove file at exit\n");
|
|
|
|
cleanup_filename = NULL;
|
|
|
|
}
|
|
|
|
if (cleanup_dirname) {
|
|
|
|
if (rmdir(cleanup_dirname) < 0)
|
|
|
|
fprintf(stderr, "Failed to remove directory at exit\n");
|
|
|
|
cleanup_dirname = NULL;
|
|
|
|
}
|
2014-05-04 19:16:30 +02:00
|
|
|
}
|
|
|
|
|
2013-12-30 11:35:46 +01:00
|
|
|
const char *gettime(void)
|
2013-02-25 06:48:29 +01:00
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
static char retbuf[60];
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
snprintf(retbuf, sizeof(retbuf), "%lld.%06lld",
|
|
|
|
(long long) tv.tv_sec, (long long) tv.tv_usec);
|
|
|
|
return retbuf;
|
2013-02-25 06:48:29 +01:00
|
|
|
}
|
|
|
|
|
2013-12-29 13:45:51 +01:00
|
|
|
static char *get_directory(void)
|
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
const char *remote_domain;
|
|
|
|
char *dir;
|
|
|
|
size_t len;
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
remote_domain = getenv("QREXEC_REMOTE_DOMAIN");
|
|
|
|
if (!remote_domain) {
|
|
|
|
fprintf(stderr, "Cannot get remote domain name\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!*remote_domain || index(remote_domain, '/'))
|
|
|
|
goto fail;
|
|
|
|
if (!strcmp(remote_domain, ".") || !strcmp(remote_domain, ".."))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
len = strlen("/tmp/-XXXXXX")+strlen(remote_domain)+1;
|
|
|
|
dir = malloc(len);
|
|
|
|
if (!dir) {
|
|
|
|
fprintf(stderr, "Cannot allocate memory\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
snprintf(dir, len, "/tmp/%s-XXXXXX", remote_domain);
|
|
|
|
|
|
|
|
ret = mkdtemp(dir);
|
|
|
|
if (ret == NULL) {
|
|
|
|
perror("mkdtemp");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
cleanup_dirname = strdup(ret);
|
|
|
|
return ret;
|
2013-12-29 13:45:51 +01:00
|
|
|
|
|
|
|
fail:
|
2018-05-26 00:54:09 +02:00
|
|
|
fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain);
|
|
|
|
exit(1);
|
2013-12-29 13:45:51 +01:00
|
|
|
}
|
|
|
|
|
2018-05-26 01:41:16 +02:00
|
|
|
char *get_filename(int *view_only)
|
2011-03-10 16:50:40 +01:00
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
char buf[DVM_FILENAME_SIZE];
|
2018-05-26 01:41:16 +02:00
|
|
|
char *fname = buf;
|
2018-05-26 00:54:09 +02:00
|
|
|
static char *retname;
|
|
|
|
int i;
|
|
|
|
char *directory;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
directory = get_directory();
|
|
|
|
if (!read_all(0, buf, sizeof(buf)))
|
|
|
|
exit(1);
|
|
|
|
buf[DVM_FILENAME_SIZE-1] = 0;
|
|
|
|
if (index(buf, '/')) {
|
|
|
|
fprintf(stderr, "filename contains /");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
for (i=0; buf[i]!=0; i++) {
|
|
|
|
// replace some characters with _ (eg mimeopen have problems with some of them)
|
|
|
|
if (index(" !?\"#$%^&*()[]<>;`~|", buf[i]))
|
|
|
|
buf[i]='_';
|
|
|
|
}
|
2018-05-26 01:41:16 +02:00
|
|
|
if (strncmp(buf, DVM_VIEW_ONLY_PREFIX, strlen(DVM_VIEW_ONLY_PREFIX)) == 0) {
|
|
|
|
*view_only = 1;
|
|
|
|
fname += strlen(DVM_VIEW_ONLY_PREFIX);
|
|
|
|
}
|
|
|
|
len = strlen(directory)+1+strlen(fname)+1;
|
2018-05-26 00:54:09 +02:00
|
|
|
retname = malloc(len);
|
|
|
|
if (!retname) {
|
|
|
|
fprintf(stderr, "Cannot allocate memory\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2018-05-26 01:41:16 +02:00
|
|
|
snprintf(retname, len, "%s/%s", directory, fname);
|
2018-05-26 00:54:09 +02:00
|
|
|
free(directory);
|
|
|
|
return retname;
|
2011-03-10 16:50:40 +01:00
|
|
|
}
|
|
|
|
|
2014-01-06 18:31:12 +01:00
|
|
|
void copy_file_by_name(const char *filename)
|
2011-03-10 16:50:40 +01:00
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("open file");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/* we now have created a new file, ensure we delete it at the end */
|
|
|
|
cleanup_filename = strdup(filename);
|
|
|
|
atexit(cleanup_file);
|
|
|
|
if (!copy_fd_all(fd, 0))
|
2011-03-11 11:54:39 +01:00
|
|
|
exit(1);
|
2018-05-26 00:54:09 +02:00
|
|
|
close(fd);
|
2011-03-10 16:50:40 +01:00
|
|
|
}
|
|
|
|
|
2013-12-30 11:35:46 +01:00
|
|
|
void send_file_back(const char * filename)
|
2011-03-10 16:50:40 +01:00
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
int fd = open(filename, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("open file");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!copy_fd_all(1, fd))
|
|
|
|
exit(1);
|
|
|
|
close(fd);
|
|
|
|
close(1);
|
2011-03-10 16:50:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main()
|
|
|
|
{
|
2018-05-26 00:54:09 +02:00
|
|
|
struct stat stat_pre, stat_post, session_stat;
|
2018-05-26 01:41:16 +02:00
|
|
|
int view_only = 0;
|
|
|
|
char *filename = get_filename(&view_only);
|
2018-05-26 00:54:09 +02:00
|
|
|
int child, status, log_fd, null_fd;
|
|
|
|
FILE *waiter_pidfile;
|
|
|
|
|
|
|
|
copy_file_by_name(filename);
|
2018-05-26 01:41:16 +02:00
|
|
|
if (view_only) {
|
|
|
|
// mark file as read-only so applications will signal it to the user
|
|
|
|
chmod(filename, 0400);
|
|
|
|
}
|
2018-05-26 00:54:09 +02:00
|
|
|
if (stat(filename, &stat_pre)) {
|
|
|
|
perror("stat pre");
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-03-05 00:38:56 +01:00
|
|
|
#ifdef DEBUG
|
2018-05-26 00:54:09 +02:00
|
|
|
fprintf(stderr, "time=%s, waiting for qubes-session\n", gettime());
|
2016-03-05 00:38:56 +01:00
|
|
|
#endif
|
2018-05-26 00:54:09 +02:00
|
|
|
// wait for X server to starts (especially in DispVM)
|
|
|
|
if (stat("/tmp/qubes-session-env", &session_stat)) {
|
|
|
|
switch (child = fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
|
|
|
waiter_pidfile = fopen("/tmp/qubes-session-waiter", "a");
|
|
|
|
if (waiter_pidfile == NULL) {
|
|
|
|
perror("fopen waiter_pidfile");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fprintf(waiter_pidfile, "%d\n", getpid());
|
|
|
|
fclose(waiter_pidfile);
|
|
|
|
// check the second time, to prevent race
|
|
|
|
if (stat("/tmp/qubes-session-env", &session_stat)) {
|
|
|
|
// wait for qubes-session notify
|
|
|
|
pause();
|
|
|
|
}
|
|
|
|
exit(0);
|
|
|
|
default:
|
|
|
|
waitpid(child, &status, 0);
|
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
|
|
|
//propagate exit code from child
|
|
|
|
exit(WEXITSTATUS(status));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-05 00:38:56 +01:00
|
|
|
#ifdef DEBUG
|
2018-05-26 00:54:09 +02:00
|
|
|
fprintf(stderr, "time=%s, starting editor\n", gettime());
|
2016-03-05 00:38:56 +01:00
|
|
|
#endif
|
2018-05-26 00:54:09 +02:00
|
|
|
switch (child = fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
|
|
|
null_fd = open("/dev/null", O_RDONLY);
|
|
|
|
dup2(null_fd, 0);
|
|
|
|
close(null_fd);
|
|
|
|
|
|
|
|
log_fd = open("/tmp/mimeopen.log", O_CREAT | O_APPEND, 0666);
|
|
|
|
if (log_fd == -1) {
|
|
|
|
perror("open /tmp/mimeopen.log");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dup2(log_fd, 1);
|
|
|
|
close(log_fd);
|
|
|
|
|
|
|
|
setenv("HOME", USER_HOME, 1);
|
|
|
|
setenv("DISPLAY", ":0", 1);
|
|
|
|
execl("/usr/bin/qubes-open", "qubes-open", filename, (char*)NULL);
|
|
|
|
perror("execl");
|
|
|
|
exit(1);
|
|
|
|
default:
|
|
|
|
waitpid(child, &status, 0);
|
|
|
|
if (status != 0) {
|
|
|
|
char cmd[512];
|
2011-03-31 13:26:41 +02:00
|
|
|
#ifdef USE_KDIALOG
|
2018-05-26 00:54:09 +02:00
|
|
|
snprintf(cmd, sizeof(cmd),
|
|
|
|
"HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
|
|
|
|
("HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
|
2011-03-31 13:26:41 +02:00
|
|
|
#else
|
2018-05-26 00:54:09 +02:00
|
|
|
snprintf(cmd, sizeof(cmd),
|
|
|
|
"HOME=/home/user DISPLAY=:0 /usr/bin/zenity --error --text 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
|
2011-03-31 13:26:41 +02:00
|
|
|
#endif
|
2018-05-26 00:54:09 +02:00
|
|
|
status = system(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(filename, &stat_post)) {
|
|
|
|
perror("stat post");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (stat_pre.st_mtime != stat_post.st_mtime)
|
|
|
|
send_file_back(filename);
|
|
|
|
free(filename);
|
|
|
|
return 0;
|
2011-03-10 16:50:40 +01:00
|
|
|
}
|