Skip to content

Commit

Permalink
Implemented polkit authorization
Browse files Browse the repository at this point in the history
Dropped dbus at_console policy and implemented polkit authorization.
By the default policy the query actions are allowed for all users, actions
which do modification to the system settings or Tuned state are by default
allowed only for active users that have console, others need admin
authorization.

Resolves: rhbz#1095142

Signed-off-by: Jaroslav Škarvada <[email protected]>
  • Loading branch information
yarda committed Jun 10, 2016
1 parent e86e1be commit 68bb447
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 29 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ release-cp: release-dir

cp -a tuned.py tuned.spec tuned.service tuned.tmpfiles Makefile tuned-adm.py \
tuned-adm.bash dbus.conf recommend.conf tuned-main.conf 00_tuned \
bootcmdline com.redhat.tuned.gui.policy tuned-gui.py tuned-gui.glade \
tuned-gui.desktop $(VERSIONED_NAME)
bootcmdline com.redhat.tuned.policy com.redhat.tuned.gui.policy \
tuned-gui.py tuned-gui.glade tuned-gui.desktop $(VERSIONED_NAME)
cp -a doc experiments libexec man profiles systemtap tuned contrib icons \
$(VERSIONED_NAME)

Expand Down Expand Up @@ -144,6 +144,7 @@ install: install-dirs
install -Dpm 0755 00_tuned $(DESTDIR)/etc/grub.d/00_tuned

# polkit configuration
install -Dpm 0644 com.redhat.tuned.policy $(DESTDIR)$(DATADIR)/polkit-1/actions/com.redhat.tuned.policy
install -Dpm 0644 com.redhat.tuned.gui.policy $(DESTDIR)$(DATADIR)/polkit-1/actions/com.redhat.tuned.gui.policy

# manual pages
Expand Down
129 changes: 129 additions & 0 deletions com.redhat.tuned.policy
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD polkit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/software/polkit/policyconfig-1.dtd">
<policyconfig>

<vendor>Tuned</vendor>
<vendor_url>https://fedorahosted.org/tuned/</vendor_url>
<icon_name>tuned</icon_name>

<action id="com.redhat.tuned.active_profile">
<description>Show active profile</description>
<message>Authentication is required to show active profile</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.disable">
<description>Disable Tuned</description>
<message>Authentication is required to disable Tuned</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.is_running">
<description>Check whether Tuned is running</description>
<message>Authentication is required to check whether Tuned is running</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.profile_info">
<description>Show information about Tuned profile</description>
<message>Authentication is required to show information about Tuned profile</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.profiles">
<description>List Tuned profiles</description>
<message>Authentication is required to list Tuned profiles</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.profiles2">
<description>List Tuned profiles</description>
<message>Authentication is required to list Tuned profiles</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.recommend_profile">
<description>Show Tuned profile name which is recommended for your system</description>
<message>Authentication is required to show recommended profile name</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.reload">
<description>Reload Tuned configuration</description>
<message>Authentication is required to reload Tuned configuration</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.start">
<description>Start Tuned daemon</description>
<message>Authentication is required to start Tuned daemon</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.stop">
<description>Stop Tuned daemon</description>
<message>Authentication is required to stop Tuned daemon</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.switch_profile">
<description>Switch Tuned profile</description>
<message>Authentication is required to switch Tuned profile</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>

<action id="com.redhat.tuned.verify_profile">
<description>Verify Tuned profile</description>
<message>Authentication is required to verify Tuned profile</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>
7 changes: 1 addition & 6 deletions dbus.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@

<busconfig>
<policy context="default">
<deny send_destination="com.redhat.tuned" />
<allow receive_sender="com.redhat.tuned" />
<allow send_destination="com.redhat.tuned" send_interface="org.freedesktop.DBus.Introspectable" />
<allow send_destination="com.redhat.tuned" send_interface="com.redhat.tuned.control" send_member="active_profile" />
<allow send_destination="com.redhat.tuned" send_interface="com.redhat.tuned.control" />
</policy>

<policy user="root">
<allow own="com.redhat.tuned" />
<allow send_destination="com.redhat.tuned" />
</policy>

<policy at_console="true">
<allow send_destination="com.redhat.tuned" />
</policy>
</busconfig>
1 change: 1 addition & 0 deletions tuned.spec
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ fi
%{_sbindir}/tuned-gui
%{python_sitelib}/tuned/gtk
%{_datadir}/tuned/ui
%{_datadir}/polkit-1/actions/com.redhat.tuned.policy
%{_datadir}/polkit-1/actions/com.redhat.tuned.gui.policy
%{_datadir}/icons/hicolor/scalable/apps/tuned.svg
%{_datadir}/applications/tuned-gui.desktop
Expand Down
2 changes: 1 addition & 1 deletion tuned/admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self, dbus = True, debug = False, async = False, timeout = consts.A
self._daemon_action_errstr = ""
self._controller = None
if self._dbus:
self._controller = tuned.admin.DBusController(consts.DBUS_BUS, consts.DBUS_OBJECT, consts.DBUS_INTERFACE, debug)
self._controller = tuned.admin.DBusController(consts.DBUS_BUS, consts.DBUS_INTERFACE, consts.DBUS_OBJECT, debug)
try:
self._controller.set_signal_handler(consts.DBUS_SIGNAL_PROFILE_CHANGED, self._signal_profile_changed_cb)
except TunedAdminDBusException as e:
Expand Down
6 changes: 4 additions & 2 deletions tuned/admin/dbus_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def __init__(self, bus_name, interface_name, object_name, debug = False):
self._interface_name = interface_name
self._object_name = object_name
self._proxy = None
self._interface = None
self._debug = debug
self._main_loop = None
self._action = None
Expand All @@ -29,7 +30,8 @@ def _init_proxy(self):
DBusGMainLoop(set_as_default=True)
self._main_loop = GLib.MainLoop()
bus = dbus.SystemBus()
self._proxy = bus.get_object(self._bus_name, self._interface_name, self._object_name)
self._proxy = bus.get_object(self._bus_name, self._object_name)
self._interface = dbus.Interface(self._proxy, dbus_interface = self._interface_name)
except dbus.exceptions.DBusException:
raise TunedAdminDBusException("Cannot talk to Tuned daemon via DBus. Is Tuned daemon running?")

Expand Down Expand Up @@ -67,7 +69,7 @@ def _call(self, method_name, *args, **kwargs):
self._init_proxy()

try:
method = self._proxy.get_dbus_method(method_name)
method = self._interface.get_dbus_method(method_name)
return method(*args, **kwargs)
except dbus.exceptions.DBusException as dbus_exception:
err_str = "DBus call to Tuned daemon failed"
Expand Down
3 changes: 2 additions & 1 deletion tuned/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
PROFILE_FILE = "tuned.conf"
AUTODETECT_FILE = "recommend.conf"
DAEMONIZE_PARENT_TIMEOUT = 5
DBUS_BUS = "com.redhat.tuned"
NAMESPACE = "com.redhat.tuned"
DBUS_BUS = NAMESPACE
DBUS_INTERFACE = "com.redhat.tuned.control"
DBUS_OBJECT = "/Tuned"
DEFAULT_PROFILE = "balanced"
Expand Down
57 changes: 44 additions & 13 deletions tuned/daemon/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,15 @@ def terminate(self):
def profile_changed(self, profile_name, result, errstr):
pass

# exports decorator checks the authorization (currently through polkit), caller is None if
# no authorization was performed (i.e. the call should process as authorized), string
# identifying caller (with DBus it's the caller bus name) if authorized and empty
# string if not authorized, caller must be the last argument

@exports.export("", "b")
def start(self):
def start(self, caller = None):
if caller == "":
return False
if self._global_config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON):
if self._daemon.is_running():
return True
Expand All @@ -55,21 +62,27 @@ def start(self):
return self._daemon.start()

@exports.export("", "b")
def stop(self):
def stop(self, caller = None):
if caller == "":
return False
if not self._daemon.is_running():
return True
else:
return self._daemon.stop()

@exports.export("", "b")
def reload(self):
def reload(self, caller = None):
if caller == "":
return False
if not self._daemon.is_running():
return False
else:
return self.stop() and self.start()

@exports.export("s", "(bs)")
def switch_profile(self, profile_name):
def switch_profile(self, profile_name, caller = None):
if caller == "":
return (False, "Unauthorized")
was_running = self._daemon.is_running()
msg = "OK"
success = True
Expand All @@ -88,46 +101,64 @@ def switch_profile(self, profile_name):
return (success, msg)

@exports.export("", "s")
def active_profile(self):
def active_profile(self, caller = None):
if caller == "":
return ""
if self._daemon.profile is not None:
return self._daemon.profile.name
else:
return ""

@exports.export("", "b")
def disable(self):
def disable(self, caller = None):
if caller == "":
return False
if self._daemon.is_running():
self._daemon.stop()
if self._daemon.is_enabled():
self._daemon.set_profile(None, save_instantly=True)
return True

@exports.export("", "b")
def is_running(self):
def is_running(self, caller = None):
if caller == "":
return False
return self._daemon.is_running()

@exports.export("", "as")
def profiles(self):
def profiles(self, caller = None):
if caller == "":
return []
return self._daemon.profile_loader.profile_locator.get_known_names()

@exports.export("", "a(ss)")
def profiles2(self):
def profiles2(self, caller = None):
if caller == "":
return []
return self._daemon.profile_loader.profile_locator.get_known_names_summary()

@exports.export("s", "(bsss)")
def profile_info(self, profile_name):
def profile_info(self, profile_name, caller = None):
if caller == "":
return tuple(False, "", "", "")
if profile_name is None or profile_name == "":
profile_name = self.active_profile()
return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""]))

@exports.export("", "s")
def recommend_profile(self):
def recommend_profile(self, caller = None):
if caller == "":
return ""
return self._cmd.recommend_profile(hardcoded = not self._global_config.get_bool(consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND))

@exports.export("", "b")
def verify_profile(self):
def verify_profile(self, caller = None):
if caller == "":
return False
return self._daemon.verify_profile(ignore_missing = False)

@exports.export("", "b")
def verify_profile_ignore_missing(self):
def verify_profile_ignore_missing(self, caller = None):
if caller == "":
return False
return self._daemon.verify_profile(ignore_missing = True)
Loading

0 comments on commit 68bb447

Please sign in to comment.