From 3df971997233b97338c34d991d68fa238370bd9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sun, 27 Oct 2013 16:09:16 +0100 Subject: [PATCH 1/7] core: add missing import --- core-modules/01QubesHVm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 51e06f1a..8847f9f5 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -28,6 +28,7 @@ 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' From 495a24a2e73d55e3e5d6db957642bc6fb2bfbd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Mon, 28 Oct 2013 05:08:28 +0100 Subject: [PATCH 2/7] core/HVM: always start qrexec daemon If not marked as installed, start it in background - waiting for possible Qubes Tools installation. If that happens, make it possible to tell the dom0 about that fact. --- core-modules/01QubesHVm.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 8847f9f5..93233e6c 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -261,7 +261,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: From e2c43d22929dd1baf76755210f885fa37944d0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Mon, 28 Oct 2013 05:09:54 +0100 Subject: [PATCH 3/7] Allow HVM to notify dom0 about tools installation HVM can set some xenstore entries (in qubes-tools/ subtree) to pass informations about installed tools to dom0. qubes.NotifyTools service triggers update of VM properties (like qrexec_installed). This way, after installation of Qubes Windows Tools, the user doesn't need to change any VM settings to use the tools. --- core-modules/01QubesHVm.py | 20 +++++++ qubes-rpc-policy/qubes.NotifyTools.policy | 6 ++ qubes-rpc/qubes-notify-tools | 70 +++++++++++++++++++++++ qubes-rpc/qubes.NotifyTools | 1 + rpm_spec/core-dom0.spec | 6 ++ 5 files changed, 103 insertions(+) create mode 100644 qubes-rpc-policy/qubes.NotifyTools.policy create mode 100755 qubes-rpc/qubes-notify-tools create mode 100644 qubes-rpc/qubes.NotifyTools diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 93233e6c..53cce267 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -280,6 +280,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..e9109e73 --- /dev/null +++ b/qubes-rpc/qubes-notify-tools @@ -0,0 +1,70 @@ +#!/usr/bin/python2 + +import os +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)) + + 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) + + # 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 + + 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/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 From 55b4c6b6d116ebf3d0f0f06de986348fbeda001e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 1 Nov 2013 02:25:04 +0100 Subject: [PATCH 4/7] missing import once again --- core-modules/01QubesHVm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 53cce267..2a17ed14 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -24,6 +24,7 @@ import os import os.path import subprocess +import stat import sys import re From c52059a23e117eadf42bbe0b41735be54212b8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 1 Nov 2013 02:25:22 +0100 Subject: [PATCH 5/7] core: unify handling dom0 case in --cdrom option --- core-modules/01QubesHVm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core-modules/01QubesHVm.py b/core-modules/01QubesHVm.py index 2a17ed14..ea1b3634 100644 --- a/core-modules/01QubesHVm.py +++ b/core-modules/01QubesHVm.py @@ -165,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 From 5291227de3ed74bf3a77808f7263c2d7b450cf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 1 Nov 2013 02:31:13 +0100 Subject: [PATCH 6/7] qvm-tools: qvm-start --install-windows-tools (#41 pro) --- qvm-tools/qvm-start | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 From 8200b15c61940886ca8c30a0c9f53c8f24a0906e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 1 Nov 2013 02:32:32 +0100 Subject: [PATCH 7/7] NotifyTools: handle default user setting If the VM provides 'default-user' setting - save it to the VM settings. --- qubes-rpc/qubes-notify-tools | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qubes-rpc/qubes-notify-tools b/qubes-rpc/qubes-notify-tools index e9109e73..47a4b0c2 100755 --- a/qubes-rpc/qubes-notify-tools +++ b/qubes-rpc/qubes-notify-tools @@ -1,6 +1,7 @@ #!/usr/bin/python2 import os +import re import sys from qubes.qubes import QubesVmCollection,QubesException,QubesHVm from qubes.qubes import xs @@ -35,6 +36,8 @@ def main(): 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 @@ -55,11 +58,20 @@ def main(): 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