qubespolicy: ask to create default policy if none is found

Fixes QubesOS/qubes-issues#3005
This commit is contained in:
Marek Marczykowski-Górecki 2017-08-13 02:36:26 +02:00
parent 670e84c835
commit 12661dccf8
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
6 changed files with 278 additions and 1 deletions

View File

@ -47,6 +47,12 @@ class PolicySyntaxError(AccessDenied):
super(PolicySyntaxError, self).__init__(
'{}:{}: {}'.format(filename, lineno, msg))
class PolicyNotFound(AccessDenied):
''' Policy was not found for this service '''
def __init__(self, service_name):
super(PolicyNotFound, self).__init__(
'Policy not found for service {}'.format(service_name))
class Action(enum.Enum):
''' Action as defined by policy '''
@ -486,6 +492,8 @@ class Policy(object):
if not os.path.exists(policy_file):
# fallback to policy without specific argument set (if any)
policy_file = os.path.join(policy_dir, service.split('+')[0])
if not os.path.exists(policy_file):
raise PolicyNotFound(service)
#: policy storage directory
self.policy_dir = policy_dir

View File

@ -30,6 +30,7 @@ from gi.repository import GLib
# pylint: enable=import-error
import qubespolicy.rpcconfirmation
import qubespolicy.policycreateconfirmation
# pylint: enable=wrong-import-position
class PolicyAgent(object):
@ -45,6 +46,11 @@ class PolicyAgent(object):
<arg type='a{ss}' name='icons' direction='in'/>
<arg type='s' name='response' direction='out'/>
</method>
<method name='ConfirmPolicyCreate'>
<arg type='s' name='source' direction='in'/>
<arg type='s' name='service_name' direction='in'/>
<arg type='b' name='response' direction='out'/>
</method>
</interface>
</node>
"""
@ -63,6 +69,13 @@ class PolicyAgent(object):
targets, default_target or None)
return response or ''
@staticmethod
def ConfirmPolicyCreate(source, service_name):
# pylint: disable=invalid-name
response = qubespolicy.policycreateconfirmation.confirm(
source, service_name)
return response
def main():
loop = GLib.MainLoop()

View File

@ -20,6 +20,7 @@
import argparse
import logging
import logging.handlers
import os
import sys
@ -46,6 +47,20 @@ parser.add_argument('process_ident', metavar='process-ident',
help='Qrexec process identifier - for connecting data channel')
def create_default_policy(service_name):
policy_file = os.path.join(qubespolicy.POLICY_DIR, service_name)
with open(policy_file, "w") as policy:
policy.write(
"## Policy file automatically created on first service call.\n")
policy.write(
"## Fill free to edit.\n")
policy.write("## Note that policy parsing stops at the first match\n")
policy.write("\n")
policy.write("## Please use a single # to start your custom comments\n")
policy.write("\n")
policy.write("$anyvm $anyvm ask\n")
def main(args=None):
args = parser.parse_args(args)
@ -64,7 +79,22 @@ def main(args=None):
log.error(log_prefix + 'error getting system info: ' + str(e))
return 1
try:
policy = qubespolicy.Policy(args.service_name)
try:
policy = qubespolicy.Policy(args.service_name)
except qubespolicy.PolicyNotFound:
service_name = args.service_name.split('+')[0]
import pydbus
bus = pydbus.SystemBus()
proxy = bus.get('org.qubesos.PolicyAgent',
'/org/qubesos/PolicyAgent')
create_policy = proxy.ConfirmPolicyCreate(
args.domain, service_name)
if create_policy:
create_default_policy(service_name)
policy = qubespolicy.Policy(args.service_name)
else:
raise
action = policy.evaluate(system_info, args.domain, args.target)
if args.assume_yes_for_ask and action.action == qubespolicy.Action.ask:
action.action = qubespolicy.Action.allow

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkMessageDialog" id="PolicyCreateConfirmationWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Default service policy</property>
<property name="icon_name">dialog-warning</property>
<property name="type_hint">dialog</property>
<property name="message_type">question</property>
<property name="buttons">ok-cancel</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel" id="messageLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Policy for requested service does not exist.
Do you want to create default one (ask for everything)?</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="sourceLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">4</property>
<property name="label" translatable="yes">Source:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="serviceLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">4</property>
<property name="label" translatable="yes">Service:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="sourceEntry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="serviceEntry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="confirmLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Type capital YES to confirm: </property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="confirmEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="activates_default">True</property>
<property name="caps_lock_warning">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,82 @@
# -*- encoding: utf-8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2017 Marek Marczykowski-Górecki
# <marmarek@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, see <http://www.gnu.org/licenses/>.
import os
import pkg_resources
# pylint: disable=import-error,wrong-import-position
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# pylint: enable=import-error
class PolicyCreateConfirmationWindow(object):
# pylint: disable=too-few-public-methods
_source_file = pkg_resources.resource_filename('qubespolicy',
os.path.join('glade', "PolicyCreateConfirmationWindow.glade"))
_source_id = {'window': "PolicyCreateConfirmationWindow",
'ok': "okButton",
'cancel': "cancelButton",
'source': "sourceEntry",
'service': "serviceEntry",
'confirm': "confirmEntry",
}
def __init__(self, source, service):
self._gtk_builder = Gtk.Builder()
self._gtk_builder.add_from_file(self._source_file)
self._window = self._gtk_builder.get_object(
self._source_id['window'])
self._rpc_ok_button = self._gtk_builder.get_object(
self._source_id['ok'])
self._rpc_cancel_button = self._gtk_builder.get_object(
self._source_id['cancel'])
self._service_entry = self._gtk_builder.get_object(
self._source_id['service'])
self._source_entry = self._gtk_builder.get_object(
self._source_id['source'])
self._confirm_entry = self._gtk_builder.get_object(
self._source_id['confirm'])
self._source_entry.set_text(source)
self._service_entry.set_text(service)
# make OK button the default
ok_button = self._window.get_widget_for_response(Gtk.ResponseType.OK)
ok_button.set_can_default(True)
ok_button.grab_default()
def run(self):
self._window.set_keep_above(True)
self._window.connect("delete-event", Gtk.main_quit)
self._window.show_all()
response = self._window.run()
self._window.hide()
if response == Gtk.ResponseType.OK:
return self._confirm_entry.get_text() == 'YES'
return False
def confirm(source, service):
window = PolicyCreateConfirmationWindow(source, service)
return window.run()

View File

@ -374,6 +374,7 @@ fi
%{python3_sitelib}/qubespolicy/cli.py
%{python3_sitelib}/qubespolicy/agent.py
%{python3_sitelib}/qubespolicy/gtkhelpers.py
%{python3_sitelib}/qubespolicy/policycreateconfirmation.py
%{python3_sitelib}/qubespolicy/rpcconfirmation.py
%{python3_sitelib}/qubespolicy/utils.py
%{python3_sitelib}/qubespolicy/graph.py
@ -386,6 +387,7 @@ fi
%{python3_sitelib}/qubespolicy/tests/rpcconfirmation.py
%dir %{python3_sitelib}/qubespolicy/glade
%{python3_sitelib}/qubespolicy/glade/PolicyCreateConfirmationWindow.glade
%{python3_sitelib}/qubespolicy/glade/RPCConfirmationWindow.glade
/usr/lib/qubes/cleanup-dispvms
@ -413,6 +415,7 @@ fi
/etc/xen/scripts/block-snapshot
/etc/xen/scripts/block-origin
/etc/xen/scripts/vif-route-qubes
%attr(2775,root,qubes) %dir /etc/qubes-rpc/policy
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/admin.*
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/include/admin-local-ro
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/include/admin-local-rwx