Merge branch 'qrexec2' of git://git.qubes-os.org/rafal/core

This commit is contained in:
Marek Marczykowski 2011-07-09 13:10:35 +02:00
commit 371fdf5884
34 changed files with 611 additions and 357 deletions

View File

@ -1,9 +1,9 @@
CC=gcc
CFLAGS=-g -Wall -I../common -fPIC -pie
all: dvm_file_editor qfile-agent-dvm qfile-agent qfile-unpacker
dvm_file_editor: dvm_file_editor.o ../common/ioall.o
all: vm-file-editor qopen-in-vm qfile-agent qfile-unpacker
vm-file-editor: vm-file-editor.o ../common/ioall.o
$(CC) -pie -g -o $@ $^
qfile-agent-dvm: qfile-agent-dvm.o ../common/ioall.o ../common/gui-fatal.o
qopen-in-vm: qopen-in-vm.o ../common/ioall.o ../common/gui-fatal.o
$(CC) -pie -g -o $@ $^
qfile-agent: qfile-agent.o ../common/ioall.o ../common/gui-fatal.o ../common/copy_file.o ../common/crc32.o
$(CC) -pie -g -o $@ $^
@ -11,4 +11,4 @@ qfile-unpacker: qfile-unpacker.o ../common/ioall.o ../common/gui-fatal.o ../comm
$(CC) -pie -g -o $@ $^
clean:
rm -f qfile-agent-dvm qfile-agent qfile-unpacker dvm_file_editor *.o *~
rm -f qopen-in-vm qfile-agent qfile-unpacker vm-file-editor *.o *~

View File

@ -20,24 +20,33 @@ enum {
};
unsigned long crc32_sum;
int write_all_with_crc(int fd, void *buf, int size) {
int write_all_with_crc(int fd, void *buf, int size)
{
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return write_all(fd, buf, size);
}
char *client_flags;
void do_notify_progress(long long total, int flag)
{
FILE *progress;
if (!client_flags[0])
char *du_size_env = getenv("FILECOPY_TOTAL_SIZE");
char *progress_type_env = getenv("PROGRESS_TYPE");
char *saved_stdout_env = getenv("SAVED_FD_1");
if (!progress_type_env)
return;
progress = fopen(client_flags, "w");
if (!progress)
return;
fprintf(progress, "%d %lld %s", getpid(), total,
flag == PROGRESS_FLAG_DONE ? "DONE" : "BUSY");
fclose(progress);
if (!strcmp(progress_type_env, "console") && du_size_env) {
char msg[256];
snprintf(msg, sizeof(msg), "sent %lld/%lld KB\r",
total / 1024, strtoull(du_size_env, NULL, 0));
write(2, msg, strlen(msg));
if (flag == PROGRESS_FLAG_DONE)
write(2, "\n", 1);
}
if (!strcmp(progress_type_env, "gui") && saved_stdout_env) {
char msg[256];
snprintf(msg, sizeof(msg), "%lld\n", total);
write(strtoul(saved_stdout_env, NULL, 0), msg,
strlen(msg));
}
}
void notify_progress(int size, int flag)
@ -136,25 +145,6 @@ int do_fs_walk(char *file)
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))
exit(1);
}
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 notify_end_and_wait_for_result()
{
struct result_header hdr;
@ -168,26 +158,40 @@ void notify_end_and_wait_for_result()
/* wait for result */
if (!read_all(0, &hdr, sizeof(hdr))) {
exit(1); // hopefully remote has produced error message
exit(1); // hopefully remote has produced error message
}
if (hdr.error_code != 0) {
gui_fatal("Error writing files: %s", strerror(hdr.error_code));
gui_fatal("Error writing files: %s",
strerror(hdr.error_code));
}
if (hdr.crc32 != crc32_sum) {
gui_fatal("File transfer failed: checksum mismatch");
}
}
void parse_entry(char *data, int datasize)
char *get_abs_path(char *cwd, char *pathname)
{
char *current = data;
char *vmname, *entry, *sep;
vmname = get_item(data, &current, datasize);
client_flags = get_item(data, &current, datasize);
char *ret;
if (pathname[0] == '/')
return strdup(pathname);
asprintf(&ret, "%s/%s", cwd, pathname);
return ret;
}
int main(int argc, char **argv)
{
int i;
char *entry;
char *cwd;
char *sep;
signal(SIGPIPE, SIG_IGN);
notify_progress(0, PROGRESS_FLAG_INIT);
send_vmname(vmname);
crc32_sum = 0;
while ((entry = get_item(data, &current, datasize))) {
cwd = getcwd(NULL, 0);
for (i = 1; i < argc; i++) {
entry = get_abs_path(cwd, argv[i]);
do {
sep = rindex(entry, '/');
if (!sep)
@ -200,53 +204,9 @@ void parse_entry(char *data, int datasize)
else if (chdir(entry))
gui_fatal("chdir to %s", entry);
do_fs_walk(sep + 1);
free(entry);
}
notify_end_and_wait_for_result();
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;
}

View File

@ -93,47 +93,11 @@ void talk_to_daemon(char *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()
int main(int argc, char ** argv)
{
signal(SIGPIPE, SIG_IGN);
scan_spool(DVM_SPOOL);
if (argc!=2)
gui_fatal("OpenInVM - no file given?");
talk_to_daemon(argv[1]);
return 0;
}
}

1
appvm/qubes.Filecopy Normal file
View File

@ -0,0 +1 @@
/usr/lib/qubes/qfile-unpacker

View File

@ -0,0 +1 @@
anyvm anyvm ask,user=root

1
appvm/qubes.OpenInVM Normal file
View File

@ -0,0 +1 @@
/usr/lib/qubes/vm-file-editor

View File

@ -0,0 +1,2 @@
anyvm dispvm allow
anyvm anyvm ask

View File

@ -20,50 +20,24 @@
#
#
if [ x"$1" = "x--without-progress" ] ; then
DO_PROGRESS=0
shift
else
DO_PROGRESS=1
fi
if [ $# -lt 2 ] ; then
echo usage: $0 '[--without-progress] dest_vmname file [file]+'
exit 1
fi
if [ x"$1" = "x--without-progress" ] ; then
export PROGRESS_TYPE=none
shift
else
export PROGRESS_TYPE=console
fi
VM="$1"
shift
if [ $DO_PROGRESS = 1 ] ; then
SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1)
if [ $PROGRESS_TYPE = console ] ; then
export FILECOPY_TOTAL_SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1)
fi
export PROGRESS_FILE=$(mktemp)
/usr/lib/qubes/qvm-trigger-copy-to-vm $VM "$@"
while ! [ -s $PROGRESS_FILE ] ; do
sleep 0.1
done
while true ; do
read agentpid sentsize agentstatus < $PROGRESS_FILE
if [ "x"$agentstatus = x ] ; then continue ; fi
if ! [ -e /proc/$agentpid ] ; then break ; fi
if [ "x"$agentstatus = xDONE ] ; then break ; fi
CURRSIZE=$(($sentsize/1024))
if [ $DO_PROGRESS = 1 ] ; then
echo -ne "\r sent $CURRSIZE/$SIZE KB "
fi
sleep 0.4
done
rm -f $PROGRESS_FILE
if [ $DO_PROGRESS = 1 ] ; then
echo
fi
if ! [ "x"$agentstatus = xDONE ] ; then
exit 1
else
exit 0
fi
exec /usr/lib/qubes/qrexec_client_vm $VM qubes.Filecopy /usr/lib/qubes/qfile-agent "$@"

View File

@ -25,19 +25,10 @@ if [ X$VM = X ] ; then exit 0 ; fi
SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1)
export PROGRESS_FILE=$(mktemp)
/usr/lib/qubes/qvm-trigger-copy-to-vm $VM "$@"
while ! [ -s $PROGRESS_FILE ] ; do
sleep 0.1
done
(while true ; do
read agentpid sentsize agentstatus < $PROGRESS_FILE
if [ "x"$agentstatus = x ] ; then continue ; fi
if ! [ -e /proc/$agentpid ] ; then break ; fi
if [ "x"$agentstatus = xdone ] ; then break ; fi
export PROGRESS_TYPE=gui
/usr/lib/qubes/qrexec_client_vm $VM qubes.Filecopy /usr/lib/qubes/qfile-agent "$@" |
(while read sentsize ; do
CURRSIZE=$(($sentsize/1024))
echo $((100*$CURRSIZE/$SIZE))
sleep 0.1
done) | zenity --progress --text="Copying files to domain: $VM..." --auto-close
rm -f $PROGRESS_FILE

View File

@ -27,23 +27,16 @@ SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1)
REF=$(kdialog --progressbar "Copy progress")
qdbus $REF org.freedesktop.DBus.Properties.Set "" maximum $SIZE
export PROGRESS_FILE=$(mktemp)
/usr/lib/qubes/qvm-trigger-copy-to-vm $VM "$@"
while ! [ -s $PROGRESS_FILE ] ; do
sleep 0.1
done
while true ; do
read agentpid sentsize agentstatus < $PROGRESS_FILE
if [ "x"$agentstatus = x ] ; then continue ; fi
if ! [ -e /proc/$agentpid ] ; then break ; fi
if [ "x"$agentstatus = xdone ] ; then break ; fi
export PROGRESS_TYPE=gui
/usr/lib/qubes/qrexec_client_vm $VM qubes.Filecopy \
/usr/lib/qubes/qfile-agent "$@" |
(while read sentsize ; do
CURRSIZE=$(($sentsize/1024))
qdbus $REF org.freedesktop.DBus.Properties.Set "" value $CURRSIZE
sleep 0.4
done
done)
qdbus $REF close
rm -f $PROGRESS_FILE
# we do not want a dozen error messages, do we
# if ! [ "x"$agentstatus = xDONE ] ; then
# kdialog --sorry 'Abnormal file copy termination; see /var/log/qubes/qrexec.xid.log in dom0 for more details'

View File

@ -25,16 +25,4 @@ if ! [ $# = 1 ] ; then
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
exec /usr/lib/qubes/qrexec_client_vm dispvm qubes.OpenInVM "/usr/lib/qubes/qopen-in-vm" "$1"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# The Qubes OS Project, http://www.qubes-os.org
#
@ -20,27 +20,9 @@
#
#
if [ $# -lt 2 ] ; then
echo usage: $0 'vmname file [file]*'
if ! [ $# = 2 ] ; then
echo "Usage: $0 vmname filename"
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
exec /usr/lib/qubes/qrexec_client_vm "$1" qubes.OpenInVM "/usr/lib/qubes/qopen-in-vm" "$2"

View File

@ -67,4 +67,4 @@ else
fi
# qvm-copy-to-vm works only from user
su -c "qvm-copy-to-vm @dom0updates $DOM0_UPDATES_DIR/packages/*.rpm" user
su -c "/usr/lib/qubes/qrexec_client_vm dom0 qubes.ReceiveUpdates /usr/lib/qubes/qfile-agent $DOM0_UPDATES_DIR/packages/*.rpm" user

View File

@ -3,5 +3,5 @@
UPDATEABLE=`/usr/bin/xenstore-read qubes_vm_updateable`
if [ "$UPDATEABLE" = "True" ]; then
echo -n SYNC > /var/run/qubes/qrexec_agent
/usr/lib/qubes/qrexec_client_vm dom0 qubes.SyncAppMenus /bin/grep -H = /usr/share/applications/*.desktop
fi

View File

@ -29,15 +29,6 @@ from qubes.qubes import QubesVmCollection
updates_dir = "/var/lib/qubes/updates"
updates_rpm_dir = updates_dir + "/rpm"
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 dom0updates_fatal(msg):
print >> sys.stderr, msg
shutil.rmtree(updates_rpm_dir)
@ -69,31 +60,13 @@ def handle_dom0updates(updatevm):
exit(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()
if vmname == '@dom0updates':
updatevm = qvm_collection.get_updatevm_vm()
handle_dom0updates(updatevm)
# handle_dom0updates never returns
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)
updatevm = qvm_collection.get_updatevm_vm()
handle_dom0updates(updatevm)
main()

View File

@ -0,0 +1 @@
/usr/lib/qubes/qubes-receive-updates

View File

@ -0,0 +1 @@
anyvm dom0 allow

1
dom0/qubes.SyncAppMenus Normal file
View File

@ -0,0 +1 @@
/usr/bin/qvm-sync-appmenus

View File

@ -0,0 +1 @@
anyvm dom0 allow

View File

@ -124,15 +124,20 @@ class QfileDaemonDvm:
def main():
global notify_object
exec_index = sys.argv[1]
src_vmname = sys.argv[2]
user = sys.argv[3]
notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
qfile = QfileDaemonDvm(os.getenv("QREXEC_REMOTE_DOMAIN"))
qfile = QfileDaemonDvm(src_vmname)
lockf = open("/var/run/qubes/qfile-daemon-dvm.lock", 'a')
fcntl.fcntl(lockf, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
fcntl.flock(lockf, fcntl.LOCK_EX)
dispname = qfile.get_dvm()
lockf.close()
if dispname is not None:
subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', dispname, 'directly:user:/usr/lib/qubes/dvm_file_editor'])
subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', dispname,
user+":exec /usr/lib/qubes/qubes_rpc_multiplexer ' + exec_index + " " + src_vmname])
subprocess.call(['/usr/sbin/xl', 'destroy', dispname])
qfile.remove_disposable_from_qdb(dispname)

View File

@ -3,12 +3,14 @@ CFLAGS+=-g -Wall -I../vchan -I../common -pie -fPIC
XENLIBS=-lvchan -lu2mfn -lxenstore -lxenctrl
COMMONIOALL=../common/ioall.o
all: qrexec_daemon qrexec_agent qrexec_client
all: qrexec_daemon qrexec_agent qrexec_client qrexec_client_vm
qrexec_daemon: qrexec_daemon.o unix_server.o $(COMMONIOALL) txrx-vchan.o buffer.o write_stdin.o
$(CC) -pie -L../vchan -L../u2mfn -g -o qrexec_daemon qrexec_daemon.o unix_server.o $(COMMONIOALL) txrx-vchan.o write_stdin.o buffer.o $(XENLIBS)
qrexec_agent: qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL)
$(CC) -pie -L../vchan -L../u2mfn -g -o qrexec_agent qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL) $(XENLIBS)
qrexec_agent: qrexec_agent.o unix_server.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL)
$(CC) -pie -L../vchan -L../u2mfn -g -o qrexec_agent qrexec_agent.o unix_server.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL) $(XENLIBS)
qrexec_client: qrexec_client.o $(COMMONIOALL) exec.o
$(CC) -pie -g -o qrexec_client qrexec_client.o $(COMMONIOALL) exec.o
qrexec_client_vm: qrexec_client_vm.o
$(CC) -pie -g -o qrexec_client_vm qrexec_client_vm.o
clean:
rm -f *.o *~ qrexec_daemon qrexec_agent qrexec_client
rm -f *.o *~ qrexec_daemon qrexec_agent qrexec_client qrexec_client_vm

64
qrexec/README.rpc Normal file
View File

@ -0,0 +1,64 @@
Currently (after commit 2600134e3bb781fca25fe77e464f8b875741dc83),
qrexec_agent can request a service (specified by a "exec_index") to be
executed on a different VM or dom0. Access control is enforced in dom0 via
files in /etc/qubes_rpc/policy. File copy, Open in Dispvm, sync appmenus,
upload updates to dom0 - they all have been ported to the new API.
See the quick HOWTO section on how to add a new service. Note we have
qvm-open-in-vm utility practically for free.
CHANGES
Besides flexibility offered by /etc/qubes_rpc/policy, writing a client
is much simpler now. The workflow used to be (using "filecopy" service as
an example):
a) "filecopy_ui" process places job description in some spool directory,
signals qrexec_agent to signal qrexec_daemon
b) qrexec_daemon executes "qrexec_client -d domain filecopy_worker ...."
and "filecopy_worker" process needed to parse spool and retrieve job
description from there. Particularly, "filecopy_ui" had no connection to
remote.
Now, the flow is:
a) qrexec_client_vm process obtains 3 unix socket descriptors from
qrexec_agent, dup stdin/out/err to them; forms "existing_process_handle" from
them
b) qrexec_client_vm signals qrexec_agent to signal qrexec_daemon, with a
"exec_index" (so, type of service) as an argument
c) qrexec_daemon executed "qrexec_client -d domain -c existing_process_handle ...."
d) qrexec_client_vm execve filecopy_program.
Thus, there is only one service program, and it has direct access to remote via
stdin/stdout.
HOWTO
Let's add a new "test.Add" service, that will add two numbers. We need the
following files in the template fs:
==========================
/usr/bin/our_test_add_client:
#!/bin/sh
echo $1 $2
exec cat >&2
# more correct: exec cat >&$SAVED_FD_1, but do not scare the reader
==========================
/usr/bin/our_test_add_server:
#!/bin/sh
read arg1 arg2
echo $(($arg1+$arg2))
==========================
/etc/qubes_rpc/test.Add:
/usr/bin/our_test_add_server
Now, on the client side, we start the client via
/usr/lib/qubes/qrexec_client_vm target_vm test.Add /usr/bin/our_test_add_client 11 22
Because there is no policy yet, dom0 will ask you to create one (of cource you
can do it before the first run of our_test_add_client). So, in dom0, create (by now,
with a file editor) the /etc/qubes_rpc/policy/test.Add file with
anyvm anyvm ask
content. The format of the /etc/qubes_rpc/policy/* files is
srcvm destvm (allow|deny|ask)[,user=user_to_run_as][,target=VM_to_redirect_to]
You can specify srcvm and destvm by name, or by one of "anyvm", "dispvm", "dom0"
reserved keywords.
Then, when you confirm the operation, you will get the result in the client vm.

View File

@ -32,7 +32,7 @@ int write_all_vchan_ext(void *buf, int size);
int buffer_space_vchan_ext();
void fix_fds(int fdin, int fdout, int fderr);
int get_server_socket(int domid, char * domname);
int get_server_socket(char *);
int do_accept(int s);
enum {

View File

@ -26,11 +26,14 @@
#define REXEC_PORT 512
#define QREXEC_AGENT_TRIGGER_PATH "/var/run/qubes/qrexec_agent"
#define QREXEC_AGENT_FDPASS_PATH "/var/run/qubes/qrexec_agent_fdpass"
enum {
MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100,
MSG_CLIENT_TO_SERVER_JUST_EXEC,
MSG_CLIENT_TO_SERVER_CONNECT_EXISTING,
MSG_SERVER_TO_AGENT_CONNECT_EXISTING,
MSG_SERVER_TO_AGENT_EXEC_CMDLINE,
MSG_SERVER_TO_AGENT_JUST_EXEC,
MSG_SERVER_TO_AGENT_INPUT,
@ -42,19 +45,13 @@ enum {
MSG_AGENT_TO_SERVER_STDOUT,
MSG_AGENT_TO_SERVER_STDERR,
MSG_AGENT_TO_SERVER_EXIT_CODE,
MSG_AGENT_TO_SERVER_TRIGGER_EXEC,
MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING,
MSG_SERVER_TO_CLIENT_STDOUT,
MSG_SERVER_TO_CLIENT_STDERR,
MSG_SERVER_TO_CLIENT_EXIT_CODE
};
enum {
QREXEC_EXECUTE_FILE_COPY=0x700,
QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM,
QREXEC_EXECUTE_APPMENUS_SYNC
};
struct server_header {
unsigned int type;
unsigned int client_id;
@ -65,3 +62,13 @@ struct client_header {
unsigned int type;
unsigned int len;
};
struct connect_existing_params {
char ident[32];
};
struct trigger_connect_params {
char exec_index[64];
char target_vmname[32];
struct connect_existing_params process_fds;
};

View File

@ -68,12 +68,14 @@ struct _process_fd process_fd[MAX_FDS];
struct _client_info client_info[MAX_FDS];
int trigger_fd;
int passfd_socket;
void init()
{
peer_server_init(REXEC_PORT);
umask(0);
mkfifo(QREXEC_AGENT_TRIGGER_PATH, 0666);
passfd_socket = get_server_socket(QREXEC_AGENT_FDPASS_PATH);
umask(077);
trigger_fd =
open(QREXEC_AGENT_TRIGGER_PATH, O_RDONLY | O_NONBLOCK);
@ -145,15 +147,9 @@ void handle_just_exec(int client_id, int len)
fprintf(stderr, "executed (nowait) %s pid %d\n", buf, pid);
}
void handle_exec(int client_id, int len)
void create_info_about_client(int client_id, int pid, int stdin_fd,
int stdout_fd, int stderr_fd)
{
char buf[len];
int pid, stdin_fd, stdout_fd, stderr_fd;
read_all_vchan_ext(buf, len);
do_fork_exec(buf, &pid, &stdin_fd, &stdout_fd, &stderr_fd);
process_fd[stdout_fd].client_id = client_id;
process_fd[stdout_fd].type = FDTYPE_STDOUT;
process_fd[stdout_fd].is_blocked = 0;
@ -177,11 +173,34 @@ void handle_exec(int client_id, int len)
client_info[client_id].is_blocked = 0;
client_info[client_id].is_close_after_flush_needed = 0;
buffer_init(&client_info[client_id].buffer);
}
void handle_exec(int client_id, int len)
{
char buf[len];
int pid, stdin_fd, stdout_fd, stderr_fd;
read_all_vchan_ext(buf, len);
do_fork_exec(buf, &pid, &stdin_fd, &stdout_fd, &stderr_fd);
create_info_about_client(client_id, pid, stdin_fd, stdout_fd,
stderr_fd);
fprintf(stderr, "executed %s pid %d\n", buf, pid);
}
void handle_connect_existing(int client_id, int len)
{
int stdin_fd, stdout_fd, stderr_fd;
char buf[len];
read_all_vchan_ext(buf, len);
sscanf(buf, "%d %d %d", &stdin_fd, &stdout_fd, &stderr_fd);
create_info_about_client(client_id, -1, stdin_fd, stdout_fd,
stderr_fd);
client_info[client_id].is_exited = 1; //do not wait for SIGCHLD
}
void update_max_process_fd()
{
@ -307,6 +326,9 @@ void handle_server_data()
case MSG_XOFF:
set_blocked_outerr(s_hdr.client_id, 1);
break;
case MSG_SERVER_TO_AGENT_CONNECT_EXISTING:
handle_connect_existing(s_hdr.client_id, s_hdr.len);
break;
case MSG_SERVER_TO_AGENT_EXEC_CMDLINE:
handle_exec(s_hdr.client_id, s_hdr.len);
break;
@ -432,9 +454,12 @@ int fill_fds_for_select(fd_set * rdset, fd_set * wrset)
FD_SET(trigger_fd, rdset);
if (trigger_fd > max)
max = trigger_fd;
FD_SET(passfd_socket, rdset);
if (passfd_socket > max)
max = passfd_socket;
for (i = 0; i < MAX_FDS; i++)
if (client_info[i].pid > 0 && client_info[i].is_blocked) {
if (client_info[i].pid && client_info[i].is_blocked) {
fd = client_info[i].stdin_fd;
FD_SET(fd, wrset);
if (fd > max)
@ -467,28 +492,31 @@ void flush_client_data_agent(int client_id)
}
}
void handle_new_passfd()
{
int fd = do_accept(passfd_socket);
if (fd >= MAX_FDS) {
fprintf(stderr, "too many clients ?\n");
exit(1);
}
// let client know what fd has been allocated
write(fd, &fd, sizeof(fd));
}
void handle_trigger_io()
{
struct server_header s_hdr;
char buf[5];
struct trigger_connect_params params;
int ret;
s_hdr.client_id = 0;
s_hdr.len = 0;
if ((ret = read(trigger_fd, buf, 4)) == 4) {
buf[4] = 0;
if (!strcmp(buf, "FCPR"))
s_hdr.client_id = QREXEC_EXECUTE_FILE_COPY;
else if (!strcmp(buf, "DVMR"))
s_hdr.client_id =
QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM;
else if (!strcmp(buf, "SYNC"))
s_hdr.client_id =
QREXEC_EXECUTE_APPMENUS_SYNC;
if (s_hdr.client_id) {
s_hdr.type = MSG_AGENT_TO_SERVER_TRIGGER_EXEC;
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
}
ret = read(trigger_fd, &params, sizeof(params));
if (ret == sizeof(params)) {
s_hdr.type = MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING;
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
write_all_vchan_ext(&params, sizeof params);
}
// trigger_fd is nonblock - so no need to reopen
// not really, need to reopen at EOF
@ -518,6 +546,9 @@ int main()
wait_for_vchan_or_argfd(max, &rdset, &wrset);
if (FD_ISSET(passfd_socket, &rdset))
handle_new_passfd();
while (read_ready_vchan_ext())
handle_server_data();
@ -526,7 +557,7 @@ int main()
handle_process_data_all(&rdset);
for (i = 0; i <= MAX_FDS; i++)
if (client_info[i].pid > 0
if (client_info[i].pid
&& client_info[i].is_blocked
&& FD_ISSET(client_info[i].stdin_fd, &wrset))
flush_client_data_agent(i);

View File

@ -209,8 +209,9 @@ void select_loop(int s)
void usage(char *name)
{
fprintf(stderr,
"usage: %s -d domain_num [-l local_prog] -e remote_cmdline\n"
"-e means exit after sending cmd\n", name);
"usage: %s -d domain_num [-l local_prog] -e -c remote_cmdline\n"
"-e means exit after sending cmd, -c: connect to existing process\n",
name);
exit(1);
}
@ -220,8 +221,9 @@ int main(int argc, char **argv)
char *domname = NULL;
int s;
int just_exec = 0;
int connect_existing = 0;
char *local_cmdline = NULL;
while ((opt = getopt(argc, argv, "d:l:e")) != -1) {
while ((opt = getopt(argc, argv, "d:l:ec")) != -1) {
switch (opt) {
case 'd':
domname = strdup(optarg);
@ -232,6 +234,9 @@ int main(int argc, char **argv)
case 'e':
just_exec = 1;
break;
case 'c':
connect_existing = 1;
break;
default:
usage(argv[0]);
}
@ -247,8 +252,12 @@ int main(int argc, char **argv)
send_cmdline(s, MSG_CLIENT_TO_SERVER_JUST_EXEC,
argv[optind]);
else {
send_cmdline(s, MSG_CLIENT_TO_SERVER_EXEC_CMDLINE,
argv[optind]);
int cmd;
if (connect_existing)
cmd = MSG_CLIENT_TO_SERVER_CONNECT_EXISTING;
else
cmd = MSG_CLIENT_TO_SERVER_EXEC_CMDLINE;
send_cmdline(s, cmd, argv[optind]);
select_loop(s);
}
return 0;

109
qrexec/qrexec_client_vm.c Normal file
View File

@ -0,0 +1,109 @@
/*
* 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 <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "qrexec.h"
int connect_unix_socket()
{
int s, len;
struct sockaddr_un remote;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
return -1;
}
remote.sun_family = AF_UNIX;
strncpy(remote.sun_path, QREXEC_AGENT_FDPASS_PATH,
sizeof(remote.sun_path));
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *) &remote, len) == -1) {
perror("connect");
exit(1);
}
return s;
}
char *get_program_name(char *prog)
{
char *basename = rindex(prog, '/');
if (basename)
return basename + 1;
else
return prog;
}
int main(int argc, char **argv)
{
int trigger_fd;
struct trigger_connect_params params;
int local_fd[3], remote_fd[3];
int i;
char *abs_exec_path;
if (argc < 4) {
fprintf(stderr,
"usage: %s target_vmname program_ident local_program [local program arguments]\n",
argv[0]);
exit(1);
}
trigger_fd = open(QREXEC_AGENT_TRIGGER_PATH, O_WRONLY);
if (trigger_fd < 0) {
perror("open QREXEC_AGENT_TRIGGER_PATH");
exit(1);
}
for (i = 0; i < 3; i++) {
local_fd[i] = connect_unix_socket();
read(local_fd[i], &remote_fd[i], sizeof(remote_fd[i]));
if (i != 2 || getenv("PASS_LOCAL_STDERR")) {
char *env;
asprintf(&env, "SAVED_FD_%d=%d", i, dup(i));
putenv(env);
dup2(local_fd[i], i);
close(local_fd[i]);
}
}
memset(&params, 0, sizeof(params));
strncpy(params.exec_index, argv[2], sizeof(params.exec_index));
strncpy(params.target_vmname, argv[1],
sizeof(params.target_vmname));
snprintf(params.process_fds.ident,
sizeof(params.process_fds.ident), "%d %d %d",
remote_fd[0], remote_fd[1], remote_fd[2]);
write(trigger_fd, &params, sizeof(params));
close(trigger_fd);
abs_exec_path = strdup(argv[3]);
argv[3] = get_program_name(argv[3]);
execv(abs_exec_path, argv + 3);
perror("execv");
return 1;
}

View File

@ -29,6 +29,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <ioall.h>
#include <string.h>
#include "qrexec.h"
#include "buffer.h"
#include "glue.h"
@ -67,6 +68,21 @@ void sigchld_handler(int x);
char *remote_domain_name; // guess what
int create_qrexec_socket(int domid, char *domname)
{
char socket_address[40];
char link_to_socket_name[strlen(domname) + sizeof(socket_address)];
snprintf(socket_address, sizeof(socket_address),
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", domid);
snprintf(link_to_socket_name, sizeof link_to_socket_name,
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname);
unlink(link_to_socket_name);
symlink(socket_address, link_to_socket_name);
return get_server_socket(socket_address);
}
/* do the preparatory tasks, needed before entering the main event loop */
void init(int xid)
{
@ -119,7 +135,7 @@ void init(int xid)
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
umask(0);
qrexec_daemon_unix_socket_fd =
get_server_socket(xid, remote_domain_name);
create_qrexec_socket(xid, remote_domain_name);
umask(0077);
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, sigchld_handler);
@ -167,8 +183,7 @@ void terminate_client_and_flush_data(int fd)
write_all_vchan_ext(&s_hdr, sizeof(s_hdr));
}
void get_cmdline_body_from_client_and_pass_to_agent(int fd,
struct server_header
void get_cmdline_body_from_client_and_pass_to_agent(int fd, struct server_header
*s_hdr)
{
int len = s_hdr->len;
@ -196,6 +211,9 @@ void handle_cmdline_message_from_client(int fd)
case MSG_CLIENT_TO_SERVER_JUST_EXEC:
s_hdr.type = MSG_SERVER_TO_AGENT_JUST_EXEC;
break;
case MSG_CLIENT_TO_SERVER_CONNECT_EXISTING:
s_hdr.type = MSG_SERVER_TO_AGENT_CONNECT_EXISTING;
break;
default:
terminate_client_and_flush_data(fd);
return;
@ -271,8 +289,7 @@ void write_buffered_data_to_client(int client_id)
The header (hdr argument) is already built. Just read the raw data from
the packet, and pass it along with the header to the client.
*/
void get_packet_data_from_agent_and_pass_to_client(int client_id,
struct client_header
void get_packet_data_from_agent_and_pass_to_client(int client_id, struct client_header
*hdr)
{
int len = hdr->len;
@ -342,33 +359,48 @@ void check_children_count_and_wait_if_too_many()
}
}
void sanitize_name(char * untrusted_s_signed)
{
unsigned char * untrusted_s;
for (untrusted_s=(unsigned char*)untrusted_s_signed; *untrusted_s; untrusted_s++) {
if (*untrusted_s >= 'a' && *untrusted_s <= 'z')
continue;
if (*untrusted_s >= 'A' && *untrusted_s <= 'Z')
continue;
if (*untrusted_s >= '0' && *untrusted_s <= '9')
continue;
if (*untrusted_s == '_' || *untrusted_s == '-' || *untrusted_s == '.' || *untrusted_s == ' ')
continue;
*untrusted_s = '_';
}
}
#define ENSURE_NULL_TERMINATED(x) x[sizeof(x)-1] = 0
/*
Called when agent sends a message asking to execute a predefined command.
*/
void handle_execute_predefined_command(int req)
void handle_execute_predefined_command()
{
char *rcmd = NULL, *lcmd = NULL;
int i;
struct trigger_connect_params untrusted_params, params;
check_children_count_and_wait_if_too_many();
switch (req) {
case QREXEC_EXECUTE_FILE_COPY:
rcmd = "directly:user:/usr/lib/qubes/qfile-agent";
lcmd = "/usr/lib/qubes/qfile-daemon";
break;
case QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM:
rcmd = "directly:user:/usr/lib/qubes/qfile-agent-dvm";
lcmd = "/usr/lib/qubes/qfile-daemon-dvm";
break;
case QREXEC_EXECUTE_APPMENUS_SYNC:
rcmd = "user:grep -H = /usr/share/applications/*.desktop";
lcmd = "/usr/bin/qvm-sync-appmenus";
break;
default: /* cannot happen, already sanitized */
fprintf(stderr, "got trigger exec no %d\n", req);
exit(1);
}
read_all_vchan_ext(&untrusted_params, sizeof(params));
/* sanitize start */
ENSURE_NULL_TERMINATED(untrusted_params.exec_index);
ENSURE_NULL_TERMINATED(untrusted_params.target_vmname);
ENSURE_NULL_TERMINATED(untrusted_params.process_fds.ident);
sanitize_name(untrusted_params.exec_index);
sanitize_name(untrusted_params.target_vmname);
sanitize_name(untrusted_params.process_fds.ident);
params = untrusted_params;
/* sanitize end */
switch (fork()) {
case -1:
perror("fork");
@ -383,8 +415,9 @@ void handle_execute_predefined_command(int req)
close(i);
signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
execl("/usr/lib/qubes/qrexec_client", "qrexec_client", "-d",
remote_domain_name, "-l", lcmd, rcmd, NULL);
execl("/usr/lib/qubes/qrexec_policy", "qrexec_policy",
remote_domain_name, params.target_vmname,
params.exec_index, params.process_fds.ident, NULL);
perror("execl");
exit(1);
}
@ -401,18 +434,8 @@ void check_client_id_in_range(unsigned int untrusted_client_id)
void sanitize_message_from_agent(struct server_header *untrusted_header)
{
int untrusted_cmd;
switch (untrusted_header->type) {
case MSG_AGENT_TO_SERVER_TRIGGER_EXEC:
untrusted_cmd = untrusted_header->client_id;
if (untrusted_cmd != QREXEC_EXECUTE_FILE_COPY &&
untrusted_cmd != QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM &&
untrusted_cmd != QREXEC_EXECUTE_APPMENUS_SYNC) {
fprintf(stderr,
"received MSG_AGENT_TO_SERVER_TRIGGER_EXEC cmd %d ?\n",
untrusted_cmd);
exit(1);
}
case MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING:
break;
case MSG_AGENT_TO_SERVER_STDOUT:
case MSG_AGENT_TO_SERVER_STDERR:
@ -451,8 +474,8 @@ void handle_message_from_agent()
// fprintf(stderr, "got %x %x %x\n", s_hdr.type, s_hdr.client_id,
// s_hdr.len);
if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_EXEC) {
handle_execute_predefined_command(s_hdr.client_id);
if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING) {
handle_execute_predefined_command();
return;
}

135
qrexec/qrexec_policy Executable file
View File

@ -0,0 +1,135 @@
#!/usr/bin/python
import sys
import os
import os.path
import subprocess
import xen.lowlevel.xl
POLICY_FILE_DIR="/etc/qubes_rpc/policy"
QREXEC_CLIENT="/usr/lib/qubes/qrexec_client"
def line_to_dict(line):
tokens=line.split()
if len(tokens) < 3:
return None
dict={}
dict['source']=tokens[0]
dict['dest']=tokens[1]
action_list=tokens[2].split(',')
dict['action']=action_list.pop(0)
for iter in action_list:
paramval=iter.split("=")
dict["action."+paramval[0]]=paramval[1]
return dict
def read_policy_file(exec_index):
policy_file=POLICY_FILE_DIR+"/"+exec_index
if not os.path.isfile(policy_file):
return None
policy_list=list()
f = open(policy_file)
for iter in f.readlines():
dict = line_to_dict(iter)
if dict is not None:
policy_list.append(dict)
f.close()
return policy_list
def is_match(item, config_term):
return (item is not "dom0" and config_term == "anyvm") or item == config_term
def get_default_policy():
dict={}
dict["action"]="deny"
return dict
def find_policy(policy, domain, target):
for iter in policy:
if not is_match(domain, iter["source"]):
continue
if not is_match(target, iter["dest"]):
continue
return iter
return get_default_policy()
def is_domain_running(target):
xl_ctx = xen.lowlevel.xl.ctx()
domains = xl_ctx.list_domains()
for dominfo in domains:
domname = xl_ctx.domid_to_name(dominfo.domid)
if domname == target:
return True
return False
def spawn_target_if_necessary(target):
if is_domain_running(target):
return
null=open("/dev/null", "r+")
subprocess.call(["qvm-run", "-a", "-q", target, "true"], stdin=null, stdout=null)
null.close()
def do_execute(domain, target, user, exec_index, process_ident):
if target == "dom0":
cmd="/usr/lib/qubes/qubes_rpc_multiplexer "+exec_index + " " + domain
elif target == "dispvm":
cmd = "/usr/lib/qubes/qfile-daemon-dvm " + exec_index + " " + domain + " " +user
else:
# see the previous commit why "qvm-run -a" is broken and dangerous
# also, dangling "xl" would keep stderr open and may prevent closing connection
spawn_target_if_necessary(target)
cmd= QREXEC_CLIENT + " -d " + target + " '" + user
cmd+=":/usr/lib/qubes/qubes_rpc_multiplexer "+ exec_index + " " + domain + "'"
os.execl(QREXEC_CLIENT, "qrexec_client", "-d", domain, "-l", cmd, "-c", process_ident)
def confirm_execution(domain, target, exec_index):
text = "Do you allow domain \"" +domain + "\" to execute " + exec_index
text+= " operation on the domain \"" + target +"\"?"
retcode = subprocess.call(["/usr/bin/zenity", "--question", "--text", text])
return retcode==0
def policy_editor(domain, target, exec_index):
text = "Policy editor not yet implemented. Please add a line in the form \""
text+= domain + " " + target + "action_to_take\""
text+= " to /etc/qubes_rpc/policy/" + exec_index +" file in dom0, then close this info."
subprocess.call(["/usr/bin/zenity", "--info", "--text", text])
def main():
domain=sys.argv[1]
target=sys.argv[2]
exec_index=sys.argv[3]
process_ident=sys.argv[4]
policy_list=read_policy_file(exec_index)
if policy_list==None:
policy_editor(domain, target, exec_index)
policy_list=read_policy_file(exec_index)
if policy_list==None:
policy_list=list()
policy_dict=find_policy(policy_list, domain, target)
if policy_dict["action"] == "ask":
if confirm_execution(domain, target, exec_index):
policy_dict["action"] = "allow"
else:
policy_dict["action"] = "deny"
if policy_dict["action"] == "allow":
if policy_dict.has_key("action.target"):
target=policy_dict["action.target"]
if policy_dict.has_key("action.user"):
user=policy_dict["action.user"]
else:
user="user"
do_execute(domain, target, user, exec_index, process_ident)
print >> sys.stderr, "Rpc denied:", domain, target, exec_index
os.execl(QREXEC_CLIENT, "qrexec_client", "-d", domain, "-l", "/bin/false", "-c", process_ident)
main()

14
qrexec/qubes_rpc_multiplexer Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
QUBES_RPC=/etc/qubes_rpc
if ! [ $# = 2 ] ; then
echo $0: bad argument count >&2
exit 1
fi
CFG_FILE=$QUBES_RPC/"$1"
if [ -s "$CFG_FILE" ] ; then
exec $(cat "$CFG_FILE") "$2"
echo "$0: failed to execute handler for" "$1" >&2
exit 1
fi
echo "$0: nonexistent or empty" "$CFG_FILE" file >&2
exit 1

View File

@ -27,20 +27,12 @@
#include <stdlib.h>
#include "qrexec.h"
int get_server_socket(int domid, char *domname)
int get_server_socket(char *socket_address)
{
struct sockaddr_un sockname;
int s;
char socket_address[40];
char link_to_socket_name[strlen(domname) + sizeof(socket_address)];
snprintf(socket_address, sizeof(socket_address),
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", domid);
snprintf(link_to_socket_name, sizeof link_to_socket_name,
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname);
unlink(socket_address);
unlink(link_to_socket_name);
symlink(socket_address, link_to_socket_name);
s = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&sockname, 0, sizeof(sockname));

View File

@ -75,17 +75,22 @@ 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-open-in-dvm2 $RPM_BUILD_ROOT/usr/bin
cp qvm-open-in-vm $RPM_BUILD_ROOT/usr/bin
cp qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes
cp qvm-copy-to-vm2.kde $RPM_BUILD_ROOT/usr/lib/qubes
cp qvm-copy-to-vm2.gnome $RPM_BUILD_ROOT/usr/lib/qubes
cp qvm-trigger-copy-to-vm $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
cp ../qrexec/qrexec_client_vm $RPM_BUILD_ROOT/usr/lib/qubes
cp ../qrexec/qubes_rpc_multiplexer $RPM_BUILD_ROOT/usr/lib/qubes
cp vm-file-editor qfile-agent qopen-in-vm qfile-unpacker $RPM_BUILD_ROOT/usr/lib/qubes
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/mnt/removable
mkdir -p $RPM_BUILD_ROOT/etc/qubes_rpc
cp qubes.Filecopy $RPM_BUILD_ROOT/etc/qubes_rpc
cp qubes.OpenInVM $RPM_BUILD_ROOT/etc/qubes_rpc
mkdir -p $RPM_BUILD_ROOT/etc/X11
cp xorg-preload-apps.conf $RPM_BUILD_ROOT/etc/X11
@ -136,16 +141,21 @@ rm -rf $RPM_BUILD_ROOT
/usr/lib/qubes/qvm-copy-to-vm2.kde
/usr/lib/qubes/qvm-copy-to-vm2.gnome
/usr/bin/qvm-open-in-dvm2
/usr/bin/qvm-open-in-vm
/usr/lib/qubes/meminfo-writer
/usr/lib/qubes/dvm_file_editor
/usr/lib/qubes/vm-file-editor
%{kde_service_dir}/qvm-copy.desktop
%{kde_service_dir}/qvm-dvm.desktop
/usr/lib/qubes/qvm-trigger-copy-to-vm
/usr/lib/qubes/qrexec_agent
/usr/lib/qubes/qrexec_client_vm
/usr/lib/qubes/qubes_rpc_multiplexer
/usr/lib/qubes/qfile-agent
/usr/lib/qubes/qfile-agent-dvm
/usr/lib/qubes/qopen-in-vm
/usr/lib/qubes/qfile-unpacker
%dir /mnt/removable
%dir /etc/qubes_rpc
/etc/qubes_rpc/qubes.Filecopy
/etc/qubes_rpc/qubes.OpenInVM
/usr/bin/qubes_timestamp
%dir /home_volatile
%attr(700,user,user) /home_volatile/user

View File

@ -96,14 +96,24 @@ 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/
cp ../qrexec/qrexec_client $RPM_BUILD_ROOT/usr/lib/qubes/
cp ../qrexec/qrexec_policy $RPM_BUILD_ROOT/usr/lib/qubes/
cp aux-tools/qfile-dom0-unpacker $RPM_BUILD_ROOT/usr/lib/qubes/
cp aux-tools/qubes-receive-updates $RPM_BUILD_ROOT/usr/lib/qubes/
mkdir -p $RPM_BUILD_ROOT/etc/qubes_rpc/policy
cp ../appvm/qubes.Filecopy.policy $RPM_BUILD_ROOT/etc/qubes_rpc/policy/qubes.Filecopy
cp ../appvm/qubes.OpenInVM.policy $RPM_BUILD_ROOT/etc/qubes_rpc/policy/qubes.OpenInVM
cp qubes.SyncAppMenus.policy $RPM_BUILD_ROOT/etc/qubes_rpc/policy/qubes.SyncAppMenus
cp qubes.SyncAppMenus $RPM_BUILD_ROOT/etc/qubes_rpc/
cp ../qrexec/qubes_rpc_multiplexer $RPM_BUILD_ROOT/usr/lib/qubes
cp aux-tools/qubes.ReceiveUpdates.policy $RPM_BUILD_ROOT/etc/qubes_rpc/policy/qubes.ReceiveUpdates
cp aux-tools/qubes.ReceiveUpdates $RPM_BUILD_ROOT/etc/qubes_rpc/
cp restore/qvm-create-default-dvm $RPM_BUILD_ROOT/usr/bin
cp restore/xenstore-watch $RPM_BUILD_ROOT/usr/bin/xenstore-watch-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/qfile-daemon-dvm $RPM_BUILD_ROOT/usr/lib/qubes
cp restore/qfile-daemon $RPM_BUILD_ROOT/usr/lib/qubes
mkdir -p $RPM_BUILD_ROOT/etc/yum.real.repos.d
cp qubes-cached.repo $RPM_BUILD_ROOT/etc/yum.real.repos.d/
@ -289,8 +299,8 @@ fi
/usr/lib/qubes/qmemman_daemon.py*
/usr/lib/qubes/meminfo-writer
/usr/lib/qubes/qfile-daemon-dvm*
/usr/lib/qubes/qfile-daemon
/usr/lib/qubes/sync_rpmdb_updatevm.sh
/usr/lib/qubes/qubes-receive-updates
%attr(4750,root,qubes) /usr/lib/qubes/qfile-dom0-unpacker
%attr(770,root,qubes) %dir /var/lib/qubes
%attr(770,root,qubes) %dir /var/lib/qubes/vm-templates
@ -321,6 +331,15 @@ fi
/etc/xen/scripts/block-origin
/etc/xen/scripts/vif-route-qubes
/usr/lib/qubes/qrexec_client
/usr/lib/qubes/qubes_rpc_multiplexer
/usr/lib/qubes/qrexec_policy
%dir /etc/qubes_rpc/policy
/etc/qubes_rpc/policy/qubes.Filecopy
/etc/qubes_rpc/policy/qubes.OpenInVM
/etc/qubes_rpc/policy/qubes.SyncAppMenus
/etc/qubes_rpc/policy//qubes.ReceiveUpdates
/etc/qubes_rpc/qubes.SyncAppMenus
/etc/qubes_rpc/qubes.ReceiveUpdates
%attr(4750,root,qubes) /usr/lib/qubes/qrexec_daemon
%attr(4750,root,qubes) /usr/lib/qubes/xenfreepages
%attr(2770,root,qubes) %dir /var/log/qubes