diff --git a/appvm/Makefile b/appvm/Makefile index c6f4d25..c1abcfa 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,12 +1,14 @@ CC=gcc CFLAGS=-Wall -I../common -all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm qfile-agent +all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm qfile-agent qfile-unpacker dvm_file_editor: dvm_file_editor.o ../common/ioall.o $(CC) -o dvm_file_editor dvm_file_editor.o ../common/ioall.o qfile-agent-dvm: qfile-agent-dvm.o ../common/ioall.o ../common/gui-fatal.o $(CC) -o qfile-agent-dvm qfile-agent-dvm.o ../common/ioall.o ../common/gui-fatal.o qfile-agent: qfile-agent.o ../common/ioall.o ../common/gui-fatal.o copy_file.o $(CC) -o qfile-agent qfile-agent.o ../common/ioall.o ../common/gui-fatal.o copy_file.o +qfile-unpacker: qfile-unpacker.o ../common/ioall.o ../common/gui-fatal.o copy_file.o unpack.o + $(CC) -o qfile-unpacker qfile-unpacker.o ../common/ioall.o ../common/gui-fatal.o copy_file.o unpack.o qubes_penctl: qubes_penctl.o $(CC) -o qubes_penctl qubes_penctl.o -lxenstore qubes_add_pendrive_script: qubes_add_pendrive_script.o diff --git a/appvm/qfile-unpacker.c b/appvm/qfile-unpacker.c new file mode 100644 index 0000000..eaa5c06 --- /dev/null +++ b/appvm/qfile-unpacker.c @@ -0,0 +1,83 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "filecopy.h" +#define INCOMING_DIR_ROOT "/home/user/incoming" +int prepare_creds_return_uid(char *username) +{ + struct passwd *pwd; + pwd = getpwnam(username); + if (!pwd) { + perror("getpwnam"); + exit(1); + } + setenv("HOME", pwd->pw_dir, 1); + setenv("USER", username, 1); + setgid(pwd->pw_gid); + initgroups(username, pwd->pw_gid); + setfsuid(pwd->pw_uid); + return pwd->pw_uid; +} + +void wait_for_child(int statusfd) +{ + int status; + if (read(statusfd, &status, sizeof status)!=sizeof status) + gui_fatal("File copy error: Internal error reading status from unpacker"); + errno = status; + switch (status) { + case LEGAL_EOF: break; + case 0: gui_fatal("File copy: Connection terminated unexpectedly"); break; + case EINVAL: gui_fatal("File copy: Corrupted data from packer"); break; + case EEXIST: gui_fatal("File copy: not overwriting existing file. Clean ~/incoming, and retry copy"); break; + default: gui_fatal("File copy"); + } +} + +extern void do_unpack(int); + +int main(int argc, char ** argv) +{ + char *incoming_dir; + int pipefds[2]; + int uid; + + pipe(pipefds); + + uid = prepare_creds_return_uid("user"); + + mkdir(INCOMING_DIR_ROOT, 0700); + asprintf(&incoming_dir, "%s/from-%s", INCOMING_DIR_ROOT, argv[1]); + mkdir(incoming_dir, 0700); + if (chdir(incoming_dir)) + gui_fatal("Error chdir to %s", incoming_dir); + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + if (chroot(incoming_dir)) //impossible + gui_fatal("Error chroot to %s", incoming_dir); + setuid(uid); + close(pipefds[0]); + do_unpack(pipefds[1]); + exit(0); + default:; + } + + setuid(uid); + close(pipefds[1]); + wait_for_child(pipefds[0]); + + return 0; +} diff --git a/appvm/unpack.c b/appvm/unpack.c new file mode 100644 index 0000000..c0353c1 --- /dev/null +++ b/appvm/unpack.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "filecopy.h" + +char namebuf[MAX_PATH_LENGTH]; +void notify_progress(int p1, int p2) +{ +} + +int global_status_fd; +void do_exit(int code) +{ + int codebuf = code; + write(global_status_fd, &codebuf, sizeof codebuf); + exit(0); +} + + +void fix_times_and_perms(struct file_header *hdr, char *name) +{ + struct timeval times[2] = + { {hdr->atime, hdr->atime_nsec / 1000}, {hdr->mtime, + hdr->mtime_nsec / 1000} + }; + if (chmod(name, hdr->mode & 07777)) + do_exit(errno); + if (utimes(name, times)) + do_exit(errno); +} + + + +void process_one_file_reg(struct file_header *hdr, char *name) +{ + char *ret; + int fdout = + open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); + if (fdout < 0) + do_exit(errno); + ret = copy_file(fdout, 0, hdr->filelen); + if (ret) + do_exit(errno); + close(fdout); + fix_times_and_perms(hdr, name); +} + + +void process_one_file_dir(struct file_header *hdr, char *name) +{ + if (mkdir(name, 0700) && errno != EEXIST) + do_exit(errno); + fix_times_and_perms(hdr, name); +} + +void process_one_file_link(struct file_header *hdr, char *name) +{ + char content[MAX_PATH_LENGTH]; + if (hdr->filelen > MAX_PATH_LENGTH - 1) + do_exit(ENAMETOOLONG); + if (!read_all(0, content, hdr->filelen)) + do_exit(errno); + content[hdr->filelen] = 0; + if (symlink(content, name)) + do_exit(errno); + +} + +void process_one_file(struct file_header *hdr) +{ + if (hdr->namelen > MAX_PATH_LENGTH - 1) + do_exit(ENAMETOOLONG); + if (!read_all(0, namebuf, hdr->namelen)) + do_exit(errno); + namebuf[hdr->namelen] = 0; + if (S_ISREG(hdr->mode)) + process_one_file_reg(hdr, namebuf); + else if (S_ISLNK(hdr->mode)) + process_one_file_link(hdr, namebuf); + else if (S_ISDIR(hdr->mode)) + process_one_file_dir(hdr, namebuf); + else + do_exit(EINVAL); +} + +void do_unpack(int fd) +{ + global_status_fd = fd; + struct file_header hdr; + while (read_all(0, &hdr, sizeof hdr)) + process_one_file(&hdr); + if (errno) + do_exit(errno); + else + do_exit(LEGAL_EOF); +} diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 3023ffa..f3c875d 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -76,7 +76,7 @@ cp qubes_timestamp qvm-copy-to-vm qvm-open-in-dvm qvm-open-in-dvm2 $RPM_BUILD_RO mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes cp qubes_add_pendrive_script qubes_penctl qvm-copy-to-vm.kde $RPM_BUILD_ROOT/usr/lib/qubes cp ../qrexec/qrexec_agent $RPM_BUILD_ROOT/usr/lib/qubes -cp dvm_file_editor qfile-agent qfile-agent-dvm $RPM_BUILD_ROOT/usr/lib/qubes +cp dvm_file_editor qfile-agent qfile-agent-dvm qfile-unpacker $RPM_BUILD_ROOT/usr/lib/qubes ln -s /usr/bin/qvm-open-in-dvm $RPM_BUILD_ROOT/usr/lib/qubes/qvm-dvm-transfer cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir} @@ -218,6 +218,7 @@ rm -rf $RPM_BUILD_ROOT /usr/lib/qubes/qrexec_agent /usr/lib/qubes/qfile-agent /usr/lib/qubes/qfile-agent-dvm +/usr/lib/qubes/qfile-unpacker /etc/udev/rules.d/qubes.rules /etc/sysconfig/iptables /var/lib/qubes