From 5deac1802f16e2c7225b0c599e06833b9370e81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 26 May 2018 00:54:09 +0200 Subject: [PATCH 1/4] qubes-rpc: fix code style - indent with spaces --- qubes-rpc/gui-fatal.c | 68 ++++---- qubes-rpc/qfile-agent.c | 162 +++++++++--------- qubes-rpc/qfile-unpacker.c | 136 +++++++-------- qubes-rpc/qopen-in-vm.c | 124 +++++++------- qubes-rpc/vm-file-editor.c | 340 ++++++++++++++++++------------------- 5 files changed, 415 insertions(+), 415 deletions(-) diff --git a/qubes-rpc/gui-fatal.c b/qubes-rpc/gui-fatal.c index 5900ce5..d50db09 100644 --- a/qubes-rpc/gui-fatal.c +++ b/qubes-rpc/gui-fatal.c @@ -10,58 +10,58 @@ static void fix_display(void) { - setenv("DISPLAY", ":0", 1); + setenv("DISPLAY", ":0", 1); } static void produce_message(const char * type, const char *fmt, va_list args) { - char *dialog_msg; - char buf[1024]; - (void) vsnprintf(buf, sizeof(buf), fmt, args); - if (asprintf(&dialog_msg, "%s: %s: %s (error type: %s)", - program_invocation_short_name, type, buf, strerror(errno)) < 0) { - fprintf(stderr, "Failed to allocate memory for error message :(\n"); - return; - } - fprintf(stderr, "%s\n", dialog_msg); - switch (fork()) { - case -1: - exit(1); //what else - case 0: - if (geteuid() == 0) - if (setuid(getuid()) != 0) - perror("setuid failed, calling kdialog/zenity as root"); - fix_display(); + char *dialog_msg; + char buf[1024]; + (void) vsnprintf(buf, sizeof(buf), fmt, args); + if (asprintf(&dialog_msg, "%s: %s: %s (error type: %s)", + program_invocation_short_name, type, buf, strerror(errno)) < 0) { + fprintf(stderr, "Failed to allocate memory for error message :(\n"); + return; + } + fprintf(stderr, "%s\n", dialog_msg); + switch (fork()) { + case -1: + exit(1); //what else + case 0: + if (geteuid() == 0) + if (setuid(getuid()) != 0) + perror("setuid failed, calling kdialog/zenity as root"); + fix_display(); #ifdef USE_KDIALOG - execlp("/usr/bin/kdialog", "kdialog", "--sorry", dialog_msg, NULL); + execlp("/usr/bin/kdialog", "kdialog", "--sorry", dialog_msg, NULL); #else - execlp("/usr/bin/zenity", "zenity", "--error", "--text", dialog_msg, NULL); + execlp("/usr/bin/zenity", "zenity", "--error", "--text", dialog_msg, NULL); #endif - exit(1); - default:; - } - free(dialog_msg); + exit(1); + default:; + } + free(dialog_msg); } void gui_fatal(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - produce_message("Fatal error", fmt, args); - va_end(args); - exit(1); + va_list args; + va_start(args, fmt); + produce_message("Fatal error", fmt, args); + va_end(args); + exit(1); } void qfile_gui_fatal(const char *fmt, va_list args) { - produce_message("Fatal error", fmt, args); + produce_message("Fatal error", fmt, args); exit(1); } void gui_nonfatal(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - produce_message("Information", fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + produce_message("Information", fmt, args); + va_end(args); } diff --git a/qubes-rpc/qfile-agent.c b/qubes-rpc/qfile-agent.c index de65788..42a1dfd 100644 --- a/qubes-rpc/qfile-agent.c +++ b/qubes-rpc/qfile-agent.c @@ -13,107 +13,107 @@ #include enum { - PROGRESS_FLAG_NORMAL, - PROGRESS_FLAG_INIT, - PROGRESS_FLAG_DONE + PROGRESS_FLAG_NORMAL, + PROGRESS_FLAG_INIT, + PROGRESS_FLAG_DONE }; void do_notify_progress(long long total, int flag) { - const char *du_size_env = getenv("FILECOPY_TOTAL_SIZE"); - const char *progress_type_env = getenv("PROGRESS_TYPE"); - const char *saved_stdout_env = getenv("SAVED_FD_1"); - int ignore; - if (!progress_type_env) - return; - if (!strcmp(progress_type_env, "console") && du_size_env) { - char msg[256]; - snprintf(msg, sizeof(msg), "sent %lld/%lld KB\r", - total / 1024, strtoull(du_size_env, NULL, 0)); - ignore = write(2, msg, strlen(msg)); - if (flag == PROGRESS_FLAG_DONE) - ignore = write(2, "\n", 1); - } - if (!strcmp(progress_type_env, "gui") && saved_stdout_env) { - char msg[256]; - snprintf(msg, sizeof(msg), "%lld\n", total); - ignore = write(strtoul(saved_stdout_env, NULL, 0), msg, - strlen(msg)); - } - if (ignore < 0) { - /* silence gcc warning */ - } + const char *du_size_env = getenv("FILECOPY_TOTAL_SIZE"); + const char *progress_type_env = getenv("PROGRESS_TYPE"); + const char *saved_stdout_env = getenv("SAVED_FD_1"); + int ignore; + if (!progress_type_env) + return; + if (!strcmp(progress_type_env, "console") && du_size_env) { + char msg[256]; + snprintf(msg, sizeof(msg), "sent %lld/%lld KB\r", + total / 1024, strtoull(du_size_env, NULL, 0)); + ignore = write(2, msg, strlen(msg)); + if (flag == PROGRESS_FLAG_DONE) + ignore = write(2, "\n", 1); + } + if (!strcmp(progress_type_env, "gui") && saved_stdout_env) { + char msg[256]; + snprintf(msg, sizeof(msg), "%lld\n", total); + ignore = write(strtoul(saved_stdout_env, NULL, 0), msg, + strlen(msg)); + } + if (ignore < 0) { + /* silence gcc warning */ + } } void notify_progress(int size, int flag) { - static long long total = 0; - static long long prev_total = 0; - total += size; - if (total > prev_total + PROGRESS_NOTIFY_DELTA - || (flag != PROGRESS_FLAG_NORMAL)) { - // check for possible error from qfile-unpacker; if error occured, - // exit() will be called, so don't bother with current state - // (notify_progress can be called as callback from copy_file()) - if (flag == PROGRESS_FLAG_NORMAL) - wait_for_result(); - do_notify_progress(total, flag); - prev_total = total; - } + static long long total = 0; + static long long prev_total = 0; + total += size; + if (total > prev_total + PROGRESS_NOTIFY_DELTA + || (flag != PROGRESS_FLAG_NORMAL)) { + // check for possible error from qfile-unpacker; if error occured, + // exit() will be called, so don't bother with current state + // (notify_progress can be called as callback from copy_file()) + if (flag == PROGRESS_FLAG_NORMAL) + wait_for_result(); + do_notify_progress(total, flag); + prev_total = total; + } } char *get_abs_path(const char *cwd, const char *pathname) { - char *ret; - if (pathname[0] == '/') - return strdup(pathname); - if (asprintf(&ret, "%s/%s", cwd, pathname) < 0) - return NULL; - else - return ret; + char *ret; + if (pathname[0] == '/') + return strdup(pathname); + if (asprintf(&ret, "%s/%s", cwd, pathname) < 0) + return NULL; + else + return ret; } int main(int argc, char **argv) { - int i; - char *entry; - char *cwd; - char *sep; - int ignore_symlinks = 0; + int i; + char *entry; + char *cwd; + char *sep; + int ignore_symlinks = 0; - qfile_pack_init(); - register_error_handler(qfile_gui_fatal); - register_notify_progress(¬ify_progress); - notify_progress(0, PROGRESS_FLAG_INIT); - cwd = getcwd(NULL, 0); - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--ignore-symlinks")==0) { - ignore_symlinks = 1; - continue; - } + qfile_pack_init(); + register_error_handler(qfile_gui_fatal); + register_notify_progress(¬ify_progress); + notify_progress(0, PROGRESS_FLAG_INIT); + cwd = getcwd(NULL, 0); + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--ignore-symlinks")==0) { + ignore_symlinks = 1; + continue; + } - entry = get_abs_path(cwd, argv[i]); + entry = get_abs_path(cwd, argv[i]); - do { - sep = rindex(entry, '/'); - if (!sep) - gui_fatal - ("Internal error: nonabsolute filenames not allowed"); - *sep = 0; - } while (sep[1] == 0); - if (entry[0] == 0) { - if (chdir("/") < 0) { - gui_fatal("Internal error: chdir(\"/\") failed?!"); - } - } else if (chdir(entry)) - gui_fatal("chdir to %s", entry); - do_fs_walk(sep + 1, ignore_symlinks); - free(entry); - } - notify_end_and_wait_for_result(); - notify_progress(0, PROGRESS_FLAG_DONE); - return 0; + do { + sep = rindex(entry, '/'); + if (!sep) + gui_fatal + ("Internal error: nonabsolute filenames not allowed"); + *sep = 0; + } while (sep[1] == 0); + if (entry[0] == 0) { + if (chdir("/") < 0) { + gui_fatal("Internal error: chdir(\"/\") failed?!"); + } + } else if (chdir(entry)) + gui_fatal("chdir to %s", entry); + do_fs_walk(sep + 1, ignore_symlinks); + free(entry); + } + notify_end_and_wait_for_result(); + notify_progress(0, PROGRESS_FLAG_DONE); + return 0; } diff --git a/qubes-rpc/qfile-unpacker.c b/qubes-rpc/qfile-unpacker.c index 86a9527..817277a 100644 --- a/qubes-rpc/qfile-unpacker.c +++ b/qubes-rpc/qfile-unpacker.c @@ -17,81 +17,81 @@ #define INCOMING_DIR_ROOT "/home/user/QubesIncoming" int prepare_creds_return_uid(const char *username) { - const struct passwd *pwd; - pwd = getpwnam(username); - if (!pwd) { - perror("getpwnam"); - exit(1); - } - setenv("HOME", pwd->pw_dir, 1); - setenv("USER", username, 1); - if (setgid(pwd->pw_gid) < 0) - gui_fatal("Error setting group permissions"); - if (initgroups(username, pwd->pw_gid) < 0) - gui_fatal("Error initializing groups"); - if (setfsuid(pwd->pw_uid) < 0) - gui_fatal("Error setting filesystem level permissions"); - return pwd->pw_uid; + const struct passwd *pwd; + pwd = getpwnam(username); + if (!pwd) { + perror("getpwnam"); + exit(1); + } + setenv("HOME", pwd->pw_dir, 1); + setenv("USER", username, 1); + if (setgid(pwd->pw_gid) < 0) + gui_fatal("Error setting group permissions"); + if (initgroups(username, pwd->pw_gid) < 0) + gui_fatal("Error initializing groups"); + if (setfsuid(pwd->pw_uid) < 0) + gui_fatal("Error setting filesystem level permissions"); + return pwd->pw_uid; } int main(int argc __attribute((__unused__)), char ** argv __attribute__((__unused__))) { - char *incoming_dir; - int uid, ret; - pid_t pid; - const char *remote_domain; - char *procdir_path; - int procfs_fd; + char *incoming_dir; + int uid, ret; + pid_t pid; + const char *remote_domain; + char *procdir_path; + int procfs_fd; - uid = prepare_creds_return_uid("user"); + uid = prepare_creds_return_uid("user"); - remote_domain = getenv("QREXEC_REMOTE_DOMAIN"); - if (!remote_domain) { - gui_fatal("Cannot get remote domain name"); - exit(1); - } - mkdir(INCOMING_DIR_ROOT, 0700); - if (asprintf(&incoming_dir, "%s/%s", INCOMING_DIR_ROOT, remote_domain) < 0) - gui_fatal("Error allocating memory"); - mkdir(incoming_dir, 0700); - if (chdir(incoming_dir)) - gui_fatal("Error chdir to %s", incoming_dir); + remote_domain = getenv("QREXEC_REMOTE_DOMAIN"); + if (!remote_domain) { + gui_fatal("Cannot get remote domain name"); + exit(1); + } + mkdir(INCOMING_DIR_ROOT, 0700); + if (asprintf(&incoming_dir, "%s/%s", INCOMING_DIR_ROOT, remote_domain) < 0) + gui_fatal("Error allocating memory"); + mkdir(incoming_dir, 0700); + if (chdir(incoming_dir)) + gui_fatal("Error chdir to %s", incoming_dir); - if (mount(".", ".", NULL, MS_BIND | MS_NODEV | MS_NOEXEC | MS_NOSUID, NULL) < 0) - gui_fatal("Failed to mount a directory %s", incoming_dir); + if (mount(".", ".", NULL, MS_BIND | MS_NODEV | MS_NOEXEC | MS_NOSUID, NULL) < 0) + gui_fatal("Failed to mount a directory %s", incoming_dir); - /* parse the input in unprivileged child process, parent will hold root - * access to unmount incoming dir */ - switch (pid=fork()) { - case -1: - gui_fatal("Failed to create new process"); - case 0: - if (asprintf(&procdir_path, "/proc/%d/fd", getpid()) < 0) { - gui_fatal("Error allocating memory"); - } - procfs_fd = open(procdir_path, O_DIRECTORY | O_RDONLY); - if (procfs_fd < 0) - perror("Failed to open /proc"); - else - set_procfs_fd(procfs_fd); - free(procdir_path); + /* parse the input in unprivileged child process, parent will hold root + * access to unmount incoming dir */ + switch (pid=fork()) { + case -1: + gui_fatal("Failed to create new process"); + case 0: + if (asprintf(&procdir_path, "/proc/%d/fd", getpid()) < 0) { + gui_fatal("Error allocating memory"); + } + procfs_fd = open(procdir_path, O_DIRECTORY | O_RDONLY); + if (procfs_fd < 0) + perror("Failed to open /proc"); + else + set_procfs_fd(procfs_fd); + free(procdir_path); - if (chroot(".")) - gui_fatal("Error chroot to %s", incoming_dir); - if (setuid(uid) < 0) { - /* no kdialog inside chroot */ - perror("setuid"); - exit(1); - } - return do_unpack(); - } - if (waitpid(pid, &ret, 0) < 0) { - gui_fatal("Failed to wait for child process"); - } - if (umount2(".", MNT_DETACH) < 0) - gui_fatal("Cannot umount incoming directory"); - if (!WIFEXITED(ret)) { - gui_fatal("Child process exited abnormally"); - } - return WEXITSTATUS(ret); + if (chroot(".")) + gui_fatal("Error chroot to %s", incoming_dir); + if (setuid(uid) < 0) { + /* no kdialog inside chroot */ + perror("setuid"); + exit(1); + } + return do_unpack(); + } + if (waitpid(pid, &ret, 0) < 0) { + gui_fatal("Failed to wait for child process"); + } + if (umount2(".", MNT_DETACH) < 0) + gui_fatal("Cannot umount incoming directory"); + if (!WIFEXITED(ret)) { + gui_fatal("Child process exited abnormally"); + } + return WEXITSTATUS(ret); } diff --git a/qubes-rpc/qopen-in-vm.c b/qubes-rpc/qopen-in-vm.c index 43cf854..45949df 100644 --- a/qubes-rpc/qopen-in-vm.c +++ b/qubes-rpc/qopen-in-vm.c @@ -14,95 +14,95 @@ void send_file(const char *fname) { - const char *base; - char sendbuf[DVM_FILENAME_SIZE]; - int fd = open(fname, O_RDONLY); - if (fd < 0) - gui_fatal("open %s", fname); - base = rindex(fname, '/'); - if (!base) - base = fname; - else - base++; - if (strlen(base) >= DVM_FILENAME_SIZE) - base += strlen(base) - DVM_FILENAME_SIZE + 1; + const char *base; + char sendbuf[DVM_FILENAME_SIZE]; + int fd = open(fname, O_RDONLY); + if (fd < 0) + gui_fatal("open %s", fname); + base = rindex(fname, '/'); + if (!base) + base = fname; + else + base++; + if (strlen(base) >= DVM_FILENAME_SIZE) + base += strlen(base) - DVM_FILENAME_SIZE + 1; strncpy(sendbuf,base,DVM_FILENAME_SIZE - 1); /* fills out with NULs */ sendbuf[DVM_FILENAME_SIZE - 1] = '\0'; - if (!write_all(1, sendbuf, DVM_FILENAME_SIZE)) - gui_fatal("send filename to dispVM"); - if (!copy_fd_all(1, fd)) - gui_fatal("send file to dispVM"); - close(1); - close(fd); + if (!write_all(1, sendbuf, DVM_FILENAME_SIZE)) + gui_fatal("send filename to dispVM"); + if (!copy_fd_all(1, fd)) + gui_fatal("send file to dispVM"); + close(1); + close(fd); } int copy_and_return_nonemptiness(int tmpfd) { - struct stat st; - if (!copy_fd_all(tmpfd, 0)) - gui_fatal("receiving file from dispVM"); - if (fstat(tmpfd, &st)) - gui_fatal("fstat"); - close(tmpfd); + struct stat st; + if (!copy_fd_all(tmpfd, 0)) + gui_fatal("receiving file from dispVM"); + if (fstat(tmpfd, &st)) + gui_fatal("fstat"); + close(tmpfd); - return st.st_size > 0; + return st.st_size > 0; } void recv_file_nowrite(const char *fname) { - char *tempfile; - char *errmsg; - int tmpfd = -1; + char *tempfile; + char *errmsg; + int tmpfd = -1; - if (asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX") != -1) - tmpfd = mkstemp(tempfile); - if (tmpfd < 0) - gui_fatal("unable to create any temporary file, aborting"); - if (!copy_and_return_nonemptiness(tmpfd)) { - unlink(tempfile); - return; - } - if (asprintf(&errmsg, - "The file %s has been edited in Disposable VM and the modified content has been received, " - "but this file is in nonwritable directory and thus cannot be modified safely. The edited file has been " - "saved to %s", fname, tempfile) != -1) + if (asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX") != -1) + tmpfd = mkstemp(tempfile); + if (tmpfd < 0) + gui_fatal("unable to create any temporary file, aborting"); + if (!copy_and_return_nonemptiness(tmpfd)) { + unlink(tempfile); + return; + } + if (asprintf(&errmsg, + "The file %s has been edited in Disposable VM and the modified content has been received, " + "but this file is in nonwritable directory and thus cannot be modified safely. The edited file has been " + "saved to %s", fname, tempfile) != -1) gui_nonfatal(errmsg); } void actually_recv_file(const char *fname, const char *tempfile, int tmpfd) { - if (!copy_and_return_nonemptiness(tmpfd)) { - unlink(tempfile); - return; - } - if (rename(tempfile, fname)) - gui_fatal("rename"); + if (!copy_and_return_nonemptiness(tmpfd)) { + unlink(tempfile); + return; + } + if (rename(tempfile, fname)) + gui_fatal("rename"); } void recv_file(const char *fname) { - int tmpfd = -1; - char *tempfile; - if (asprintf(&tempfile, "%s.XXXXXX", fname) != -1) { - tmpfd = mkstemp(tempfile); - } - if (tmpfd < 0) - recv_file_nowrite(fname); - else - actually_recv_file(fname, tempfile, tmpfd); + int tmpfd = -1; + char *tempfile; + if (asprintf(&tempfile, "%s.XXXXXX", fname) != -1) { + tmpfd = mkstemp(tempfile); + } + if (tmpfd < 0) + recv_file_nowrite(fname); + else + actually_recv_file(fname, tempfile, tmpfd); } void talk_to_daemon(const char *fname) { - send_file(fname); - recv_file(fname); + send_file(fname); + recv_file(fname); } int main(int argc, char ** argv) { - signal(SIGPIPE, SIG_IGN); - if (argc!=2) - gui_fatal("OpenInVM - no file given?"); - talk_to_daemon(argv[1]); - return 0; + signal(SIGPIPE, SIG_IGN); + if (argc!=2) + gui_fatal("OpenInVM - no file given?"); + talk_to_daemon(argv[1]); + return 0; } diff --git a/qubes-rpc/vm-file-editor.c b/qubes-rpc/vm-file-editor.c index 55594d2..054fef3 100644 --- a/qubes-rpc/vm-file-editor.c +++ b/qubes-rpc/vm-file-editor.c @@ -19,217 +19,217 @@ static const char *cleanup_dirname = NULL; static void cleanup_file(void) { - 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; - } + 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; + } } const char *gettime(void) { - 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; + 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; } static char *get_directory(void) { - const char *remote_domain; - char *dir; - size_t len; - char *ret; + 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; + 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); + 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; + ret = mkdtemp(dir); + if (ret == NULL) { + perror("mkdtemp"); + exit(1); + } + cleanup_dirname = strdup(ret); + return ret; fail: - fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain); - exit(1); + fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain); + exit(1); } char *get_filename(void) { - char buf[DVM_FILENAME_SIZE]; - static char *retname; - int i; - char *directory; - size_t len; + char buf[DVM_FILENAME_SIZE]; + 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]='_'; - } - len = strlen(directory)+1+strlen(buf)+1; - retname = malloc(len); - if (!retname) { - fprintf(stderr, "Cannot allocate memory\n"); - exit(1); - } - snprintf(retname, len, "%s/%s", directory, buf); - free(directory); - return retname; + 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]='_'; + } + len = strlen(directory)+1+strlen(buf)+1; + retname = malloc(len); + if (!retname) { + fprintf(stderr, "Cannot allocate memory\n"); + exit(1); + } + snprintf(retname, len, "%s/%s", directory, buf); + free(directory); + return retname; } void copy_file_by_name(const char *filename) { - 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)) + int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + perror("open file"); exit(1); - close(fd); + } + /* 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)) + exit(1); + close(fd); } void send_file_back(const char * filename) { - 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); + 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); } int main() { - struct stat stat_pre, stat_post, session_stat; - char *filename = get_filename(); - int child, status, log_fd, null_fd; - FILE *waiter_pidfile; + struct stat stat_pre, stat_post, session_stat; + char *filename = get_filename(); + int child, status, log_fd, null_fd; + FILE *waiter_pidfile; - copy_file_by_name(filename); - if (stat(filename, &stat_pre)) { - perror("stat pre"); - exit(1); - } + copy_file_by_name(filename); + if (stat(filename, &stat_pre)) { + perror("stat pre"); + exit(1); + } #ifdef DEBUG - fprintf(stderr, "time=%s, waiting for qubes-session\n", gettime()); + fprintf(stderr, "time=%s, waiting for qubes-session\n", gettime()); #endif - // 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)); - } - } - } + // 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)); + } + } + } #ifdef DEBUG - fprintf(stderr, "time=%s, starting editor\n", gettime()); + fprintf(stderr, "time=%s, starting editor\n", gettime()); #endif - 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); + 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); + 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]; + 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]; #ifdef USE_KDIALOG - 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 /tmp/kdialog.log 2>&1 /tmp/kdialog.log 2>&1 /tmp/kdialog.log 2>&1 /tmp/kdialog.log 2>&1 /tmp/kdialog.log 2>&1 Date: Sat, 26 May 2018 01:39:07 +0200 Subject: [PATCH 2/4] qvm-open-in-vm: implement --view-only option Implement option to disallow (ignore in fact) modifications of file opened in another VM (including DispVM). This commit implements actual services part and handling in wrapping scripts. Fixes QubesOS/qubes-issues#1118 --- qubes-rpc/qopen-in-vm.c | 35 +++++++++++++++++++++++++++-------- qubes-rpc/qvm-open-in-dvm | 6 +++--- qubes-rpc/qvm-open-in-vm | 33 +++++++++++++++++++++++++++------ 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/qubes-rpc/qopen-in-vm.c b/qubes-rpc/qopen-in-vm.c index 45949df..8d2b24f 100644 --- a/qubes-rpc/qopen-in-vm.c +++ b/qubes-rpc/qopen-in-vm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "dvm2.h" @@ -92,17 +93,35 @@ void recv_file(const char *fname) actually_recv_file(fname, tempfile, tmpfd); } -void talk_to_daemon(const char *fname) -{ - send_file(fname); - recv_file(fname); -} - int main(int argc, char ** argv) { + char *fname; + int view_only = 0; + int ret; + const struct option opts[] = { + {"view-only", no_argument, &view_only, 1}, + {0} + }; + + while ((ret=getopt_long(argc, argv, "", opts, NULL)) != -1) { + if (ret == '?') { + exit(2); + } + } + signal(SIGPIPE, SIG_IGN); - if (argc!=2) + + if (optind >= argc) gui_fatal("OpenInVM - no file given?"); - talk_to_daemon(argv[1]); + fname = argv[optind]; + send_file(fname); + if (!view_only) { + recv_file(fname); + } else { + /* discard received data */ + int null_fd = open("/dev/null", O_WRONLY); + copy_fd_all(null_fd, 0); + close(null_fd); + } return 0; } diff --git a/qubes-rpc/qvm-open-in-dvm b/qubes-rpc/qvm-open-in-dvm index 84af921..8046858 100755 --- a/qubes-rpc/qvm-open-in-dvm +++ b/qubes-rpc/qvm-open-in-dvm @@ -20,10 +20,10 @@ # # -if ! [ $# = 1 ] ; then - echo "Usage: $0 filename" +if ! [ $# = 1 ] && ! [ $# = 2 ]; then + echo "Usage: $0 [--view-only] filename" exit 1 fi # shellcheck disable=SC2016 -exec qvm-open-in-vm '$dispvm' "$1" +exec qvm-open-in-vm '$dispvm' "$@" diff --git a/qubes-rpc/qvm-open-in-vm b/qubes-rpc/qvm-open-in-vm index d109e6b..ead9acf 100755 --- a/qubes-rpc/qvm-open-in-vm +++ b/qubes-rpc/qvm-open-in-vm @@ -20,16 +20,37 @@ # # -if ! [ $# = 2 ] ; then - echo "Usage: $0 vmname filename" - exit 1 +usage() { + echo "Usage: $0 [--view-only] vmname filename" + exit 2 +} + +qopen_opts= +target= +filename= + +while [ $# -gt 0 ]; do + if [ "x$1" = "x--view-only" ]; then + qopen_opts=--view-only + elif [ -z "$target" ]; then + target="$1" + elif [ -z "$filename" ]; then + filename="$1" + else + usage + fi + shift +done + +if [ -z "$target" ] || [ -z "$filename" ]; then + usage fi -case "$2" in +case "$filename" in *://*) - exec /usr/lib/qubes/qrexec-client-vm "$1" qubes.OpenURL /bin/echo "$2" + exec /usr/lib/qubes/qrexec-client-vm "$target" qubes.OpenURL /bin/echo "$filename" ;; *) - exec /usr/lib/qubes/qrexec-client-vm "$1" qubes.OpenInVM "/usr/lib/qubes/qopen-in-vm" "$2" + exec /usr/lib/qubes/qrexec-client-vm "$target" qubes.OpenInVM "/usr/lib/qubes/qopen-in-vm" $qopen_opts "$filename" ;; esac From 42b1355957f83715cd27229e6dd1e90a7a9c9c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 26 May 2018 01:41:16 +0200 Subject: [PATCH 3/4] qvm-open-in-vm: mark file as read-only if opened with --view-only This will cause most applications to disallow changing the file and also add some visual indication about the view being read only. This will avoid making the changes that would be discarded later. QubesOS/qubes-issues#1118 --- qubes-rpc/dvm2.h | 1 + qubes-rpc/qopen-in-vm.c | 19 ++++++++++++------- qubes-rpc/vm-file-editor.c | 18 ++++++++++++++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/qubes-rpc/dvm2.h b/qubes-rpc/dvm2.h index 0e5922c..72b73f7 100644 --- a/qubes-rpc/dvm2.h +++ b/qubes-rpc/dvm2.h @@ -1,2 +1,3 @@ #define DVM_FILENAME_SIZE 256 #define DVM_SPOOL "/home/user/.dvmspool" +#define DVM_VIEW_ONLY_PREFIX "view-only-" diff --git a/qubes-rpc/qopen-in-vm.c b/qubes-rpc/qopen-in-vm.c index 8d2b24f..5e796a5 100644 --- a/qubes-rpc/qopen-in-vm.c +++ b/qubes-rpc/qopen-in-vm.c @@ -13,22 +13,27 @@ #include #include "dvm2.h" -void send_file(const char *fname) +void send_file(const char *fname, int view_only) { const char *base; - char sendbuf[DVM_FILENAME_SIZE]; + char sendbuf[DVM_FILENAME_SIZE] = {0}; + size_t sendbuf_size = DVM_FILENAME_SIZE; int fd = open(fname, O_RDONLY); if (fd < 0) gui_fatal("open %s", fname); + if (view_only) { + strncpy(sendbuf, DVM_VIEW_ONLY_PREFIX, sendbuf_size); + sendbuf_size -= strlen(DVM_VIEW_ONLY_PREFIX); + } base = rindex(fname, '/'); if (!base) base = fname; else base++; - if (strlen(base) >= DVM_FILENAME_SIZE) - base += strlen(base) - DVM_FILENAME_SIZE + 1; - strncpy(sendbuf,base,DVM_FILENAME_SIZE - 1); /* fills out with NULs */ - sendbuf[DVM_FILENAME_SIZE - 1] = '\0'; + if (strlen(base) >= sendbuf_size) + base += strlen(base) - sendbuf_size + 1; + strncat(sendbuf,base,sendbuf_size - 1); /* fills out with NULs */ + sendbuf[DVM_FILENAME_SIZE - 1] = '\0'; if (!write_all(1, sendbuf, DVM_FILENAME_SIZE)) gui_fatal("send filename to dispVM"); if (!copy_fd_all(1, fd)) @@ -114,7 +119,7 @@ int main(int argc, char ** argv) if (optind >= argc) gui_fatal("OpenInVM - no file given?"); fname = argv[optind]; - send_file(fname); + send_file(fname, view_only); if (!view_only) { recv_file(fname); } else { diff --git a/qubes-rpc/vm-file-editor.c b/qubes-rpc/vm-file-editor.c index 054fef3..45004e8 100644 --- a/qubes-rpc/vm-file-editor.c +++ b/qubes-rpc/vm-file-editor.c @@ -79,9 +79,10 @@ fail: exit(1); } -char *get_filename(void) +char *get_filename(int *view_only) { char buf[DVM_FILENAME_SIZE]; + char *fname = buf; static char *retname; int i; char *directory; @@ -100,13 +101,17 @@ char *get_filename(void) if (index(" !?\"#$%^&*()[]<>;`~|", buf[i])) buf[i]='_'; } - len = strlen(directory)+1+strlen(buf)+1; + 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; retname = malloc(len); if (!retname) { fprintf(stderr, "Cannot allocate memory\n"); exit(1); } - snprintf(retname, len, "%s/%s", directory, buf); + snprintf(retname, len, "%s/%s", directory, fname); free(directory); return retname; } @@ -143,11 +148,16 @@ int main() { struct stat stat_pre, stat_post, session_stat; - char *filename = get_filename(); + int view_only = 0; + char *filename = get_filename(&view_only); int child, status, log_fd, null_fd; FILE *waiter_pidfile; copy_file_by_name(filename); + if (view_only) { + // mark file as read-only so applications will signal it to the user + chmod(filename, 0400); + } if (stat(filename, &stat_pre)) { perror("stat pre"); exit(1); From e8a2d9c32ad06fd5b06fd6ad85675ddd66b1ab38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 26 May 2018 02:50:55 +0200 Subject: [PATCH 4/4] Add file managers integration for qvm-open-in-dvm --view-only Rename existing entry from 'Open In DisposableVM' to 'Edit in DisposableVM', then add new 'View In DisposableVM'. Fixes QubesOS/qubes-issues#1118 --- misc/uca_qubes.xml | 15 ++++++++++++++- qubes-rpc/qvm-actions.sh | 6 ++++++ qubes-rpc/qvm-dvm.desktop | 9 +++++++-- qubes-rpc/qvm_dvm_nautilus.py | 26 ++++++++++++++++++++------ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/misc/uca_qubes.xml b/misc/uca_qubes.xml index 2e4ad8d..64a3ce9 100644 --- a/misc/uca_qubes.xml +++ b/misc/uca_qubes.xml @@ -59,7 +59,7 @@ document-open - Open in DisposableVM + Edit in DisposableVM 1507455559234996-8 /usr/lib/qubes/qvm-actions.sh opendvm %F @@ -70,3 +70,16 @@ + + document-open + View in DisposableVM + 1507455559234997-9 + /usr/lib/qubes/qvm-actions.sh viewdvm %F + + * + + + + + + diff --git a/qubes-rpc/qvm-actions.sh b/qubes-rpc/qvm-actions.sh index 691b3f2..3e4a968 100755 --- a/qubes-rpc/qvm-actions.sh +++ b/qubes-rpc/qvm-actions.sh @@ -45,6 +45,12 @@ case "$action" in qvm-open-in-dvm "$file" | zenity --notification --text "Opening $file in DisposableVM..." --timeout 3 & done ;; + viewdvm) + for file in "$@" + do + qvm-open-in-dvm --view-only "$file" | zenity --notification --text "Opening $file in DisposableVM..." --timeout 3 & + done + ;; *) echo "Unknown action. Aborting..." exit 1 diff --git a/qubes-rpc/qvm-dvm.desktop b/qubes-rpc/qvm-dvm.desktop index ba34250..e293b01 100644 --- a/qubes-rpc/qvm-dvm.desktop +++ b/qubes-rpc/qvm-dvm.desktop @@ -1,10 +1,15 @@ [Desktop Entry] -Actions=QvmDvm; +Actions=QvmDvm;QvmViewDvm Type=Service X-KDE-ServiceTypes=KonqPopupMenu/Plugin,all/allfiles [Desktop Action QvmDvm] Exec=/usr/bin/qvm-open-in-dvm %U Icon=kget -Name=Open In DisposableVM +Name=Edit In DisposableVM + +[Desktop Action QvmViewDvm] +Exec=/usr/bin/qvm-open-in-dvm --view-only %U +Icon=kget +Name=View In DisposableVM diff --git a/qubes-rpc/qvm_dvm_nautilus.py b/qubes-rpc/qvm_dvm_nautilus.py index a4311a4..7614396 100755 --- a/qubes-rpc/qvm_dvm_nautilus.py +++ b/qubes-rpc/qvm_dvm_nautilus.py @@ -17,15 +17,24 @@ class OpenInDvmItemExtension(GObject.GObject, Nautilus.MenuProvider): if not files: return - menu_item = Nautilus.MenuItem(name='QubesMenuProvider::OpenInDvm', - label='Open In DisposableVM', + menu_item1 = Nautilus.MenuItem(name='QubesMenuProvider::OpenInDvm', + label='Edit In DisposableVM', tip='', icon='') - menu_item.connect('activate', self.on_menu_item_clicked, files) - return menu_item, + menu_item1.connect('activate', self.on_menu_item_clicked, files) - def on_menu_item_clicked(self, menu, files): + menu_item2 = Nautilus.MenuItem(name='QubesMenuProvider::ViewInDvm', + label='View In DisposableVM', + tip='', + icon='') + + menu_item2.connect('activate', + self.on_menu_item_clicked, + files, True) + return menu_item1, menu_item2, + + def on_menu_item_clicked(self, menu, files, view_only=False): '''Called when user chooses files though Nautilus context menu. ''' for file_obj in files: @@ -38,6 +47,11 @@ class OpenInDvmItemExtension(GObject.GObject, Nautilus.MenuProvider): # Use subprocess.DEVNULL in python >= 3.3 devnull = open(os.devnull, 'wb') + command = ['nohup', '/usr/bin/qvm-open-in-dvm'] + if view_only: + command.append('--view-only') + command.append(gio_file.get_path()) # Use Popen instead of subprocess.call to spawn the process - Popen(['nohup', '/usr/bin/qvm-open-in-dvm', gio_file.get_path()], stdout=devnull, stderr=devnull) + Popen(command, stdout=devnull, stderr=devnull) + devnull.close()