Merge branch 'spring-merge' of git.qubes-os.org:/var/lib/qubes/git/rafal/core
This commit is contained in:
commit
036e1b9b13
@ -1,6 +1,6 @@
|
||||
CC=gcc
|
||||
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
|
||||
all: dvm_file_editor qfile-agent-dvm qfile-agent qfile-unpacker
|
||||
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
|
||||
@ -9,13 +9,6 @@ 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) -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
|
||||
$(CC) -o qubes_add_pendrive_script qubes_add_pendrive_script.o -lxenstore
|
||||
qvm-open-in-dvm: qvm-open-in-dvm.o
|
||||
$(CC) -o qvm-open-in-dvm qvm-open-in-dvm.o -lxenstore
|
||||
|
||||
clean:
|
||||
rm -f qfile-agent-dvm qfile-agent qfile-unpacker dvm_file_editor qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm *.o *~
|
||||
rm -f xenstore-watch
|
||||
rm -f qfile-agent-dvm qfile-agent qfile-unpacker dvm_file_editor *.o *~
|
||||
|
@ -1,6 +0,0 @@
|
||||
#define DBDIR "/home/user/.dvm"
|
||||
struct dvm_header {
|
||||
unsigned long long file_size;
|
||||
char name[1024-sizeof(unsigned long long)];
|
||||
};
|
||||
|
@ -58,11 +58,11 @@ main()
|
||||
exit(1);
|
||||
}
|
||||
snprintf(cmdbuf, sizeof(cmdbuf),
|
||||
"HOME=/home/user DISPLAY=:0 /usr/bin/mimeopen -n -M '%s' 2>&1 > /tmp/kde-open.log </dev/null",
|
||||
"HOME=/home/user DISPLAY=:0 /usr/bin/mimeopen -n -M '%s' > /tmp/kde-open.log 2>&1 </dev/null",
|
||||
filename);
|
||||
if (system(cmdbuf))
|
||||
system
|
||||
("HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file!'");
|
||||
("HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file!' > /tmp/kdialog.log 2>&1 </dev/null");
|
||||
if (stat(filename, &stat_post)) {
|
||||
perror("stat post");
|
||||
exit(1);
|
||||
|
@ -1 +0,0 @@
|
||||
SUBSYSTEM=="block", KERNEL=="xvdh", ACTION=="add", RUN+="/usr/lib/qubes/qubes_add_pendrive_script"
|
@ -1,284 +0,0 @@
|
||||
/*
|
||||
* The Qubes OS Project, http://www.qubes-os.org
|
||||
*
|
||||
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <xs.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include "dvm.h"
|
||||
|
||||
int parse_events(char *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
struct inotify_event *ev =
|
||||
(struct inotify_event *) (buf + i);
|
||||
if ((ev->mask & IN_UNMOUNT) || (ev->mask & IN_IGNORED))
|
||||
return 1;
|
||||
i += sizeof(struct inotify_event) + ev->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BUFLEN 1024
|
||||
void wait_for_umount(char *name)
|
||||
{
|
||||
char buf[BUFLEN];
|
||||
int fd = inotify_init();
|
||||
int len;
|
||||
int ret = inotify_add_watch(fd, name, IN_ATTRIB);
|
||||
if (ret < 0) {
|
||||
perror("inotify_add_watch");
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
len = read(fd, buf, BUFLEN - 1);
|
||||
if (len <= 0) {
|
||||
perror("read inotify");
|
||||
return;
|
||||
}
|
||||
if (parse_events(buf, len))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void background()
|
||||
{
|
||||
int i, fd;
|
||||
for (i = 0; i < 256; i++)
|
||||
close(i);
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
for (i = 0; i <= 2; i++)
|
||||
dup2(fd, i);
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
exit(1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int check_legal_filename(char *name)
|
||||
{
|
||||
if (index(name, '/')) {
|
||||
syslog(LOG_DAEMON | LOG_ERR,
|
||||
"the received filename contains /");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void drop_to_user()
|
||||
{
|
||||
struct passwd *pw = getpwnam("user");
|
||||
if (pw)
|
||||
setuid(pw->pw_uid);
|
||||
}
|
||||
|
||||
int copy_from_xvdh(int destfd, int srcfd, unsigned long long count)
|
||||
{
|
||||
int n, size;
|
||||
char buf[4096];
|
||||
unsigned long long total = 0;
|
||||
while (total < count) {
|
||||
if (count - total > sizeof(buf))
|
||||
size = sizeof(buf);
|
||||
else
|
||||
size = count - total;
|
||||
n = read(srcfd, buf, size);
|
||||
if (n != size) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "reading xvdh");
|
||||
return 0;
|
||||
}
|
||||
if (write(destfd, buf, size) != size) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "writing file");
|
||||
return 0;
|
||||
}
|
||||
total += size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void redirect_stderr()
|
||||
{
|
||||
int fd =
|
||||
open("/var/log/dvm.log", O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open dvm.log");
|
||||
exit(1);
|
||||
}
|
||||
dup2(fd, 2);
|
||||
}
|
||||
|
||||
void suicide(struct xs_handle *xs)
|
||||
{
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "killme", 6);
|
||||
xs_daemon_close(xs);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// we are DVM, AppVM sends us a document to work on
|
||||
// /dev/xvdh contains the dvm_header and document data
|
||||
void dvm_transaction_request(char *seq, struct xs_handle *xs)
|
||||
{
|
||||
char filename[1024], cmdbuf[1024];
|
||||
struct dvm_header header;
|
||||
int xvdh_fd, file_fd;
|
||||
char *src_vm;
|
||||
unsigned int len;
|
||||
struct stat stat_pre, stat_post;
|
||||
xvdh_fd = open("/dev/xvdh", O_RDONLY);
|
||||
if (read(xvdh_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read dvm_header");
|
||||
suicide(xs);
|
||||
}
|
||||
|
||||
header.name[sizeof(header.name) - 1] = 0;
|
||||
if (!check_legal_filename(header.name))
|
||||
suicide(xs);
|
||||
snprintf(filename, sizeof(filename), "/tmp/%s", header.name);
|
||||
drop_to_user();
|
||||
|
||||
file_fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (file_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open file");
|
||||
suicide(xs);
|
||||
}
|
||||
if (!copy_from_xvdh(file_fd, xvdh_fd, header.file_size))
|
||||
suicide(xs);
|
||||
close(xvdh_fd);
|
||||
close(file_fd);
|
||||
if (stat(filename, &stat_pre)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "stat pre");
|
||||
suicide(xs);
|
||||
}
|
||||
snprintf(cmdbuf, sizeof(cmdbuf),
|
||||
"HOME=/home/user DISPLAY=:0 /usr/bin/mimeopen -n -M '/tmp/%s' 2>&1 > /tmp/kde-open.log", header.name);
|
||||
if (system(cmdbuf))
|
||||
system("HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file!'");
|
||||
if (stat(filename, &stat_post)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "stat post");
|
||||
suicide(xs);
|
||||
}
|
||||
src_vm = xs_read(xs, XBT_NULL, "qubes_blocksrc", &len);
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
if (stat_pre.st_mtime == stat_post.st_mtime)
|
||||
suicide(xs);
|
||||
xs_daemon_close(xs);
|
||||
// if the modify timestamp of the document file has changed, write back the
|
||||
// modified content to the requestor AppVM
|
||||
execl("/usr/lib/qubes/qvm-dvm-transfer", "qvm-dvm-transfer", src_vm,
|
||||
filename, seq, NULL);
|
||||
syslog(LOG_DAEMON | LOG_ERR, "execl qvm-dvm-transfer");
|
||||
suicide(xs);
|
||||
}
|
||||
|
||||
// we are AppVM, DVM sends us a modified document
|
||||
// /dev/xvdh contains the dvm_header and document data
|
||||
void dvm_transaction_return(char *seq_string, struct xs_handle *xs)
|
||||
{
|
||||
int seq = strtoul(seq_string, 0, 10);
|
||||
char db_name[1024];
|
||||
char file_name[1024];
|
||||
int db_fd, file_fd, xvdh_fd;
|
||||
|
||||
struct dvm_header header;
|
||||
xvdh_fd = open("/dev/xvdh", O_RDONLY);
|
||||
if (xvdh_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open xvdh");
|
||||
goto out_err;
|
||||
}
|
||||
if (read(xvdh_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read dvm_header");
|
||||
goto out_err;
|
||||
}
|
||||
drop_to_user();
|
||||
// read the file name for which the open-in-dvm with transaction=="seq" was started
|
||||
snprintf(db_name, sizeof(db_name), DBDIR "/%d", seq);
|
||||
db_fd = open(db_name, O_RDONLY);
|
||||
if (!db_fd) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open db");
|
||||
goto out_err;
|
||||
}
|
||||
if (read(db_fd, file_name, sizeof(file_name)) < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read db");
|
||||
goto out_err;
|
||||
}
|
||||
close(db_fd);
|
||||
file_fd = open(file_name, O_WRONLY | O_TRUNC);
|
||||
if (file_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open filename");
|
||||
goto out_err;
|
||||
}
|
||||
copy_from_xvdh(file_fd, xvdh_fd, header.file_size);
|
||||
close(xvdh_fd);
|
||||
close(file_fd);
|
||||
out_err:
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
xs_daemon_close(xs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dvm_transaction(char *seq, struct xs_handle *xs)
|
||||
{
|
||||
struct stat st;
|
||||
redirect_stderr();
|
||||
if (stat("/etc/this_is_dvm", &st))
|
||||
dvm_transaction_return(seq, xs);
|
||||
else
|
||||
dvm_transaction_request(seq, xs);
|
||||
}
|
||||
|
||||
#define MOUNTDIR "/mnt/incoming"
|
||||
int main()
|
||||
{
|
||||
struct xs_handle *xs;
|
||||
char *seq;
|
||||
unsigned int len;
|
||||
background();
|
||||
openlog("qubes_add_pendrive_script", LOG_CONS | LOG_PID,
|
||||
LOG_DAEMON);
|
||||
xs = xs_domain_open();
|
||||
if (!xs) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
seq = xs_read(xs, XBT_NULL, "qubes_transaction_seq", &len);
|
||||
if (seq && len > 0 && strcmp(seq, "0")) {
|
||||
dvm_transaction(seq, xs);
|
||||
exit(0);
|
||||
}
|
||||
if (!system("su - user -c 'mount " MOUNTDIR "'"))
|
||||
wait_for_umount(MOUNTDIR "/.");
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
xs_daemon_close(xs);
|
||||
return 0;
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* The Qubes OS Project, http://www.qubes-os.org
|
||||
*
|
||||
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <xs.h>
|
||||
void check_name(unsigned char *s)
|
||||
{
|
||||
int c;
|
||||
for (; *s; s++) {
|
||||
c = *s;
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c == '_' || c == '-')
|
||||
continue;
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
fprintf(stderr, "invalid string %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
A tool to request action from qfileexchgd by writing to device/qpen xenstore key.
|
||||
new - please attach a vfat-formatted block device at /dev/xvdg; I will either write some files to it and
|
||||
then request sending it to other AppVM, or I will place dvm_header+some file on it and send it to DVM
|
||||
send vmname - detach my /dev/xvdg and attach it to vmname at /dev/xvdh
|
||||
umount - I am done with my /dev/xvdh, please detach it
|
||||
*/
|
||||
|
||||
void usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [new|umount]\n"
|
||||
"%s send vmname [seq]\n", argv0, argv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[256];
|
||||
struct xs_handle *xs;
|
||||
xs = xs_domain_open();
|
||||
setuid(getuid());
|
||||
if (!xs) {
|
||||
perror("xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
switch (argc) {
|
||||
case 2:
|
||||
if (!strcmp(argv[1], "umount"))
|
||||
strcpy(buf, "umount");
|
||||
else
|
||||
strcpy(buf, "new");
|
||||
break;
|
||||
case 3:
|
||||
check_name((unsigned char *) argv[2]);
|
||||
snprintf(buf, sizeof(buf), "send %s", argv[2]);
|
||||
break;
|
||||
case 4:
|
||||
check_name((unsigned char *) argv[2]);
|
||||
check_name((unsigned char *) argv[3]);
|
||||
snprintf(buf, sizeof(buf), "send %s %s", argv[2], argv[3]);
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
if (!xs_write(xs, 0, "device/qpen", buf, strlen(buf))) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
}
|
||||
xs_daemon_close(xs);
|
||||
return 0;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
#
|
||||
# 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 [ $# -lt 2 ] ; then
|
||||
echo usage: $0 'vmname file [file]*'
|
||||
exit 1
|
||||
fi
|
||||
/usr/lib/qubes/qubes_penctl new || exit 1
|
||||
echo -n Waiting for the Qubes virtual pendrive
|
||||
while ! [ -e /dev/xvdg ] ; do
|
||||
echo -n .
|
||||
sleep 1
|
||||
done
|
||||
echo " received"
|
||||
mount /mnt/outgoing
|
||||
VMNAME=$1
|
||||
shift
|
||||
cp -v -a "$@" /mnt/outgoing
|
||||
#sometimes Dolphin lags a bit
|
||||
umount /mnt/outgoing || (sleep 1; umount /mnt/outgoing) || exit 1
|
||||
/usr/lib/qubes/qubes_penctl send $VMNAME || exit 1
|
@ -1,41 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
#
|
||||
# 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
|
||||
DEST=/mnt/outgoing
|
||||
SIZE=$(du -c "$@" | tail -1 | cut -f 1)
|
||||
REF=$(kdialog --progressbar "Copy progress")
|
||||
qdbus $REF org.freedesktop.DBus.Properties.Set "" maximum $SIZE
|
||||
FLAG=$(mktemp)
|
||||
(qvm-copy-to-vm $VM "$@" ; rm $FLAG) &
|
||||
while ! grep -q $DEST /proc/mounts && [ -f $FLAG ] ; do
|
||||
sleep 0.1
|
||||
done
|
||||
while grep -q $DEST /proc/mounts ; do
|
||||
CURRSIZE=$(du -c $DEST | tail -1 | cut -f 1)
|
||||
qdbus $REF org.freedesktop.DBus.Properties.Set "" value $CURRSIZE
|
||||
sleep 1
|
||||
done
|
||||
qdbus $REF close
|
||||
|
||||
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
* The Qubes OS Project, http://www.qubes-os.org
|
||||
*
|
||||
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <xs.h>
|
||||
#include "dvm.h"
|
||||
|
||||
void check_name(unsigned char *s)
|
||||
{
|
||||
int c;
|
||||
for (; *s; s++) {
|
||||
c = *s;
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c == '_' || c == '-')
|
||||
continue;
|
||||
fprintf(stderr, "invalid string %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int get_and_set_seq()
|
||||
{
|
||||
int seq_fd, seq, n;
|
||||
mkdir(DBDIR, 0700);
|
||||
seq_fd = open(DBDIR "/seq", O_CREAT | O_RDWR, 0600);
|
||||
if (seq_fd < 0) {
|
||||
perror("open seq_fd");
|
||||
exit(1);
|
||||
}
|
||||
n = read(seq_fd, &seq, sizeof(seq));
|
||||
if (n < sizeof(seq))
|
||||
seq = 0;
|
||||
seq++;
|
||||
lseek(seq_fd, 0, SEEK_SET);
|
||||
write(seq_fd, &seq, sizeof(seq));
|
||||
close(seq_fd);
|
||||
return seq;
|
||||
}
|
||||
/*
|
||||
Write the filename we are sending to DVM to DBDIR/transaction_seq
|
||||
When DVM sends us a modified document via transaction with transaction_seq,
|
||||
we will know that we are supposed to update the document with the
|
||||
filename at DBDIR/transaction_seq
|
||||
*/
|
||||
void write_db(char *name, int seq)
|
||||
{
|
||||
int db_fd;
|
||||
char dbname[256];
|
||||
struct stat st;
|
||||
if (!stat("/etc/this_is_dvm", &st))
|
||||
return;
|
||||
snprintf(dbname, sizeof(dbname), DBDIR "/%d", seq);
|
||||
db_fd = open(dbname, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
if (db_fd < 0) {
|
||||
perror("open dbfile");
|
||||
exit(1);
|
||||
}
|
||||
if (write(db_fd, name, strlen(name) + 1) != strlen(name) + 1) {
|
||||
perror("write db");
|
||||
exit(1);
|
||||
}
|
||||
close(db_fd);
|
||||
}
|
||||
|
||||
void copy_file(int xvdg_fd, int file_fd)
|
||||
{
|
||||
int n;
|
||||
char buf[4096];
|
||||
|
||||
for (;;) {
|
||||
n = read(file_fd, buf, sizeof(buf));
|
||||
if (n < 0) {
|
||||
perror("read file");
|
||||
exit(1);
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
if (write(xvdg_fd, buf, n) != n) {
|
||||
perror("write file");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct dvm_header header = { 0, };
|
||||
struct stat st;
|
||||
struct xs_handle *xs;
|
||||
int seq;
|
||||
int xvdg_fd, file_fd;
|
||||
char *abs_filename;
|
||||
char buf[4096];
|
||||
|
||||
if (argc != 3 && argc != 4) {
|
||||
fprintf(stderr, "usage: %s vmname file\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
check_name((unsigned char *) argv[1]);
|
||||
if (argv[2][0] == '/')
|
||||
abs_filename = argv[2];
|
||||
else {
|
||||
char cwd[4096];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
asprintf(&abs_filename, "%s/%s", cwd, argv[2]);
|
||||
}
|
||||
if (stat(abs_filename, &st)) {
|
||||
perror("stat file");
|
||||
exit(1);
|
||||
}
|
||||
header.file_size = st.st_size;
|
||||
strncpy(header.name, rindex(abs_filename, '/') + 1,
|
||||
sizeof(header.name) - 1);
|
||||
xs = xs_domain_open();
|
||||
if (!xs) {
|
||||
perror("xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
// request a new block device at /dev/xvdg from qfileexchgd
|
||||
if (!xs_write(xs, 0, "device/qpen", "new", 3)) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
}
|
||||
while (stat("/dev/xvdg", &st))
|
||||
usleep(100000);
|
||||
xvdg_fd = open("/dev/xvdg", O_WRONLY);
|
||||
if (xvdg_fd < 0) {
|
||||
perror("open xvdg");
|
||||
exit(1);
|
||||
}
|
||||
setuid(getuid());
|
||||
if (argc == 3)
|
||||
// we are AppVM; get new seq
|
||||
seq = get_and_set_seq();
|
||||
else
|
||||
// we are DVM; use the cmdline transaction_seq
|
||||
seq = strtoul(argv[3], 0, 0);
|
||||
file_fd = open(abs_filename, O_RDONLY);
|
||||
if (file_fd < 0) {
|
||||
perror("open file");
|
||||
exit(1);
|
||||
}
|
||||
if (write(xvdg_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
perror("write filesize");
|
||||
exit(1);
|
||||
}
|
||||
copy_file(xvdg_fd, file_fd);
|
||||
close(file_fd);
|
||||
close(xvdg_fd);
|
||||
// request qfileexchgd to send our /dev/xvdg to its destination
|
||||
// either "disposable", which means "create DVM for me"
|
||||
// or vmname, meaning this is a reply to originator AppVM
|
||||
snprintf(buf, sizeof(buf), "send %s %d", argv[1], seq);
|
||||
if (!xs_write(xs, 0, "device/qpen", buf, strlen(buf))) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
}
|
||||
write_db(abs_filename, seq);
|
||||
xs_daemon_close(xs);
|
||||
return 0;
|
||||
}
|
@ -13,6 +13,4 @@ tmpfs /dev/shm tmpfs defaults 0 0
|
||||
devpts /dev/pts devpts gid=5,mode=620 0 0
|
||||
sysfs /sys sysfs defaults 0 0
|
||||
proc /proc proc defaults 0 0
|
||||
/dev/xvdg /mnt/outgoing vfat noauto,user,rw 0 0
|
||||
/dev/xvdh /mnt/incoming vfat noauto,user,rw 0 0
|
||||
/dev/xvdi /mnt/removable auto noauto,user,rw 0 0
|
||||
|
@ -53,7 +53,6 @@ stop()
|
||||
rm -f /var/lock/subsys/qubes_core
|
||||
killall meminfo-writer
|
||||
killall qmemman_daemon.py
|
||||
killall qfilexchgd
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
qfilexchgd is a daemon responsible for managing exchange of block
|
||||
devices ("virtual pendrives") between VMs. It is used for
|
||||
a) copying files between AppVMs
|
||||
b) copying a single file between an AppVM and a DVM
|
||||
|
||||
qfilexchgd is event driven. The sources of events are:
|
||||
a) trigger of xenstore watch for the changes in /local/domain xenstore hierarchy -
|
||||
to detect start/stop of VMs, and maintain vmname->vm_xid dictionary
|
||||
b) triger of xenstore watch for a change in /local/domain/domid/device/qpen
|
||||
key - VMs write to this key to request service from qfilexchgd
|
||||
|
||||
Copying files between AppVMs is implemented as follows:
|
||||
1) AppVM1 user runs qvm-copy-to-vm script (accessible from Dolphin file manager by
|
||||
"right click on a file(s)->Actions->Send to VM" menu). It calls
|
||||
"/usr/lib/qubes/qubes_penctl new", and it writes "new" request to its device/qpen
|
||||
key. qfilexchgd creates a new 1G file, makes vfat fs on it, and does block-attach
|
||||
so that this file is attached as /dev/xvdg in AppVM1.
|
||||
2) AppVM1 mounts /dev/xvdg on /mnt/outgoing and copies some files there,
|
||||
then unmounts it.
|
||||
3) AppVM1 writes "send DestVM" request to its device/qpen key (calling
|
||||
"/usr/lib/qubes/qubes_penctl send DestVM"). After getting confirmation by
|
||||
displaying a dialog box in dom0 display, qfilexchgd detaches /dev/xvdg
|
||||
from AppVM1, attaches it as /dev/xvdh to DestVM.
|
||||
4) In DestVM, udev script for /dev/xvdh named qubes_add_pendrive_script (see
|
||||
/etc/udev/rules.d/qubes.rules) mounts /dev/xvdh on /mnt/incoming, and then
|
||||
waits for /mnt/incoming to become unmounted. A file manager
|
||||
running in DestVM shows a new volume, and user in DestVM may copy files from
|
||||
it. When user in DestVM is done, then user unmounts /dev/xvdh.
|
||||
qubes_add_pendrive_script then tells qfilexchgd to detach /dev/xvdh and
|
||||
terminates.
|
||||
|
||||
Copying a single file between AppVM and a DVM is implemented as
|
||||
follows:
|
||||
1) User in AppVM1 runs qvm-open-in-dvm (accessible from Dolphin file manager
|
||||
by "right click on a file->Actions->Open in DVM" menu). qvm-open-in-dvm
|
||||
a) gets a new /dev/xvdg (just as described in previous paragraph)
|
||||
b) computes a new unique transaction seq SEQ,
|
||||
c) writes the requested file name (say, /home/user/document.txt) to
|
||||
/home/user/.dvm/SEQ.
|
||||
d) creates a dvm_header (see core.git/appvm/dvm.h) on /dev/xvdg, followed by
|
||||
file contents
|
||||
e) writes the "send disposable SEQ" to its device/qpen xenstore key.
|
||||
2) qfilexchgd sees that "send" argument=="disposable", and creates the new
|
||||
DVM by calling /usr/lib/qubes/qubes_restore. It adds new DVM to qubesDB via
|
||||
qvm_collection.add_new_appvm. Then it attaches /dev/xvdg from AppVM1 as
|
||||
/dev/xvdh in DVM.
|
||||
3) In DVM, qubes_add_pendrive_script sees non-zero "qubes_transaction_seq"
|
||||
key in xenstore, and instead processing it as in the case of normal copy,
|
||||
treats it as a request to DVM (because we run in DVM). It retrieves the
|
||||
body of the file passed in
|
||||
/dev/xvdh, copies to /tmp, and runs "mime-open" to open appropriate
|
||||
executable to edit it. When mime-open returns, if the file was modified,
|
||||
it is sent back to AppVM1 (by writing "send AppVM1 SEQ" to device/qpen).
|
||||
Then DVM destroys itself.
|
||||
4) In AppVM1, a new /dev/xvdh appears (because DVM sent it).
|
||||
qubes_add_pendrive_script sees non-zero "qubes_transaction_seq" key, and
|
||||
treats it as response from DVM (because we run in AppVM, not DVM). It
|
||||
retrieves the filename from
|
||||
/home/user/.dvm/SEQ, and copies data from /dev/xvdh to it.
|
||||
|
||||
qfilexchgd is started after first qubes_guid is started, so that it
|
||||
has access to X display in dom0 to present dialog messages.
|
@ -1,358 +0,0 @@
|
||||
#!/usr/bin/python2.6
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
import xen.lowlevel.xs
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import subprocess
|
||||
import daemon
|
||||
import time
|
||||
import dbus
|
||||
from qubes.qubes import QubesVmCollection
|
||||
from qubes.qubes import QubesException
|
||||
from qubes.qubes import QubesDaemonPidfile
|
||||
from qubes.qmemman_client import QMemmanClient
|
||||
|
||||
filename_seq = 50
|
||||
pen_cmd = '/usr/lib/qubes/qubes_pencmd'
|
||||
disposable_domains_dict = {}
|
||||
current_savefile = '/var/run/qubes/current_savefile'
|
||||
|
||||
notify_object = None
|
||||
|
||||
|
||||
def get_next_filename_seq():
|
||||
global filename_seq
|
||||
filename_seq = filename_seq + 1
|
||||
return str(filename_seq)
|
||||
|
||||
def logproc(msg):
|
||||
f = file('/var/log/qubes/qfileexchgd', 'a')
|
||||
f.write(msg+'\n')
|
||||
f.close()
|
||||
|
||||
def get_req_node(domain_id):
|
||||
return '/local/domain/'+domain_id+'/device/qpen'
|
||||
|
||||
def get_name_node(domain_id):
|
||||
return '/local/domain/'+domain_id+'/name'
|
||||
|
||||
def only_in_first_list(l1, l2):
|
||||
ret=[]
|
||||
for i in l1:
|
||||
if not i in l2:
|
||||
ret.append(i)
|
||||
return ret
|
||||
|
||||
|
||||
class WatchType:
|
||||
def __init__(self, fn, param):
|
||||
self.fn = fn
|
||||
self.param = param
|
||||
|
||||
class DomainState:
|
||||
def __init__(self, domain, dict):
|
||||
self.rcv_state = 'idle'
|
||||
self.send_state = 'idle'
|
||||
self.domain_id = domain
|
||||
self.domdict = dict
|
||||
self.send_seq = None
|
||||
self.rcv_seq = None
|
||||
self.waiting_sender = None
|
||||
self.allowed_dest = None
|
||||
self.allowed_seq = None
|
||||
|
||||
def killme(self):
|
||||
if not os.path.isfile('/etc/debug-dvm'):
|
||||
subprocess.call(['/usr/sbin/xm', 'destroy', self.domain_id])
|
||||
|
||||
def handle_request(self, request):
|
||||
req_ok = False
|
||||
if request is None:
|
||||
return
|
||||
tmp = request.split()
|
||||
rq = tmp[0]
|
||||
if len(tmp) > 1:
|
||||
vmname = tmp[1]
|
||||
else:
|
||||
vmname = None
|
||||
if len(tmp) > 2:
|
||||
transaction_seq = tmp[2]
|
||||
else:
|
||||
transaction_seq = '0'
|
||||
if rq == 'killme':
|
||||
self.killme()
|
||||
req_ok = True
|
||||
if rq == 'new' and self.send_state == 'idle':
|
||||
self.send_seq = get_next_filename_seq()
|
||||
retcode = subprocess.call([pen_cmd, 'new', self.domain_id, self.send_seq])
|
||||
logproc( 'Give domain ' + self.domain_id + ' a clean pendrive, retcode= ' + str(retcode))
|
||||
if retcode == 0:
|
||||
self.send_state = 'has_clean_pendrive'
|
||||
req_ok = True
|
||||
if rq == 'send' and self.send_state == 'has_clean_pendrive' and vmname is not None:
|
||||
logproc( 'send from ' + self.domain_id + ' to ' + vmname)
|
||||
if self.handle_transfer(vmname, transaction_seq):
|
||||
self.send_state = 'idle'
|
||||
req_ok = True;
|
||||
if rq == 'umount' and self.rcv_state == 'has_loaded_pendrive':
|
||||
retcode = subprocess.call([pen_cmd, 'umount', self.domain_id, self.rcv_seq])
|
||||
if retcode == 0:
|
||||
self.rcv_state = 'idle'
|
||||
self.rcv_seq = None
|
||||
logproc( 'set state of ' + self.domain_id + ' loaded->idle retcode=' + str(retcode))
|
||||
req_ok = True
|
||||
if rq == 'umount' and self.rcv_state == 'waits_to_umount':
|
||||
req_ok = True
|
||||
retcode = subprocess.call([pen_cmd, 'umount', self.domain_id, self.rcv_seq])
|
||||
if retcode != 0:
|
||||
return
|
||||
assert(self.waiting_sender != None)
|
||||
self.rcv_state = 'idle'
|
||||
self.rcv_seq = None
|
||||
tmp = self.waiting_sender
|
||||
self.waiting_sender = None
|
||||
if tmp.send_state == 'has_clean_pendrive':
|
||||
if tmp.handle_transfer(self.name, tmp.delayed_transaction_seq):
|
||||
tmp.send_state = 'idle'
|
||||
|
||||
if not req_ok:
|
||||
logproc( 'request ' + request + ' not served due to nonmatching state')
|
||||
|
||||
def ask_to_umount(self, vmname):
|
||||
q = 'VM ' + vmname + ' has already an incoming pendrive, and thus '
|
||||
q+= 'cannot accept another one. If you intend to unmount its current '
|
||||
q+= 'pendrive and retry this transfer, press Yes. '
|
||||
q+= 'Otherwise press No to fail this transfer.'
|
||||
retcode = subprocess.call(['/usr/bin/kdialog', '--yesno', q, '--title', 'Some additional action required'])
|
||||
if retcode == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def handle_transfer_regular(self, vmname, transaction_seq):
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_reading()
|
||||
qvm_collection.load()
|
||||
qvm_collection.unlock_db()
|
||||
|
||||
vm = qvm_collection.get_vm_by_name(vmname)
|
||||
if vm is None:
|
||||
logproc( 'Domain ' + vmname + ' does not exist ?')
|
||||
return False
|
||||
if not vm.is_running():
|
||||
logproc( 'Domain ' + vmname + ' is not running ?')
|
||||
return False
|
||||
target=self.domdict[str(vm.get_xid())]
|
||||
if target.rcv_state != 'idle':
|
||||
if self.ask_to_umount(vmname):
|
||||
target.rcv_state='waits_to_umount'
|
||||
target.waiting_sender=self
|
||||
self.delayed_transaction_seq=transaction_seq
|
||||
logproc( 'target domain ' + target.domain_id + ' is not idle, now ' + target.rcv_state)
|
||||
return False
|
||||
if self.allowed_seq is not None:
|
||||
if self.allowed_seq != transaction_seq or self.allowed_dest != target.name:
|
||||
logproc('sender ' + self.name + ' receiver ' + target.name + ' : allowed attributes mismatch, denied')
|
||||
return False
|
||||
else:
|
||||
transaction_seq = '0'
|
||||
retcode = subprocess.call(['/usr/bin/kdialog', '--yesno', 'Do you authorize pendrive transfer from ' + self.name + ' to ' + vmname + '?' , '--title', 'Security confirmation'])
|
||||
logproc('handle_transfer: kdialog retcode=' + str(retcode))
|
||||
if retcode != 0:
|
||||
return False
|
||||
target.rcv_state='has_loaded_pendrive'
|
||||
retcode = subprocess.call([pen_cmd, 'send', self.domain_id, target.domain_id, self.send_seq, transaction_seq])
|
||||
target.rcv_seq = self.send_seq
|
||||
self.send_seq = None
|
||||
logproc( 'set state of ' + target.domain_id + ' to has_loaded_pendrive, retcode=' + str(retcode))
|
||||
if self.allowed_seq is not None:
|
||||
self.killme()
|
||||
return True
|
||||
|
||||
def handle_transfer_disposable(self, transaction_seq):
|
||||
|
||||
qmemman_client = QMemmanClient()
|
||||
if not qmemman_client.request_memory(400*1024*1024):
|
||||
qmemman_client.close()
|
||||
errmsg = 'Not enough memory to create DVM. '
|
||||
errmsg +='Terminate some appVM and retry.'
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
|
||||
return False
|
||||
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_writing()
|
||||
qvm_collection.load()
|
||||
|
||||
vm = qvm_collection.get_vm_by_name(self.name)
|
||||
if vm is None:
|
||||
logproc( 'Domain ' + vmname + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
qmemman_client.close()
|
||||
return False
|
||||
retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
|
||||
current_savefile,
|
||||
'-c', vm.label.color,
|
||||
'-i', vm.label.icon,
|
||||
'-l', str(vm.label.index)])
|
||||
qmemman_client.close()
|
||||
if retcode != 0:
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
f = open('/var/run/qubes/dispVM_xid', 'r');
|
||||
disp_xid = f.readline().rstrip('\n')
|
||||
disp_name = f.readline().rstrip('\n')
|
||||
disptempl = f.readline().rstrip('\n')
|
||||
f.close()
|
||||
vm_disptempl = qvm_collection.get_vm_by_name(disptempl);
|
||||
if vm_disptempl is None:
|
||||
logproc( 'Domain ' + disptempl + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
qvm_collection.add_new_disposablevm(disp_name, vm_disptempl.template_vm, label=vm.label)
|
||||
qvm_collection.save()
|
||||
qvm_collection.unlock_db()
|
||||
|
||||
dispdom = DomainState(disp_xid, self.domdict)
|
||||
disposable_domains_dict[disp_xid] = dispdom
|
||||
retcode = subprocess.call([pen_cmd, 'send', self.domain_id, disp_xid, self.send_seq, transaction_seq])
|
||||
dispdom.rcv_seq = self.send_seq
|
||||
dispdom.rcv_state = 'has_loaded_pendrive'
|
||||
dispdom.allowed_dest = self.name
|
||||
dispdom.allowed_seq = transaction_seq
|
||||
self.send_seq = None
|
||||
logproc( 'sent pendrive to disposable xid ' + disp_xid)
|
||||
return True
|
||||
|
||||
def dvm_setup_ok(self):
|
||||
dvmdata_dir = '/var/lib/qubes/dvmdata/'
|
||||
if not os.path.isfile(current_savefile):
|
||||
return False
|
||||
if not os.path.isfile(dvmdata_dir+'default_savefile') or not os.path.isfile(dvmdata_dir+'savefile_root'):
|
||||
return False
|
||||
dvm_mtime = os.stat(current_savefile).st_mtime
|
||||
root_mtime = os.stat(dvmdata_dir+'savefile_root').st_mtime
|
||||
if dvm_mtime < root_mtime:
|
||||
return False
|
||||
return True
|
||||
|
||||
def tray_notify(self, str, timeout = 3000):
|
||||
notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
||||
|
||||
def tray_notify_error(self, str, timeout = 3000):
|
||||
notify_object.Notify("Qubes", 0, "dialog-error", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
||||
|
||||
def handle_transfer(self, vmname, transaction_seq):
|
||||
if vmname != 'disposable':
|
||||
return self.handle_transfer_regular(vmname, transaction_seq)
|
||||
if not self.dvm_setup_ok():
|
||||
self.tray_notify("Updating DisposableVM savefile, please wait")
|
||||
if os.system("qvm-create-default-dvm --default-template --default-script") != 0:
|
||||
self.tray_notify_error("DVM savefile creation failed")
|
||||
return False
|
||||
return self.handle_transfer_disposable(transaction_seq)
|
||||
|
||||
class XS_Watcher:
|
||||
def __init__(self):
|
||||
self.handle = xen.lowlevel.xs.xs()
|
||||
self.handle.watch('/vm', WatchType(XS_Watcher.dom_list_change, None))
|
||||
self.domdict = {}
|
||||
|
||||
def dom_list_change(self, param):
|
||||
curr = self.handle.ls('', '/local/domain')
|
||||
if curr == None:
|
||||
return
|
||||
for i in only_in_first_list(curr, self.domdict.keys()):
|
||||
if disposable_domains_dict.has_key(i):
|
||||
newdom = disposable_domains_dict[i]
|
||||
else:
|
||||
newdom = DomainState(i, self.domdict)
|
||||
newdom.name = ''
|
||||
self.domdict[i] = newdom
|
||||
newdom.watch_token = WatchType(XS_Watcher.request, newdom)
|
||||
newdom.watch_name = WatchType(XS_Watcher.namechange, newdom)
|
||||
self.handle.watch(get_req_node(i), newdom.watch_token)
|
||||
self.handle.watch(get_name_node(i), newdom.watch_name)
|
||||
logproc( 'added domain ' + i)
|
||||
for i in only_in_first_list(self.domdict.keys(), curr):
|
||||
if disposable_domains_dict.has_key(i):
|
||||
self.remove_disposable_from_qdb(self.domdict[i].name)
|
||||
disposable_domains_dict.pop(i)
|
||||
self.handle.unwatch(get_req_node(i), self.domdict[i].watch_token)
|
||||
self.handle.unwatch(get_name_node(i), self.domdict[i].watch_name)
|
||||
self.domdict.pop(i)
|
||||
logproc( 'removed domain ' + i)
|
||||
|
||||
def request(self, domain_param):
|
||||
ret = self.handle.read('', get_req_node(domain_param.domain_id))
|
||||
domain_param.handle_request(ret)
|
||||
|
||||
def namechange(self, domain_param):
|
||||
ret = self.handle.read('', get_name_node(domain_param.domain_id))
|
||||
if ret!= '' and ret!=None:
|
||||
domain_param.name = ret
|
||||
logproc( 'Name for domain xid ' + domain_param.domain_id + ' is ' + ret )
|
||||
|
||||
def remove_disposable_from_qdb(self, name):
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_writing()
|
||||
qvm_collection.load()
|
||||
|
||||
vm = qvm_collection.get_vm_by_name(name)
|
||||
if vm is None:
|
||||
logproc( 'remove_disposable_from_qdb: Domain ' + name + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
qvm_collection.pop(vm.qid)
|
||||
qvm_collection.save()
|
||||
qvm_collection.unlock_db()
|
||||
|
||||
def watch_loop(self):
|
||||
global notify_object
|
||||
notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
||||
|
||||
sys.stderr = file('/var/log/qubes/qfileexchgd.errors', 'a')
|
||||
while True:
|
||||
result = self.handle.read_watch()
|
||||
token = result[1]
|
||||
token.fn(self, token.param)
|
||||
|
||||
def main():
|
||||
|
||||
lock = QubesDaemonPidfile ("qfileexchgd")
|
||||
if lock.pidfile_exists():
|
||||
if lock.pidfile_is_stale():
|
||||
lock.remove_pidfile()
|
||||
print "Removed stale pidfile (has the previous daemon instance crashed?)."
|
||||
else:
|
||||
exit (0)
|
||||
|
||||
|
||||
context = daemon.DaemonContext(
|
||||
working_directory = "/var/run/qubes",
|
||||
pidfile = lock)
|
||||
with context:
|
||||
XS_Watcher().watch_loop()
|
||||
|
||||
main()
|
@ -1,75 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
SHARE_DIR=/var/run/qubes
|
||||
function do_new()
|
||||
{
|
||||
FILE=$SHARE_DIR/pendrive.$2
|
||||
truncate -s 1G $FILE || exit 1
|
||||
vmname=$(xenstore-read /local/domain/$1/name)
|
||||
mkfs.vfat -n "$vmname" $FILE || exit 1
|
||||
xm block-attach $1 file:/$FILE /dev/xvdg w || exit 1
|
||||
}
|
||||
|
||||
function do_umount()
|
||||
{
|
||||
xm block-detach $1 /dev/xvdh || exit 1
|
||||
rm $SHARE_DIR/pendrive.$2
|
||||
}
|
||||
|
||||
function do_send()
|
||||
{
|
||||
FILE=$SHARE_DIR/pendrive.$3
|
||||
vmname=$(xenstore-read /local/domain/$1/name)
|
||||
xenstore-write /local/domain/$2/qubes_blocksrc $vmname
|
||||
xenstore-write /local/domain/$2/qubes_transaction_seq "$4"
|
||||
xm block-detach $1 /dev/xvdg || exit 1
|
||||
xm block-attach $2 file:/$FILE /dev/xvdh w || exit 1
|
||||
}
|
||||
export PATH=$PATH:/sbin:/usr/sbin
|
||||
if [ $# -lt 1 ] ; then
|
||||
echo args missing ?
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" = "new" ] ; then
|
||||
if ! [ $# = 3 ] ; then
|
||||
echo new requires 2 more args
|
||||
exit 1
|
||||
fi
|
||||
do_new "$2" "$3"
|
||||
elif [ "$1" = "umount" ] ; then
|
||||
if ! [ $# = 3 ] ; then
|
||||
echo umount requires 2 more args
|
||||
exit 1
|
||||
fi
|
||||
do_umount "$2" "$3"
|
||||
elif [ "$1" = "send" ] ; then
|
||||
if ! [ $# = 5 ] ; then
|
||||
echo send requires 4 more args
|
||||
exit 1
|
||||
fi
|
||||
do_send "$2" "$3" "$4" "$5"
|
||||
else
|
||||
echo bad cmd
|
||||
exit 1
|
||||
fi
|
||||
|
@ -34,7 +34,6 @@ import os.path
|
||||
|
||||
qubes_guid_path = "/usr/bin/qubes_guid"
|
||||
qubes_clipd_path = "/usr/bin/qclipd"
|
||||
qubes_qfilexchgd_path= "/usr/bin/qfilexchgd"
|
||||
qrexec_daemon_path = "/usr/lib/qubes/qrexec_daemon"
|
||||
qrexec_client_path = "/usr/lib/qubes/qrexec_client"
|
||||
notify_object = None
|
||||
@ -258,11 +257,5 @@ def main():
|
||||
if options.tray:
|
||||
tray_notify ("ERROR: Cannot start the Qubes Clipboard Notifier!")
|
||||
|
||||
retcode = subprocess.call([qubes_qfilexchgd_path])
|
||||
if retcode != 0:
|
||||
print "ERROR: Cannot start qfilexchgd!"
|
||||
if options.tray:
|
||||
tray_notify ("ERROR: Cannot start the Qubes Inter-VM File Exchange Daemon!")
|
||||
|
||||
|
||||
main()
|
||||
|
@ -30,7 +30,9 @@ fi
|
||||
DVMTMPL="$TEMPLATENAME"-dvm
|
||||
DVMTMPLDIR="/var/lib/qubes/appvms/$DVMTMPL"
|
||||
if ! [ -d "$DVMTMPLDIR" ] ; then
|
||||
if ! qvm-create -t "$TEMPLATENAME" -l gray "$DVMTMPL" ; then exit 1 ; fi
|
||||
# unfortunately, currently there are reliability issues with save of a domain
|
||||
# with multiple CPUs
|
||||
if ! qvm-create --vcpus=1 -t "$TEMPLATENAME" -l gray "$DVMTMPL" ; then exit 1 ; fi
|
||||
fi
|
||||
if ! /usr/lib/qubes/qubes_prepare_saved_domain.sh \
|
||||
"$DVMTMPL" "/var/lib/qubes/appvms/$DVMTMPL/dvm-savefile" $SCRIPTNAME ; then
|
||||
@ -55,6 +57,9 @@ else
|
||||
ln -s $SHMCOPY $CURRENT
|
||||
fi
|
||||
|
||||
chgrp qubes "$DVMTMPLDIR" "$DVMTMPLDIR"/*
|
||||
chmod 660 "$DVMTMPLDIR"/*
|
||||
chmod 770 "$DVMTMPLDIR"
|
||||
if [ $(whoami) = "root" ] ; then
|
||||
chgrp qubes "$DVMTMPLDIR" "$DVMTMPLDIR"/*
|
||||
chmod 660 "$DVMTMPLDIR"/*
|
||||
chmod 770 "$DVMTMPLDIR"
|
||||
fi
|
||||
|
||||
|
@ -85,7 +85,6 @@ void init(int xid)
|
||||
"/var/log/qubes/qrexec.%d.log", xid);
|
||||
umask(0007);
|
||||
logfd = open(dbg_log, O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
umask(0077);
|
||||
|
||||
dup2(logfd, 1);
|
||||
dup2(logfd, 2);
|
||||
@ -98,7 +97,10 @@ void init(int xid)
|
||||
|
||||
remote_domain_name = peer_client_init(xid, REXEC_PORT);
|
||||
setuid(getuid());
|
||||
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
|
||||
umask(0);
|
||||
server_fd = get_server_socket(xid, remote_domain_name);
|
||||
umask(0077);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
signal(SIGUSR1, SIG_DFL);
|
||||
|
@ -70,21 +70,15 @@ mkdir -p $RPM_BUILD_ROOT/etc/init.d
|
||||
cp qubes_core_appvm $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 qubes_timestamp 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
|
||||
cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir}
|
||||
cp qvm-copy.desktop qvm-dvm.desktop $RPM_BUILD_ROOT/%{kde_service_dir}
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/udev/rules.d
|
||||
cp qubes.rules $RPM_BUILD_ROOT/etc/udev/rules.d
|
||||
mkdir -p $RPM_BUILD_ROOT/mnt/incoming
|
||||
mkdir -p $RPM_BUILD_ROOT/mnt/outgoing
|
||||
mkdir -p $RPM_BUILD_ROOT/mnt/removable
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/X11
|
||||
@ -129,26 +123,17 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
/etc/init.d/qubes_core_appvm
|
||||
/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
|
||||
/usr/lib/qubes/meminfo-writer
|
||||
/usr/lib/qubes/dvm_file_editor
|
||||
%{kde_service_dir}/qvm-copy.desktop
|
||||
%{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
|
||||
/usr/lib/qubes/qfile-agent
|
||||
/usr/lib/qubes/qfile-agent-dvm
|
||||
/usr/lib/qubes/qfile-unpacker
|
||||
/etc/udev/rules.d/qubes.rules
|
||||
%dir /mnt/incoming
|
||||
%dir /mnt/outgoing
|
||||
%dir /mnt/removable
|
||||
/usr/bin/qubes_timestamp
|
||||
%dir /home_volatile
|
||||
|
@ -65,7 +65,6 @@ cp init.d/qubes_setupdvm $RPM_BUILD_ROOT/etc/init.d/
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/bin/
|
||||
cp qvm-tools/qvm-* $RPM_BUILD_ROOT/usr/bin
|
||||
cp clipboard_notifier/qclipd $RPM_BUILD_ROOT/usr/bin
|
||||
cp pendrive_swapper/qfilexchgd $RPM_BUILD_ROOT/usr/bin
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/xen/scripts
|
||||
cp restore/block.qubes $RPM_BUILD_ROOT/etc/xen/scripts
|
||||
@ -90,7 +89,6 @@ cp aux-tools/convert_dirtemplate2vm.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp aux-tools/create_apps_for_appvm.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp aux-tools/remove_appvm_appmenus.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp aux-tools/reset_vm_configs.py $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp pendrive_swapper/qubes_pencmd $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp qmemman/server.py $RPM_BUILD_ROOT/usr/lib/qubes/qmemman_daemon.py
|
||||
cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes/
|
||||
cp ../qrexec/qrexec_daemon $RPM_BUILD_ROOT/usr/lib/qubes/
|
||||
@ -275,7 +273,6 @@ fi
|
||||
/etc/init.d/qubes_setupdvm
|
||||
/usr/bin/qvm-*
|
||||
/usr/bin/qclipd
|
||||
/usr/bin/qfilexchgd
|
||||
%{python_sitearch}/qubes/qubes.py
|
||||
%{python_sitearch}/qubes/qubes.pyc
|
||||
%{python_sitearch}/qubes/qubes.pyo
|
||||
@ -291,7 +288,6 @@ fi
|
||||
/usr/lib/qubes/create_apps_for_appvm.sh
|
||||
/usr/lib/qubes/remove_appvm_appmenus.sh
|
||||
/usr/lib/qubes/reset_vm_configs.py*
|
||||
/usr/lib/qubes/qubes_pencmd
|
||||
/usr/lib/qubes/qmemman_daemon.py*
|
||||
/usr/lib/qubes/meminfo-writer
|
||||
/usr/lib/qubes/qfile-daemon-dvm*
|
||||
|
Loading…
Reference in New Issue
Block a user