Browse Source

qubes/tools/qvm-features: add tool for managing qvm-features

QubesOS/qubes-issues#1637
Wojtek Porczyk 8 years ago
parent
commit
e757444c35

+ 8 - 6
Makefile

@@ -67,16 +67,18 @@ endif
 	$(MAKE) install -C dispvm
 	mkdir -p $(DESTDIR)/etc/qubes-rpc/policy
 	mkdir -p $(DESTDIR)/usr/libexec/qubes
+	cp qubes-rpc-policy/qubes.FeaturesRequest.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.FeaturesRequest
 	cp qubes-rpc-policy/qubes.Filecopy.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.Filecopy
-	cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM
-	cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell
-	cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates
-	cp qubes-rpc-policy/qubes.NotifyTools.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyTools
 	cp qubes-rpc-policy/qubes.GetImageRGBA.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetImageRGBA
 	cp qubes-rpc-policy/qubes.GetRandomizedTime.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetRandomizedTime
-	cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/
-	cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/
+	cp qubes-rpc-policy/qubes.NotifyTools.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyTools
+	cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates
+	cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM
+	cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell
+	cp qubes-rpc/qubes.FeaturesRequest $(DESTDIR)/etc/qubes-rpc/
 	cp qubes-rpc/qubes.GetRandomizedTime $(DESTDIR)/etc/qubes-rpc/
+	cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/
+	cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/
 	cp qubes-rpc/qubes-notify-updates $(DESTDIR)/usr/libexec/qubes/
 	cp qubes-rpc/qubes-notify-tools $(DESTDIR)/usr/libexec/qubes/
 

+ 53 - 0
doc/manpages/qvm-features.rst

@@ -0,0 +1,53 @@
+.. program:: qvm-features
+
+:program:`qvm-features` -- manage domain's features
+===================================================
+
+Synopsis
+--------
+
+:command:`qvm-features` [-h] [--verbose] [--quiet] *VMNAME* [*FEATURE* [*VALUE*]]
+
+Options
+-------
+
+.. option:: --help, -h
+
+   show this help message and exit
+
+.. option:: --verbose, -v
+
+   increase verbosity
+
+.. option:: --quiet, -q
+
+   decrease verbosity
+
+Description
+-----------
+
+This command is used to manually manage the *features* of the domain. The
+features are key-value pairs with both key and value being strings. They are
+used by extensions to store information about the domain and make policy
+decisions based on them. For example, they may indicate that some specific
+software package was installed inside the template and the domains based on it
+have some specific capability.
+
+.. warning::
+
+   The features are normally managed by the extensions themselves and you should
+   not change them directly. Strange things might happen otherwise.
+
+Some extensions interpret the values as boolean. In this case, the empty string
+means :py:obj:`False` and non-empty string (commonly ``'1'``) means
+:py:obj:`True`. An absence of the feature means "default", which is
+extension-dependent.
+
+Authors
+-------
+
+| Joanna Rutkowska <joanna at invisiblethingslab dot com>
+| Marek Marczykowski <marmarek at invisiblethingslab dot com>
+| Wojtek Porczyk <woju at invisiblethingslab dot com>
+
+.. vim: ts=3 sw=3 et tw=80

+ 6 - 0
qubes-rpc-policy/qubes.FeaturesRequest.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

+ 13 - 0
qubes-rpc/qubes.FeaturesRequest

@@ -0,0 +1,13 @@
+#!/usr/bin/env python2
+
+import os
+import qubes
+
+PREFIX = '/features-request/'
+
+app = qubes.Qubes()
+vm = app.domains[os.environ['QREXEC_REMOTE_DOMAIN']]
+vm.fire_event('features-request',
+    untrusted_features={key[len(PREFIX):]: vm.qdb.read(key)
+        for key in vm.qdb.list(PREFIX)})
+app.save()

+ 101 - 0
qubes/tools/qvm_features.py

@@ -0,0 +1,101 @@
+#!/usr/bin/python2 -O
+# vim: fileencoding=utf-8
+
+#
+# The Qubes OS Project, https://www.qubes-os.org/
+#
+# Copyright (C) 2010-2016  Joanna Rutkowska <joanna@invisiblethingslab.com>
+# Copyright (C) 2016       Wojtek Porczyk <woju@invisiblethingslab.com>
+#
+# 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.
+#
+
+'''qvm-features - Manage domain's features'''
+
+import argparse
+import qubes
+
+parser = qubes.tools.QubesArgumentParser(
+    want_vm=True,
+    description='manage domain\'s features')
+
+parser.add_argument('--request',
+    action='store_true', default=False,
+    help=argparse.SUPPRESS)
+
+parser.add_argument('feature', metavar='FEATURE',
+    action='store', nargs='?',
+    help='name of the feature')
+
+parser.add_argument('value', metavar='VALUE',
+    action='store', nargs='?',
+    help='new value of the feature')
+
+parser.add_argument('--unset', '--default', '--delete', '-D',
+    dest='delete',
+    action='store_true',
+    help='unset the feature')
+
+
+def main(args=None):
+    '''Main routine of :program:`qvm-features`.
+
+    :param list args: Optional arguments to override those delivered from \
+        command line.
+    '''
+
+    args = parser.parse_args(args)
+
+    if args.request:
+        # Request mode: instead of setting the features directly,
+        # let the extensions handle them first.
+        args.vm.fire_event('feature-request', untrusted_features=args.features)
+        return 0
+
+    if args.feature is None:
+        if args.delete:
+            parser.error('--unset requires a feature')
+
+        width = max(len(feature) for feature in args.vm.features)
+        for feature in sorted(args.vm.features):
+            print('{name:{width}s}  {value}'.format(
+                name=feature, value=args.vm.features[feature], width=width))
+
+        return 0
+
+    if args.delete:
+        if args.value is not None:
+            parser.error('cannot both set and unset a value')
+        try:
+            del args.vm.features[args.feature]
+            args.app.save()
+        except KeyError:
+            pass
+        return 0
+
+    if args.value is None:
+        try:
+            print(args.vm.features[args.feature])
+            return 0
+        except KeyError:
+            return 1
+
+    args.vm.features[args.feature] = args.value
+    args.app.save()
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 6 - 3
rpm_spec/core-dom0.spec

@@ -243,6 +243,7 @@ fi
 %{python_sitelib}/qubes/tools/qubes_monitor_layout_notify.py*
 %{python_sitelib}/qubes/tools/qubes_prefs.py*
 %{python_sitelib}/qubes/tools/qvm_create.py*
+%{python_sitelib}/qubes/tools/qvm_features.py*
 %{python_sitelib}/qubes/tools/qvm_kill.py*
 %{python_sitelib}/qubes/tools/qvm_ls.py*
 %{python_sitelib}/qubes/tools/qvm_pause.py*
@@ -340,16 +341,18 @@ fi
 /etc/xen/scripts/block-snapshot
 /etc/xen/scripts/block-origin
 /etc/xen/scripts/vif-route-qubes
+%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.FeaturesRequest
 %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.Filecopy
 %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetImageRGBA
-%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.OpenInVM
+%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetRandomizedTime
 %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.OpenInVM
 %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell
-%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetRandomizedTime
+/etc/qubes-rpc/qubes.FeaturesRequest
+/etc/qubes-rpc/qubes.GetRandomizedTime
 /etc/qubes-rpc/qubes.NotifyTools
 /etc/qubes-rpc/qubes.NotifyUpdates
-/etc/qubes-rpc/qubes.GetRandomizedTime
 %attr(2770,root,qubes) %dir /var/log/qubes
 %attr(0770,root,qubes) %dir /var/run/qubes
 /etc/xdg/autostart/qubes-guid.desktop