From: Lennart Poettering Date: Wed, 22 Jan 2020 11:39:22 +0100 Subject: =?utf-8?q?shared=3A_split_out_polkit_stuff_from_bus-util=2Ec_?= =?utf-8?q?=E2=86=92_bus-polkit=2Ec?= It's enough, complex stuff to warrant its own source file. No other changes, just splitting out. (cherry picked from commit 269e4d2d6b75329ae39a71ebe2c14500e03cda95) (cherry picked from commit 0a19ff7004e4a567566a0a7be6b050cf34c0bfe5) (cherry picked from commit 31a1d569db43af04669ec487f3e741ddc6d12969) (cherry picked from commit a4722a8df23f6612c47f1bb848a6a7c81dcbdccb) --- 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 | 1 + 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 | 2 + src/network/networkd-manager-bus.c | 3 + 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, 406 insertions(+), 373 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 17c2003..ce0fbdb 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 255b86e..91c06ce 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 7777450..9b98f32 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.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 "env-file-label.h" #include "env-file.h" diff --git a/src/import/importd.c b/src/import/importd.c index 2426933..15430d8 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 6b6b32a..c203c7a 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -6,7 +6,9 @@ #include #include "bus-util.h" +#include "bus-polkit.h" #include "def.h" +#include "env-file-label.h" #include "env-file.h" #include "env-file-label.h" #include "env-util.h" diff --git a/src/locale/localed.c b/src/locale/localed.c index f851d35..0bc02a0 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -14,7 +14,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 b9ea370..91350fd 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -12,6 +12,7 @@ #include "audit-util.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" diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 6ee5a1c..28ea5b7 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" +#include "bus-polkit.h" #include "bus-util.h" #include "logind-seat.h" #include "logind.h" diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index df5bfba..bd5c1fe 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -6,6 +6,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-session-device.h" diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index fcaeba1..129696e 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -4,6 +4,7 @@ #include #include "alloc-util.h" +#include "bus-polkit.h" #include "bus-util.h" #include "format-util.h" #include "logind-user.h" diff --git a/src/login/logind.c b/src/login/logind.c index 95ec0a5..171b898 100644 --- a/src/login/logind.c +++ b/src/login/logind.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 "def.h" #include "device-util.h" diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 7e7f0d5..1322f3e 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 7a558df..39905e5 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -15,6 +15,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 fea9cc2..f00be23 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -9,6 +9,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 "fd-util.h" diff --git a/src/machine/machined.c b/src/machine/machined.c index 0b92b1c..e3456d8 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -8,7 +8,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 0dbcd86..beee910 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" #include "networkd-link.h" #include "networkd-manager.h" diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 8c52783..7628878 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -1,7 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-polkit.h" #include "bus-util.h" +#include "networkd-link.h" #include "networkd-manager.h" #include "strv.h" diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index acb9a75..bd29fd0 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -9,6 +9,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 3cbdb0b..708ec94 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 3605598..beebcf8 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -3,6 +3,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 49a359f..f5a34ff 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -4,7 +4,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 5b547ba..1638d3b 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 "missing_capability.h" diff --git a/src/resolve/resolved-dnssd-bus.c b/src/resolve/resolved-dnssd-bus.c index 24bb37b..f7dcb3b 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 96093ff..53f017c 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -2,6 +2,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 2017b0e..422ec23 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -11,7 +11,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 0000000..da4aee5 --- /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 0000000..29b3923 --- /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 a406dd8..c9d7e76 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -11,7 +11,6 @@ #include #include -#include "sd-bus-protocol.h" #include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" @@ -24,15 +23,14 @@ #include "bus-util.h" #include "cap-list.h" #include "cgroup-util.h" -#include "def.h" -#include "escape.h" -#include "fd-util.h" #include "missing.h" #include "mountpoint-util.h" #include "nsflags.h" #include "parse-util.h" #include "proc-cmdline.h" +#include "path-util.h" #include "rlimit-util.h" +#include "socket-util.h" #include "stdio-util.h" #include "strv.h" #include "user-util.h" @@ -187,357 +185,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)) - 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 71c248f..c9cbf76 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" typedef enum BusTransport { @@ -51,11 +51,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 99d6ba1..f6d1092 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -25,6 +25,8 @@ shared_sources = files(''' bus-unit-util.h bus-util.c bus-util.h + bus-polkit.c + bus-polkit.h calendarspec.c calendarspec.h cgroup-show.c diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 324d4a4..398d4f4 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -11,7 +11,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 "def.h" #include "fileio-label.h"