qubespolicy: run GUI code inside user session and expose it as dbus object

This way it will work independently from where qrexec-policy tool will
be called (in most cases - from a system service, as root).
This is also very similar architecture to what we'll need when moving to
GUI domain - there GUI part will also be separated from policy
evaluation logic.

QubesOS/qubes-issues#910
This commit is contained in:
Marek Marczykowski-Górecki 2017-04-06 15:39:31 +02:00
parent e76ede3ad0
commit a3da85bfda
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
7 changed files with 119 additions and 9 deletions

View File

@ -8,4 +8,8 @@ install:
ln -s block-snapshot $(DESTDIR)/etc/xen/scripts/block-origin
install -d $(DESTDIR)/etc/xdg/autostart
install -m 0644 qubes-guid.desktop $(DESTDIR)/etc/xdg/autostart/
install -m 0644 qrexec-policy-agent.desktop $(DESTDIR)/etc/xdg/autostart/
install -m 0644 -D tmpfiles-qubes.conf $(DESTDIR)/usr/lib/tmpfiles.d/qubes.conf
install -d $(DESTDIR)/etc/dbus-1/system.d
install -m 0644 dbus-org.qubesos.PolicyAgent.conf \
$(DESTDIR)/etc/dbus-1/system.d/org.qubesos.PolicyAgent.conf

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- User need to be in qubes group to own the service -->
<policy group="qubes">
<allow own="org.qubesos.PolicyAgent"/>
</policy>
<policy context="default">
<allow send_destination="org.qubesos.PolicyAgent"
send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="org.qubesos.PolicyAgent"
send_interface="org.qubesos.PolicyAgent"/>
</policy>
</busconfig>

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Name=Qubes Qrexec Policy agent
Comment=Agent for handling policy confirmation prompts
Icon=qubes
Exec=qrexec-policy-agent
Terminal=false
Type=Application

70
qubespolicy/agent.py Normal file
View File

@ -0,0 +1,70 @@
# -*- encoding: utf8 -*-
#
# 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/>.
''' Agent running in user session, responsible for asking the user about policy
decisions.'''
import pydbus
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib
import qubespolicy.rpcconfirmation
class PolicyAgent(object):
dbus = """
<node>
<interface name='org.qubesos.PolicyAgent'>
<method name='Ask'>
<arg type='s' name='source' direction='in'/>
<arg type='s' name='service_name' direction='in'/>
<arg type='as' name='targets' direction='in'/>
<arg type='s' name='default_target' direction='in'/>
<arg type='a{ss}' name='icons' direction='in'/>
<arg type='s' name='response' direction='out'/>
</method>
</interface>
</node>
"""
def Ask(self, source, service_name, targets, default_target,
icons):
entries_info = {}
for target in targets:
entries_info[target] = {}
entries_info[target]['icon'] = icons.get(target, None)
response = qubespolicy.rpcconfirmation.confirm_rpc(
entries_info, source, service_name,
targets, default_target or None)
return response or ''
def main():
loop = GLib.MainLoop()
bus = pydbus.SystemBus()
obj = PolicyAgent()
bus.publish('org.qubesos.PolicyAgent', obj)
loop.run()
if __name__ == '__main__':
main()

View File

@ -68,20 +68,24 @@ def main(args=None):
action = policy.evaluate(system_info, args.domain, args.target)
if action.action == qubespolicy.Action.ask:
# late import to save on time for allow/deny actions
import qubespolicy.rpcconfirmation as rpcconfirmation
entries_info = system_info['domains'].copy()
import pydbus
bus = pydbus.SystemBus()
proxy = bus.get('org.qubesos.PolicyAgent',
'/org/qubesos/PolicyAgent')
icons = {name: system_info['domains'][name]['icon']
for name in system_info['domains'].keys()}
for dispvm_base in system_info['domains']:
if not system_info['domains'][dispvm_base]['dispvm_allowed']:
continue
dispvm_api_name = '$dispvm:' + dispvm_base
entries_info[dispvm_api_name] = \
system_info['domains'][dispvm_base].copy()
entries_info[dispvm_api_name]['icon'] = \
entries_info[dispvm_api_name]['icon'].replace('app', 'disp')
icons[dispvm_api_name] = \
system_info['domains'][dispvm_base]['icon']
icons[dispvm_api_name] = \
icons[dispvm_api_name].replace('app', 'disp')
response = rpcconfirmation.confirm_rpc(
entries_info, args.domain, args.service_name,
action.targets_for_ask, action.target)
response = proxy.Ask(args.domain, args.service_name,
action.targets_for_ask, action.target or '', icons)
if response:
action.handle_user_response(True, response)
else:

View File

@ -73,6 +73,7 @@ Requires: python3
Requires: python3-docutils
Requires: python3-jinja2
Requires: python3-lxml
Requires: python3-pydbus
Requires: python3-qubesdb
Requires: python3-setuptools
Requires: python3-xen
@ -210,11 +211,13 @@ fi
%files
%defattr(-,root,root,-)
%config(noreplace) %attr(0664,root,qubes) %{_sysconfdir}/qubes/qmemman.conf
%config(noreplace) /etc/dbus-1/system.d/org.qubesos.PolicyAgent.conf
/usr/bin/qvm-*
/usr/bin/qubes-*
/usr/bin/qmemmand
/usr/bin/qubesd*
/usr/bin/qrexec-policy
/usr/bin/qrexec-policy-agent
%dir %{python3_sitelib}/qubes-*.egg-info
%{python3_sitelib}/qubes-*.egg-info/*
@ -385,6 +388,7 @@ fi
%{python3_sitelib}/qubespolicy/__pycache__/*
%{python3_sitelib}/qubespolicy/__init__.py
%{python3_sitelib}/qubespolicy/cli.py
%{python3_sitelib}/qubespolicy/agent.py
%{python3_sitelib}/qubespolicy/gtkhelpers.py
%{python3_sitelib}/qubespolicy/rpcconfirmation.py
%{python3_sitelib}/qubespolicy/utils.py
@ -454,5 +458,6 @@ fi
%attr(2770,root,qubes) %dir /var/log/qubes
%attr(0770,root,qubes) %dir /var/run/qubes
/etc/xdg/autostart/qubes-guid.desktop
/etc/xdg/autostart/qrexec-policy-agent.desktop
/usr/share/doc/qubes/relaxng/*.rng

View File

@ -33,6 +33,7 @@ if __name__ == '__main__':
entry_points={
'console_scripts': list(get_console_scripts()) + [
'qrexec-policy = qubespolicy.cli:main',
'qrexec-policy-agent = qubespolicy.agent:main',
],
'qubes.vm': [
'AppVM = qubes.vm.appvm:AppVM',