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

@ -1,7 +1,5 @@
#!/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
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
UPDATES_DISABLE_FLAG=/var/lib/qubes/updates/disable-updates
@ -19,10 +17,7 @@ if [ "$RETCODE" -ne 100 ]; then
exit $RETCODE
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 $UPDATES_STAT_FILE
touch "$UPDATES_STAT_FILE"
chgrp qubes "$UPDATES_STAT_FILE"
chmod g+w "$UPDATES_STAT_FILE"

@ -3,5 +3,9 @@
installkernel() {
# 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)
echo
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
/usr/bin/qvm-sync-clock &
/usr/bin/qvm-sync-clock
}
case "$1" in

@ -12,6 +12,7 @@ if sys.argv[1] in ["suspend", "hibernate"]:
for vm in qc.values():
if vm.is_running():
try:
vm.run_service("qubes.SuspendPreAll", user="root")
vm.suspend()
except Exception as e:
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"]:
try:
vm.resume()
vm.run_service("qubes.SuspendPostAll", user="root")
except Exception as e:
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)
{
int status;
// sever communication lines; wait for child, if any
// so that qrexec-daemon can count (recursively) spawned processes correctly
/* 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_stdout_fd);
// sever communication lines; wait for child, if any
// so that qrexec-daemon can count (recursively) spawned processes correctly
waitpid(-1, &status, 0);
exit(code);
}
@ -269,9 +273,15 @@ static void handle_input(libvchan_t *vchan)
{
char buf[MAX_DATA_CHUNK];
int ret;
size_t max_len;
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) {
perror("read");
do_exit(1);
@ -328,12 +338,25 @@ void do_replace_esc(char *buf, int len) {
buf[i] = '_';
}
static void handle_vchan_data(libvchan_t *vchan)
static int handle_vchan_data(libvchan_t *vchan, struct buffer *stdin_buf)
{
int status;
struct msg_header hdr;
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) {
perror("read vchan");
do_exit(1);
@ -356,16 +379,29 @@ static void handle_vchan_data(libvchan_t *vchan)
if (replace_esc_stdout)
do_replace_esc(buf, hdr.len);
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);
local_stdin_fd = -1;
} else if (!write_all(local_stdin_fd, buf, hdr.len)) {
if (errno == EPIPE) {
// remote side have closed its stdin, handle data in oposite
// direction (if any) before exit
local_stdin_fd = -1;
} else {
perror("write local stdout");
do_exit(1);
} else {
switch (write_stdin(local_stdin_fd, buf, hdr.len, stdin_buf)) {
case WRITE_STDIN_BUFFERED:
return WRITE_STDIN_BUFFERED;
case WRITE_STDIN_ERROR:
if (errno == EPIPE) {
// local process have closed its stdin, handle data in oposite
// 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;
@ -381,12 +417,17 @@ static void handle_vchan_data(libvchan_t *vchan)
else
memcpy(&status, buf, sizeof(status));
flush_client_data(local_stdin_fd, stdin_buf);
do_exit(status);
break;
default:
fprintf(stderr, "unknown msg %d\n", hdr.type);
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)
@ -409,36 +450,52 @@ static void check_child_status(libvchan_t *vchan)
static void select_loop(libvchan_t *vchan)
{
fd_set select_set;
fd_set wr_set;
int max_fd;
int ret;
int vchan_fd;
sigset_t selectmask;
struct timespec zero_timeout = { 0, 0 };
struct timespec select_timeout = { 10, 0 };
struct buffer stdin_buf;
sigemptyset(&selectmask);
sigaddset(&selectmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &selectmask, NULL);
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 (;;) {
vchan_fd = libvchan_fd_for_select(vchan);
FD_ZERO(&select_set);
FD_ZERO(&wr_set);
FD_SET(vchan_fd, &select_set);
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);
if (local_stdout_fd > max_fd)
max_fd = local_stdout_fd;
}
if (child_exited && local_stdout_fd == -1)
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 */
ret = pselect(max_fd + 1, &select_set, NULL, NULL,
ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
&zero_timeout, &selectmask);
} else
ret = pselect(max_fd + 1, &select_set, NULL, NULL,
ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
&select_timeout, &selectmask);
if (ret < 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))
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))
handle_vchan_data(vchan);
if (handle_vchan_data(vchan, &stdin_buf) != WRITE_STDIN_OK)
break;
if (local_stdout_fd != -1
&& FD_ISSET(local_stdout_fd, &select_set))

@ -4,7 +4,9 @@ import os
import os.path
import subprocess
from qubes.qubes import vmm
from qubes.qubes import QubesVmCollection
import qubes.guihelpers
import libvirt
from optparse import OptionParser
import fcntl
@ -82,45 +84,36 @@ def find_policy(policy, domain, target):
return iter
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):
# special targets
if target in ['$dispvm', 'dom0']:
if target in ['$dispvm']:
return True
from qubes.qubes import QubesVmCollection
qc = QubesVmCollection()
qc.lock_db_for_reading()
qc.load()
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):
if is_domain_running(target):
def spawn_target_if_necessary(vm):
if vm.is_running():
return
null=open("/dev/null", "r+")
subprocess.call(["qvm-run", "-a", "-q", target, "true"], stdin=null, stdout=null)
# use qvm-run instead of vm.start() to make sure that nothing is written
# 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()
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":
cmd = "/usr/lib/qubes/qfile-daemon-dvm " + service_name + " " + domain + " " +user
os.execl(QREXEC_CLIENT, "qrexec-client",
"-d", "dom0", "-c", process_ident, cmd)
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)
if isinstance(vm, qubes.qubes.QubesVm):
spawn_target_if_necessary(vm)
if target == "dom0":
cmd = QUBES_RPC_MULTIPLEXER_PATH + " " + service_name + " " + domain
else:
@ -151,10 +144,25 @@ def add_always_allow(domain, target, service_name, options):
f.write("".join(lines))
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):
text = "No policy definition found for " + service_name + " action. "
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():
usage = "usage: %prog [options] <src-domain-id> <src-domain> <target-domain> <service> <process-ident>"
@ -175,11 +183,12 @@ def main():
# connection
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
text = "Domain '%s' doesn't exist (service %s called by domain %s)." % (
target, service_name, domain)
subprocess.call(["/usr/bin/zenity", "--error", "--text", text])
info_dialog("error", text)
exit(1)
policy_list=read_policy_file(service_name)
@ -218,7 +227,7 @@ def main():
else:
user="DEFAULT"
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
exit(1)

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

@ -1 +1 @@
3.0.15
3.0.20

Loading…
Cancel
Save