From 269e4d2d6b75329ae39a71ebe2c14500e03cda95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 11:39:22 +0100 Subject: [PATCH] =?utf8?q?shared:=20split=20out=20polkit=20stuff=20from=20?= =?utf8?q?bus-util.c=20=E2=86=92=20bus-polkit.c?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit It's enough, complex stuff to warrant its own source file. No other changes, just splitting out. --- src/core/dbus-unit.c | 1 + src/core/dbus.c | 2 +- src/hostname/hostnamed.c | 2 +- src/import/importd.c | 2 +- src/locale/keymap-util.c | 2 +- src/locale/localed.c | 2 +- src/login/logind-dbus.c | 3 +- src/login/logind-seat-dbus.c | 1 + src/login/logind-session-dbus.c | 1 + src/login/logind-user-dbus.c | 1 + src/login/logind.c | 2 +- src/machine/image-dbus.c | 1 + src/machine/machine-dbus.c | 1 + src/machine/machined-dbus.c | 1 + src/machine/machined.c | 2 +- src/network/networkd-link-bus.c | 1 + src/network/networkd-manager-bus.c | 2 +- src/network/networkd-manager.c | 1 + src/portable/portabled-bus.c | 2 +- src/portable/portabled-image-bus.c | 1 + src/portable/portabled.c | 2 +- src/resolve/resolved-bus.c | 1 + src/resolve/resolved-dnssd-bus.c | 5 +- src/resolve/resolved-link-bus.c | 1 + src/resolve/resolved-manager.c | 2 +- src/shared/bus-polkit.c | 358 +++++++++++++++++++++++++++++ src/shared/bus-polkit.h | 11 + src/shared/bus-util.c | 357 +--------------------------- src/shared/bus-util.h | 7 +- src/shared/meson.build | 2 + src/timedate/timedated.c | 2 +- 31 files changed, 402 insertions(+), 377 deletions(-) create mode 100644 src/shared/bus-polkit.c create mode 100644 src/shared/bus-polkit.h diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 1c5fd2a23b8..73d5b2ee1eb 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "bpf-firewall.h" #include "bus-common-errors.h" +#include "bus-polkit.h" #include "cgroup-util.h" #include "condition.h" #include "dbus-job.h" diff --git a/src/core/dbus.c b/src/core/dbus.c index 941219fa1ef..c86e049c78b 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -10,7 +10,7 @@ #include "bus-common-errors.h" #include "bus-error.h" #include "bus-internal.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "dbus-automount.h" #include "dbus-cgroup.h" #include "dbus-device.h" diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index deecd9b8db3..21f64714951 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -8,7 +8,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "def.h" #include "env-file-label.h" #include "env-file.h" diff --git a/src/import/importd.c b/src/import/importd.c index a75ab6bc070..93e704ed612 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -7,7 +7,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "def.h" #include "fd-util.h" #include "float.h" diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index 519dd0d188c..30669a9359e 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -5,7 +5,7 @@ #include #include -#include "bus-util.h" +#include "bus-polkit.h" #include "env-file-label.h" #include "env-file.h" #include "env-util.h" diff --git a/src/locale/localed.c b/src/locale/localed.c index 2031cd25ced..09f16d25f4c 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -15,7 +15,7 @@ #include "alloc-util.h" #include "bus-error.h" #include "bus-message.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "def.h" #include "keymap-util.h" #include "locale-util.h" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index d3aa6815a6c..8017aa5c3cc 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -12,13 +12,14 @@ #include "bootspec.h" #include "bus-common-errors.h" #include "bus-error.h" +#include "bus-polkit.h" #include "bus-unit-util.h" #include "bus-util.h" #include "cgroup-util.h" #include "device-util.h" #include "dirent-util.h" -#include "efivars.h" #include "efi-loader.h" +#include "efivars.h" #include "env-util.h" #include "escape.h" #include "fd-util.h" diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 34ac0350f2d..5b41e60fd6a 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "logind-dbus.h" #include "logind-seat-dbus.h" diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 80f3e432de8..37385142828 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "fd-util.h" #include "logind-brightness.h" diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 7943a007e14..9bf68a610e4 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -3,6 +3,7 @@ #include #include "alloc-util.h" +#include "bus-polkit.h" #include "bus-util.h" #include "format-util.h" #include "logind-dbus.h" diff --git a/src/login/logind.c b/src/login/logind.c index d8c1bbe15b9..8f3708d2a4f 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -9,7 +9,7 @@ #include "alloc-util.h" #include "bus-error.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "cgroup-util.h" #include "def.h" #include "device-util.h" diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index b45355d86fc..294ef349321 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "copy.h" #include "dissect-image.h" diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 3b2ac382985..a2990452af1 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -14,6 +14,7 @@ #include "bus-common-errors.h" #include "bus-internal.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "copy.h" #include "env-file.h" diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 6fc3b930570..d0cc07678fa 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" #include "cgroup-util.h" #include "errno-util.h" diff --git a/src/machine/machined.c b/src/machine/machined.c index a3bed035dc8..ace2131c2de 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -10,7 +10,7 @@ #include "alloc-util.h" #include "bus-error.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "cgroup-util.h" #include "dirent-util.h" #include "fd-util.h" diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 8f3b2e92f8f..5658fea140b 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" #include "dns-domain.h" #include "networkd-link-bus.h" diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 660c2847eb3..b7279a582ce 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -6,7 +6,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "networkd-link-bus.h" #include "networkd-link.h" #include "networkd-manager-bus.h" diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 380f5c1c61f..90f734a03c5 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -11,6 +11,7 @@ #include "sd-netlink.h" #include "alloc-util.h" +#include "bus-polkit.h" #include "bus-util.h" #include "conf-parser.h" #include "def.h" diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c index 89168c3c43b..0fa05434efb 100644 --- a/src/portable/portabled-bus.c +++ b/src/portable/portabled-bus.c @@ -3,7 +3,7 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "bus-common-errors.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "fd-util.h" #include "io-util.h" #include "machine-image.h" diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index fd2b7c99944..2bd1c495e4e 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "fd-util.h" #include "fileio.h" diff --git a/src/portable/portabled.c b/src/portable/portabled.c index c74ec429627..75b76926e55 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -7,7 +7,7 @@ #include "sd-daemon.h" #include "alloc-util.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "def.h" #include "main-func.h" #include "portabled-bus.h" diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index ff6acb2eac1..ffe61bdb9f5 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -2,6 +2,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" #include "dns-domain.h" #include "memory-util.h" diff --git a/src/resolve/resolved-dnssd-bus.c b/src/resolve/resolved-dnssd-bus.c index 24bb37b35e8..f7dcb3bfa56 100644 --- a/src/resolve/resolved-dnssd-bus.c +++ b/src/resolve/resolved-dnssd-bus.c @@ -1,9 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "missing_capability.h" -#include "resolved-dnssd.h" #include "resolved-dnssd-bus.h" +#include "resolved-dnssd.h" #include "resolved-link.h" #include "strv.h" #include "user-util.h" diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index a8480f190a6..2a166c11b04 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" #include "parse-util.h" #include "resolve-util.h" diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index af91a8ec1a5..4f72077720b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -14,7 +14,7 @@ #include "af-list.h" #include "alloc-util.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "dirent-util.h" #include "dns-domain.h" #include "fd-util.h" diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c new file mode 100644 index 00000000000..da4aee50860 --- /dev/null +++ b/src/shared/bus-polkit.c @@ -0,0 +1,358 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-polkit.h" +#include "strv.h" +#include "user-util.h" + +static int check_good_user(sd_bus_message *m, uid_t good_user) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + uid_t sender_uid; + int r; + + assert(m); + + if (good_user == UID_INVALID) + return 0; + + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + /* Don't trust augmented credentials for authorization */ + assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM); + + r = sd_bus_creds_get_euid(creds, &sender_uid); + if (r < 0) + return r; + + return sender_uid == good_user; +} + +int bus_test_polkit( + sd_bus_message *call, + int capability, + const char *action, + const char **details, + uid_t good_user, + bool *_challenge, + sd_bus_error *e) { + + int r; + + assert(call); + assert(action); + + /* Tests non-interactively! */ + + r = check_good_user(call, good_user); + if (r != 0) + return r; + + r = sd_bus_query_sender_privilege(call, capability); + if (r < 0) + return r; + else if (r > 0) + return 1; +#if ENABLE_POLKIT + else { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int authorized = false, challenge = false; + const char *sender, **k, **v; + + sender = sd_bus_message_get_sender(call); + if (!sender) + return -EBADMSG; + + r = sd_bus_message_new_method_call( + call->bus, + &request, + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + "CheckAuthorization"); + if (r < 0) + return r; + + r = sd_bus_message_append( + request, + "(sa{sv})s", + "system-bus-name", 1, "name", "s", sender, + action); + if (r < 0) + return r; + + r = sd_bus_message_open_container(request, 'a', "{ss}"); + if (r < 0) + return r; + + STRV_FOREACH_PAIR(k, v, details) { + r = sd_bus_message_append(request, "{ss}", *k, *v); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(request); + if (r < 0) + return r; + + r = sd_bus_message_append(request, "us", 0, NULL); + if (r < 0) + return r; + + r = sd_bus_call(call->bus, request, 0, e, &reply); + if (r < 0) { + /* Treat no PK available as access denied */ + if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { + sd_bus_error_free(e); + return -EACCES; + } + + return r; + } + + r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "bb", &authorized, &challenge); + if (r < 0) + return r; + + if (authorized) + return 1; + + if (_challenge) { + *_challenge = challenge; + return 0; + } + } +#endif + + return -EACCES; +} + +#if ENABLE_POLKIT + +typedef struct AsyncPolkitQuery { + sd_bus_message *request, *reply; + sd_bus_message_handler_t callback; + void *userdata; + sd_bus_slot *slot; + Hashmap *registry; +} AsyncPolkitQuery; + +static void async_polkit_query_free(AsyncPolkitQuery *q) { + + if (!q) + return; + + sd_bus_slot_unref(q->slot); + + if (q->registry && q->request) + hashmap_remove(q->registry, q->request); + + sd_bus_message_unref(q->request); + sd_bus_message_unref(q->reply); + + free(q); +} + +static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + AsyncPolkitQuery *q = userdata; + int r; + + assert(reply); + assert(q); + + q->slot = sd_bus_slot_unref(q->slot); + q->reply = sd_bus_message_ref(reply); + + r = sd_bus_message_rewind(q->request, true); + if (r < 0) { + r = sd_bus_reply_method_errno(q->request, r, NULL); + goto finish; + } + + r = q->callback(q->request, q->userdata, &error_buffer); + r = bus_maybe_reply_error(q->request, r, &error_buffer); + +finish: + async_polkit_query_free(q); + + return r; +} + +#endif + +int bus_verify_polkit_async( + sd_bus_message *call, + int capability, + const char *action, + const char **details, + bool interactive, + uid_t good_user, + Hashmap **registry, + sd_bus_error *error) { + +#if ENABLE_POLKIT + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; + AsyncPolkitQuery *q; + const char *sender, **k, **v; + sd_bus_message_handler_t callback; + void *userdata; + int c; +#endif + int r; + + assert(call); + assert(action); + assert(registry); + + r = check_good_user(call, good_user); + if (r != 0) + return r; + +#if ENABLE_POLKIT + q = hashmap_get(*registry, call); + if (q) { + int authorized, challenge; + + /* This is the second invocation of this function, and + * there's already a response from polkit, let's + * process it */ + assert(q->reply); + + if (sd_bus_message_is_method_error(q->reply, NULL)) { + const sd_bus_error *e; + + e = sd_bus_message_get_error(q->reply); + + /* Treat no PK available as access denied */ + if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) || + sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) + return -EACCES; + + /* Copy error from polkit reply */ + sd_bus_error_copy(error, e); + return -sd_bus_error_get_errno(e); + } + + r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); + if (r >= 0) + r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); + if (r < 0) + return r; + + if (authorized) + return 1; + + if (challenge) + return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); + + return -EACCES; + } +#endif + + r = sd_bus_query_sender_privilege(call, capability); + if (r < 0) + return r; + else if (r > 0) + return 1; + +#if ENABLE_POLKIT + if (sd_bus_get_current_message(call->bus) != call) + return -EINVAL; + + callback = sd_bus_get_current_handler(call->bus); + if (!callback) + return -EINVAL; + + userdata = sd_bus_get_current_userdata(call->bus); + + sender = sd_bus_message_get_sender(call); + if (!sender) + return -EBADMSG; + + c = sd_bus_message_get_allow_interactive_authorization(call); + if (c < 0) + return c; + if (c > 0) + interactive = true; + + r = hashmap_ensure_allocated(registry, NULL); + if (r < 0) + return r; + + r = sd_bus_message_new_method_call( + call->bus, + &pk, + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + "CheckAuthorization"); + if (r < 0) + return r; + + r = sd_bus_message_append( + pk, + "(sa{sv})s", + "system-bus-name", 1, "name", "s", sender, + action); + if (r < 0) + return r; + + r = sd_bus_message_open_container(pk, 'a', "{ss}"); + if (r < 0) + return r; + + STRV_FOREACH_PAIR(k, v, details) { + r = sd_bus_message_append(pk, "{ss}", *k, *v); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(pk); + if (r < 0) + return r; + + r = sd_bus_message_append(pk, "us", interactive, NULL); + if (r < 0) + return r; + + q = new0(AsyncPolkitQuery, 1); + if (!q) + return -ENOMEM; + + q->request = sd_bus_message_ref(call); + q->callback = callback; + q->userdata = userdata; + + r = hashmap_put(*registry, call, q); + if (r < 0) { + async_polkit_query_free(q); + return r; + } + + q->registry = *registry; + + r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); + if (r < 0) { + async_polkit_query_free(q); + return r; + } + + return 0; +#endif + + return -EACCES; +} + +void bus_verify_polkit_async_registry_free(Hashmap *registry) { +#if ENABLE_POLKIT + hashmap_free_with_destructor(registry, async_polkit_query_free); +#endif +} diff --git a/src/shared/bus-polkit.h b/src/shared/bus-polkit.h new file mode 100644 index 00000000000..29b39230472 --- /dev/null +++ b/src/shared/bus-polkit.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "hashmap.h" + +int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e); + +int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); +void bus_verify_polkit_async_registry_free(Hashmap *registry); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 10c05eba184..15bc0ed71bf 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -9,7 +9,6 @@ #include #include -#include "sd-bus-protocol.h" #include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" @@ -22,15 +21,12 @@ #include "bus-util.h" #include "cap-list.h" #include "cgroup-util.h" -#include "def.h" -#include "escape.h" -#include "fd-util.h" #include "mountpoint-util.h" #include "nsflags.h" #include "parse-util.h" #include "path-util.h" -#include "proc-cmdline.h" #include "rlimit-util.h" +#include "socket-util.h" #include "stdio-util.h" #include "strv.h" #include "user-util.h" @@ -185,357 +181,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { return has_owner; } -static int check_good_user(sd_bus_message *m, uid_t good_user) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - uid_t sender_uid; - int r; - - assert(m); - - if (good_user == UID_INVALID) - return 0; - - r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds); - if (r < 0) - return r; - - /* Don't trust augmented credentials for authorization */ - assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM); - - r = sd_bus_creds_get_euid(creds, &sender_uid); - if (r < 0) - return r; - - return sender_uid == good_user; -} - -int bus_test_polkit( - sd_bus_message *call, - int capability, - const char *action, - const char **details, - uid_t good_user, - bool *_challenge, - sd_bus_error *e) { - - int r; - - assert(call); - assert(action); - - /* Tests non-interactively! */ - - r = check_good_user(call, good_user); - if (r != 0) - return r; - - r = sd_bus_query_sender_privilege(call, capability); - if (r < 0) - return r; - else if (r > 0) - return 1; -#if ENABLE_POLKIT - else { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - int authorized = false, challenge = false; - const char *sender, **k, **v; - - sender = sd_bus_message_get_sender(call); - if (!sender) - return -EBADMSG; - - r = sd_bus_message_new_method_call( - call->bus, - &request, - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - "org.freedesktop.PolicyKit1.Authority", - "CheckAuthorization"); - if (r < 0) - return r; - - r = sd_bus_message_append( - request, - "(sa{sv})s", - "system-bus-name", 1, "name", "s", sender, - action); - if (r < 0) - return r; - - r = sd_bus_message_open_container(request, 'a', "{ss}"); - if (r < 0) - return r; - - STRV_FOREACH_PAIR(k, v, details) { - r = sd_bus_message_append(request, "{ss}", *k, *v); - if (r < 0) - return r; - } - - r = sd_bus_message_close_container(request); - if (r < 0) - return r; - - r = sd_bus_message_append(request, "us", 0, NULL); - if (r < 0) - return r; - - r = sd_bus_call(call->bus, request, 0, e, &reply); - if (r < 0) { - /* Treat no PK available as access denied */ - if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { - sd_bus_error_free(e); - return -EACCES; - } - - return r; - } - - r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); - if (r < 0) - return r; - - r = sd_bus_message_read(reply, "bb", &authorized, &challenge); - if (r < 0) - return r; - - if (authorized) - return 1; - - if (_challenge) { - *_challenge = challenge; - return 0; - } - } -#endif - - return -EACCES; -} - -#if ENABLE_POLKIT - -typedef struct AsyncPolkitQuery { - sd_bus_message *request, *reply; - sd_bus_message_handler_t callback; - void *userdata; - sd_bus_slot *slot; - Hashmap *registry; -} AsyncPolkitQuery; - -static void async_polkit_query_free(AsyncPolkitQuery *q) { - - if (!q) - return; - - sd_bus_slot_unref(q->slot); - - if (q->registry && q->request) - hashmap_remove(q->registry, q->request); - - sd_bus_message_unref(q->request); - sd_bus_message_unref(q->reply); - - free(q); -} - -static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { - _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - AsyncPolkitQuery *q = userdata; - int r; - - assert(reply); - assert(q); - - q->slot = sd_bus_slot_unref(q->slot); - q->reply = sd_bus_message_ref(reply); - - r = sd_bus_message_rewind(q->request, true); - if (r < 0) { - r = sd_bus_reply_method_errno(q->request, r, NULL); - goto finish; - } - - r = q->callback(q->request, q->userdata, &error_buffer); - r = bus_maybe_reply_error(q->request, r, &error_buffer); - -finish: - async_polkit_query_free(q); - - return r; -} - -#endif - -int bus_verify_polkit_async( - sd_bus_message *call, - int capability, - const char *action, - const char **details, - bool interactive, - uid_t good_user, - Hashmap **registry, - sd_bus_error *error) { - -#if ENABLE_POLKIT - _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; - AsyncPolkitQuery *q; - const char *sender, **k, **v; - sd_bus_message_handler_t callback; - void *userdata; - int c; -#endif - int r; - - assert(call); - assert(action); - assert(registry); - - r = check_good_user(call, good_user); - if (r != 0) - return r; - -#if ENABLE_POLKIT - q = hashmap_get(*registry, call); - if (q) { - int authorized, challenge; - - /* This is the second invocation of this function, and - * there's already a response from polkit, let's - * process it */ - assert(q->reply); - - if (sd_bus_message_is_method_error(q->reply, NULL)) { - const sd_bus_error *e; - - e = sd_bus_message_get_error(q->reply); - - /* Treat no PK available as access denied */ - if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) || - sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) - return -EACCES; - - /* Copy error from polkit reply */ - sd_bus_error_copy(error, e); - return -sd_bus_error_get_errno(e); - } - - r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); - if (r >= 0) - r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); - if (r < 0) - return r; - - if (authorized) - return 1; - - if (challenge) - return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); - - return -EACCES; - } -#endif - - r = sd_bus_query_sender_privilege(call, capability); - if (r < 0) - return r; - else if (r > 0) - return 1; - -#if ENABLE_POLKIT - if (sd_bus_get_current_message(call->bus) != call) - return -EINVAL; - - callback = sd_bus_get_current_handler(call->bus); - if (!callback) - return -EINVAL; - - userdata = sd_bus_get_current_userdata(call->bus); - - sender = sd_bus_message_get_sender(call); - if (!sender) - return -EBADMSG; - - c = sd_bus_message_get_allow_interactive_authorization(call); - if (c < 0) - return c; - if (c > 0) - interactive = true; - - r = hashmap_ensure_allocated(registry, NULL); - if (r < 0) - return r; - - r = sd_bus_message_new_method_call( - call->bus, - &pk, - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - "org.freedesktop.PolicyKit1.Authority", - "CheckAuthorization"); - if (r < 0) - return r; - - r = sd_bus_message_append( - pk, - "(sa{sv})s", - "system-bus-name", 1, "name", "s", sender, - action); - if (r < 0) - return r; - - r = sd_bus_message_open_container(pk, 'a', "{ss}"); - if (r < 0) - return r; - - STRV_FOREACH_PAIR(k, v, details) { - r = sd_bus_message_append(pk, "{ss}", *k, *v); - if (r < 0) - return r; - } - - r = sd_bus_message_close_container(pk); - if (r < 0) - return r; - - r = sd_bus_message_append(pk, "us", interactive, NULL); - if (r < 0) - return r; - - q = new0(AsyncPolkitQuery, 1); - if (!q) - return -ENOMEM; - - q->request = sd_bus_message_ref(call); - q->callback = callback; - q->userdata = userdata; - - r = hashmap_put(*registry, call, q); - if (r < 0) { - async_polkit_query_free(q); - return r; - } - - q->registry = *registry; - - r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0); - if (r < 0) { - async_polkit_query_free(q); - return r; - } - - return 0; -#endif - - return -EACCES; -} - -void bus_verify_polkit_async_registry_free(Hashmap *registry) { -#if ENABLE_POLKIT - hashmap_free_with_destructor(registry, async_polkit_query_free); -#endif -} - int bus_check_peercred(sd_bus *c) { struct ucred ucred; int fd, r; diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 1e2f04cc5df..db245a791ea 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -9,8 +9,8 @@ #include "sd-bus.h" #include "sd-event.h" -#include "hashmap.h" #include "macro.h" +#include "set.h" #include "string-util.h" #include "time-util.h" @@ -52,11 +52,6 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error); int bus_check_peercred(sd_bus *c); -int bus_test_polkit(sd_bus_message *call, int capability, const char *action, const char **details, uid_t good_user, bool *_challenge, sd_bus_error *e); - -int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); -void bus_verify_polkit_async_registry_free(Hashmap *registry); - int bus_connect_system_systemd(sd_bus **_bus); int bus_connect_user_systemd(sd_bus **_bus); diff --git a/src/shared/meson.build b/src/shared/meson.build index a7320fc4ed6..bf3b730d146 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -27,6 +27,8 @@ shared_sources = files(''' bus-unit-util.h bus-util.c bus-util.h + bus-polkit.c + bus-polkit.h bus-wait-for-jobs.c bus-wait-for-jobs.h bus-wait-for-units.c diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 4ec3b503592..5e2fb50d837 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -12,7 +12,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" -#include "bus-util.h" +#include "bus-polkit.h" #include "clock-util.h" #include "conf-files.h" #include "def.h" -- 2.39.2