From ede96353afed029b537e66a6232d74f7d9cafcdb Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Wed, 12 Oct 2011 00:08:28 +0200 Subject: [PATCH] dom0/qrexec: Add always allow option in qrexec confirmation dialog (#278) --- dom0/qvm-core/guihelpers.py | 55 +++++++++++++++++++++++++++++++++++++ qrexec/qrexec_policy | 36 ++++++++++++++++++++---- rpm_spec/core-dom0.spec | 15 ++++++---- 3 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 dom0/qvm-core/guihelpers.py diff --git a/dom0/qvm-core/guihelpers.py b/dom0/qvm-core/guihelpers.py new file mode 100644 index 00000000..dbda6022 --- /dev/null +++ b/dom0/qvm-core/guihelpers.py @@ -0,0 +1,55 @@ +#!/usr/bin/python2 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2011 Marek Marczykowski +# +# 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. +# +# + +import sys +from optparse import OptionParser +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +app = None + +def prepare_app(): + global app + app = QApplication(sys.argv) + app.setOrganizationName("The Qubes Project") + app.setOrganizationDomain("http://qubes-os.org") + app.setApplicationName("Qubes") + +def ask(text, title="Question", yestoall=False): + global app + if app is None: + prepare_app() + + buttons = QMessageBox.Yes | QMessageBox.No + if yestoall: + buttons |= QMessageBox.YesToAll + + reply = QMessageBox.question(None, title, text, buttons) + if reply == QMessageBox.Yes: + return 0 + elif reply == QMessageBox.No: + return 1 + elif reply == QMessageBox.YesToAll: + return 2 + else: + #?! + return 127 diff --git a/qrexec/qrexec_policy b/qrexec/qrexec_policy index 52632abf..8400af2b 100755 --- a/qrexec/qrexec_policy +++ b/qrexec/qrexec_policy @@ -4,10 +4,17 @@ import os import os.path import subprocess import xen.lowlevel.xl +import qubes.guihelpers +import fcntl POLICY_FILE_DIR="/etc/qubes_rpc/policy" QREXEC_CLIENT="/usr/lib/qubes/qrexec_client" +class UserChoice: + ALLOW=0 + DENY=1 + ALWAYS_ALLOW=2 + def line_to_dict(line): tokens=line.split() if len(tokens) < 3: @@ -20,6 +27,7 @@ def line_to_dict(line): dict['source']=tokens[0] dict['dest']=tokens[1] + dict['full-action']=tokens[2] action_list=tokens[2].split(',') dict['action']=action_list.pop(0) @@ -36,6 +44,7 @@ def read_policy_file(exec_index): return None policy_list=list() f = open(policy_file) + fcntl.flock(f, fcntl.LOCK_SH) for iter in f.readlines(): dict = line_to_dict(iter) if dict is not None: @@ -92,9 +101,23 @@ def do_execute(domain, target, user, exec_index, process_ident): def confirm_execution(domain, target, exec_index): text = "Do you allow domain \"" +domain + "\" to execute " + exec_index - text+= " operation on the domain \"" + target +"\"?" - retcode = subprocess.call(["/usr/bin/zenity", "--question", "--text", text]) - return retcode==0 + text+= " operation on the domain \"" + target +"\"?
" + text+= " \"Yes to All\" option will automatically allow this operation in the future." + return qubes.guihelpers.ask(text, yestoall=True) + +def add_always_allow(domain, target, exec_index, options): + policy_file=POLICY_FILE_DIR+"/"+exec_index + if not os.path.isfile(policy_file): + return None + f = open(policy_file, 'r+') + fcntl.flock(f, fcntl.LOCK_EX) + lines = [] + for l in f.readlines(): + lines.append(l) + lines.insert(0, "%s\t%s\tallow%s\n" % (domain, target, options)) + f.seek(0) + f.write("".join(lines)) + f.close() def policy_editor(domain, target, exec_index): text = "Policy editor not yet implemented. Please add a line in the form \"" @@ -118,7 +141,11 @@ def main(): policy_dict=find_policy(policy_list, domain, target) if policy_dict["action"] == "ask": - if confirm_execution(domain, target, exec_index): + user_choice = confirm_execution(domain, target, exec_index) + if user_choice == UserChoice.ALWAYS_ALLOW: + add_always_allow(domain, target, exec_index, policy_dict["full-action"].lstrip('ask')) + policy_dict["action"] = "allow" + elif user_choice == UserChoice.ALLOW: policy_dict["action"] = "allow" else: policy_dict["action"] = "deny" @@ -136,4 +163,3 @@ def main(): os.execl(QREXEC_CLIENT, "qrexec_client", "-d", domain, "-l", "/bin/false", "-c", process_ident) main() - \ No newline at end of file diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 0b8919dd..22003dc0 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -82,6 +82,8 @@ cp qvm-core/qubes.py $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/qubes.py[co] $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/qubesutils.py $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/qubesutils.py[co] $RPM_BUILD_ROOT%{python_sitearch}/qubes +cp qvm-core/guihelpers.py $RPM_BUILD_ROOT%{python_sitearch}/qubes +cp qvm-core/guihelpers.py[co] $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/__init__.py $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/__init__.py[co] $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qmemman/qmemman*py $RPM_BUILD_ROOT%{python_sitearch}/qubes @@ -303,6 +305,9 @@ fi %{python_sitearch}/qubes/qubesutils.py %{python_sitearch}/qubes/qubesutils.pyc %{python_sitearch}/qubes/qubesutils.pyo +%{python_sitearch}/qubes/guihelpers.py +%{python_sitearch}/qubes/guihelpers.pyc +%{python_sitearch}/qubes/guihelpers.pyo %{python_sitearch}/qubes/__init__.py %{python_sitearch}/qubes/__init__.pyc %{python_sitearch}/qubes/__init__.pyo @@ -358,11 +363,11 @@ fi /usr/lib/qubes/qubes_rpc_multiplexer /usr/lib/qubes/qrexec_policy %dir /etc/qubes_rpc/policy -/etc/qubes_rpc/policy/qubes.Filecopy -/etc/qubes_rpc/policy/qubes.OpenInVM -/etc/qubes_rpc/policy/qubes.SyncAppMenus -/etc/qubes_rpc/policy//qubes.ReceiveUpdates -/etc/qubes_rpc/policy/qubes.VMShell +%attr(0664,root,qubes) /etc/qubes_rpc/policy/qubes.Filecopy +%attr(0664,root,qubes) /etc/qubes_rpc/policy/qubes.OpenInVM +%attr(0664,root,qubes) /etc/qubes_rpc/policy/qubes.SyncAppMenus +%attr(0664,root,qubes) /etc/qubes_rpc/policy/qubes.ReceiveUpdates +%attr(0664,root,qubes) /etc/qubes_rpc/policy/qubes.VMShell /etc/qubes_rpc/qubes.SyncAppMenus /etc/qubes_rpc/qubes.ReceiveUpdates %attr(4750,root,qubes) /usr/lib/qubes/qrexec_daemon