Merge pull request #14633 from poettering/logind-switch-polkit

add polkit hookup for VT switching in logind
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-01-28 16:09:09 +01:00 committed by GitHub
commit d2b45da40a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 499 additions and 378 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -5,7 +5,7 @@
#include <sys/types.h>
#include <unistd.h>
#include "bus-util.h"
#include "bus-polkit.h"
#include "env-file-label.h"
#include "env-file.h"
#include "env-util.h"

View File

@ -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"

View File

@ -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"
@ -1015,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);
}
@ -1046,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;

View File

@ -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"
@ -177,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;
@ -197,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)
@ -213,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;
@ -227,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;

View File

@ -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"
@ -190,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;

View File

@ -3,6 +3,7 @@
#include <errno.h>
#include "alloc-util.h"
#include "bus-polkit.h"
#include "bus-util.h"
#include "format-util.h"
#include "logind-dbus.h"

View File

@ -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"

View File

@ -391,4 +391,14 @@
</defaults>
</action>
<action id="org.freedesktop.login1.chvt">
<description gettext-domain="systemd">Change Session</description>
<message gettext-domain="systemd">Authentication is required for changing the virtual terminal.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

358
src/shared/bus-polkit.c Normal file
View File

@ -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
}

11
src/shared/bus-polkit.h Normal file
View File

@ -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);

View File

@ -9,7 +9,6 @@
#include <sys/socket.h>
#include <unistd.h>
#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;

View File

@ -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);

View File

@ -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

View File

@ -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"