diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 51e06f1a..ea1b3634 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -24,10 +24,12 @@ import os import os.path import subprocess +import stat import sys import re from qubes.qubes import QubesVm,register_qubes_vm_class,xs,xc,dry_run +from qubes.qubes import QubesException from qubes.qubes import system_path,defaults system_path["config_template_hvm"] = '/usr/share/qubes/vm-template-hvm.conf' @@ -163,6 +165,8 @@ class QubesHVm(QubesVm): if backend_split: backend_domain = "," + backend_split.group(1) drive_path = backend_split.group(2) + if backend_domain.lower() == "dom0": + backend_domain = "" # FIXME: os.stat will work only when backend in dom0... stat_res = None @@ -260,7 +264,17 @@ class QubesHVm(QubesVm): raise QubesException("Cannot start qubes-guid!") def start_qrexec_daemon(self, **kwargs): - if self.qrexec_installed: + if not self.qrexec_installed: + if kwargs.get('verbose', False): + print >> sys.stderr, "--> Starting the qrexec daemon..." + xid = self.get_xid() + qrexec_env = os.environ + qrexec_env['QREXEC_STARTUP_NOWAIT'] = '1' + retcode = subprocess.call ([system_path["qrexec_daemon_path"], str(xid), self.name, self.default_user], env=qrexec_env) + if (retcode != 0) : + self.force_shutdown(xid=xid) + raise OSError ("ERROR: Cannot execute qrexec-daemon!") + else: super(QubesHVm, self).start_qrexec_daemon(**kwargs) if self._start_guid_first: @@ -269,6 +283,26 @@ class QubesHVm(QubesVm): self.wait_for_session(notify_function=kwargs.get('notify_function', None)) + def create_xenstore_entries(self, xid = None): + if dry_run: + return + + super(QubesHVm, self).create_xenstore_entries(xid) + + if xid is None: + xid = self.xid + + domain_path = xs.get_domain_path(xid) + + # Prepare xenstore directory for tools advertise + xs.write('', + "{0}/qubes-tools".format(domain_path), + '') + + # Allow VM writes there + xs.set_permissions('', '{0}/qubes-tools'.format(domain_path), + [{ 'dom': xid }]) + def suspend(self): if dry_run: return diff --git a/qubes-rpc-policy/qubes.NotifyTools.policy b/qubes-rpc-policy/qubes.NotifyTools.policy new file mode 100644 index 00000000..0f00b0b6 --- /dev/null +++ b/qubes-rpc-policy/qubes.NotifyTools.policy @@ -0,0 +1,6 @@ +## Note that policy parsing stops at the first match, +## so adding anything below "$anyvm $anyvm action" line will have no effect + +## Please use a single # to start your custom comments + +$anyvm dom0 allow diff --git a/qubes-rpc/qubes-notify-tools b/qubes-rpc/qubes-notify-tools new file mode 100755 index 00000000..47a4b0c2 --- /dev/null +++ b/qubes-rpc/qubes-notify-tools @@ -0,0 +1,82 @@ +#!/usr/bin/python2 + +import os +import re +import sys +from qubes.qubes import QubesVmCollection,QubesException,QubesHVm +from qubes.qubes import xs + +def main(): + + source = os.getenv("QREXEC_REMOTE_DOMAIN") + + if source is None: + print >> sys.stderr, 'This script must be called as qrexec service!' + exit(1) + + qvm_collection = QubesVmCollection() + qvm_collection.lock_db_for_writing() + try: + qvm_collection.load() + + source_vm = qvm_collection.get_vm_by_name(source) + if source_vm is None: + raise QubesException('Domain ' + source + ' does not exists (?!)') + + if not isinstance(source_vm, QubesHVm): + raise QubesException('Service qubes.ToolsNotify is designed only for HVM domains') + + xs_path = "/local/domain/{0}/qubes-tools".format(source_vm.get_xid()) + + # for now used only to check for the tools presence + untrusted_version = xs.read('', '{0}/version'.format(xs_path)) + # reserved for future use + untrusted_os = xs.read('', '{0}/os'.format(xs_path)) + # qrexec agent presence (0 or 1) + untrusted_qrexec = xs.read('', '{0}/qrexec'.format(xs_path)) + # gui agent presence (0 or 1) + untrusted_gui = xs.read('', '{0}/gui'.format(xs_path)) + # default user for qvm-run etc + untrusted_user = xs.read('', '{0}/default-user'.format(xs_path)) + + if untrusted_version is None: + # tools didn't advertised its features; it's strange that this + # service is called, but ignore it + return + + # any suspicious string will raise exception here + version = int(untrusted_version) + + # untrusted_os - ignore for now + + if untrusted_qrexec is None: + qrexec = 0 + else: + qrexec = int(untrusted_qrexec) + + if untrusted_gui is None: + gui = 0 + else: + gui = int(untrusted_gui) + + if untrusted_user is not None: + if re.match(r'^[a-zA-Z0-9-]+$', untrusted_user): + user = untrusted_user + else: + user = None + + # Let the tools to be able to enable *or disable* each particular component + source_vm.qrexec_installed = qrexec > 0 + source_vm.guiagent_installed = gui > 0 + + if user: + source_vm.default_user = user + + qvm_collection.save() + except Exception as e: + print >> sys.stderr, e.message + exit(1) + finally: + qvm_collection.unlock_db() + +main() diff --git a/qubes-rpc/qubes.NotifyTools b/qubes-rpc/qubes.NotifyTools new file mode 100644 index 00000000..5c7e590a --- /dev/null +++ b/qubes-rpc/qubes.NotifyTools @@ -0,0 +1 @@ +/usr/lib/qubes/qubes-notify-tools diff --git a/qvm-tools/qvm-start b/qvm-tools/qvm-start index 28d5fab1..0ecd063d 100755 --- a/qvm-tools/qvm-start +++ b/qvm-tools/qvm-start @@ -56,6 +56,8 @@ def main(): help="Temporarily attach specified drive as hard disk") parser.add_option ("--cdrom", dest="drive_cdrom", default=None, help="Temporarily attach specified drive as CD/DVD") + parser.add_option ("--install-windows-tools", action="store_true", dest="install_windows_tools", default=False, + help="Attach Windows tools CDROM to the VM") parser.add_option ("--dvm", action="store_true", dest="preparing_dvm", default=False, help="Do actions necessary when preparing DVM image") parser.add_option ("--custom-config", action="store", dest="custom_config", default=None, @@ -82,10 +84,13 @@ def main(): print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname) exit(1) - if bool(options.drive_hd) + bool(options.drive_cdrom) + bool(options.drive) > 1: - print >> sys.stderr, "Only one of --drive, --cdrom, --hddisk can be specified" + if bool(options.drive_hd) + bool(options.drive_cdrom) + bool(options.drive) + bool(options.install_windows_tools) > 1: + print >> sys.stderr, "Only one of --drive, --cdrom, --hddisk, --install-windows-tools can be specified" exit(1) + if options.install_windows_tools: + options.drive = 'cdrom:dom0:/usr/lib/qubes/qubes-windows-tools.iso' + if options.drive_hd: options.drive = 'hd:' + options.drive_hd diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index f12d2cec..a31aaac1 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -130,6 +130,7 @@ cp linux/aux-tools/startup-misc.sh $RPM_BUILD_ROOT/usr/lib/qubes cp linux/aux-tools/prepare-volatile-img.sh $RPM_BUILD_ROOT/usr/lib/qubes cp qmemman/server.py $RPM_BUILD_ROOT/usr/lib/qubes/qmemman_daemon.py cp qmemman/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes/ +cp qubes-rpc/qubes-notify-tools $RPM_BUILD_ROOT/usr/lib/qubes/ cp qubes-rpc/qubes-notify-updates $RPM_BUILD_ROOT/usr/lib/qubes/ cp linux/aux-tools/vusb-ctl.py $RPM_BUILD_ROOT/usr/lib/qubes/ cp linux/aux-tools/xl-qvm-usb-attach.py $RPM_BUILD_ROOT/usr/lib/qubes/ @@ -141,6 +142,8 @@ mkdir -p $RPM_BUILD_ROOT/etc/qubes-rpc/policy cp qubes-rpc-policy/qubes.Filecopy.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.Filecopy cp qubes-rpc-policy/qubes.OpenInVM.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.OpenInVM cp qubes-rpc-policy/qubes.VMShell.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.VMShell +cp qubes-rpc-policy/qubes.NotifyTools.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.NotifyTools +cp qubes-rpc/qubes.NotifyTools $RPM_BUILD_ROOT/etc/qubes-rpc/ cp qubes-rpc-policy/qubes.NotifyUpdates.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.NotifyUpdates cp qubes-rpc/qubes.NotifyUpdates $RPM_BUILD_ROOT/etc/qubes-rpc/ @@ -280,6 +283,7 @@ fi /usr/lib/qubes/qmemman_daemon.py* /usr/lib/qubes/meminfo-writer /usr/lib/qubes/qfile-daemon-dvm* +/usr/lib/qubes/qubes-notify-tools /usr/lib/qubes/qubes-notify-updates /usr/lib/qubes/block-cleaner-daemon.py* /usr/lib/qubes/vusb-ctl.py* @@ -314,8 +318,10 @@ fi /etc/xen/scripts/vif-route-qubes %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.Filecopy %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.OpenInVM +%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.NotifyTools %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.NotifyUpdates %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell +/etc/qubes-rpc/qubes.NotifyTools /etc/qubes-rpc/qubes.NotifyUpdates %attr(2770,root,qubes) %dir /var/log/qubes %attr(0770,root,qubes) %dir /var/run/qubes