1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-25 01:34:28 +03:00

Merge pull request #28056 from dtardon/polkit-cleanup

Some bus-polkit cleanup
This commit is contained in:
Lennart Poettering 2023-06-19 15:50:35 +02:00 committed by GitHub
commit ab93429dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -32,10 +32,7 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) {
}
#if ENABLE_POLKIT
static int bus_message_append_strv_key_value(
sd_bus_message *m,
const char **l) {
static int bus_message_append_strv_key_value(sd_bus_message *m, const char **l) {
int r;
assert(m);
@ -56,6 +53,51 @@ static int bus_message_append_strv_key_value(
return r;
}
static int bus_message_new_polkit_auth_call(
sd_bus_message *m,
const char *action,
const char **details,
bool interactive,
sd_bus_message **ret) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
const char *sender;
int r;
assert(m);
assert(action);
assert(ret);
sender = sd_bus_message_get_sender(m);
if (!sender)
return -EBADMSG;
r = sd_bus_message_new_method_call(
ASSERT_PTR(m->bus),
&c,
"org.freedesktop.PolicyKit1",
"/org/freedesktop/PolicyKit1/Authority",
"org.freedesktop.PolicyKit1.Authority",
"CheckAuthorization");
if (r < 0)
return r;
r = sd_bus_message_append(c, "(sa{sv})s", "system-bus-name", 1, "name", "s", sender, action);
if (r < 0)
return r;
r = bus_message_append_strv_key_value(c, details);
if (r < 0)
return r;
r = sd_bus_message_append(c, "us", interactive, NULL);
if (r < 0)
return r;
*ret = TAKE_PTR(c);
return 0;
}
#endif
int bus_test_polkit(
@ -81,71 +123,42 @@ int bus_test_polkit(
r = sd_bus_query_sender_privilege(call, capability);
if (r < 0)
return r;
else if (r > 0)
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;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL, *reply = NULL;
int authorized = false, challenge = false;
sender = sd_bus_message_get_sender(call);
if (!sender)
return -EBADMSG;
r = bus_message_new_polkit_auth_call(call, action, details, /* interactive = */ false, &request);
if (r < 0)
return r;
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 = bus_message_append_strv_key_value(request, details);
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, ret_error, &reply);
if (r < 0) {
/* Treat no PK available as access denied */
if (bus_error_is_unknown_service(ret_error)) {
sd_bus_error_free(ret_error);
return -EACCES;
}
return r;
r = sd_bus_call(call->bus, request, 0, ret_error, &reply);
if (r < 0) {
/* Treat no PK available as access denied */
if (bus_error_is_unknown_service(ret_error)) {
sd_bus_error_free(ret_error);
return -EACCES;
}
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
if (r < 0)
return r;
return r;
}
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
if (r < 0)
return r;
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
if (r < 0)
return r;
if (authorized)
return 1;
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
if (r < 0)
return r;
if (_challenge) {
*_challenge = challenge;
return 0;
}
if (authorized)
return 1;
if (_challenge) {
*_challenge = challenge;
return 0;
}
#endif
@ -165,9 +178,9 @@ typedef struct AsyncPolkitQuery {
sd_event_source *defer_event_source;
} AsyncPolkitQuery;
static void async_polkit_query_free(AsyncPolkitQuery *q) {
static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) {
if (!q)
return;
return NULL;
sd_bus_slot_unref(q->slot);
@ -181,11 +194,12 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
strv_free(q->details);
sd_event_source_disable_unref(q->defer_event_source);
free(q);
return mfree(q);
}
static int async_polkit_defer(sd_event_source *s, void *userdata) {
AsyncPolkitQuery *q = userdata;
AsyncPolkitQuery *q = ASSERT_PTR(userdata);
assert(s);
@ -245,6 +259,60 @@ fail:
return r;
}
static int process_polkit_response(
AsyncPolkitQuery *q,
sd_bus_message *call,
const char *action,
const char **details,
Hashmap **registry,
sd_bus_error *ret_error) {
int authorized, challenge, r;
assert(q);
assert(call);
assert(action);
assert(registry);
assert(ret_error);
assert(q->action);
assert(q->reply);
/* If the operation we want to authenticate changed between the first and the second time,
* let's not use this authentication, it might be out of date as the object and context we
* operate on might have changed. */
if (!streq(q->action, action) || !strv_equal(q->details, (char**) details))
return -ESTALE;
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 (bus_error_is_unknown_service(e))
return -EACCES;
/* Copy error from polkit reply */
sd_bus_error_copy(ret_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(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
return -EACCES;
}
#endif
int bus_verify_polkit_async(
@ -257,7 +325,6 @@ int bus_verify_polkit_async(
Hashmap **registry,
sd_bus_error *ret_error) {
const char *sender;
int r;
assert(call);
@ -270,60 +337,18 @@ int bus_verify_polkit_async(
#if ENABLE_POLKIT
AsyncPolkitQuery *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 the operation we want to authenticate changed between the first and the second time,
* let's not use this authentication, it might be out of date as the object and context we
* operate on might have changed. */
if (!streq(q->action, action) ||
!strv_equal(q->details, (char**) details))
return -ESTALE;
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 (bus_error_is_unknown_service(e))
return -EACCES;
/* Copy error from polkit reply */
sd_bus_error_copy(ret_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(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
return -EACCES;
}
/* This is the second invocation of this function, and there's already a response from
* polkit, let's process it */
if (q)
return process_polkit_response(q, call, action, details, registry, ret_error);
#endif
r = sd_bus_query_sender_privilege(call, capability);
if (r < 0)
return r;
else if (r > 0)
if (r > 0)
return 1;
sender = sd_bus_message_get_sender(call);
if (!sender)
return -EBADMSG;
#if ENABLE_POLKIT
_cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
@ -337,29 +362,7 @@ int bus_verify_polkit_async(
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 = bus_message_append_strv_key_value(pk, details);
if (r < 0)
return r;
r = sd_bus_message_append(pk, "us", interactive, NULL);
r = bus_message_new_polkit_auth_call(call, action, details, interactive, &pk);
if (r < 0)
return r;