Added qfile-unpacker and qfile-daemon
This commit is contained in:
parent
f0a7620449
commit
84b1a186ff
@ -1,12 +1,14 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -I../common
|
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
|
dvm_file_editor: dvm_file_editor.o ../common/ioall.o
|
||||||
$(CC) -o 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
|
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
|
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) -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
|
qubes_penctl: qubes_penctl.o
|
||||||
$(CC) -o qubes_penctl qubes_penctl.o -lxenstore
|
$(CC) -o qubes_penctl qubes_penctl.o -lxenstore
|
||||||
qubes_add_pendrive_script: qubes_add_pendrive_script.o
|
qubes_add_pendrive_script: qubes_add_pendrive_script.o
|
||||||
|
83
appvm/qfile-unpacker.c
Normal file
83
appvm/qfile-unpacker.c
Normal 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;
|
||||||
|
}
|
101
appvm/unpack.c
Normal file
101
appvm/unpack.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
59
dom0/restore/qfile-daemon
Normal file
59
dom0/restore/qfile-daemon
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/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 os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from qubes.qubes import QubesVmCollection
|
||||||
|
|
||||||
|
def is_copy_allowed(vm):
|
||||||
|
# if vm.copy_allowed:
|
||||||
|
# return True
|
||||||
|
q = 'Do you authorize file copy from '
|
||||||
|
q+= os.getenv("QREXEC_REMOTE_DOMAIN")
|
||||||
|
q+= ' to ' + vm.name + ' ?'
|
||||||
|
retcode = subprocess.call(['/usr/bin/kdialog', '--yesno', q, '--title', 'File transfer confirmation'])
|
||||||
|
return retcode == 0
|
||||||
|
|
||||||
|
def main():
|
||||||
|
FILECOPY_VMNAME_SIZE = 32
|
||||||
|
blob=os.read(0, FILECOPY_VMNAME_SIZE)
|
||||||
|
vmname = blob.split("\x00")[0]
|
||||||
|
|
||||||
|
qvm_collection = QubesVmCollection()
|
||||||
|
qvm_collection.lock_db_for_reading()
|
||||||
|
qvm_collection.load()
|
||||||
|
qvm_collection.unlock_db()
|
||||||
|
|
||||||
|
vm = qvm_collection.get_vm_by_name(vmname)
|
||||||
|
# we do not want to flood dom0 with error windows; so just log to stderr
|
||||||
|
if vm is None:
|
||||||
|
print >> sys.stderr, 'Domain ' + vmname + ' does not exist ?'
|
||||||
|
exit(1)
|
||||||
|
if not vm.is_running():
|
||||||
|
print >> sys.stderr, 'Domain ' + vmname + ' is not running ?'
|
||||||
|
exit(1)
|
||||||
|
if not is_copy_allowed(vm):
|
||||||
|
exit(1)
|
||||||
|
cmd = "root:/usr/lib/qubes/qfile-unpacker " + os.getenv("QREXEC_REMOTE_DOMAIN")
|
||||||
|
os.execl("/usr/lib/qubes/qrexec_client", "qrexec_client", "-d", vmname, cmd)
|
||||||
|
|
||||||
|
main()
|
@ -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
|
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 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 ../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
|
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
|
cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir}
|
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/qrexec_agent
|
||||||
/usr/lib/qubes/qfile-agent
|
/usr/lib/qubes/qfile-agent
|
||||||
/usr/lib/qubes/qfile-agent-dvm
|
/usr/lib/qubes/qfile-agent-dvm
|
||||||
|
/usr/lib/qubes/qfile-unpacker
|
||||||
/etc/udev/rules.d/qubes.rules
|
/etc/udev/rules.d/qubes.rules
|
||||||
/etc/sysconfig/iptables
|
/etc/sysconfig/iptables
|
||||||
/var/lib/qubes
|
/var/lib/qubes
|
||||||
|
@ -96,6 +96,7 @@ cp restore/xenstore-watch restore/qvm-create-default-dvm $RPM_BUILD_ROOT/usr/bin
|
|||||||
cp restore/qubes_restore restore/xenfreepages $RPM_BUILD_ROOT/usr/lib/qubes
|
cp restore/qubes_restore restore/xenfreepages $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
cp restore/qubes_prepare_saved_domain.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
cp restore/qubes_prepare_saved_domain.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
cp restore/qfile-daemon-dvm $RPM_BUILD_ROOT/usr/lib/qubes
|
cp restore/qfile-daemon-dvm $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
|
cp restore/qfile-daemon $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
|
|
||||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes
|
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes
|
||||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/vm-templates
|
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/vm-templates
|
||||||
@ -265,6 +266,7 @@ fi
|
|||||||
/usr/lib/qubes/qmemman_daemon.py*
|
/usr/lib/qubes/qmemman_daemon.py*
|
||||||
/usr/lib/qubes/meminfo-writer
|
/usr/lib/qubes/meminfo-writer
|
||||||
/usr/lib/qubes/qfile-daemon-dvm*
|
/usr/lib/qubes/qfile-daemon-dvm*
|
||||||
|
/usr/lib/qubes/qfile-daemon
|
||||||
%attr(770,root,qubes) %dir /var/lib/qubes
|
%attr(770,root,qubes) %dir /var/lib/qubes
|
||||||
%attr(770,root,qubes) %dir /var/lib/qubes/vm-templates
|
%attr(770,root,qubes) %dir /var/lib/qubes/vm-templates
|
||||||
%attr(770,root,qubes) %dir /var/lib/qubes/appvms
|
%attr(770,root,qubes) %dir /var/lib/qubes/appvms
|
||||||
|
Loading…
Reference in New Issue
Block a user