mirror of
https://github.com/systemd/systemd.git
synced 2024-12-12 11:44:13 +08:00
Merge pull request #14633 from poettering/logind-switch-polkit
add polkit hookup for VT switching in logind
This commit is contained in:
commit
d2b45da40a
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
358
src/shared/bus-polkit.c
Normal 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
11
src/shared/bus-polkit.h
Normal 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);
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user