diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c index 85b907faa9d..e3e327198cb 100644 --- a/src/shared/bus-polkit.c +++ b/src/shared/bus-polkit.c @@ -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;