diff --git a/etc-conf/dbus/polkit/com.redhat.RHSM1.policy b/etc-conf/dbus/polkit/com.redhat.RHSM1.policy index 8d0407d4a8..746b1aa776 100644 --- a/etc-conf/dbus/polkit/com.redhat.RHSM1.policy +++ b/etc-conf/dbus/polkit/com.redhat.RHSM1.policy @@ -6,13 +6,17 @@ Red Hat Subscription Management http://redhat.com + RHSM default System policy prevents access to com.redhat.RHSM1 - yes - yes - yes + auth_admin + auth_admin + auth_admin_keep diff --git a/etc-conf/dbus/system.d/com.redhat.RHSM1.conf b/etc-conf/dbus/system.d/com.redhat.RHSM1.conf index 48b38e0c59..44c3dfa3ae 100644 --- a/etc-conf/dbus/system.d/com.redhat.RHSM1.conf +++ b/etc-conf/dbus/system.d/com.redhat.RHSM1.conf @@ -88,6 +88,21 @@ send_interface="com.redhat.RHSM1.Consumer" send_member="GetUuid"/> + + + + + + + diff --git a/src/rhsmlib/client_info.py b/src/rhsmlib/client_info.py index a7132266d3..f1346b03d5 100644 --- a/src/rhsmlib/client_info.py +++ b/src/rhsmlib/client_info.py @@ -36,6 +36,11 @@ class DBusSender: @rhsm.utils.call_once def __init__(self): self._cmd_line = None + self._sender = None + + @property + def sender(self): + return self._sender @property def cmd_line(self): @@ -70,6 +75,7 @@ def set_cmd_line(self, sender, cmd_line=None, bus=None): """ if cmd_line is None: self.cmd_line = self.get_cmd_line(sender, bus) + self._sender = sender else: self.cmd_line = cmd_line log.debug("D-Bus sender: %s (cmd-line: %s)" % (sender, self.cmd_line)) diff --git a/src/rhsmlib/dbus/objects/register.py b/src/rhsmlib/dbus/objects/register.py index c31151ddf0..b1f0df6ea3 100644 --- a/src/rhsmlib/dbus/objects/register.py +++ b/src/rhsmlib/dbus/objects/register.py @@ -94,8 +94,10 @@ def __init__(self, conn=None, object_path=None, bus_name=None): out_signature="s", ) @util.dbus_handle_sender + @util.dbus_admin_auth_policy @util.dbus_handle_exceptions def Start(self, locale, sender=None): + log.debug(f"D-Bus method: Start({locale}, {sender})") locale = dbus_utils.dbus_to_python(locale, expected_type=str) Locale.set(locale) @@ -108,8 +110,10 @@ def Start(self, locale, sender=None): out_signature="b", ) @util.dbus_handle_sender + @util.dbus_admin_auth_policy @util.dbus_handle_exceptions def Stop(self, locale, sender=None): + log.debug(f"D-Bus method: Stop({locale}, {sender})") locale = dbus_utils.dbus_to_python(locale, expected_type=str) Locale.set(locale) diff --git a/src/rhsmlib/dbus/objects/unregister.py b/src/rhsmlib/dbus/objects/unregister.py index 8627045b02..29b029b6c4 100644 --- a/src/rhsmlib/dbus/objects/unregister.py +++ b/src/rhsmlib/dbus/objects/unregister.py @@ -73,6 +73,7 @@ def __init__(self, conn=None, object_path=None, bus_name=None): out_signature="", ) @util.dbus_handle_sender + @util.dbus_admin_auth_policy @util.dbus_handle_exceptions def Unregister(self, proxy_options, locale, sender=None): """ diff --git a/src/rhsmlib/dbus/util.py b/src/rhsmlib/dbus/util.py index 266a8cba96..6dcc41c89d 100644 --- a/src/rhsmlib/dbus/util.py +++ b/src/rhsmlib/dbus/util.py @@ -14,16 +14,20 @@ import logging import sys import decorator +import dbus import dbus.service import json import re from rhsmlib.dbus import exceptions from rhsmlib.client_info import DBusSender +from rhsmlib.dbus.dbus_utils import pid_of_sender, dbus_to_python log = logging.getLogger(__name__) __all__ = [ + "dbus_admin_auth_policy", + "dbus_domain_admin_auth_policy", "dbus_handle_exceptions", "dbus_handle_sender", "dbus_service_method", @@ -31,6 +35,83 @@ ] +def _check_polkit_policy(sender, func, *args, **kwargs): + """ + Check if given sender is authorized to call given function + """ + bus = dbus.SystemBus() + try: + pid = pid_of_sender(bus, sender) + except Exception as err: + raise exceptions.RHSM1DBusException(f"Unable to get PID of sender: {sender}: {err}") + dbus_obj = bus.get_object("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority") + dbus_iface = dbus.Interface(dbus_obj, "org.freedesktop.PolicyKit1.Authority") + subject = ( + "unix-process", + {"pid": dbus.UInt32(pid), "start-time": dbus.UInt64(0)} + ) + # TODO: Modify code to be able to use at least two IDs (one for "register" and another + # for "unregister") + action_id = "com.redhat.RHSM1.default" + details = {} + flags = 1 + cancellation_id = "" + + try: + is_authorized, is_challenge, details = dbus_iface.CheckAuthorization( + subject, action_id, details, flags, cancellation_id) + except Exception as err: + raise exceptions.RHSM1DBusException(f"Unable to check authorization of {sender}: {err}") + else: + is_authorized = dbus_to_python(is_authorized, expected_type=bool) + if is_authorized is True: + return func(*args, **kwargs) + else: + details = dbus_to_python(details, expected_type=dict) + raise exceptions.RHSM1DBusException(f"{sender} is not authorized to call {func}: {details}") + + +@decorator.decorator +def dbus_admin_auth_policy(func, *args, **kwargs): + """ + When this decorator is used, then it is required that sender process + is admin authenticated. This is workaround for some applications using + our D-Bus API. + """ + + sender = None + # Get sender from arguments + if "sender" in kwargs: + sender = kwargs["sender"] + elif len(args) > 0: + sender = args[-1] + + if sender is not None: + return _check_polkit_policy(sender, func, *args, **kwargs) + else: + raise exceptions.RHSM1DBusException(f"No sender specified, unable to check authorization for calling {func}") + + +@decorator.decorator +def dbus_domain_admin_auth_policy(func, *args, **kwargs): + """ + This modified version of decorator dbus_admin_auth_policy(), but this could be + used in the case, when unix socket is used for registration + """ + # TODO: This does not work as expected and it is not used ATM. + # The pid_of_sender() in _check_polkit_policy() is not able to + # find process for some reason, but process communicating over + # unix socket should be authorized by polkit. + with DBusSender() as dbus_sender: + sender = dbus_sender.sender + if sender is not None: + return _check_polkit_policy(sender, func, *args, **kwargs) + else: + raise exceptions.RHSM1DBusException( + f"No sender specified, unable to check authorization for calling {func}" + ) + + @decorator.decorator def dbus_handle_sender(func, *args, **kwargs): """