From 269e4d2d6b75329ae39a71ebe2c14500e03cda95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 11:39:22 +0100 Subject: [PATCH 1/2] =?UTF-8?q?shared:=20split=20out=20polkit=20stuff=20fr?= =?UTF-8?q?om=20bus-util.c=20=E2=86=92=20bus-polkit.c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 1c5fd2a23b..73d5b2ee1e 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 941219fa1e..c86e049c78 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 deecd9b8db..21f6471495 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 a75ab6bc07..93e704ed61 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 519dd0d188..30669a9359 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 2031cd25ce..09f16d25f4 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 d3aa6815a6..8017aa5c3c 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 34ac0350f2..5b41e60fd6 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 80f3e432de..3738514282 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 7943a007e1..9bf68a610e 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 d8c1bbe15b..8f3708d2a4 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 b45355d86f..294ef34932 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 3b2ac38298..a2990452af 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 6fc3b93057..d0cc07678f 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 a3bed035dc..ace2131c2d 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 8f3b2e92f8..5658fea140 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 660c2847eb..b7279a582c 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 380f5c1c61..90f734a03c 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 89168c3c43..0fa05434ef 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 fd2b7c9994..2bd1c495e4 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 c74ec42962..75b76926e5 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 ff6acb2eac..ffe61bdb9f 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 24bb37b35e..f7dcb3bfa5 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 a8480f190a..2a166c11b0 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 af91a8ec1a..4f72077720 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 0000000000..da4aee5086 --- /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 0000000000..29b3923047 --- /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 10c05eba18..15bc0ed71b 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 1e2f04cc5d..db245a791e 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 a7320fc4ed..bf3b730d14 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 4ec3b50359..5e2fb50d83 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" From 4acf0cfd2f92edb94ad48d04f1ce6c9ab4e19d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2020 12:04:38 +0100 Subject: [PATCH 2/2] logind: check PolicyKit before allowing VT switch Let's lock this down a bit. Effectively nothing much changes, since the default PK policy will allow users on the VT to change VT. Only users with no local VT session won't be able to switch VTs. --- src/login/logind-dbus.c | 16 +++++++ src/login/logind-seat-dbus.c | 58 ++++++++++++++++++++++++- src/login/logind-session-dbus.c | 14 ++++++ src/login/org.freedesktop.login1.policy | 10 +++++ 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 8017aa5c3c..52a7ea3c77 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1016,6 +1016,8 @@ static int method_activate_session(sd_bus_message *message, void *userdata, sd_b if (r < 0) return r; + /* PolicyKit is done by bus_session_method_activate() */ + return bus_session_method_activate(message, session, error); } @@ -1047,6 +1049,20 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + r = session_activate(session); if (r < 0) return r; diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 5b41e60fd6..0a5df937cc 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -178,6 +178,20 @@ static int method_activate_session(sd_bus_message *message, void *userdata, sd_b if (session->seat != s) return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &s->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + r = session_activate(session); if (r < 0) return r; @@ -198,7 +212,21 @@ static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_erro return r; if (to <= 0) - return -EINVAL; + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal"); + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &s->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ r = seat_switch_to(s, to); if (r < 0) @@ -214,6 +242,20 @@ static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus assert(message); assert(s); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &s->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + r = seat_switch_to_next(s); if (r < 0) return r; @@ -228,6 +270,20 @@ static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd assert(message); assert(s); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &s->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + r = seat_switch_to_previous(s); if (r < 0) return r; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 3738514282..80ec89ba0a 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -191,6 +191,20 @@ int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_ assert(message); assert(s); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &s->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + r = session_activate(s); if (r < 0) return r; diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy index 6dc79aa32a..a269c8e313 100644 --- a/src/login/org.freedesktop.login1.policy +++ b/src/login/org.freedesktop.login1.policy @@ -391,4 +391,14 @@ + + Change Session + Authentication is required for changing the virtual terminal. + + auth_admin_keep + auth_admin_keep + yes + + +