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

QubesOS/qubes-issues#1637
This commit is contained in:
Wojtek Porczyk 2016-05-17 18:12:24 +02:00
parent a65b0edcd4
commit e757444c35
6 changed files with 187 additions and 9 deletions

View File

@ -67,16 +67,18 @@ endif
$(MAKE) install -C dispvm $(MAKE) install -C dispvm
mkdir -p $(DESTDIR)/etc/qubes-rpc/policy mkdir -p $(DESTDIR)/etc/qubes-rpc/policy
mkdir -p $(DESTDIR)/usr/libexec/qubes 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.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.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-policy/qubes.GetRandomizedTime.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetRandomizedTime
cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/ cp qubes-rpc-policy/qubes.NotifyTools.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyTools
cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/ 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.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-updates $(DESTDIR)/usr/libexec/qubes/
cp qubes-rpc/qubes-notify-tools $(DESTDIR)/usr/libexec/qubes/ cp qubes-rpc/qubes-notify-tools $(DESTDIR)/usr/libexec/qubes/

View File

@ -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

View File

@ -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
qubes-rpc/qubes.FeaturesRequest Executable file
View File

@ -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
qubes/tools/qvm_features.py Normal file
View File

@ -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())

View File

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