Compare commits

...

21 Commits

Author SHA1 Message Date
Marek Marczykowski-Górecki 0ac1b2cbe6
version 3.0.20
8 years ago
Marek Marczykowski-Górecki 2d8e7f378e
pm-utils: call qubes.SuspendPreAll/qubes.SuspendPostAll services
8 years ago
Marek Marczykowski-Górecki 978d87858a
dom0-update: remove cached metadata when --clean is used
8 years ago
Marek Marczykowski-Górecki 35a7d5ef53
pm-utils: do not leave background tasks - will be killed by systemd
8 years ago
Marek Marczykowski-Górecki ab5e1182c5
Use qubes.SetDateTime instead of direct call in post-suspend time sync
8 years ago
Marek Marczykowski-Górecki af1a352343
version 3.0.19
8 years ago
Marek Marczykowski-Górecki d5ccd02fa0
dom0-update: do not output scary messagge about missing repomd.xml
8 years ago
Marek Marczykowski-Górecki 85b848393d
version 3.0.18
8 years ago
Marek Marczykowski-Górecki 8563d1aa7d
Fix typo in "d9d48e8 qrexec: use tray notification when..."
8 years ago
Marek Marczykowski-Górecki fdd7daf436
qrexec: use tray notification when VM needs to be started
8 years ago
Marek Marczykowski-Górecki 961616cb8e
dracut: include all USB controllers drivers
8 years ago
Marek Marczykowski-Górecki cdc1c719d4
dom0-updates: remove "updates pending" flag also when no actual updates were found
8 years ago
Marek Marczykowski-Górecki 137ed7d331
dom0-updates: wait for apper to finish, then remove "updates pending" flag
8 years ago
Marek Marczykowski-Górecki 0376f2f940
dom0-updates: ensure proper permissions on "updates pending" flag
8 years ago
Marek Marczykowski-Górecki cbd33cd5c6
dom0-updates: remove unused code from cron job
8 years ago
Marek Marczykowski-Górecki d2f5e0a97f
version 3.0.17
9 years ago
Marek Marczykowski-Górecki 7286eee2ef
Require new enough qubes-utils package for updated libqrexec-utils
9 years ago
Marek Marczykowski-Górecki 819204bc73
qrexec: implement buffered write to child stdin to prevent deadlock
9 years ago
Marek Marczykowski-Górecki 95b10d1843
version 3.0.16
9 years ago
Marek Marczykowski-Górecki b20e40b6cf
qrexec: fallback to kdialog if zenity is not installed
9 years ago
Marek Marczykowski-Górecki dac1b7702f
qrexec: fix handling autostarting RPC target VM
9 years ago

@ -86,7 +86,7 @@ if [ "$GUI" == "1" ]; then
if type $app &>/dev/null; then if type $app &>/dev/null; then
guiapp=$app guiapp=$app
case $guiapp in case $guiapp in
apper) guiapp="apper --updates" ;; apper) guiapp="apper --updates --nofork" ;;
*) guiapp=$app ;; *) guiapp=$app ;;
esac esac
break; break;
@ -119,6 +119,7 @@ fi
if [ -n "$CLEAN" ]; then if [ -n "$CLEAN" ]; then
rm -f /var/lib/qubes/updates/rpm/* rm -f /var/lib/qubes/updates/rpm/*
rm -f /var/lib/qubes/updates/repodata/*
fi fi
rm -f /var/lib/qubes/updates/errors rm -f /var/lib/qubes/updates/errors
@ -169,5 +170,6 @@ elif [ -f /var/lib/qubes/updates/repodata/repomd.xml ]; then
fi fi
yum -q check-update && rm -f $UPDATES_STAT_FILE yum -q check-update && rm -f $UPDATES_STAT_FILE
else else
rm -f $UPDATES_STAT_FILE
echo "No updates avaliable" >&2 echo "No updates avaliable" >&2
fi fi

@ -1,7 +1,5 @@
#!/bin/bash #!/bin/bash
# Get normal user name
LOCAL_USER=`users | sed -e 's/root *//' | cut -d' ' -f 1`
NOTIFY_ICON=/usr/share/qubes/icons/dom0-update-avail.svg NOTIFY_ICON=/usr/share/qubes/icons/dom0-update-avail.svg
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
UPDATES_DISABLE_FLAG=/var/lib/qubes/updates/disable-updates UPDATES_DISABLE_FLAG=/var/lib/qubes/updates/disable-updates
@ -19,10 +17,7 @@ if [ "$RETCODE" -ne 100 ]; then
exit $RETCODE exit $RETCODE
fi fi
if [ -z "$LOCAL_USER" ]; then
echo "ERROR: no user logged in, cannot nofity about updates" >&2
exit 1
fi
# Touch stat file for qubes-manager # Touch stat file for qubes-manager
touch $UPDATES_STAT_FILE touch "$UPDATES_STAT_FILE"
chgrp qubes "$UPDATES_STAT_FILE"
chmod g+w "$UPDATES_STAT_FILE"

@ -3,5 +3,9 @@
installkernel() { installkernel() {
# ehci-hcd split off # ehci-hcd split off
instmods ehci-pci ehci-platform || : hostonly='' instmods ehci-pci ehci-platform || :
# xhci-hcd split off
hostonly='' instmods xhci-pci xhci-plat-hcd || :
# ohci-hcd split off
hostonly='' instmods ohci-pci || :
} }

@ -6,9 +6,9 @@ sync_qubes_vms_wallclock()
DATE=$(date) DATE=$(date)
echo echo
echo "Syncing VMs clock to: $DATE" echo "Syncing VMs clock to: $DATE"
qvm-run --all -u root "date -s \"$DATE\"" qvm-run --all -u root --localcmd="date -u -Iseconds" "qubes.SetDateTime dom0"
# Then try to sync from the network # Then try to sync from the network
/usr/bin/qvm-sync-clock & /usr/bin/qvm-sync-clock
} }
case "$1" in case "$1" in

@ -12,6 +12,7 @@ if sys.argv[1] in ["suspend", "hibernate"]:
for vm in qc.values(): for vm in qc.values():
if vm.is_running(): if vm.is_running():
try: try:
vm.run_service("qubes.SuspendPreAll", user="root")
vm.suspend() vm.suspend()
except Exception as e: except Exception as e:
print >>sys.stderr, "Failed to suspend VM %s: %s" % (vm.name, e.message) print >>sys.stderr, "Failed to suspend VM %s: %s" % (vm.name, e.message)
@ -21,5 +22,6 @@ elif sys.argv[1] in ["resume", "thaw"]:
if vm.get_power_state() in ["Paused", "Suspended"]: if vm.get_power_state() in ["Paused", "Suspended"]:
try: try:
vm.resume() vm.resume()
vm.run_service("qubes.SuspendPostAll", user="root")
except Exception as e: except Exception as e:
print >>sys.stderr, "Failed to resume VM %s: %s" % (vm.name, e.message) print >>sys.stderr, "Failed to resume VM %s: %s" % (vm.name, e.message)

@ -170,10 +170,14 @@ void do_exec(const char *prog)
static void do_exit(int code) static void do_exit(int code)
{ {
int status; int status;
// sever communication lines; wait for child, if any /* restore flags, as we may have not the only copy of this file descriptor
// so that qrexec-daemon can count (recursively) spawned processes correctly */
if (local_stdin_fd != -1)
set_block(local_stdin_fd);
close(local_stdin_fd); close(local_stdin_fd);
close(local_stdout_fd); close(local_stdout_fd);
// sever communication lines; wait for child, if any
// so that qrexec-daemon can count (recursively) spawned processes correctly
waitpid(-1, &status, 0); waitpid(-1, &status, 0);
exit(code); exit(code);
} }
@ -269,9 +273,15 @@ static void handle_input(libvchan_t *vchan)
{ {
char buf[MAX_DATA_CHUNK]; char buf[MAX_DATA_CHUNK];
int ret; int ret;
size_t max_len;
struct msg_header hdr; struct msg_header hdr;
ret = read(local_stdout_fd, buf, sizeof(buf)); max_len = libvchan_buffer_space(vchan)-sizeof(hdr);
if (max_len > sizeof(buf))
max_len = sizeof(buf);
if (max_len == 0)
return;
ret = read(local_stdout_fd, buf, max_len);
if (ret < 0) { if (ret < 0) {
perror("read"); perror("read");
do_exit(1); do_exit(1);
@ -328,12 +338,25 @@ void do_replace_esc(char *buf, int len) {
buf[i] = '_'; buf[i] = '_';
} }
static void handle_vchan_data(libvchan_t *vchan) static int handle_vchan_data(libvchan_t *vchan, struct buffer *stdin_buf)
{ {
int status; int status;
struct msg_header hdr; struct msg_header hdr;
char buf[MAX_DATA_CHUNK]; char buf[MAX_DATA_CHUNK];
if (local_stdin_fd != -1) {
switch(flush_client_data(local_stdin_fd, stdin_buf)) {
case WRITE_STDIN_ERROR:
perror("write stdin");
close(local_stdin_fd);
local_stdin_fd = -1;
break;
case WRITE_STDIN_BUFFERED:
return WRITE_STDIN_BUFFERED;
case WRITE_STDIN_OK:
break;
}
}
if (libvchan_recv(vchan, &hdr, sizeof hdr) < 0) { if (libvchan_recv(vchan, &hdr, sizeof hdr) < 0) {
perror("read vchan"); perror("read vchan");
do_exit(1); do_exit(1);
@ -356,16 +379,29 @@ static void handle_vchan_data(libvchan_t *vchan)
if (replace_esc_stdout) if (replace_esc_stdout)
do_replace_esc(buf, hdr.len); do_replace_esc(buf, hdr.len);
if (hdr.len == 0) { if (hdr.len == 0) {
/* restore flags, as we may have not the only copy of this file descriptor
*/
if (local_stdin_fd != -1)
set_block(local_stdin_fd);
close(local_stdin_fd); close(local_stdin_fd);
local_stdin_fd = -1; local_stdin_fd = -1;
} else if (!write_all(local_stdin_fd, buf, hdr.len)) { } else {
if (errno == EPIPE) { switch (write_stdin(local_stdin_fd, buf, hdr.len, stdin_buf)) {
// remote side have closed its stdin, handle data in oposite case WRITE_STDIN_BUFFERED:
// direction (if any) before exit return WRITE_STDIN_BUFFERED;
local_stdin_fd = -1; case WRITE_STDIN_ERROR:
} else { if (errno == EPIPE) {
perror("write local stdout"); // local process have closed its stdin, handle data in oposite
do_exit(1); // direction (if any) before exit
close(local_stdin_fd);
local_stdin_fd = -1;
} else {
perror("write local stdout");
do_exit(1);
}
break;
case WRITE_STDIN_OK:
break;
} }
} }
break; break;
@ -381,12 +417,17 @@ static void handle_vchan_data(libvchan_t *vchan)
else else
memcpy(&status, buf, sizeof(status)); memcpy(&status, buf, sizeof(status));
flush_client_data(local_stdin_fd, stdin_buf);
do_exit(status); do_exit(status);
break; break;
default: default:
fprintf(stderr, "unknown msg %d\n", hdr.type); fprintf(stderr, "unknown msg %d\n", hdr.type);
do_exit(1); do_exit(1);
} }
/* intentionally do not distinguish between _ERROR and _OK, because in case
* of write error, we simply eat the data - no way to report it to the
* other side */
return WRITE_STDIN_OK;
} }
static void check_child_status(libvchan_t *vchan) static void check_child_status(libvchan_t *vchan)
@ -409,36 +450,52 @@ static void check_child_status(libvchan_t *vchan)
static void select_loop(libvchan_t *vchan) static void select_loop(libvchan_t *vchan)
{ {
fd_set select_set; fd_set select_set;
fd_set wr_set;
int max_fd; int max_fd;
int ret; int ret;
int vchan_fd; int vchan_fd;
sigset_t selectmask; sigset_t selectmask;
struct timespec zero_timeout = { 0, 0 }; struct timespec zero_timeout = { 0, 0 };
struct timespec select_timeout = { 10, 0 }; struct timespec select_timeout = { 10, 0 };
struct buffer stdin_buf;
sigemptyset(&selectmask); sigemptyset(&selectmask);
sigaddset(&selectmask, SIGCHLD); sigaddset(&selectmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &selectmask, NULL); sigprocmask(SIG_BLOCK, &selectmask, NULL);
sigemptyset(&selectmask); sigemptyset(&selectmask);
buffer_init(&stdin_buf);
/* remember to set back to blocking mode before closing the FD - this may
* be not the only copy and some processes may misbehave when get
* nonblocking FD for input/output
*/
set_nonblock(local_stdin_fd);
for (;;) { for (;;) {
vchan_fd = libvchan_fd_for_select(vchan); vchan_fd = libvchan_fd_for_select(vchan);
FD_ZERO(&select_set); FD_ZERO(&select_set);
FD_ZERO(&wr_set);
FD_SET(vchan_fd, &select_set); FD_SET(vchan_fd, &select_set);
max_fd = vchan_fd; max_fd = vchan_fd;
if (local_stdout_fd != -1 && libvchan_buffer_space(vchan)) { if (local_stdout_fd != -1 &&
(size_t)libvchan_buffer_space(vchan) > sizeof(struct msg_header)) {
FD_SET(local_stdout_fd, &select_set); FD_SET(local_stdout_fd, &select_set);
if (local_stdout_fd > max_fd) if (local_stdout_fd > max_fd)
max_fd = local_stdout_fd; max_fd = local_stdout_fd;
} }
if (child_exited && local_stdout_fd == -1) if (child_exited && local_stdout_fd == -1)
check_child_status(vchan); check_child_status(vchan);
if (libvchan_data_ready(vchan) > 0) { if (local_stdin_fd != -1 && buffer_len(&stdin_buf)) {
FD_SET(local_stdin_fd, &wr_set);
if (local_stdin_fd > max_fd)
max_fd = local_stdin_fd;
}
if ((local_stdin_fd == -1 || buffer_len(&stdin_buf) == 0) &&
libvchan_data_ready(vchan) > 0) {
/* check for other FDs, but exit immediately */ /* check for other FDs, but exit immediately */
ret = pselect(max_fd + 1, &select_set, NULL, NULL, ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
&zero_timeout, &selectmask); &zero_timeout, &selectmask);
} else } else
ret = pselect(max_fd + 1, &select_set, NULL, NULL, ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
&select_timeout, &selectmask); &select_timeout, &selectmask);
if (ret < 0) { if (ret < 0) {
if (errno == EINTR && local_pid > 0) { if (errno == EINTR && local_pid > 0) {
@ -456,8 +513,18 @@ static void select_loop(libvchan_t *vchan)
} }
if (FD_ISSET(vchan_fd, &select_set)) if (FD_ISSET(vchan_fd, &select_set))
libvchan_wait(vchan); libvchan_wait(vchan);
if (buffer_len(&stdin_buf) &&
local_stdin_fd != -1 &&
FD_ISSET(local_stdin_fd, &wr_set)) {
if (flush_client_data(local_stdin_fd, &stdin_buf) == WRITE_STDIN_ERROR) {
perror("write stdin");
close(local_stdin_fd);
local_stdin_fd = -1;
}
}
while (libvchan_data_ready(vchan)) while (libvchan_data_ready(vchan))
handle_vchan_data(vchan); if (handle_vchan_data(vchan, &stdin_buf) != WRITE_STDIN_OK)
break;
if (local_stdout_fd != -1 if (local_stdout_fd != -1
&& FD_ISSET(local_stdout_fd, &select_set)) && FD_ISSET(local_stdout_fd, &select_set))

@ -4,7 +4,9 @@ import os
import os.path import os.path
import subprocess import subprocess
from qubes.qubes import vmm from qubes.qubes import vmm
from qubes.qubes import QubesVmCollection
import qubes.guihelpers import qubes.guihelpers
import libvirt
from optparse import OptionParser from optparse import OptionParser
import fcntl import fcntl
@ -82,45 +84,36 @@ def find_policy(policy, domain, target):
return iter return iter
return get_default_policy() return get_default_policy()
def is_domain_running(target):
if target == "dom0":
return True
libvirt_dom = vmm.libvirt_conn.lookupByName(target)
if libvirt_dom:
return libvirt_dom.isActive()
else:
return False
def validate_target(target): def validate_target(target):
# special targets # special targets
if target in ['$dispvm', 'dom0']: if target in ['$dispvm']:
return True return True
from qubes.qubes import QubesVmCollection
qc = QubesVmCollection() qc = QubesVmCollection()
qc.lock_db_for_reading() qc.lock_db_for_reading()
qc.load() qc.load()
qc.unlock_db() qc.unlock_db()
return qc.get_vm_by_name(target) is not None return qc.get_vm_by_name(target)
def spawn_target_if_necessary(target): def spawn_target_if_necessary(vm):
if is_domain_running(target): if vm.is_running():
return return
null=open("/dev/null", "r+") # use qvm-run instead of vm.start() to make sure that nothing is written
subprocess.call(["qvm-run", "-a", "-q", target, "true"], stdin=null, stdout=null) # to stdout and nothing is read from stdin
null = open("/dev/null", "r+")
subprocess.call(["qvm-run", "-a", "--tray", "-q", vm.name, "true"],
stdin=null, stdout=null)
null.close() null.close()
def do_execute(domain, target, user, service_name, process_ident): def do_execute(domain, target, user, service_name, process_ident, vm=None):
if target == "$dispvm": if target == "$dispvm":
cmd = "/usr/lib/qubes/qfile-daemon-dvm " + service_name + " " + domain + " " +user cmd = "/usr/lib/qubes/qfile-daemon-dvm " + service_name + " " + domain + " " +user
os.execl(QREXEC_CLIENT, "qrexec-client", os.execl(QREXEC_CLIENT, "qrexec-client",
"-d", "dom0", "-c", process_ident, cmd) "-d", "dom0", "-c", process_ident, cmd)
else: else:
# see the previous commit why "qvm-run -a" is broken and dangerous if isinstance(vm, qubes.qubes.QubesVm):
# also, dangling "xl" would keep stderr open and may prevent closing connection spawn_target_if_necessary(vm)
spawn_target_if_necessary(target)
if target == "dom0": if target == "dom0":
cmd = QUBES_RPC_MULTIPLEXER_PATH + " " + service_name + " " + domain cmd = QUBES_RPC_MULTIPLEXER_PATH + " " + service_name + " " + domain
else: else:
@ -151,10 +144,25 @@ def add_always_allow(domain, target, service_name, options):
f.write("".join(lines)) f.write("".join(lines))
f.close() f.close()
def info_dialog(msg_type, text):
if msg_type not in ['info', 'warning', 'error']:
raise ValueError("Invalid msg_type value")
try:
subprocess.call(["/usr/bin/zenity", "--{}".format(msg_type), "--text",
text])
except OSError:
kdialog_msg_type = {
'info': 'msgbox',
'warning': 'sorry',
'error': 'error'
}[msg_type]
subprocess.call(["/usr/bin/kdialog", "--{}".format(kdialog_msg_type),
text])
def policy_editor(domain, target, service_name): def policy_editor(domain, target, service_name):
text = "No policy definition found for " + service_name + " action. " text = "No policy definition found for " + service_name + " action. "
text+= "Please create a policy file in Dom0 in " + POLICY_FILE_DIR + "/" + service_name text+= "Please create a policy file in Dom0 in " + POLICY_FILE_DIR + "/" + service_name
subprocess.call(["/usr/bin/zenity", "--info", "--text", text]) info_dialog("warning", text)
def main(): def main():
usage = "usage: %prog [options] <src-domain-id> <src-domain> <target-domain> <service> <process-ident>" usage = "usage: %prog [options] <src-domain-id> <src-domain> <target-domain> <service> <process-ident>"
@ -175,11 +183,12 @@ def main():
# connection # connection
process_ident+=","+domain+","+domain_id process_ident+=","+domain+","+domain_id
if not validate_target(target): vm = validate_target(target)
if vm is None:
print >> sys.stderr, "Rpc failed (unknown domain):", domain, target, service_name print >> sys.stderr, "Rpc failed (unknown domain):", domain, target, service_name
text = "Domain '%s' doesn't exist (service %s called by domain %s)." % ( text = "Domain '%s' doesn't exist (service %s called by domain %s)." % (
target, service_name, domain) target, service_name, domain)
subprocess.call(["/usr/bin/zenity", "--error", "--text", text]) info_dialog("error", text)
exit(1) exit(1)
policy_list=read_policy_file(service_name) policy_list=read_policy_file(service_name)
@ -218,7 +227,7 @@ def main():
else: else:
user="DEFAULT" user="DEFAULT"
print >> sys.stderr, "Rpc allowed:", domain, target, service_name print >> sys.stderr, "Rpc allowed:", domain, target, service_name
do_execute(domain, target, user, service_name, process_ident) do_execute(domain, target, user, service_name, process_ident, vm=vm)
print >> sys.stderr, "Rpc denied:", domain, target, service_name print >> sys.stderr, "Rpc denied:", domain, target, service_name
exit(1) exit(1)

@ -43,10 +43,10 @@ URL: http://www.qubes-os.org
BuildRequires: ImageMagick BuildRequires: ImageMagick
BuildRequires: pandoc BuildRequires: pandoc
BuildRequires: qubes-utils-devel >= 2.0.5 BuildRequires: qubes-utils-devel >= 3.0.12
BuildRequires: qubes-libvchan-devel BuildRequires: qubes-libvchan-devel
Requires: qubes-core-dom0 Requires: qubes-core-dom0
Requires: qubes-utils >= 2.0.6 Requires: qubes-utils >= 3.0.12
Requires: %{name}-kernel-install Requires: %{name}-kernel-install
%define _builddir %(pwd) %define _builddir %(pwd)

@ -1 +1 @@
3.0.15 3.0.20

Loading…
Cancel
Save