diff --git a/dom0/aux-tools/block_cleaner_daemon.py b/dom0/aux-tools/block_cleaner_daemon.py new file mode 100755 index 00000000..76154759 --- /dev/null +++ b/dom0/aux-tools/block_cleaner_daemon.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import xen.lowlevel.xs +import time +import subprocess + +xs = xen.lowlevel.xs.xs() + +domain_list = [] + +def setup_watches(): + global domain_list + + new_domain_list = xs.ls('', '/local/domain') + for dom in new_domain_list: + if dom not in domain_list: + print "Adding: %s" % dom + xs.watch('/local/domain/%s/backend/vbd' % dom, int(dom)) + for dom in domain_list: + if dom not in new_domain_list: + print "Removing: %s" % dom + xs.unwatch('/local/domain/%s/backend/vbd' % dom, int(dom)) + domain_list = new_domain_list + +def handle_vbd_state(path): + state = xs.read('', path) + if state == '6': + # Closed state; wait a moment to not interrupt reconnect + time.sleep(0.500) + state = xs.read('', path) + if state == '6': + # If still closed, detach device + path_components = path.split('/') + # /local/domain//backend/vbd///... + vm_xid = path_components[6] + vm_dev = path_components[7] + if vm_xid in domain_list: + subprocess.call('xl', 'block-detach', vm_xid, vm_dev) + +def main(): + + xs.watch('@introduceDomain', 'reload') + xs.watch('@releaseDomain', 'reload') + setup_watches() + while True: + (path, token) = xs.read_watch() + if token == 'reload': + setup_watches() + else: + if path.endswith('/state'): + handle_vbd_state(path) + +main() diff --git a/dom0/aux-tools/qubes-dom0-updates.cron b/dom0/aux-tools/qubes-dom0-updates.cron index 8cf805fe..b30a0b43 100755 --- a/dom0/aux-tools/qubes-dom0-updates.cron +++ b/dom0/aux-tools/qubes-dom0-updates.cron @@ -4,6 +4,7 @@ LOCAL_USER=`users | sed -e 's/root *//' | cut -d' ' -f 1` PIDFILE=/var/run/qubes/dom0-update-notification.pid NOTIFY_ICON=/usr/share/qubes/icons/dom0-update-avail.svg +UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available # Do not allow multiple instances [ -r $PIDFILE ] && kill -0 `cat $PIDFILE` && exit 0 @@ -13,7 +14,7 @@ echo $$ > $PIDFILE trap "rm $PIDFILE" EXIT # If no updates available - exit here -qubes-dom0-updates --check-only && exit +qubes-dom0-update --check-only >/dev/null && exit RETCODE=$? if [ "$RETCODE" -ne 100 ]; then @@ -26,6 +27,9 @@ if [ -z "$LOCAL_USER" ]; then exit 1 fi +# Touch stat file for qubes-manager +touch $UPDATES_STAT_FILE + # Notify about updates using system tray zenity --notification --window-icon=$NOTIFY_ICON --text="Qubes dom0 updates available." @@ -33,3 +37,6 @@ zenity --question --title="Qubes Dom0 updates" \ --text="There are updates for dom0 available, do you want to download them now?" || exit 0 su -c "DISPLAY=:0 qubes-dom0-update --gui" $LOCAL_USER + +# Check if user installed updates +yum -q check-updates && rm $UPDATES_STAT_FILE diff --git a/dom0/aux-tools/qubes-notify-updates b/dom0/aux-tools/qubes-notify-updates index 2e09f411..d34de46c 100755 --- a/dom0/aux-tools/qubes-notify-updates +++ b/dom0/aux-tools/qubes-notify-updates @@ -24,6 +24,7 @@ import os.path import sys import subprocess import shutil +import grp from datetime import datetime from qubes.qubes import QubesVmCollection from qubes.qubes import updates_stat_file @@ -46,6 +47,9 @@ def main(): print >> sys.stderr, 'Domain ' + source + ' does not exists (?!)' exit(1) + os.umask(0002) + qubes_gid = grp.getgrnam('qubes').gr_gid + update_count = sys.stdin.readline(128).strip() if not update_count.isdigit(): print >> sys.stderr, 'Domain ' + source + ' sent invalid number of updates: ' + update_count @@ -55,6 +59,7 @@ def main(): update_f = open(source_vm.dir_path + '/' + updates_stat_file, "w") update_f.write(update_count) update_f.close() + os.chown(source_vm.dir_path + '/' + updates_stat_file, -1, qubes_gid) elif source_vm.template is not None: # Hint about updates availability in template # If template is running - it will notify about updates itself @@ -72,6 +77,7 @@ def main(): update_f = open(stat_file, "w") update_f.write(update_count) update_f.close() + os.chown(stat_file, -1, qubes_gid) else: print >> sys.stderr, 'Ignoring notification of no updates' diff --git a/dom0/init.d/qubes_core b/dom0/init.d/qubes_core index dbcadccc..b491da6d 100755 --- a/dom0/init.d/qubes_core +++ b/dom0/init.d/qubes_core @@ -53,6 +53,11 @@ start() MEMINFO_DELAY_USEC=100000 /usr/lib/qubes/meminfo-writer $MEM_CHANGE_THRESHOLD_KB $MEMINFO_DELAY_USEC & + /usr/lib/qubes/block_cleaner_daemon.py > /var/log/qubes/block_cleaner.log 2>&1 & + + # Reply block events to hide mounted devices from qubes-block list (at first udev run, only / is mounted) + udevadm trigger --subsystem-match=block --action=add + touch /var/lock/subsys/qubes_core success echo diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 65c87843..2db9fd1e 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -74,7 +74,6 @@ default_appmenus_template_templates_subdir = "apps-template.templates" default_kernels_subdir = "kernels" default_firewall_conf_file = "firewall.xml" default_memory = 400 -default_servicevm_vcpus = 1 default_kernelopts = "" default_kernelopts_pcidevs = "iommu=soft swiotlb=2048" @@ -107,6 +106,9 @@ qubes_appmenu_create_cmd = "/usr/lib/qubes/create_apps_for_appvm.sh" qubes_appmenu_remove_cmd = "/usr/lib/qubes/remove_appvm_appmenus.sh" qubes_pciback_cmd = '/usr/lib/qubes/unbind_pci_device.sh' +yum_proxy_ip = '10.137.255.254' +yum_proxy_port = '8082' + class QubesException (Exception) : pass if not dry_run: @@ -401,7 +403,7 @@ class QubesVm(object): shutil.copy(self.firewall_conf, "%s/backup/%s-firewall-%s.xml" % (qubes_base_dir, self.name, time.strftime('%Y-%m-%d-%H:%M:%S'))) self.write_firewall_conf({'allow': False, 'allowDns': False, - 'allowIcmp': False, 'rules': []}) + 'allowIcmp': False, 'allowYumProxy': False, 'rules': []}) else: new_netvm.connected_vms[self.qid]=self @@ -848,6 +850,9 @@ class QubesVm(object): "{0}/qubes-block-devices".format(domain_path), '') + xs.write('', "{0}/qubes-debug-mode".format(domain_path), + str(int(self.debug))) + # Fix permissions xs.set_permissions('', '{0}/device'.format(domain_path), [{ 'dom': xid }]) @@ -1165,7 +1170,8 @@ class QubesVm(object): "QubesFirwallRules", policy = "allow" if conf["allow"] else "deny", dns = "allow" if conf["allowDns"] else "deny", - icmp = "allow" if conf["allowIcmp"] else "deny" + icmp = "allow" if conf["allowIcmp"] else "deny", + yumProxy = "allow" if conf["allowYumProxy"] else "deny" ) for rule in conf["rules"]: @@ -1205,13 +1211,20 @@ class QubesVm(object): os.path.basename(sys.argv[0]), err) return False + # Automatically enable/disable 'yum-proxy-setup' service based on allowYumProxy + if conf['allowYumProxy']: + self.services['yum-proxy-setup'] = True + else: + if self.services.has_key('yum-proxy-setup'): + self.services.pop('yum-proxy-setup') + return True def has_firewall(self): return os.path.exists (self.firewall_conf) def get_firewall_conf(self): - conf = { "rules": list(), "allow": True, "allowDns": True, "allowIcmp": True } + conf = { "rules": list(), "allow": True, "allowDns": True, "allowIcmp": True, "allowYumProxy": False } try: tree = xml.etree.ElementTree.parse(self.firewall_conf) @@ -1220,6 +1233,7 @@ class QubesVm(object): conf["allow"] = (root.get("policy") == "allow") conf["allowDns"] = (root.get("dns") == "allow") conf["allowIcmp"] = (root.get("icmp") == "allow") + conf["allowYumProxy"] = (root.get("yumProxy") == "allow") for element in root: rule = {} @@ -1710,10 +1724,8 @@ class QubesNetVm(QubesVm): attrs_config = super(QubesNetVm, self)._get_attrs_config() attrs_config['dir_path']['eval'] = 'value if value is not None else qubes_servicevms_dir + "/" + self.name' attrs_config['label']['default'] = default_servicevm_label - attrs_config['vcpus']['default'] = default_servicevm_vcpus attrs_config['memory']['default'] = 200 - attrs_config['maxmem']['eval'] = 'self.memory' - + # New attributes attrs_config['netid'] = { 'save': 'str(self.netid)', 'order': 30 } attrs_config['netprefix'] = { 'eval': '"10.137.{0}.".format(self.netid)' } @@ -1969,7 +1981,7 @@ class QubesProxyVm(QubesNetVm): if vm.has_firewall(): conf = vm.get_firewall_conf() else: - conf = { "rules": list(), "allow": True, "allowDns": True, "allowIcmp": True } + conf = { "rules": list(), "allow": True, "allowDns": True, "allowIcmp": True, "allowYumProxy": False } xid = vm.get_xid() if xid < 0: # VM not active ATM @@ -2012,6 +2024,10 @@ class QubesProxyVm(QubesNetVm): iptables += "-A FORWARD -s {0} -p udp -d {1} --dport 53 -j ACCEPT\n".format(ip,self.netvm.secondary_dns) if conf["allowIcmp"]: iptables += "-A FORWARD -s {0} -p icmp -j ACCEPT\n".format(ip) + if conf["allowYumProxy"]: + iptables += "-A FORWARD -s {0} -p tcp -d {1} --dport {2} -j ACCEPT\n".format(ip, yum_proxy_ip, yum_proxy_port) + else: + iptables += "-A FORWARD -s {0} -p tcp -d {1} --dport {2} -j DROP\n".format(ip, yum_proxy_ip, yum_proxy_port) iptables += "-A FORWARD -s {0} -j {1}\n".format(ip, default_action) iptables += "COMMIT\n" diff --git a/dom0/qvm-tools/qvm-firewall b/dom0/qvm-tools/qvm-firewall index f85bc6ff..581fd3ca 100755 --- a/dom0/qvm-tools/qvm-firewall +++ b/dom0/qvm-tools/qvm-firewall @@ -189,7 +189,8 @@ def display_firewall(conf): print "Firewall policy: %s" % ( "ALLOW all traffic except" if conf['allow'] else "DENY all traffic except") print "ICMP: %s" % ("ALLOW" if conf['allowIcmp'] else 'DENY') - print "DMS: %s" % ("ALLOW" if conf['allowDns'] else 'DENY') + print "DNS: %s" % ("ALLOW" if conf['allowDns'] else 'DENY') + print "Qubes yum proxy: %s" % ("ALLOW" if conf['allowYumProxy'] else 'DENY') list_rules(conf['rules']) def add_rule(conf, args): @@ -251,6 +252,8 @@ def main(): help="Set ICMP access (allow/deny)") parser.add_option ("-D", "--dns", dest="set_dns", action="store", default=None, help="Set DNS access (allow/deny)") + parser.add_option ("-Y", "--yum-proxy", dest="set_yum_proxy", action="store", default=None, + help="Set access to Qubes yum proxy (allow/deny)") parser.add_option ("-n", "--numeric", dest="numeric", action="store_true", default=False, help="Display port numbers instead of services (makes sense only with --list)") @@ -261,7 +264,7 @@ def main(): vmname = args[0] args = args[1:] - if options.do_add or options.do_del or options.set_policy or options.set_icmp or options.set_dns: + if options.do_add or options.do_del or options.set_policy or options.set_icmp or options.set_dns or options.set_yum_proxy: options.do_list = False qvm_collection = QubesVmCollection() if options.do_list: @@ -289,6 +292,9 @@ def main(): if options.set_dns: conf['allowDns'] = allow_deny_value(options.set_dns) changed = True + if options.set_yum_proxy: + conf['allowYumProxy'] = allow_deny_value(options.set_yum_proxy) + changed = True if options.do_add: load_services() @@ -308,6 +314,7 @@ def main(): if vm.is_running(): if vm.netvm is not None and vm.netvm.is_proxyvm(): vm.netvm.write_iptables_xenstore_entry() + qvm_collection.save() if not options.do_list: qvm_collection.unlock_db() diff --git a/dom0/qvm-tools/qvm-ls b/dom0/qvm-tools/qvm-ls index d4e4e0ee..ac94a71d 100755 --- a/dom0/qvm-tools/qvm-ls +++ b/dom0/qvm-tools/qvm-ls @@ -76,6 +76,9 @@ fields = { "label" : {"func" : "vm.label.name"}, + "kernel" : {"func" : "('*' if vm.uses_default_kernel else '') + str(vm.kernel) if hasattr(vm, 'kernel') else 'n/a'"}, + "kernelopts" : {"func" : "('*' if vm.uses_default_kernelopts else '') + str(vm.kernelopts) if hasattr(vm, 'kernelopts') else 'n/a'"}, + "on" : {"func" : "'*' if vm.is_running() else ''"} } @@ -102,6 +105,10 @@ def main(): action="store_true", default=False, help="Show VM disk utilization statistics") + parser.add_option ("-k", "--kernel", dest="kernel", + action="store_true", default=False, + help="Show VM kernel options") + parser.add_option ("-i", "--ids", dest="ids", action="store_true", default=False, help="Show Qubes and Xen id#s") @@ -141,6 +148,9 @@ def main(): fields_to_display.remove ("netvm") fields_to_display += ["priv-curr", "priv-max", "root-curr", "root-max", "disk" ] + if (options.kernel): + fields_to_display += ["kernel", "kernelopts" ] + vms_list = [vm for vm in qvm_collection.values()] no_vms = len (vms_list) diff --git a/dom0/qvm-tools/qvm-service b/dom0/qvm-tools/qvm-service new file mode 100755 index 00000000..6dbb8a6c --- /dev/null +++ b/dom0/qvm-tools/qvm-service @@ -0,0 +1,97 @@ +#!/usr/bin/python +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2012 Marek Marczykowski +# +# 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. +# +# + +from qubes.qubes import QubesVmCollection +from optparse import OptionParser; +import subprocess +import sys +import re + +def do_list(vm): + max_len = 0 + for s in vm.services.keys(): + max_len = max(max_len, len(s)) + fmt="{{0:<{0}}}: {{1}}".format(max_len) + + for s in vm.services.keys(): + print fmt.format (s, "Enabled" if vm.services[s] else "Disabled") + + +def main(): + usage = "usage: %prog [action] [service]\n" + parser = OptionParser (usage) + parser.add_option ("-l", "--list", dest="do_list", action="store_true", default=True, + help="List services (default action)") + parser.add_option ("-e", "--enable", dest="set_enable", action="store_true", default=False, + help="Enable service") + parser.add_option ("-d", "--disable", dest="set_disable", action="store_true", default=False, + help="Disable service") + parser.add_option ("-D", "--default", dest="set_default", action="store_true", default=False, + help="Reset service to its default state (remove from the list)") + + (options, args) = parser.parse_args () + if (len (args) < 1): + parser.error ("You must specify VM name!") + vmname = args[0] + args = args[1:] + + if options.set_enable or options.set_disable or options.set_default: + if (len(args) < 1): + parser.error("You must specify service name!") + options.do_list = False + + qvm_collection = QubesVmCollection() + if options.do_list: + qvm_collection.lock_db_for_reading() + qvm_collection.load() + qvm_collection.unlock_db() + else: + qvm_collection.lock_db_for_writing() + qvm_collection.load() + + vm = qvm_collection.get_vm_by_name(vmname) + if vm is None: + print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname) + exit(1) + + changed = False + if options.do_list: + do_list(vm) + elif options.set_enable: + vm.services[args[0]] = True + changed = True + elif options.set_disable: + vm.services[args[0]] = False + changed = True + elif options.set_default: + if vm.services.has_key(args[0]): + vm.services.pop(args[0]) + changed = True + + if changed: + qvm_collection.save() + + if not options.do_list: + qvm_collection.unlock_db() + + +main() diff --git a/network/filter-qubes-yum b/network/filter-qubes-yum new file mode 100644 index 00000000..b244f3cf --- /dev/null +++ b/network/filter-qubes-yum @@ -0,0 +1,6 @@ +.*/repodata/[A-Za-z0-9-]*\(primary\|filelist\|comps\(-[a-z0-9]*\)\?\|other\|prestodelta\)\.\(sqlite\|xml\)\(\.bz2\|\.gz\)\?$ +.*/repodata/repomd\.xml$ +.*\.rpm$ +.*\.drpm$ +mirrors.fedoraproject.org:443 +^http://mirrors\..*/mirrorlist diff --git a/network/iptables b/network/iptables index 6e6e6d89..5977ff22 100644 --- a/network/iptables +++ b/network/iptables @@ -4,7 +4,9 @@ :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :PR-QBS - [0:0] +:PR-QBS-SERVICES - [0:0] -A PREROUTING -j PR-QBS +-A PREROUTING -j PR-QBS-SERVICES -A POSTROUTING -o vif+ -j ACCEPT -A POSTROUTING -o lo -j ACCEPT -A POSTROUTING -j MASQUERADE diff --git a/network/tinyproxy-qubes-yum.conf b/network/tinyproxy-qubes-yum.conf new file mode 100644 index 00000000..43b5082f --- /dev/null +++ b/network/tinyproxy-qubes-yum.conf @@ -0,0 +1,30 @@ +User tinyproxy +Group tinyproxy +Port 8082 +Timeout 60 +DefaultErrorFile "/usr/share/tinyproxy/default.html" + +#StatHost "tinyproxy.stats" +StatFile "/usr/share/tinyproxy/stats.html" +Syslog On +LogLevel Notice +PidFile "/var/run/tinyproxy/tinyproxy-qubes-yum.pid" + +MaxClients 50 +MinSpareServers 2 +MaxSpareServers 10 +StartServers 2 +MaxRequestsPerChild 0 +ViaProxyName "tinyproxy" + +Allow 127.0.0.1 +Allow 10.137.0.0/16 + + +Filter "/etc/tinyproxy/filter-qubes-yum" +FilterURLs On +#FilterExtended On +#FilterCaseSensitive On +FilterDefaultDeny Yes +ConnectPort 443 + diff --git a/network/vif-route-qubes b/network/vif-route-qubes index c8070177..6809028b 100755 --- a/network/vif-route-qubes +++ b/network/vif-route-qubes @@ -53,8 +53,9 @@ if [ "${ip}" ] ; then for addr in ${ip} ; do ${cmdprefix} ip route ${ipcmd} ${addr} dev ${vif} metric $metric done - echo ${cmdprefix} iptables -t raw $iptables_cmd -i ${vif} \! -s ${ip} -j DROP - ${cmdprefix} iptables -t raw $iptables_cmd -i ${vif} \! -s ${ip} -j DROP + ${cmdprefix} iptables -t raw $iptables_cmd -i ${vif} \! -s ${ip} -j DROP + back_ip=${ip%.*}.1 + ${cmdprefix} ip addr ${ipcmd} ${back_ip}/32 dev ${vif} fi log debug "Successful vif-route-qubes $command for $vif." diff --git a/qrexec/qrexec.h b/qrexec/qrexec.h index e3a556ea..4313d119 100644 --- a/qrexec/qrexec.h +++ b/qrexec/qrexec.h @@ -19,6 +19,8 @@ * */ +/* See also http://wiki.qubes-os.org/trac/wiki/Qrexec */ + #define QREXEC_DAEMON_SOCKET_DIR "/var/run/qubes" #define MAX_FDS 256 #define MAX_DATA_CHUNK 4096 @@ -30,26 +32,52 @@ #define MEMINFO_WRITER_PIDFILE "/var/run/meminfo-writer.pid" enum { + /* messages from qrexec_client to qrexec_daemon (both in dom0) */ + /* start process in VM and pass its stdin/out/err to dom0 */ MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100, + /* start process in VM discarding its stdin/out/err (connect to /dev/null) */ MSG_CLIENT_TO_SERVER_JUST_EXEC, + /* connect to existing process in VM to receive its stdin/out/err + * struct connect_existing_params passed as data */ MSG_CLIENT_TO_SERVER_CONNECT_EXISTING, + /* messages qrexec_daemon(dom0)->qrexec_agent(VM) */ + /* same as MSG_CLIENT_TO_SERVER_CONNECT_EXISTING */ MSG_SERVER_TO_AGENT_CONNECT_EXISTING, + /* same as MSG_CLIENT_TO_SERVER_EXEC_CMDLINE */ MSG_SERVER_TO_AGENT_EXEC_CMDLINE, + /* same as MSG_CLIENT_TO_SERVER_JUST_EXEC */ MSG_SERVER_TO_AGENT_JUST_EXEC, + /* pass data to process stdin */ MSG_SERVER_TO_AGENT_INPUT, + /* detach from process; qrexec_agent should close pipes to process + * stdin/out/err; it's up to the VM child process if it cause its termination */ MSG_SERVER_TO_AGENT_CLIENT_END, + /* flow control, qrexec_daemon->qrexec_agent */ + /* suspend reading of named fd from child process */ MSG_XOFF, + /* resume reading of named fd from child process */ MSG_XON, + /* messages qrexec_agent(VM)->qrexec_daemon(dom0) */ + /* pass data from process stdout */ MSG_AGENT_TO_SERVER_STDOUT, + /* pass data from process stderr */ MSG_AGENT_TO_SERVER_STDERR, + /* inform that process terminated and pass its exit code; this should be + * send after all data from stdout/err are send */ MSG_AGENT_TO_SERVER_EXIT_CODE, + /* call Qubes RPC service + * struct trigger_connect_params passed as data */ MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING, + /* messages qrexec_daemon->qrexec_client (both in dom0) */ + /* same as MSG_AGENT_TO_SERVER_STDOUT */ MSG_SERVER_TO_CLIENT_STDOUT, + /* same as MSG_AGENT_TO_SERVER_STDERR */ MSG_SERVER_TO_CLIENT_STDERR, + /* same as MSG_AGENT_TO_SERVER_EXIT_CODE */ MSG_SERVER_TO_CLIENT_EXIT_CODE }; diff --git a/qrexec/qrexec_agent.c b/qrexec/qrexec_agent.c index 0741f8e8..93fa100d 100644 --- a/qrexec/qrexec_agent.c +++ b/qrexec/qrexec_agent.c @@ -113,28 +113,6 @@ void no_colon_in_cmd() exit(1); } -void do_exec_directly(char *cmd) -{ - struct passwd *pwd; - char *sep = index(cmd, ':'); - if (!sep) - no_colon_in_cmd(); - *sep = 0; - pwd = getpwnam(cmd); - if (!pwd) { - perror("getpwnam"); - exit(1); - } - setgid(pwd->pw_gid); - initgroups(cmd, pwd->pw_gid); - setuid(pwd->pw_uid); - setenv("HOME", pwd->pw_dir, 1); - setenv("USER", cmd, 1); - execl(sep + 1, sep + 1, NULL); - perror("execl"); - exit(1); -} - void do_exec(char *cmd) { char *sep = index(cmd, ':'); @@ -144,8 +122,6 @@ void do_exec(char *cmd) signal(SIGCHLD, SIG_DFL); signal(SIGPIPE, SIG_DFL); - if (!strcmp(cmd, "directly")) - do_exec_directly(sep + 1); execl("/bin/su", "su", "-", cmd, "-c", sep + 1, NULL); perror("execl"); exit(1); diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index f6ec33e1..4de15029 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -114,6 +114,7 @@ cp aux-tools/qubes-receive-updates $RPM_BUILD_ROOT/usr/lib/qubes/ cp ../misc/block_add_change $RPM_BUILD_ROOT/usr/lib/qubes/ cp ../misc/block_remove $RPM_BUILD_ROOT/usr/lib/qubes/ cp ../misc/block_cleanup $RPM_BUILD_ROOT/usr/lib/qubes/ +cp aux-tools/block_cleaner_daemon.py $RPM_BUILD_ROOT/usr/lib/qubes/ mkdir -p $RPM_BUILD_ROOT/etc/qubes_rpc/policy cp ../qubes_rpc/qubes.Filecopy.policy $RPM_BUILD_ROOT/etc/qubes_rpc/policy/qubes.Filecopy @@ -344,6 +345,7 @@ fi /usr/lib/qubes/block_add_change /usr/lib/qubes/block_remove /usr/lib/qubes/block_cleanup +/usr/lib/qubes/block_cleaner_daemon.py* %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 diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index 0b9d5ffd..06004ea5 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -37,6 +37,7 @@ Requires: yum-plugin-post-transaction-actions Requires: NetworkManager >= 0.8.1-1 Requires: /usr/bin/mimeopen Requires: /sbin/ethtool +Requires: tinyproxy Provides: qubes-core-vm Obsoletes: qubes-core-commonvm Obsoletes: qubes-core-appvm @@ -80,7 +81,7 @@ su user -c 'touch /home/user/.gnome2/nautilus-scripts/.scripts_created2' %install -install -D misc/fstab $RPM_BUILD_ROOT/etc/fstab +install -m 0644 -D misc/fstab $RPM_BUILD_ROOT/etc/fstab install -d $RPM_BUILD_ROOT/etc/init.d install vm-init.d/* $RPM_BUILD_ROOT/etc/init.d/ @@ -116,7 +117,7 @@ mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes install -D misc/qubes_core.modules $RPM_BUILD_ROOT/etc/sysconfig/modules/qubes_core.modules -install network/qubes_network.rules $RPM_BUILD_ROOT/etc/udev/rules.d/99-qubes_network.rules +install -m 0644 network/qubes_network.rules $RPM_BUILD_ROOT/etc/udev/rules.d/99-qubes_network.rules install network/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes install network/qubes_fix_nm_conf.sh $RPM_BUILD_ROOT/usr/lib/qubes install network/setup_ip $RPM_BUILD_ROOT/usr/lib/qubes/ @@ -126,7 +127,12 @@ ln -s /usr/lib/qubes/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes install -d $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/ install network/{qubes_nmhook,30-qubes_external_ip} $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/ install -D network/vif-route-qubes $RPM_BUILD_ROOT/etc/xen/scripts/vif-route-qubes -install -D network/iptables $RPM_BUILD_ROOT/etc/sysconfig/iptables +install -m 0644 -D network/iptables $RPM_BUILD_ROOT/etc/sysconfig/iptables +install -m 0644 -D network/tinyproxy-qubes-yum.conf $RPM_BUILD_ROOT/etc/tinyproxy/tinyproxy-qubes-yum.conf +install -m 0644 -D network/filter-qubes-yum $RPM_BUILD_ROOT/etc/tinyproxy/filter-qubes-yum + +install -d $RPM_BUILD_ROOT/etc/yum.conf.d +touch $RPM_BUILD_ROOT/etc/yum.conf.d/qubes-proxy.conf install -d $RPM_BUILD_ROOT/usr/sbin install network/qubes_firewall $RPM_BUILD_ROOT/usr/sbin/ @@ -233,6 +239,12 @@ fi # Remove ip_forward setting from sysctl, so NM will not reset it sed 's/^net.ipv4.ip_forward.*/#\0/' -i /etc/sysctl.conf +if ! grep -q '/etc/yum\.conf\.d/qubes-proxy\.conf'; then + echo >> /etc/yum.conf + echo '# Yum does not support inclusion of config dir...' >> /etc/yum.conf + echo 'include=file:///etc/yum.conf.d/qubes-proxy.conf' >> /etc/yum.conf +fi + # Prevent unnecessary updates in VMs: sed -i -e '/^exclude = kernel/d' /etc/yum.conf echo 'exclude = kernel, xorg-x11-drv-*, xorg-x11-drivers, xorg-x11-server-*' >> /etc/yum.conf @@ -334,10 +346,13 @@ rm -rf $RPM_BUILD_ROOT /etc/sudoers.d/qubes /etc/sysconfig/iptables /etc/sysconfig/modules/qubes_core.modules +/etc/tinyproxy/filter-qubes-yum +/etc/tinyproxy/tinyproxy-qubes-yum.conf /etc/udev/rules.d/50-qubes_memory.rules /etc/udev/rules.d/99-qubes_block.rules /etc/udev/rules.d/99-qubes_network.rules /etc/xen/scripts/vif-route-qubes +/etc/yum.conf.d/qubes-proxy.conf /etc/yum.repos.d/qubes.repo /etc/yum/post-actions/qubes_trigger_sync_appmenus.action /lib/firmware/updates @@ -422,6 +437,7 @@ The Qubes core startup configuration for SysV init (or upstart). /etc/init.d/qubes_core_netvm /etc/init.d/qubes-firewall /etc/init.d/qubes-netwatcher +/etc/init.d/qubes-yum-proxy %post sysvinit @@ -454,6 +470,8 @@ chkconfig --add qubes_firewall || echo "WARNING: Cannot add service qubes_core!" chkconfig qubes_firewall on || echo "WARNING: Cannot enable service qubes_core!" chkconfig --add qubes-netwatcher || echo "WARNING: Cannot add service qubes_core!" chkconfig qubes-netwatcher on || echo "WARNING: Cannot enable service qubes_core!" +chkconfig --add qubes-yum-proxy || echo "WARNING: Cannot add service qubes-yum-proxy!" +chkconfig qubes-yum-proxy on || echo "WARNING: Cannot enable service qubes-yum-proxy!" # TODO: make this not display the silly message about security context... sed -i s/^id:.:initdefault:/id:3:initdefault:/ /etc/inittab @@ -466,6 +484,7 @@ if [ "$1" = 0 ] ; then chkconfig qubes_core_appvm off chkconfig qubes-firewall off chkconfig qubes-netwatcher off + chkconfig qubes-yum-proxy off fi %package systemd @@ -495,6 +514,7 @@ The Qubes core startup configuration for SystemD init. /lib/systemd/system/qubes-sysinit.service /lib/systemd/system/qubes-update-check.service /lib/systemd/system/qubes-update-check.timer +/lib/systemd/system/qubes-yum-proxy.service %dir /usr/lib/qubes/init /usr/lib/qubes/init/prepare-dvm.sh /usr/lib/qubes/init/network-proxy-setup.sh @@ -509,7 +529,7 @@ The Qubes core startup configuration for SystemD init. %post systemd -for srv in qubes-dvm qubes-meminfo-writer qubes-qrexec-agent qubes-sysinit qubes-misc-post qubes-netwatcher qubes-network qubes-firewall; do +for srv in qubes-dvm qubes-meminfo-writer qubes-qrexec-agent qubes-sysinit qubes-misc-post qubes-netwatcher qubes-network qubes-firewall qubes-yum-proxy; do /bin/systemctl enable $srv.service 2> /dev/null done diff --git a/version_dom0 b/version_dom0 index 18f812ff..efb45341 100644 --- a/version_dom0 +++ b/version_dom0 @@ -1 +1 @@ -2.0.23 +2.0.25 diff --git a/vm-init.d/qubes-yum-proxy b/vm-init.d/qubes-yum-proxy new file mode 100755 index 00000000..52f329ba --- /dev/null +++ b/vm-init.d/qubes-yum-proxy @@ -0,0 +1,121 @@ +#!/bin/sh +# +# tinyproxy Startup script for the tinyproxy server as Qubes yum proxy +# +# chkconfig: - 85 15 +# description: small, efficient HTTP/SSL proxy daemon +# +# processname: tinyproxy +# config: /etc/tinyproxy/tinyproxy-qubes-yum.conf +# config: /etc/sysconfig/tinyproxy-qubes-yum +# pidfile: /var/run/tinyproxy/tinyproxy-qubes-yum.pid +# +# Note: pidfile is created by tinyproxy in its config +# see PidFile in the configuration file. + +# Source function library. +. /etc/rc.d/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ "$NETWORKING" = "no" ] && exit 0 + +exec="/usr/sbin/tinyproxy" +prog=$(basename $exec) +config="/etc/tinyproxy/tinyproxy-qubes-yum.conf" +pidfile="/var/run/tinyproxy/tinyproxy-qubes-yum.pid" + +[ -e /etc/sysconfig/tinyproxy-qubes-yum ] && . /etc/sysconfig/tinyproxy-qubes-yum + +lockfile=/var/lock/subsys/tinyproxy-qubes-yum + +start() { + type=`/usr/bin/xenstore-read qubes_vm_type` + start_yum_proxy=`/usr/bin/xenstore-read qubes-service/qubes-yum-proxy 2>/dev/null` + if [ -z "$start_yum_proxy" ] && [ "$type" != "NetVM" ] || [ "$start_yum_proxy" != "1" ]; then + # Yum proxy disabled + exit 0 + fi + + [ -x $exec ] || exit 5 + [ -f $config ] || exit 6 + # setup network redirection + /sbin/iptables -I INPUT -i vif+ -p tcp --dport 8082 -j ACCEPT + /sbin/iptables -t nat -A PR-QBS-SERVICES -i vif+ -d 10.137.255.254 -p tcp --dport 8082 -j REDIRECT + + echo -n $"Starting $prog (as Qubes yum proxy): " + daemon $exec -c $config + retval=$? + echo + [ $retval -eq 0 ] && touch $lockfile + return $retval +} + +stop() { + echo -n $"Stopping $prog: " + killproc -p $pidfile $prog + retval=$? + echo + /sbin/iptables -t nat -D PR-QBS-SERVICES -i vif+ -d 10.137.255.254 -p tcp --dport 8082 -j REDIRECT + /sbin/iptables -D INPUT -i vif+ -p tcp --dport 8082 -j ACCEPT + [ $retval -eq 0 ] && rm -f $lockfile + return $retval +} + +restart() { + stop + start +} + +reload() { + echo -n $"Reloading $prog: " + killproc -p $pidfile $prog -HUP + echo +} + +force_reload() { + restart +} + +rh_status() { + status $prog +} + +rh_status_q() { + rh_status >/dev/null 2>&1 +} + +case "$1" in + start) + rh_status_q && exit 0 + $1 + ;; + stop) + rh_status_q || exit 0 + $1 + ;; + restart) + $1 + ;; + reload) + rh_status_q || exit 7 + $1 + ;; + force-reload) + force_reload + ;; + status) + rh_status + ;; + condrestart|try-restart) + rh_status_q || exit 0 + restart + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" + exit 2 +esac +exit $? + diff --git a/vm-init.d/qubes_core b/vm-init.d/qubes_core index 7193d386..de194f89 100755 --- a/vm-init.d/qubes_core +++ b/vm-init.d/qubes_core @@ -36,6 +36,13 @@ start() echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock fi + yum_proxy_setup=$(/usr/bin/xenstore-read qubes-service/yum-proxy-setup 2> /dev/null) + if [ "$yum_proxy_setup" != "0" ]; then + echo proxy=http://10.137.255.254:8082/ > /etc/yum.conf.d/qubes-proxy.conf + else + echo > /etc/yum.conf.d/qubes-proxy.conf + fi + # Set IP address again (besides action in udev rules); this is needed by # DispVM (to override DispVM-template IP) and in case when qubes_ip was # called by udev before loading evtchn kernel module - in which case diff --git a/vm-systemd/misc-post.sh b/vm-systemd/misc-post.sh index 9ebdf2e0..dbefd432 100755 --- a/vm-systemd/misc-post.sh +++ b/vm-systemd/misc-post.sh @@ -1,5 +1,11 @@ #!/bin/sh +if [ -f /var/run/qubes-service/yum-proxy-setup ]; then + echo proxy=http://10.137.255.254:8082/ > /etc/yum.conf.d/qubes-proxy.conf +else + echo > /etc/yum.conf.d/qubes-proxy.conf +fi + # Set IP address again (besides action in udev rules); this is needed by # DispVM (to override DispVM-template IP) and in case when qubes_ip was # called by udev before loading evtchn kernel module - in which case diff --git a/vm-systemd/qubes-sysinit.sh b/vm-systemd/qubes-sysinit.sh index 02e2a9a0..0c8e9d0f 100755 --- a/vm-systemd/qubes-sysinit.sh +++ b/vm-systemd/qubes-sysinit.sh @@ -1,7 +1,7 @@ #!/bin/sh # List of services enabled by default (in case of absence of xenstore entry) -DEFAULT_ENABLED_NETVM="network-manager qubes-network qubes-update-check" +DEFAULT_ENABLED_NETVM="network-manager qubes-network qubes-update-check qubes-yum-proxy" DEFAULT_ENABLED_PROXYVM="meminfo-writer qubes-network qubes-firewall qubes-netwatcher qubes-update-check" DEFAULT_ENABLED_APPVM="meminfo-writer cups qubes-update-check" DEFAULT_ENABLED_TEMPLATEVM=$DEFAULT_ENABLED_APPVM @@ -61,3 +61,11 @@ if [ -n "$timezone" ]; then echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock fi + +# Prepare environment for other services +echo > /var/run/qubes-service-environment + +debug_mode=`$XS_READ qubes-debug-mode 2> /dev/null` +if [ -n "$debug_mode" -a "$debug_mode" -gt 0 ]; then + echo "GUI_OPTS=-vv" >> /var/run/qubes-service-environment +fi diff --git a/vm-systemd/qubes-update-check.service b/vm-systemd/qubes-update-check.service index 5566eda4..6ac37e3d 100644 --- a/vm-systemd/qubes-update-check.service +++ b/vm-systemd/qubes-update-check.service @@ -4,4 +4,4 @@ ConditionPathExists=/var/run/qubes-service/qubes-update-check [Service] Type=oneshot -ExecStart=/usr/lib/qubes/qrexec_client_vm dom0 qubes.NotifyUpdates /bin/sh -c 'yum -q check-update|wc -l' +ExecStart=/usr/lib/qubes/qrexec_client_vm dom0 qubes.NotifyUpdates /bin/sh -c 'yum -q check-update >/dev/null; [ $? -eq 100 ] && echo 1 || echo 0' diff --git a/vm-systemd/qubes-yum-proxy.service b/vm-systemd/qubes-yum-proxy.service new file mode 100644 index 00000000..b03c34de --- /dev/null +++ b/vm-systemd/qubes-yum-proxy.service @@ -0,0 +1,15 @@ +[Unit] +Description=Qubes yum proxy (tinyproxy) +ConditionPathExists=/var/run/qubes-service/qubes-yum-proxy +After=iptables.service + +[Service] +ExecStartPre=/usr/bin/install -d --owner tinyproxy --group tinyproxy /var/run/tinyproxy +ExecStartPre=/sbin/iptables -I INPUT -i vif+ -p tcp --dport 8082 -j ACCEPT +ExecStartPre=/sbin/iptables -t nat -A PR-QBS-SERVICES -i vif+ -d 10.137.255.254 -p tcp --dport 8082 -j REDIRECT +ExecStart=/usr/sbin/tinyproxy -d -c /etc/tinyproxy/tinyproxy-qubes-yum.conf +ExecStopPost=/sbin/iptables -t nat -D PR-QBS-SERVICES -i vif+ -d 10.137.255.254 -p tcp --dport 8082 -j REDIRECT +ExecStopPost=/sbin/iptables -D INPUT -i vif+ -p tcp --dport 8082 -j ACCEPT + +[Install] +WantedBy=multi-user.target