From df5f01c6ed0c20d269f7239901d21883cc871bbb Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 9 Feb 2022 02:10:40 +0100 Subject: [PATCH] dbus: Add missing checks for authorization using Polkit --- configure.ac | 2 +- src/DBus/DBusBridge.cpp | 137 ++++++++++++++++++++++++++++++++++++++++ src/DBus/DBusBridge.hpp | 2 + 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f565b87..a45174a 100644 --- a/configure.ac +++ b/configure.ac @@ -405,7 +405,7 @@ if test "x$with_dbus" = xyes; then # # Check for required D-Bus modules # - PKG_CHECK_MODULES([dbus], [dbus-1 dbus-glib-1 >= 0.100 gio-2.0], + PKG_CHECK_MODULES([dbus], [dbus-1 gio-2.0 polkit-gobject-1], [AC_DEFINE([HAVE_DBUS], [1], [Required GLib DBus API available]) dbus_summary="system-wide; $dbus_CFLAGS $dbus_LIBS"], [AC_MSG_FAILURE([Required D-Bus modules (dbus-1, dbus-glib-1, gio-2.0) not found!])] diff --git a/src/DBus/DBusBridge.cpp b/src/DBus/DBusBridge.cpp index f9209f7..696d906 100644 --- a/src/DBus/DBusBridge.cpp +++ b/src/DBus/DBusBridge.cpp @@ -15,12 +15,14 @@ // along with this program. If not, see . // // Authors: Daniel Kopecek +// Authors: Sebastian Pipping // #ifdef HAVE_BUILD_CONFIG_H #include #endif #include "DBusBridge.hpp" +#include namespace usbguard { @@ -78,6 +80,10 @@ namespace usbguard void DBusBridge::handleRootMethodCall(const std::string& method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { if (method_name == "getParameter") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + const char* name_cstr = nullptr; g_variant_get(parameters, "(&s)", &name_cstr); std::string name(name_cstr); @@ -87,6 +93,10 @@ namespace usbguard } if (method_name == "setParameter") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + const char* name_cstr = nullptr; const char* value_cstr = nullptr; g_variant_get(parameters, "(&s&s)", &name_cstr, &value_cstr); @@ -105,6 +115,10 @@ namespace usbguard void DBusBridge::handlePolicyMethodCall(const std::string& method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { if (method_name == "listRules") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + const char* query_cstr = nullptr; g_variant_get(parameters, "(&s)", &query_cstr); std::string query(query_cstr); @@ -138,6 +152,10 @@ namespace usbguard } if (method_name == "appendRule") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + const char* rule_spec_cstr = nullptr; uint32_t parent_id = 0; g_variant_get(parameters, "(&su)", &rule_spec_cstr, &parent_id); @@ -148,6 +166,10 @@ namespace usbguard } if (method_name == "removeRule") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + uint32_t rule_id = 0; g_variant_get(parameters, "(u)", &rule_id); removeRule(rule_id); @@ -164,6 +186,10 @@ namespace usbguard GDBusMethodInvocation* invocation) { if (method_name == "listDevices") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + const char* query_cstr = nullptr; g_variant_get(parameters, "(&s)", &query_cstr); std::string query(query_cstr); @@ -196,6 +222,10 @@ namespace usbguard } if (method_name == "applyDevicePolicy") { + if (! isAuthorizedByPolkit(invocation)) { + return; + } + uint32_t device_id = 0; uint32_t target_integer = 0; gboolean permanent = false; @@ -327,6 +357,113 @@ namespace usbguard with_interface_string.c_str()); return builder; } + + std::string DBusBridge::formatGError(GError* error) + { + if (error) { + std::stringstream formatGError; + formatGError << error->message << " (code " << error->code << ")"; + return formatGError.str(); + } + else { + return "unknown error"; + } + } + + bool DBusBridge::isAuthorizedByPolkit(GDBusMethodInvocation* invocation) + { + GError* error = NULL; + USBGUARD_LOG(Trace) << "Extracting bus name..."; + const gchar* const /*no-free!*/ bus_name = g_dbus_method_invocation_get_sender (invocation); + + if (! bus_name) { + USBGUARD_LOG(Trace) << "Failed to extract bus name."; + return false; + } + + USBGUARD_LOG(Trace) << "Extracted bus name \"" << bus_name << "\"."; + USBGUARD_LOG(Trace) << "Extracting interface name..."; + const gchar* const /*no-free!*/ interfaceName = g_dbus_method_invocation_get_interface_name(invocation); + + if (! interfaceName) { + USBGUARD_LOG(Trace) << "Failed to extract interface name."; + return false; + } + + USBGUARD_LOG(Trace) << "Extracted interface name \"" << interfaceName << "\"."; + USBGUARD_LOG(Trace) << "Extracting method name..."; + const gchar* const /*no-free!*/ methodName = g_dbus_method_invocation_get_method_name(invocation); + + if (! methodName) { + USBGUARD_LOG(Trace) << "Failed to extract method name."; + return false; + } + + std::stringstream action_id; + action_id << interfaceName << "." << methodName; + USBGUARD_LOG(Trace) << "Extracted method name \"" << methodName << "\"."; + USBGUARD_LOG(Trace) << "Creating a system bus Polkit subject..."; + PolkitSubject* const subject = polkit_system_bus_name_new(bus_name); + + if (! subject) { + USBGUARD_LOG(Trace) << "Failed to create Polkit subject."; + return false; + } + + USBGUARD_LOG(Trace) << "Created."; + USBGUARD_LOG(Trace) << "Connecting with Polkit authority..."; + PolkitAuthority* const authority = polkit_authority_get_sync(/*cancellable=*/ NULL, &error); + + if (! authority || error) { + USBGUARD_LOG(Trace) << "Failed to connect to Polkit authority: " << formatGError(error) << "."; + g_error_free(error); + g_object_unref(authority); + g_object_unref(subject); + return false; + } + + USBGUARD_LOG(Trace) << "Connected."; + USBGUARD_LOG(Trace) << "Customizing Polkit authentification dialog..."; + PolkitDetails* const details = polkit_details_new(); + + if (! details) { + USBGUARD_LOG(Trace) << "Failed to customize the Polkit authentification dialog."; + g_object_unref(authority); + g_object_unref(subject); + return false; + } + + polkit_details_insert (details, "polkit.message", "This USBGuard action needs authorization"); + USBGUARD_LOG(Trace) << "Customized."; + USBGUARD_LOG(Trace) << "Checking authorization of action \"" << action_id.str() << "\" with Polkit ..."; + const PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION; + PolkitAuthorizationResult* const result = polkit_authority_check_authorization_sync + (authority, + subject, + action_id.str().c_str(), + details, + flags, + /*cancellable=*/ NULL, + &error); + + if (! result || error) { + USBGUARD_LOG(Trace) << "Failed to check back with Polkit for authoriation: " << formatGError(error) << "."; + g_error_free(error); + g_object_unref(result); + g_object_unref(details); + g_object_unref(authority); + g_object_unref(subject); + return false; + } + + gboolean isAuthorized = polkit_authorization_result_get_is_authorized(result); + USBGUARD_LOG(Trace) << (isAuthorized ? "Authorized" : "Not authorized") << "."; + g_object_unref(result); + g_object_unref(details); + g_object_unref(authority); + g_object_unref(subject); + return isAuthorized; + } } /* namespace usbguard */ /* vim: set ts=2 sw=2 et */ diff --git a/src/DBus/DBusBridge.hpp b/src/DBus/DBusBridge.hpp index bb9d96a..838ab34 100644 --- a/src/DBus/DBusBridge.hpp +++ b/src/DBus/DBusBridge.hpp @@ -71,6 +71,8 @@ namespace usbguard bool rule_match, uint32_t rule_id); + static std::string formatGError(GError* error); + static bool isAuthorizedByPolkit(GDBusMethodInvocation* invocation); GDBusConnection* const p_gdbus_connection; void(*p_ipc_callback)(bool); -- 2.23.0