From f3428531a87961b669783357b7295f2491305a15 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 4 Mar 2011 16:32:58 +0100 Subject: [PATCH 01/30] qrexec* tools, initial version --- rpm_spec/core-appvm.spec | 3 +++ rpm_spec/core-netvm.spec | 3 +++ 2 files changed, 6 insertions(+) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index c9a009d..6dccb5f 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -60,6 +60,7 @@ fi %build make clean all make -C ../common +make -C ../qrexec %install @@ -72,6 +73,7 @@ mkdir -p $RPM_BUILD_ROOT/usr/bin cp qubes_timestamp qvm-copy-to-vm qvm-open-in-dvm $RPM_BUILD_ROOT/usr/bin 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 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} @@ -199,6 +201,7 @@ rm -rf $RPM_BUILD_ROOT %{kde_service_dir}/qvm-dvm.desktop %attr(4755,root,root) /usr/lib/qubes/qubes_penctl /usr/lib/qubes/qubes_add_pendrive_script +/usr/lib/qubes/qrexec_agent /etc/udev/rules.d/qubes.rules /etc/sysconfig/iptables /var/lib/qubes diff --git a/rpm_spec/core-netvm.spec b/rpm_spec/core-netvm.spec index 83d88c2..678da3a 100644 --- a/rpm_spec/core-netvm.spec +++ b/rpm_spec/core-netvm.spec @@ -50,6 +50,7 @@ fi %build +make -C ../qrexec %install @@ -61,6 +62,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/init.d cp qubes_core $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes +cp ../qrexec/qrexec_agent $RPM_BUILD_ROOT/usr/lib/qubes cp ../common/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes cp ../common/qubes_fix_nm_conf.sh $RPM_BUILD_ROOT/usr/lib/qubes mkdir -p $RPM_BUILD_ROOT/etc/dhclient.d @@ -175,6 +177,7 @@ rm -rf $RPM_BUILD_ROOT /etc/sysconfig/iptables /etc/init.d/qubes_core /var/lib/qubes +/usr/lib/qubes/qrexec_agent /usr/lib/qubes/qubes_setup_dnat_to_ns /usr/lib/qubes/qubes_fix_nm_conf.sh /etc/dhclient.d/qubes_setup_dnat_to_ns.sh From 0f655f93441f4cba31247ffc2df4c30a323d4db9 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 4 Mar 2011 17:19:51 +0100 Subject: [PATCH 02/30] Start qrexec daemon and agent --- appvm/qubes_core | 2 ++ netvm/qubes_core | 3 +++ 2 files changed, 5 insertions(+) diff --git a/appvm/qubes_core b/appvm/qubes_core index 714727a..6b10029 100755 --- a/appvm/qubes_core +++ b/appvm/qubes_core @@ -85,6 +85,8 @@ start() MEMINFO_DELAY_USEC=100000 /usr/lib/qubes/meminfo-writer $MEM_CHANGE_THRESHOLD_KB $MEMINFO_DELAY_USEC & + /usr/lib/qubes/qrexec_agent 2>/var/log/qubes/qrexec_agent.log & + [ -x /rw/config/rc.local ] && /rw/config/rc.local success echo "" diff --git a/netvm/qubes_core b/netvm/qubes_core index dbfaad7..d7f8594 100755 --- a/netvm/qubes_core +++ b/netvm/qubes_core @@ -28,6 +28,9 @@ start() echo "NS2=$secondary_dns" >> /var/run/qubes/qubes_ns /usr/lib/qubes/qubes_setup_dnat_to_ns echo "1" > /proc/sys/net/ipv4/ip_forward + + /usr/lib/qubes/qrexec_agent 2>/var/log/qubes/qrexec_agent.log & + success echo "" return 0 From ffb0fe1d872ffec9306fbecd896abc47baf574b8 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Mon, 7 Mar 2011 16:13:15 +0100 Subject: [PATCH 03/30] added "make -C qrexec clean" --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 01085b2..5601dcd 100644 --- a/Makefile +++ b/Makefile @@ -27,3 +27,4 @@ clean: (cd dom0/restore && make clean) (cd dom0/qmemman && make clean) (cd common && make clean) + make -C qrexec clean From 06c0bd007c0c5ff1562381d7b0df6180e8b8ca71 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 8 Mar 2011 12:24:47 +0100 Subject: [PATCH 04/30] Moved vchan and u2mfn code to core. --- Makefile | 1 + rpm_spec/core-appvm.spec | 26 ++++++++++++++++++++++++++ rpm_spec/core-netvm.spec | 7 +++++++ 3 files changed, 34 insertions(+) diff --git a/Makefile b/Makefile index 5601dcd..bab9705 100644 --- a/Makefile +++ b/Makefile @@ -28,3 +28,4 @@ clean: (cd dom0/qmemman && make clean) (cd common && make clean) make -C qrexec clean + make -C vchan clean diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 6dccb5f..8ca5dae 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -61,6 +61,8 @@ fi make clean all make -C ../common make -C ../qrexec +make -C ../vchan +make -C ../u2mfn %install @@ -98,6 +100,14 @@ cp xorg-preload-apps.conf $RPM_BUILD_ROOT/etc/X11 mkdir -p $RPM_BUILD_ROOT/home_volatile/user chown 500:500 $RPM_BUILD_ROOT/home_volatile/user +install -D ../vchan/libvchan.h $RPM_BUILD_ROOT/usr/include/libvchan.h +install -D ../u2mfn/u2mfnlib.h $RPM_BUILD_ROOT/usr/include/u2mfnlib.h +install -D ../u2mfn/u2mfn-kernel.h $RPM_BUILD_ROOT/usr/include/u2mfn-kernel.h + +install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so +install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so + + %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -214,3 +224,19 @@ rm -rf $RPM_BUILD_ROOT %dir /home_volatile %attr(700,user,user) /home_volatile/user /etc/X11/xorg-preload-apps.conf +/usr/include/libvchan.h +%{_libdir}/libvchan.so +%{_libdir}/libu2mfn.so + + +%package devel +Summary: Include files for qubes core libraries +License: GPL v2 only +Group: Development/Sources + +%description devel + +%files devel +/usr/include/libvchan.h +/usr/include/u2mfnlib.h +/usr/include/u2mfn-kernel.h diff --git a/rpm_spec/core-netvm.spec b/rpm_spec/core-netvm.spec index 678da3a..6c88fca 100644 --- a/rpm_spec/core-netvm.spec +++ b/rpm_spec/core-netvm.spec @@ -51,6 +51,8 @@ fi %build make -C ../qrexec +make -C ../vchan +make -C ../u2mfn %install @@ -78,6 +80,9 @@ cp ../common/serial.conf $RPM_BUILD_ROOT/var/lib/qubes/ mkdir -p $RPM_BUILD_ROOT/var/run/qubes mkdir -p $RPM_BUILD_ROOT/etc/xen/scripts cp ../common/vif-route-qubes $RPM_BUILD_ROOT/etc/xen/scripts +install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so +install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so + %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -186,3 +191,5 @@ rm -rf $RPM_BUILD_ROOT /sbin/qubes_serial_login /etc/xen/scripts/vif-route-qubes %dir /var/run/qubes +%{_libdir}/libvchan.so +%{_libdir}/libu2mfn.so From 9f3fcc862a84badf3d23bce79954d13c9e680e25 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Thu, 10 Mar 2011 15:41:31 +0100 Subject: [PATCH 05/30] Implemented mechanism to trigger predefined execution in dom0. Processes in AppVM can ask qrexec-agent to send a MSG_AGENT_TO_SERVER_TRIGGER_EXEC message to qrexec-daemon. The latter will execute predefined program. It is useful for the purpose of file copy; the predefined program will create a connected qfile-daemon<->qfile-agent pair. --- rpm_spec/core-appvm.spec | 2 ++ rpm_spec/core-netvm.spec | 2 ++ 2 files changed, 4 insertions(+) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 8ca5dae..5d3038f 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -107,6 +107,7 @@ install -D ../u2mfn/u2mfn-kernel.h $RPM_BUILD_ROOT/usr/include/u2mfn-kernel.h install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so +mkdir -p $RPM_BUILD_ROOT/var/run/qubes %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -227,6 +228,7 @@ rm -rf $RPM_BUILD_ROOT /usr/include/libvchan.h %{_libdir}/libvchan.so %{_libdir}/libu2mfn.so +%dir /var/run/qubes %package devel diff --git a/rpm_spec/core-netvm.spec b/rpm_spec/core-netvm.spec index 6c88fca..84df5cb 100644 --- a/rpm_spec/core-netvm.spec +++ b/rpm_spec/core-netvm.spec @@ -83,6 +83,7 @@ cp ../common/vif-route-qubes $RPM_BUILD_ROOT/etc/xen/scripts install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so +mkdir -p $RPM_BUILD_ROOT/var/run/qubes %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -193,3 +194,4 @@ rm -rf $RPM_BUILD_ROOT %dir /var/run/qubes %{_libdir}/libvchan.so %{_libdir}/libu2mfn.so +%dir /var/run/qubes From 7342404846f0413b32495fc8b523942944df1774 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Thu, 10 Mar 2011 16:50:40 +0100 Subject: [PATCH 06/30] Added dvm_file_editor. It works with qrexec - reads/writes data from stdin/stdout. --- appvm/Makefile | 6 +- appvm/dvm2.h | 1 + appvm/dvm_file_editor.c | 126 +++++++++++++++++++++++++++++++++++++++ rpm_spec/core-appvm.spec | 2 + 4 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 appvm/dvm2.h create mode 100644 appvm/dvm_file_editor.c diff --git a/appvm/Makefile b/appvm/Makefile index 6bb1dea..e247ce9 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,6 +1,8 @@ CC=gcc CFLAGS=-Wall -all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm +all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor +dvm_file_editor: dvm_file_editor.o + $(CC) -o dvm_file_editor dvm_file_editor.o qubes_penctl: qubes_penctl.o $(CC) -o qubes_penctl qubes_penctl.o -lxenstore qubes_add_pendrive_script: qubes_add_pendrive_script.o @@ -8,4 +10,4 @@ qubes_add_pendrive_script: qubes_add_pendrive_script.o qvm-open-in-dvm: qvm-open-in-dvm.o $(CC) -o qvm-open-in-dvm qvm-open-in-dvm.o -lxenstore clean: - rm -f qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm *.o *~ + rm -f dvm_file_editor qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm *.o *~ diff --git a/appvm/dvm2.h b/appvm/dvm2.h new file mode 100644 index 0000000..837999c --- /dev/null +++ b/appvm/dvm2.h @@ -0,0 +1 @@ +#define DVM_FILENAME_SIZE 256 diff --git a/appvm/dvm_file_editor.c b/appvm/dvm_file_editor.c new file mode 100644 index 0000000..cadb450 --- /dev/null +++ b/appvm/dvm_file_editor.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include "dvm2.h" + +int write_all(int fd, void *buf, int size) +{ + int written = 0; + int ret; + while (written < size) { + ret = write(fd, (char *) buf + written, size - written); + if (ret <= 0) { + perror("write"); + return 0; + } + written += ret; + } +// fprintf(stderr, "sent %d bytes\n", size); + return 1; +} + +int read_all(int fd, void *buf, int size) +{ + int got_read = 0; + int ret; + while (got_read < size) { + ret = read(fd, (char *) buf + got_read, size - got_read); + if (ret == 0) { + fprintf(stderr, "EOF\n"); + return 0; + } + if (ret < 0) { + perror("read"); + return 0; + } + got_read += ret; + } +// fprintf(stderr, "read %d bytes\n", size); + return 1; +} + +char *get_filename() +{ + char buf[DVM_FILENAME_SIZE]; + static char retname[sizeof(buf) + sizeof("/tmp/")]; + if (!read_all(0, buf, sizeof(buf))) + exit(1); + if (index(buf, '/')) { + fprintf(stderr, "filename contains /"); + exit(1); + } + snprintf(retname, sizeof(retname), "/tmp/%s", buf); + return retname; +} + +void copy_all(int fdout, int fdin) +{ + int ret; + char buf[4096]; + for (;;) { + ret = read(fdin, buf, sizeof(buf)); + if (!ret) + break; + if (ret < 0) { + perror("read"); + exit(1); + } + if (!write_all(fdout, buf, ret)) { + perror("write"); + exit(1); + } + } +} + + +void copy_file(char *filename) +{ + int fd = open(filename, O_WRONLY | O_CREAT, 0600); + if (fd < 0) { + perror("open file"); + exit(1); + } + copy_all(fd, 0); + close(fd); +} + +void send_file_back(char * filename) +{ + int fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("open file"); + exit(1); + } + copy_all(1, fd); + close(fd); +} + +int +main() +{ + char cmdbuf[512]; + struct stat stat_pre, stat_post; + char *filename = get_filename(); + + copy_file(filename); + if (stat(filename, &stat_pre)) { + perror("stat pre"); + exit(1); + } + snprintf(cmdbuf, sizeof(cmdbuf), + "HOME=/home/user DISPLAY=:0 /usr/bin/mimeopen -n -M '%s' 2>&1 > /tmp/kde-open.log Date: Fri, 11 Mar 2011 11:34:07 +0100 Subject: [PATCH 07/30] Added DVM_SPOOL definition to dvm2.h --- appvm/dvm2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/appvm/dvm2.h b/appvm/dvm2.h index 837999c..0e5922c 100644 --- a/appvm/dvm2.h +++ b/appvm/dvm2.h @@ -1 +1,2 @@ #define DVM_FILENAME_SIZE 256 +#define DVM_SPOOL "/home/user/.dvmspool" From af0bd7a9b445b51a76cec533f8da13830935d221 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 11 Mar 2011 11:47:20 +0100 Subject: [PATCH 08/30] Moved ioall.c file to "common" --- common/ioall.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/ioall.h | 2 ++ 2 files changed, 63 insertions(+) create mode 100644 common/ioall.c create mode 100644 common/ioall.h diff --git a/common/ioall.c b/common/ioall.c new file mode 100644 index 0000000..ce550c7 --- /dev/null +++ b/common/ioall.c @@ -0,0 +1,61 @@ +/* + * The Qubes OS Project, http://www.qubes-os.org + * + * Copyright (C) 2010 Rafal Wojtczuk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include + +int write_all(int fd, void *buf, int size) +{ + int written = 0; + int ret; + while (written < size) { + ret = write(fd, (char *) buf + written, size - written); + if (ret <= 0) { + perror("write"); + return 0; + } + written += ret; + } +// fprintf(stderr, "sent %d bytes\n", size); + return 1; +} + +int read_all(int fd, void *buf, int size) +{ + int got_read = 0; + int ret; + while (got_read < size) { + ret = read(fd, (char *) buf + got_read, size - got_read); + if (ret == 0) { + fprintf(stderr, "EOF\n"); + return 0; + } + if (ret < 0) { + perror("read"); + return 0; + } + got_read += ret; + } +// fprintf(stderr, "read %d bytes\n", size); + return 1; +} diff --git a/common/ioall.h b/common/ioall.h new file mode 100644 index 0000000..1e76353 --- /dev/null +++ b/common/ioall.h @@ -0,0 +1,2 @@ +int write_all(int fd, void *buf, int size); +int read_all(int fd, void *buf, int size); From a750229be6ba7c6d2f2a1174b578695ccee9a3e2 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 11 Mar 2011 11:50:52 +0100 Subject: [PATCH 09/30] Make dvm_file_editor use ioall.c --- appvm/Makefile | 6 +++--- appvm/dvm_file_editor.c | 37 +------------------------------------ 2 files changed, 4 insertions(+), 39 deletions(-) diff --git a/appvm/Makefile b/appvm/Makefile index e247ce9..be08e07 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,8 +1,8 @@ CC=gcc -CFLAGS=-Wall +CFLAGS=-Wall -I../common all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor -dvm_file_editor: dvm_file_editor.o - $(CC) -o dvm_file_editor dvm_file_editor.o +dvm_file_editor: dvm_file_editor.o ../common/ioall.o + $(CC) -o dvm_file_editor dvm_file_editor.o ../common/ioall.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/dvm_file_editor.c b/appvm/dvm_file_editor.c index cadb450..fd60ca4 100644 --- a/appvm/dvm_file_editor.c +++ b/appvm/dvm_file_editor.c @@ -4,44 +4,9 @@ #include #include #include +#include #include "dvm2.h" -int write_all(int fd, void *buf, int size) -{ - int written = 0; - int ret; - while (written < size) { - ret = write(fd, (char *) buf + written, size - written); - if (ret <= 0) { - perror("write"); - return 0; - } - written += ret; - } -// fprintf(stderr, "sent %d bytes\n", size); - return 1; -} - -int read_all(int fd, void *buf, int size) -{ - int got_read = 0; - int ret; - while (got_read < size) { - ret = read(fd, (char *) buf + got_read, size - got_read); - if (ret == 0) { - fprintf(stderr, "EOF\n"); - return 0; - } - if (ret < 0) { - perror("read"); - return 0; - } - got_read += ret; - } -// fprintf(stderr, "read %d bytes\n", size); - return 1; -} - char *get_filename() { char buf[DVM_FILENAME_SIZE]; From dd014e4cab1ce3cb76ac96f05215011224d5d8bb Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 11 Mar 2011 11:54:39 +0100 Subject: [PATCH 10/30] Changed copy_all signature. --- appvm/dvm_file_editor.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/appvm/dvm_file_editor.c b/appvm/dvm_file_editor.c index fd60ca4..3cc8818 100644 --- a/appvm/dvm_file_editor.c +++ b/appvm/dvm_file_editor.c @@ -21,7 +21,7 @@ char *get_filename() return retname; } -void copy_all(int fdout, int fdin) +int copy_fd_all(int fdout, int fdin) { int ret; char buf[4096]; @@ -31,13 +31,14 @@ void copy_all(int fdout, int fdin) break; if (ret < 0) { perror("read"); - exit(1); + return 0; } if (!write_all(fdout, buf, ret)) { perror("write"); - exit(1); + return 0; } } + return 1; } @@ -48,7 +49,8 @@ void copy_file(char *filename) perror("open file"); exit(1); } - copy_all(fd, 0); + if (!copy_fd_all(fd, 0)) + exit(1); close(fd); } @@ -59,7 +61,8 @@ void send_file_back(char * filename) perror("open file"); exit(1); } - copy_all(1, fd); + if (!copy_fd_all(1, fd)) + exit(1); close(fd); } From 9d8e066a7fcd731165afa176a485396b2c06f500 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 11 Mar 2011 11:57:16 +0100 Subject: [PATCH 11/30] Move copy_all_fd from dvm_file_editor.c to ioall.c It is useful in e.g. qfile-agent-dvm. --- appvm/dvm_file_editor.c | 21 --------------------- common/ioall.c | 21 +++++++++++++++++++++ common/ioall.h | 1 + 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/appvm/dvm_file_editor.c b/appvm/dvm_file_editor.c index 3cc8818..4eed30b 100644 --- a/appvm/dvm_file_editor.c +++ b/appvm/dvm_file_editor.c @@ -21,27 +21,6 @@ char *get_filename() return retname; } -int copy_fd_all(int fdout, int fdin) -{ - int ret; - char buf[4096]; - for (;;) { - ret = read(fdin, buf, sizeof(buf)); - if (!ret) - break; - if (ret < 0) { - perror("read"); - return 0; - } - if (!write_all(fdout, buf, ret)) { - perror("write"); - return 0; - } - } - return 1; -} - - void copy_file(char *filename) { int fd = open(filename, O_WRONLY | O_CREAT, 0600); diff --git a/common/ioall.c b/common/ioall.c index ce550c7..1fca6f1 100644 --- a/common/ioall.c +++ b/common/ioall.c @@ -59,3 +59,24 @@ int read_all(int fd, void *buf, int size) // fprintf(stderr, "read %d bytes\n", size); return 1; } + +int copy_fd_all(int fdout, int fdin) +{ + int ret; + char buf[4096]; + for (;;) { + ret = read(fdin, buf, sizeof(buf)); + if (!ret) + break; + if (ret < 0) { + perror("read"); + return 0; + } + if (!write_all(fdout, buf, ret)) { + perror("write"); + return 0; + } + } + return 1; +} + diff --git a/common/ioall.h b/common/ioall.h index 1e76353..1a700c6 100644 --- a/common/ioall.h +++ b/common/ioall.h @@ -1,2 +1,3 @@ int write_all(int fd, void *buf, int size); int read_all(int fd, void *buf, int size); +int copy_fd_all(int fdout, int fdin); From f075e66a87e3dc66e66bb414f3fbf30cad2ab6d7 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Fri, 11 Mar 2011 12:44:19 +0100 Subject: [PATCH 12/30] Added qfile-agent-dvm.c Nations, rejoice. --- appvm/Makefile | 4 +- appvm/qfile-agent-dvm.c | 156 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 appvm/qfile-agent-dvm.c diff --git a/appvm/Makefile b/appvm/Makefile index be08e07..d6bfb6a 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,8 +1,10 @@ CC=gcc CFLAGS=-Wall -I../common -all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor +all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm 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 + $(CC) -o qfile-agent-dvm qfile-agent-dvm.o ../common/ioall.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-agent-dvm.c b/appvm/qfile-agent-dvm.c new file mode 100644 index 0000000..194d67c --- /dev/null +++ b/appvm/qfile-agent-dvm.c @@ -0,0 +1,156 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvm2.h" + +//the below usage of "system" is smelly, but should be fine - input comes from the same vm +void fatal(char *msg) +{ + char *errcmd; + asprintf(&errcmd, "DISPLAY=:0 kdialog --sorry 'qfile-agent-dvm: %s'", msg); + system(errcmd); + perror(msg); + exit(1); +} + +void nonfatal(char *msg) +{ + char *errcmd; + asprintf(&errcmd, "DISPLAY=:0 kdialog --sorry 'qfile-agent-dvm: %s'", msg); + system(errcmd); + fprintf(stderr, "%s", msg); +} + +void send_file(char *fname) +{ + char *base; + int fd = open(fname, O_RDONLY); + if (fd < 0) + fatal("open file_to_be_edited"); + base = rindex(fname, '/'); + if (!base) + base = fname; + else + base++; + if (strlen(base) >= DVM_FILENAME_SIZE) + base += strlen(base) - DVM_FILENAME_SIZE + 1; + if (!write_all(1, base, DVM_FILENAME_SIZE)) + fatal("send filename"); + if (!copy_fd_all(1, fd)) + fatal("send file"); + close(1); +} + +int copy_and_return_nonemptiness(int tmpfd) +{ + struct stat st; + if (!copy_fd_all(tmpfd, 0)) + fatal("receiving file"); + if (fstat(tmpfd, &st)) + fatal("fstat"); + close(tmpfd); + + return st.st_size; +} + +void recv_file_nowrite(char *fname) +{ + char *tempfile; + char *errmsg; + int tmpfd; + + asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX"); + tmpfd = mkstemp(tempfile); + if (tmpfd < 0) + fatal("unable to create any temporary file, aborting"); + if (!copy_and_return_nonemptiness(tmpfd)) { + unlink(tempfile); + return; + } + 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); + nonfatal(errmsg); +} + +void actually_recv_file(char *fname, char *tempfile, int tmpfd) +{ + if (!copy_and_return_nonemptiness(tmpfd)) { + unlink(tempfile); + return; + } + if (rename(tempfile, fname)) + fatal("rename"); +} + +void recv_file(char *fname) +{ + int tmpfd; + char *tempfile; + asprintf(&tempfile, "%s.XXXXXX", fname); + tmpfd = mkstemp(tempfile); + if (tmpfd < 0) + recv_file_nowrite(fname); + else + actually_recv_file(fname, tempfile, tmpfd); +} + +void talk_to_daemon(char *fname) +{ + send_file(fname); + recv_file(fname); +} + +void process_spoolentry(char *entry_name) +{ + char *abs_spool_entry_name; + int entry_fd; + struct stat st; + char *filename; + int entry_size; + asprintf(&abs_spool_entry_name, "%s/%s", DVM_SPOOL, entry_name); + entry_fd = open(abs_spool_entry_name, O_RDONLY); + unlink(abs_spool_entry_name); + if (entry_fd < 0 || fstat(entry_fd, &st)) + fatal("bad dvm_entry"); + entry_size = st.st_size; + filename = calloc(1, entry_size + DVM_FILENAME_SIZE); + if (!filename) + fatal("malloc"); + if (!read_all(entry_fd, filename, entry_size)) + fatal("read dvm entry"); + close(entry_fd); + talk_to_daemon(filename); +} + +void scan_spool(char *name) +{ + struct dirent *ent; + DIR *dir = opendir(name); + if (!dir) + fatal("opendir"); + while ((ent = readdir(dir))) { + char *fname = ent->d_name; + if (!strcmp(fname, ".") || !strcmp(fname, "..")) + continue; + process_spoolentry(fname); + break; + } + closedir(dir); +} + +int main() +{ + signal(SIGPIPE, SIG_IGN); + scan_spool(DVM_SPOOL); + return 0; +} From c52d8b54d57fcb64089102eac9ce1b8466ee53fd Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Mon, 14 Mar 2011 11:25:18 +0100 Subject: [PATCH 13/30] Added new qvm-open-in-dvm, aka qvm-open-in-dvm2 Small, childless bash script. --- appvm/qvm-dvm.desktop | 2 +- appvm/qvm-open-in-dvm2 | 40 ++++++++++++++++++++++++++++++++++++++++ rpm_spec/core-appvm.spec | 3 ++- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100755 appvm/qvm-open-in-dvm2 diff --git a/appvm/qvm-dvm.desktop b/appvm/qvm-dvm.desktop index a7f5ad7..67f9ea5 100644 --- a/appvm/qvm-dvm.desktop +++ b/appvm/qvm-dvm.desktop @@ -4,7 +4,7 @@ Type=Service X-KDE-ServiceTypes=KonqPopupMenu/Plugin,all/allfiles [Desktop Action QvmDvm] -Exec=/usr/bin/qvm-open-in-dvm disposable %U +Exec=/usr/bin/qvm-open-in-dvm2 %U Icon=kget Name=Open In DisposableVM diff --git a/appvm/qvm-open-in-dvm2 b/appvm/qvm-open-in-dvm2 new file mode 100755 index 0000000..eb0d4e2 --- /dev/null +++ b/appvm/qvm-open-in-dvm2 @@ -0,0 +1,40 @@ +#!/bin/bash +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +if ! [ $# = 1 ] ; then + echo "Usage: $0 filename" + exit 1 +fi + +FILE="$1" +if ! [ "X""${FILE:0:1}" = X/ ] ; then + FILE="$PWD"/"$1" +fi + +DVMSPOOL=/home/user/.dvmspool +if ! [ -e $DVMSPOOL ] ; then + mkdir $DVMSPOOL || exit 1 +fi + +echo -n "$FILE" > $DVMSPOOL/req.$$ +echo -n DVMR > /var/run/qubes/qrexec_agent + diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index f7cc731..b947b83 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -72,7 +72,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/init.d cp qubes_core $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/bin -cp qubes_timestamp qvm-copy-to-vm qvm-open-in-dvm $RPM_BUILD_ROOT/usr/bin +cp qubes_timestamp qvm-copy-to-vm qvm-open-in-dvm qvm-open-in-dvm2 $RPM_BUILD_ROOT/usr/bin 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 @@ -207,6 +207,7 @@ rm -rf $RPM_BUILD_ROOT /usr/bin/qvm-copy-to-vm /usr/lib/qubes/qvm-copy-to-vm.kde %attr(4755,root,root) /usr/bin/qvm-open-in-dvm +/usr/bin/qvm-open-in-dvm2 /usr/lib/qubes/qvm-dvm-transfer /usr/lib/qubes/meminfo-writer /usr/lib/qubes/dvm_file_editor From e1739269ff46796c3c6e3664ecbbb77f111694eb Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 10:36:50 +0100 Subject: [PATCH 14/30] Make sure read_all sets errno to 0 at EOF. --- common/ioall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/ioall.c b/common/ioall.c index 1fca6f1..413477f 100644 --- a/common/ioall.c +++ b/common/ioall.c @@ -23,6 +23,7 @@ #include #include #include +#include int write_all(int fd, void *buf, int size) { @@ -47,6 +48,7 @@ int read_all(int fd, void *buf, int size) while (got_read < size) { ret = read(fd, (char *) buf + got_read, size - got_read); if (ret == 0) { + errno = 0; fprintf(stderr, "EOF\n"); return 0; } From 237ce31f27a1a55ba0d5a31cf18026f1083a463f Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 13:00:12 +0100 Subject: [PATCH 15/30] Handy gui_fatal() etc routines. --- common/gui-fatal.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ common/gui-fatal.h | 2 ++ 2 files changed, 52 insertions(+) create mode 100644 common/gui-fatal.c create mode 100644 common/gui-fatal.h diff --git a/common/gui-fatal.c b/common/gui-fatal.c new file mode 100644 index 0000000..ed2b3d4 --- /dev/null +++ b/common/gui-fatal.c @@ -0,0 +1,50 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +static void fix_display() +{ + setenv("DISPLAY", ":0", 1); +} + +static void produce_message(char * type, const char *fmt, va_list args) +{ + char *kdialog_msg; + char buf[1024]; + (void) vsnprintf(buf, sizeof(buf), fmt, args); + asprintf(&kdialog_msg, "%s: %s: %s (error type: %s)", + program_invocation_short_name, type, buf, strerror(errno)); + fprintf(stderr, "%s", kdialog_msg); + switch (fork()) { + case -1: + exit(1); //what else + case 0: + fix_display(); + execlp("kdialog", "kdialog", "--sorry", kdialog_msg, NULL); + exit(1); + default:; + } +} + +void gui_fatal(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + produce_message("Fatal error", fmt, args); + va_end(args); + exit(1); +} + +void gui_nonfatal(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + produce_message("Information", fmt, args); + va_end(args); +} diff --git a/common/gui-fatal.h b/common/gui-fatal.h new file mode 100644 index 0000000..de9799f --- /dev/null +++ b/common/gui-fatal.h @@ -0,0 +1,2 @@ +void gui_fatal(const char *fmt, ...); +void gui_nonfatal(const char *fmt, ...); From 29ffbfd474982ed7f393a68fa0a9af37959e8b42 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 13:12:21 +0100 Subject: [PATCH 16/30] Use gui_fatal in qfile-agent-dvm.c --- appvm/Makefile | 4 ++-- appvm/qfile-agent-dvm.c | 43 +++++++++++++---------------------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/appvm/Makefile b/appvm/Makefile index d6bfb6a..3f81fb9 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -3,8 +3,8 @@ CFLAGS=-Wall -I../common all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm 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 - $(CC) -o qfile-agent-dvm qfile-agent-dvm.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 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-agent-dvm.c b/appvm/qfile-agent-dvm.c index 194d67c..5db430c 100644 --- a/appvm/qfile-agent-dvm.c +++ b/appvm/qfile-agent-dvm.c @@ -9,32 +9,15 @@ #include #include #include +#include #include "dvm2.h" -//the below usage of "system" is smelly, but should be fine - input comes from the same vm -void fatal(char *msg) -{ - char *errcmd; - asprintf(&errcmd, "DISPLAY=:0 kdialog --sorry 'qfile-agent-dvm: %s'", msg); - system(errcmd); - perror(msg); - exit(1); -} - -void nonfatal(char *msg) -{ - char *errcmd; - asprintf(&errcmd, "DISPLAY=:0 kdialog --sorry 'qfile-agent-dvm: %s'", msg); - system(errcmd); - fprintf(stderr, "%s", msg); -} - void send_file(char *fname) { char *base; int fd = open(fname, O_RDONLY); if (fd < 0) - fatal("open file_to_be_edited"); + gui_fatal("open %s", fname); base = rindex(fname, '/'); if (!base) base = fname; @@ -43,9 +26,9 @@ void send_file(char *fname) if (strlen(base) >= DVM_FILENAME_SIZE) base += strlen(base) - DVM_FILENAME_SIZE + 1; if (!write_all(1, base, DVM_FILENAME_SIZE)) - fatal("send filename"); + gui_fatal("send filename to dispVM"); if (!copy_fd_all(1, fd)) - fatal("send file"); + gui_fatal("send file to dispVM"); close(1); } @@ -53,9 +36,9 @@ int copy_and_return_nonemptiness(int tmpfd) { struct stat st; if (!copy_fd_all(tmpfd, 0)) - fatal("receiving file"); + gui_fatal("receiving file from dispVM"); if (fstat(tmpfd, &st)) - fatal("fstat"); + gui_fatal("fstat"); close(tmpfd); return st.st_size; @@ -70,7 +53,7 @@ void recv_file_nowrite(char *fname) asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX"); tmpfd = mkstemp(tempfile); if (tmpfd < 0) - fatal("unable to create any temporary file, aborting"); + gui_fatal("unable to create any temporary file, aborting"); if (!copy_and_return_nonemptiness(tmpfd)) { unlink(tempfile); return; @@ -79,7 +62,7 @@ void recv_file_nowrite(char *fname) "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); - nonfatal(errmsg); + gui_nonfatal(errmsg); } void actually_recv_file(char *fname, char *tempfile, int tmpfd) @@ -89,7 +72,7 @@ void actually_recv_file(char *fname, char *tempfile, int tmpfd) return; } if (rename(tempfile, fname)) - fatal("rename"); + gui_fatal("rename"); } void recv_file(char *fname) @@ -121,13 +104,13 @@ void process_spoolentry(char *entry_name) entry_fd = open(abs_spool_entry_name, O_RDONLY); unlink(abs_spool_entry_name); if (entry_fd < 0 || fstat(entry_fd, &st)) - fatal("bad dvm_entry"); + gui_fatal("bad dvm_entry"); entry_size = st.st_size; filename = calloc(1, entry_size + DVM_FILENAME_SIZE); if (!filename) - fatal("malloc"); + gui_fatal("malloc"); if (!read_all(entry_fd, filename, entry_size)) - fatal("read dvm entry"); + gui_fatal("read dvm entry %s", abs_spool_entry_name); close(entry_fd); talk_to_daemon(filename); } @@ -137,7 +120,7 @@ void scan_spool(char *name) struct dirent *ent; DIR *dir = opendir(name); if (!dir) - fatal("opendir"); + gui_fatal("opendir %s", name); while ((ent = readdir(dir))) { char *fname = ent->d_name; if (!strcmp(fname, ".") || !strcmp(fname, "..")) From 17fb4614e78b3ea2835424428b66b62458756081 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 16:07:00 +0100 Subject: [PATCH 17/30] Added qfile-agent --- appvm/Makefile | 6 +- appvm/copy_file.c | 28 ++++++ appvm/filecopy.h | 18 ++++ appvm/qfile-agent.c | 201 +++++++++++++++++++++++++++++++++++++++ rpm_spec/core-appvm.spec | 3 +- 5 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 appvm/copy_file.c create mode 100644 appvm/filecopy.h create mode 100644 appvm/qfile-agent.c diff --git a/appvm/Makefile b/appvm/Makefile index 3f81fb9..c6f4d25 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,10 +1,12 @@ CC=gcc CFLAGS=-Wall -I../common -all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm +all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm dvm_file_editor qfile-agent-dvm qfile-agent 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 + $(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 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/copy_file.c b/appvm/copy_file.c new file mode 100644 index 0000000..5f7fc79 --- /dev/null +++ b/appvm/copy_file.c @@ -0,0 +1,28 @@ +#include +#include +extern void notify_progress(int, int); + +char * copy_file(int outfd, int infd, long long size) +{ + char buf[4096]; + long long written = 0; + int ret; + int count; + while (written < size) { + if (size - written > sizeof(buf)) + count = sizeof buf; + else + count = size - written; + ret = read(infd, buf, count); + if (!ret) + return("EOF while reading file"); + if (ret < 0) + return("error reading file"); + if (!write_all(outfd, buf, ret)) + return("error writing file content"); + notify_progress(ret, 0); + written += ret; + } + return NULL; +} + diff --git a/appvm/filecopy.h b/appvm/filecopy.h new file mode 100644 index 0000000..b4f6638 --- /dev/null +++ b/appvm/filecopy.h @@ -0,0 +1,18 @@ +#define FILECOPY_SPOOL "/home/user/.filecopyspool" +#define FILECOPY_VMNAME_SIZE 32 +#define PROGRESS_NOTIFY_DELTA (15*1000*1000) +#define MAX_PATH_LENGTH 16384 + +#define LEGAL_EOF 31415926 + +struct file_header { +unsigned int namelen; +unsigned int mode; +unsigned long long filelen; +unsigned int atime; +unsigned int atime_nsec; +unsigned int mtime; +unsigned int mtime_nsec; +}; + +char * copy_file(int outfd, int infd, long long size); diff --git a/appvm/qfile-agent.c b/appvm/qfile-agent.c new file mode 100644 index 0000000..b4ba354 --- /dev/null +++ b/appvm/qfile-agent.c @@ -0,0 +1,201 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "filecopy.h" + +char *client_flags; +void do_notify_progress(long long total) +{ + FILE *progress; + if (!client_flags[0]) + return; + progress = fopen(client_flags, "w"); + if (!progress) + return; + fprintf(progress, "%d %lld", getpid(), total); + fclose(progress); +} + +void notify_progress(int size, int force) +{ + static long long total = 0; + static long long prev_total = 0; + total += size; + if (total > prev_total + PROGRESS_NOTIFY_DELTA || force) { + do_notify_progress(total); + prev_total = total; + } +} + +void write_headers(struct file_header *hdr, char *filename) +{ + if (!write_all(1, hdr, sizeof(*hdr)) + || !write_all(1, filename, hdr->namelen)) + gui_fatal("writing file headers to remove AppVM"); +} + +int single_file_processor(char *filename, struct stat *st) +{ + struct file_header hdr; + int fd; + mode_t mode = st->st_mode; + + hdr.namelen = strlen(filename) + 1; + hdr.mode = mode; + hdr.atime = st->st_atim.tv_sec; + hdr.atime_nsec = st->st_atim.tv_nsec; + hdr.mtime = st->st_mtim.tv_sec; + hdr.mtime_nsec = st->st_mtim.tv_nsec; + + if (S_ISREG(mode)) { + char * ret; + fd = open(filename, O_RDONLY); + if (!fd) + gui_fatal("open %s", filename); + hdr.filelen = st->st_size; + write_headers(&hdr, filename); + ret=copy_file(1, fd, hdr.filelen); + if (ret) + gui_fatal("Copying file %s: %s", filename, ret); + close(fd); + } + if (S_ISDIR(mode)) { + hdr.filelen = 0; + write_headers(&hdr, filename); + } + if (S_ISLNK(mode)) { + char name[st->st_size + 1]; + if (readlink(filename, name, sizeof(name)) != st->st_size) + gui_fatal("readlink %s", filename); + hdr.filelen = st->st_size + 1; + write_headers(&hdr, filename); + if (!write_all(1, name, st->st_size + 1)) + gui_fatal("write to remote VM"); + } + return 0; +} + +int do_fs_walk(char *file) +{ + char *newfile; + struct stat st; + struct dirent *ent; + DIR *dir; + + if (lstat(file, &st)) + gui_fatal("stat %s", file); + single_file_processor(file, &st); + if (!S_ISDIR(st.st_mode)) + return 0; + dir = opendir(file); + if (!dir) + gui_fatal("opendir %s", file); + while ((ent = readdir(dir))) { + char *fname = ent->d_name; + if (!strcmp(fname, ".") || !strcmp(fname, "..")) + continue; + asprintf(&newfile, "%s/%s", file, fname); + do_fs_walk(newfile); + free(newfile); + } + closedir(dir); + // directory metadata is resent; this makes the code simple, + // and the atime/mtime is set correctly at the second time + single_file_processor(file, &st); + return 0; +} + +void send_vmname(char *vmname) +{ + char buf[FILECOPY_VMNAME_SIZE]; + memset(buf, 0, sizeof(buf)); + strncat(buf, vmname, sizeof(buf) - 1); + if (!write_all(1, buf, sizeof buf)) + gui_fatal("writing vmname to remote VM"); +} + +char *get_item(char *data, char **current, int size) +{ + char *ret; + if ((unsigned long) *current >= (unsigned long) data + size) + return NULL; + ret = *current; + *current += strlen(ret) + 1; + return ret; +} + +void parse_entry(char *data, int datasize) +{ + char *current = data; + char *vmname, *entry, *sep; + vmname = get_item(data, ¤t, datasize); + client_flags = get_item(data, ¤t, datasize); + notify_progress(0, 1); + send_vmname(vmname); + while ((entry = get_item(data, ¤t, datasize))) { + sep = rindex(entry, '/'); + if (!sep) + gui_fatal("Internal error: nonabsolute filenames not allowed"); + *sep = 0; + if (entry[0] == 0) + chdir("/"); + else if (chdir(entry)) + gui_fatal("chdir to %s", entry); + do_fs_walk(sep + 1); + } + notify_progress(0, 1); +} + +void process_spoolentry(char *entry_name) +{ + char *abs_spool_entry_name; + int entry_fd; + struct stat st; + char *entry; + int entry_size; + asprintf(&abs_spool_entry_name, "%s/%s", FILECOPY_SPOOL, + entry_name); + entry_fd = open(abs_spool_entry_name, O_RDONLY); + unlink(abs_spool_entry_name); + if (entry_fd < 0 || fstat(entry_fd, &st)) + gui_fatal("bad file copy spool entry"); + entry_size = st.st_size; + entry = calloc(1, entry_size + 1); + if (!entry) + gui_fatal("malloc"); + if (!read_all(entry_fd, entry, entry_size)) + gui_fatal("read filecopy entry"); + close(entry_fd); + parse_entry(entry, entry_size); +} + +void scan_spool(char *name) +{ + struct dirent *ent; + DIR *dir = opendir(name); + if (!dir) + gui_fatal("opendir %s", name); + while ((ent = readdir(dir))) { + char *fname = ent->d_name; + if (fname[0] != '.') + process_spoolentry(fname); + break; + } + closedir(dir); +} + +int main() +{ + signal(SIGPIPE, SIG_IGN); + scan_spool(FILECOPY_SPOOL); + return 0; +} diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index b947b83..df0b590 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 $RPM_BUILD_ROOT/usr/lib/qubes +cp dvm_file_editor qfile-agent $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} @@ -216,6 +216,7 @@ rm -rf $RPM_BUILD_ROOT %attr(4755,root,root) /usr/lib/qubes/qubes_penctl /usr/lib/qubes/qubes_add_pendrive_script /usr/lib/qubes/qrexec_agent +/usr/lib/qubes/qfile-agent /etc/udev/rules.d/qubes.rules /etc/sysconfig/iptables /var/lib/qubes From b459bcbca019f80fa90c70f5e7d4589e4b51a26a Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 16:19:42 +0100 Subject: [PATCH 18/30] Package qfile-agent-dvm, too. --- rpm_spec/core-appvm.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index df0b590..3023ffa 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 $RPM_BUILD_ROOT/usr/lib/qubes +cp dvm_file_editor qfile-agent qfile-agent-dvm $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} @@ -217,6 +217,7 @@ rm -rf $RPM_BUILD_ROOT /usr/lib/qubes/qubes_add_pendrive_script /usr/lib/qubes/qrexec_agent /usr/lib/qubes/qfile-agent +/usr/lib/qubes/qfile-agent-dvm /etc/udev/rules.d/qubes.rules /etc/sysconfig/iptables /var/lib/qubes From 31c7a7a1c9357ef2ac906c9f03d5f34607f75112 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 15 Mar 2011 16:43:43 +0100 Subject: [PATCH 19/30] Added qfile-unpacker and qfile-daemon --- appvm/Makefile | 4 +- appvm/qfile-unpacker.c | 83 ++++++++++++++++++++++++++++++++ appvm/unpack.c | 101 +++++++++++++++++++++++++++++++++++++++ rpm_spec/core-appvm.spec | 3 +- 4 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 appvm/qfile-unpacker.c create mode 100644 appvm/unpack.c 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 From f370fdab66b280a9aa01467eab274a3e124239f2 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 10:11:55 +0100 Subject: [PATCH 20/30] Build filecopy tools with -g. --- appvm/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appvm/Makefile b/appvm/Makefile index c1abcfa..56f9091 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,14 +1,14 @@ CC=gcc -CFLAGS=-Wall -I../common +CFLAGS=-g -Wall -I../common 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 + $(CC) -g -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 + $(CC) -g -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 + $(CC) -g -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 + $(CC) -g -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 From cdc5756f79b65872e7bd14d5513a36e23718794d Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 10:14:39 +0100 Subject: [PATCH 21/30] Scan filecopy sppool properly. --- appvm/qfile-agent.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appvm/qfile-agent.c b/appvm/qfile-agent.c index b4ba354..7ab2639 100644 --- a/appvm/qfile-agent.c +++ b/appvm/qfile-agent.c @@ -186,9 +186,10 @@ void scan_spool(char *name) gui_fatal("opendir %s", name); while ((ent = readdir(dir))) { char *fname = ent->d_name; - if (fname[0] != '.') + if (fname[0] != '.') { process_spoolentry(fname); - break; + break; + } } closedir(dir); } From 337d479e399b6c4e635fabc261f4e96b483db4e8 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 10:48:27 +0100 Subject: [PATCH 22/30] qfile-agent: Handle filenames with trailing slash properly. --- appvm/qfile-agent.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/appvm/qfile-agent.c b/appvm/qfile-agent.c index 7ab2639..71c86e5 100644 --- a/appvm/qfile-agent.c +++ b/appvm/qfile-agent.c @@ -57,15 +57,15 @@ int single_file_processor(char *filename, struct stat *st) hdr.mtime_nsec = st->st_mtim.tv_nsec; if (S_ISREG(mode)) { - char * ret; + char *ret; fd = open(filename, O_RDONLY); if (!fd) gui_fatal("open %s", filename); hdr.filelen = st->st_size; write_headers(&hdr, filename); - ret=copy_file(1, fd, hdr.filelen); + ret = copy_file(1, fd, hdr.filelen); if (ret) - gui_fatal("Copying file %s: %s", filename, ret); + gui_fatal("Copying file %s: %s", filename, ret); close(fd); } if (S_ISDIR(mode)) { @@ -142,10 +142,13 @@ void parse_entry(char *data, int datasize) notify_progress(0, 1); send_vmname(vmname); while ((entry = get_item(data, ¤t, datasize))) { - sep = rindex(entry, '/'); - if (!sep) - gui_fatal("Internal error: nonabsolute filenames not allowed"); - *sep = 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) chdir("/"); else if (chdir(entry)) @@ -188,8 +191,8 @@ void scan_spool(char *name) char *fname = ent->d_name; if (fname[0] != '.') { process_spoolentry(fname); - break; - } + break; + } } closedir(dir); } From de799e1b775ee035535705026560e2333567aff1 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 10:50:11 +0100 Subject: [PATCH 23/30] New qvm-copy-to-vm, aka qvm-copy-to-vm2 --- appvm/qvm-copy-to-vm2 | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 appvm/qvm-copy-to-vm2 diff --git a/appvm/qvm-copy-to-vm2 b/appvm/qvm-copy-to-vm2 new file mode 100755 index 0000000..ddababe --- /dev/null +++ b/appvm/qvm-copy-to-vm2 @@ -0,0 +1,47 @@ +#!/bin/sh +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +set -x + +if [ $# -lt 2 ] ; then + echo usage: $0 'vmname file [file]*' + exit 1 +fi + +FILECOPY_SPOOL=/home/user/.filecopyspool +if ! [ -e $FILECOPY_SPOOL ] ; then + mkdir $FILECOPY_SPOOL +fi + +REQ_FILE_TMP=$FILECOPY_SPOOL/.req.$$ +echo -ne "$1""\x00" > $REQ_FILE_TMP +echo -ne "$PROGRESS_FILE""\x00" >> $REQ_FILE_TMP + +shift +for FILE in "$@" ; do + if ! [ "X""${FILE:0:1}" = X/ ] ; then + FILE="$PWD"/"$FILE" + fi + echo -ne "$FILE""\x00" >> $REQ_FILE_TMP +done + +mv $REQ_FILE_TMP $FILECOPY_SPOOL/req.$$ +echo -n FCPR > /var/run/qubes/qrexec_agent From dadffda27c12862ec4ec7c66b93e1e19f0688af1 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 11:06:27 +0100 Subject: [PATCH 24/30] qfile-agent writes DONE to the status file at the end of work. --- appvm/qfile-agent.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/appvm/qfile-agent.c b/appvm/qfile-agent.c index 71c86e5..f7e27a9 100644 --- a/appvm/qfile-agent.c +++ b/appvm/qfile-agent.c @@ -12,8 +12,16 @@ #include #include "filecopy.h" +enum { + PROGRESS_FLAG_NORMAL, + PROGRESS_FLAG_INIT, + PROGRESS_FLAG_DONE +}; + + + char *client_flags; -void do_notify_progress(long long total) +void do_notify_progress(long long total, int flag) { FILE *progress; if (!client_flags[0]) @@ -21,17 +29,19 @@ void do_notify_progress(long long total) progress = fopen(client_flags, "w"); if (!progress) return; - fprintf(progress, "%d %lld", getpid(), total); + fprintf(progress, "%d %lld %s", getpid(), total, + flag == PROGRESS_FLAG_DONE ? "DONE" : "BUSY"); fclose(progress); } -void notify_progress(int size, int force) +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 || force) { - do_notify_progress(total); + if (total > prev_total + PROGRESS_NOTIFY_DELTA + || (flag != PROGRESS_FLAG_NORMAL)) { + do_notify_progress(total, flag); prev_total = total; } } @@ -139,7 +149,7 @@ void parse_entry(char *data, int datasize) char *vmname, *entry, *sep; vmname = get_item(data, ¤t, datasize); client_flags = get_item(data, ¤t, datasize); - notify_progress(0, 1); + notify_progress(0, PROGRESS_FLAG_INIT); send_vmname(vmname); while ((entry = get_item(data, ¤t, datasize))) { do { @@ -155,7 +165,7 @@ void parse_entry(char *data, int datasize) gui_fatal("chdir to %s", entry); do_fs_walk(sep + 1); } - notify_progress(0, 1); + notify_progress(0, PROGRESS_FLAG_DONE); } void process_spoolentry(char *entry_name) From edc1b82986876ee405bab779a4a774874a1b4943 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 11:07:27 +0100 Subject: [PATCH 25/30] removed set -x from qvm-copy-to-vm2 --- appvm/qvm-copy-to-vm2 | 1 - 1 file changed, 1 deletion(-) diff --git a/appvm/qvm-copy-to-vm2 b/appvm/qvm-copy-to-vm2 index ddababe..56dcdef 100755 --- a/appvm/qvm-copy-to-vm2 +++ b/appvm/qvm-copy-to-vm2 @@ -19,7 +19,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # -set -x if [ $# -lt 2 ] ; then echo usage: $0 'vmname file [file]*' From 3ae47689bc71fd04e16cc7fb86201768f0eeba7f Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 12:00:22 +0100 Subject: [PATCH 26/30] Added qvm-copy-to-vm2.kde --- appvm/qvm-copy-to-vm2.kde | 48 +++++++++++++++++++++++++++++++++++++++ appvm/qvm-copy.desktop | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100755 appvm/qvm-copy-to-vm2.kde diff --git a/appvm/qvm-copy-to-vm2.kde b/appvm/qvm-copy-to-vm2.kde new file mode 100755 index 0000000..879279b --- /dev/null +++ b/appvm/qvm-copy-to-vm2.kde @@ -0,0 +1,48 @@ +#!/bin/sh +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +VM=$(kdialog -inputbox "Enter the VM name to send files to:") +if [ X$VM = X ] ; then exit 0 ; fi + +SIZE=$(du -c "$@" | tail -1 | cut -f 1) +REF=$(kdialog --progressbar "Copy progress") +qdbus $REF org.freedesktop.DBus.Properties.Set "" maximum $SIZE + +export PROGRESS_FILE=$(mktemp) +qvm-copy-to-vm2 $VM "$@" +while ! [ -s $PROGRESS_FILE ] ; do + sleep 0.1 +done +while true ; do + read agentpid sentsize agentstatus < $PROGRESS_FILE + if ! [ -e /proc/$agentpid ] ; then break ; fi + if [ "x"$agentstatus = xdone ] ; then break ; fi + CURRSIZE=$(($sentsize/1024)) + qdbus $REF org.freedesktop.DBus.Properties.Set "" value $CURRSIZE + sleep 0.4 +done + +qdbus $REF close +rm -f $PROGRESS_FILE +if ! [ "x"$agentstatus = xDONE ] ; then + kdialog --sorry 'Abnormal file copy termination; see /var/log/qubes/qrexec.xid.log in dom0 for more details' +fi diff --git a/appvm/qvm-copy.desktop b/appvm/qvm-copy.desktop index 5795eb6..4d5e800 100644 --- a/appvm/qvm-copy.desktop +++ b/appvm/qvm-copy.desktop @@ -4,7 +4,7 @@ Type=Service X-KDE-ServiceTypes=KonqPopupMenu/Plugin,inode/directory,all/allfiles [Desktop Action QvmCopy] -Exec=/usr/lib/qubes/qvm-copy-to-vm.kde %U +Exec=/usr/lib/qubes/qvm-copy-to-vm2.kde %U Icon=kget Name=Send To VM From 6f8daea8f2fdb7f863a4bbd8e23814f949463593 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 12:48:29 +0100 Subject: [PATCH 27/30] In qfile-unpacker, set perms on the directory only on second pass. It solves problem with transferring r.x directory. Originally, it would fail when creating files in the directory (as it is not writable). Now, we will create it rwx, create files in it, and fix perms and utimes on the second pass. [user@devel fcopy]$ ls -ald /boot dr-xr-xr-x 4 root root 4096 Sep 1 2010 /boot --- appvm/unpack.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appvm/unpack.c b/appvm/unpack.c index c0353c1..ad53ebf 100644 --- a/appvm/unpack.c +++ b/appvm/unpack.c @@ -53,7 +53,11 @@ void process_one_file_reg(struct file_header *hdr, char *name) void process_one_file_dir(struct file_header *hdr, char *name) { - if (mkdir(name, 0700) && errno != EEXIST) +// fix perms only when the directory is sent for the second time +// it allows to transfer r.x directory contents, as we create it rwx initially + if (!mkdir(name, 0700)) + return; + if (errno != EEXIST) do_exit(errno); fix_times_and_perms(hdr, name); } From 01e0c73c618d1dd21b50a3f1ff0779d8b45b3bdf Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 12:58:40 +0100 Subject: [PATCH 28/30] In read_all()/write_all(), continue upon EINTR. --- common/ioall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/ioall.c b/common/ioall.c index 413477f..a99a8aa 100644 --- a/common/ioall.c +++ b/common/ioall.c @@ -31,6 +31,8 @@ int write_all(int fd, void *buf, int size) int ret; while (written < size) { ret = write(fd, (char *) buf + written, size - written); + if (ret == -1 && errno == EINTR) + continue; if (ret <= 0) { perror("write"); return 0; @@ -47,6 +49,8 @@ int read_all(int fd, void *buf, int size) int ret; while (got_read < size) { ret = read(fd, (char *) buf + got_read, size - got_read); + if (ret == -1 && errno == EINTR) + continue; if (ret == 0) { errno = 0; fprintf(stderr, "EOF\n"); @@ -68,6 +72,8 @@ int copy_fd_all(int fdout, int fdin) char buf[4096]; for (;;) { ret = read(fdin, buf, sizeof(buf)); + if (ret == -1 && errno == EINTR) + continue; if (!ret) break; if (ret < 0) { @@ -81,4 +87,3 @@ int copy_fd_all(int fdout, int fdin) } return 1; } - From b170b5b5da436ac79e9e9a8e55b8d04662892aa4 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 16:24:54 +0100 Subject: [PATCH 29/30] Bloody perror messes with errno; need to save errno. --- common/ioall.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/common/ioall.c b/common/ioall.c index a99a8aa..239f333 100644 --- a/common/ioall.c +++ b/common/ioall.c @@ -25,6 +25,14 @@ #include #include +void perror_wrapper(char * msg) +{ + int prev=errno; + perror(msg); + errno=prev; +} + + int write_all(int fd, void *buf, int size) { int written = 0; @@ -34,7 +42,7 @@ int write_all(int fd, void *buf, int size) if (ret == -1 && errno == EINTR) continue; if (ret <= 0) { - perror("write"); + perror_wrapper("write"); return 0; } written += ret; @@ -57,7 +65,7 @@ int read_all(int fd, void *buf, int size) return 0; } if (ret < 0) { - perror("read"); + perror_wrapper("read"); return 0; } got_read += ret; @@ -77,11 +85,11 @@ int copy_fd_all(int fdout, int fdin) if (!ret) break; if (ret < 0) { - perror("read"); + perror_wrapper("read"); return 0; } if (!write_all(fdout, buf, ret)) { - perror("write"); + perror_wrapper("write"); return 0; } } From d50a7063bf694b16a758c5c4c922b92c73830bbd Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 16 Mar 2011 16:47:32 +0100 Subject: [PATCH 30/30] Package qvm-copy-to-vm2*, too. --- rpm_spec/core-appvm.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index f3c875d..7821292 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -73,8 +73,10 @@ cp qubes_core $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/bin cp qubes_timestamp qvm-copy-to-vm qvm-open-in-dvm qvm-open-in-dvm2 $RPM_BUILD_ROOT/usr/bin +cp qvm-copy-to-vm2 $RPM_BUILD_ROOT/usr/bin 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 qvm-copy-to-vm2.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 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 @@ -205,7 +207,9 @@ rm -rf $RPM_BUILD_ROOT /etc/fstab /etc/init.d/qubes_core /usr/bin/qvm-copy-to-vm +/usr/bin/qvm-copy-to-vm2 /usr/lib/qubes/qvm-copy-to-vm.kde +/usr/lib/qubes/qvm-copy-to-vm2.kde %attr(4755,root,root) /usr/bin/qvm-open-in-dvm /usr/bin/qvm-open-in-dvm2 /usr/lib/qubes/qvm-dvm-transfer