Merge branch 'spring-merge' of ssh://git.qubes-os.org/var/lib/qubes/git/rafal/core into spring-merge

This commit is contained in:
Marek Marczykowski 2011-03-23 19:45:59 -04:00
commit 51b0e00b7b
23 changed files with 1015 additions and 7 deletions

View File

@ -33,3 +33,5 @@ clean:
(cd dom0/restore && make clean)
(cd dom0/qmemman && make clean)
(cd common && make clean)
make -C qrexec clean
make -C vchan clean

View File

@ -1,6 +1,14 @@
CC=gcc
CFLAGS=-Wall
all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm
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) -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) -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) -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
@ -9,4 +17,5 @@ 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 xenstore-watch *.o *~
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

28
appvm/copy_file.c Normal file
View File

@ -0,0 +1,28 @@
#include <unistd.h>
#include <ioall.h>
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;
}

2
appvm/dvm2.h Normal file
View File

@ -0,0 +1,2 @@
#define DVM_FILENAME_SIZE 256
#define DVM_SPOOL "/home/user/.dvmspool"

73
appvm/dvm_file_editor.c Normal file
View File

@ -0,0 +1,73 @@
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <ioall.h>
#include "dvm2.h"
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_file(char *filename)
{
int fd = open(filename, O_WRONLY | O_CREAT, 0600);
if (fd < 0) {
perror("open file");
exit(1);
}
if (!copy_fd_all(fd, 0))
exit(1);
close(fd);
}
void send_file_back(char * filename)
{
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("open file");
exit(1);
}
if (!copy_fd_all(1, fd))
exit(1);
close(fd);
}
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 </dev/null",
filename);
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)) {
perror("stat post");
exit(1);
}
if (stat_pre.st_mtime != stat_post.st_mtime)
send_file_back(filename);
return 0;
}

18
appvm/filecopy.h Normal file
View File

@ -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);

139
appvm/qfile-agent-dvm.c Normal file
View File

@ -0,0 +1,139 @@
#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdlib.h>
#include <ioall.h>
#include <unistd.h>
#include <gui-fatal.h>
#include "dvm2.h"
void send_file(char *fname)
{
char *base;
int fd = open(fname, O_RDONLY);
if (fd < 0)
gui_fatal("open %s", fname);
base = rindex(fname, '/');
if (!base)
base = fname;
else
base++;
if (strlen(base) >= DVM_FILENAME_SIZE)
base += strlen(base) - DVM_FILENAME_SIZE + 1;
if (!write_all(1, base, DVM_FILENAME_SIZE))
gui_fatal("send filename to dispVM");
if (!copy_fd_all(1, fd))
gui_fatal("send file to dispVM");
close(1);
}
int copy_and_return_nonemptiness(int tmpfd)
{
struct stat st;
if (!copy_fd_all(tmpfd, 0))
gui_fatal("receiving file from dispVM");
if (fstat(tmpfd, &st))
gui_fatal("fstat");
close(tmpfd);
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)
gui_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);
gui_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))
gui_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))
gui_fatal("bad dvm_entry");
entry_size = st.st_size;
filename = calloc(1, entry_size + DVM_FILENAME_SIZE);
if (!filename)
gui_fatal("malloc");
if (!read_all(entry_fd, filename, entry_size))
gui_fatal("read dvm entry %s", abs_spool_entry_name);
close(entry_fd);
talk_to_daemon(filename);
}
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 (!strcmp(fname, ".") || !strcmp(fname, ".."))
continue;
process_spoolentry(fname);
break;
}
closedir(dir);
}
int main()
{
signal(SIGPIPE, SIG_IGN);
scan_spool(DVM_SPOOL);
return 0;
}

215
appvm/qfile-agent.c Normal file
View File

@ -0,0 +1,215 @@
#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdlib.h>
#include <ioall.h>
#include <unistd.h>
#include <gui-fatal.h>
#include "filecopy.h"
enum {
PROGRESS_FLAG_NORMAL,
PROGRESS_FLAG_INIT,
PROGRESS_FLAG_DONE
};
char *client_flags;
void do_notify_progress(long long total, int flag)
{
FILE *progress;
if (!client_flags[0])
return;
progress = fopen(client_flags, "w");
if (!progress)
return;
fprintf(progress, "%d %lld %s", getpid(), total,
flag == PROGRESS_FLAG_DONE ? "DONE" : "BUSY");
fclose(progress);
}
void notify_progress(int size, int flag)
{
static long long total = 0;
static long long prev_total = 0;
total += size;
if (total > prev_total + PROGRESS_NOTIFY_DELTA
|| (flag != PROGRESS_FLAG_NORMAL)) {
do_notify_progress(total, flag);
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, &current, datasize);
client_flags = get_item(data, &current, datasize);
notify_progress(0, PROGRESS_FLAG_INIT);
send_vmname(vmname);
while ((entry = get_item(data, &current, datasize))) {
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))
gui_fatal("chdir to %s", entry);
do_fs_walk(sep + 1);
}
notify_progress(0, PROGRESS_FLAG_DONE);
}
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;
}

83
appvm/qfile-unpacker.c Normal file
View File

@ -0,0 +1,83 @@
#define _GNU_SOURCE
#include <ioall.h>
#include <grp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <sys/fsuid.h>
#include <gui-fatal.h>
#include <errno.h>
#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;
}

46
appvm/qvm-copy-to-vm2 Executable file
View File

@ -0,0 +1,46 @@
#!/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
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

48
appvm/qvm-copy-to-vm2.kde Executable file
View File

@ -0,0 +1,48 @@
#!/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
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

View File

@ -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

View File

@ -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

40
appvm/qvm-open-in-dvm2 Executable file
View File

@ -0,0 +1,40 @@
#!/bin/bash
#
# 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 ! [ $# = 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

105
appvm/unpack.c Normal file
View File

@ -0,0 +1,105 @@
#include <errno.h>
#include <ioall.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#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)
{
// 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);
}
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);
}

50
common/gui-fatal.c Normal file
View File

@ -0,0 +1,50 @@
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
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);
}

2
common/gui-fatal.h Normal file
View File

@ -0,0 +1,2 @@
void gui_fatal(const char *fmt, ...);
void gui_nonfatal(const char *fmt, ...);

97
common/ioall.c Normal file
View File

@ -0,0 +1,97 @@
/*
* 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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
void perror_wrapper(char * msg)
{
int prev=errno;
perror(msg);
errno=prev;
}
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 == -1 && errno == EINTR)
continue;
if (ret <= 0) {
perror_wrapper("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 == -1 && errno == EINTR)
continue;
if (ret == 0) {
errno = 0;
fprintf(stderr, "EOF\n");
return 0;
}
if (ret < 0) {
perror_wrapper("read");
return 0;
}
got_read += ret;
}
// 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 == -1 && errno == EINTR)
continue;
if (!ret)
break;
if (ret < 0) {
perror_wrapper("read");
return 0;
}
if (!write_all(fdout, buf, ret)) {
perror_wrapper("write");
return 0;
}
}
return 1;
}

3
common/ioall.h Normal file
View File

@ -0,0 +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);

View File

@ -54,6 +54,8 @@ start()
fi
fi
/usr/lib/qubes/qrexec_agent 2>/var/log/qubes/qrexec_agent.log &
[ -x /rw/config/rc.local ] && /rw/config/rc.local
success
echo ""

View File

@ -32,6 +32,7 @@ start()
/usr/lib/qubes/qubes_setup_dnat_to_ns
echo "1" > /proc/sys/net/ipv4/ip_forward
fi
success
echo ""
return 0

View File

@ -60,6 +60,9 @@ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes
%build
make clean all
make -C ../common
make -C ../vchan
make -C ../u2mfn
make -C ../qrexec
%install
@ -67,9 +70,13 @@ 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 $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
cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes
mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir}
@ -86,6 +93,18 @@ 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
mkdir -p $RPM_BUILD_ROOT/var/run/qubes
%triggerin -- initscripts
cp /var/lib/qubes/serial.conf /etc/init/serial.conf
%post
chkconfig --add qubes_core_appvm || echo "WARNING: Cannot add service qubes_core!"
@ -111,14 +130,22 @@ rm -rf $RPM_BUILD_ROOT
%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
@ -127,3 +154,20 @@ 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
%dir /var/run/qubes
%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

View File

@ -45,6 +45,8 @@ The Qubes core files for installation inside a Qubes NetVM.
%pre
%build
make -C ../vchan
make -C ../u2mfn
%install
@ -89,4 +91,3 @@ rm -rf $RPM_BUILD_ROOT
/etc/NetworkManager/dispatcher.d/qubes_nmhook
/etc/NetworkManager/dispatcher.d/30-qubes_external_ip
/etc/xen/scripts/vif-route-qubes
%dir /var/run/qubes