1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "bus-internal.h"
4 #include "bus-message.h"
5 #include "bus-polkit.h"
9 static int check_good_user(sd_bus_message
*m
, uid_t good_user
) {
10 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
16 if (good_user
== UID_INVALID
)
19 r
= sd_bus_query_sender_creds(m
, SD_BUS_CREDS_EUID
, &creds
);
23 /* Don't trust augmented credentials for authorization */
24 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_EUID
) == 0, -EPERM
);
26 r
= sd_bus_creds_get_euid(creds
, &sender_uid
);
30 return sender_uid
== good_user
;
47 /* Tests non-interactively! */
49 r
= check_good_user(call
, good_user
);
53 r
= sd_bus_query_sender_privilege(call
, capability
);
60 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*request
= NULL
;
61 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
62 int authorized
= false, challenge
= false;
63 const char *sender
, **k
, **v
;
65 sender
= sd_bus_message_get_sender(call
);
69 r
= sd_bus_message_new_method_call(
72 "org.freedesktop.PolicyKit1",
73 "/org/freedesktop/PolicyKit1/Authority",
74 "org.freedesktop.PolicyKit1.Authority",
75 "CheckAuthorization");
79 r
= sd_bus_message_append(
82 "system-bus-name", 1, "name", "s", sender
,
87 r
= sd_bus_message_open_container(request
, 'a', "{ss}");
91 STRV_FOREACH_PAIR(k
, v
, details
) {
92 r
= sd_bus_message_append(request
, "{ss}", *k
, *v
);
97 r
= sd_bus_message_close_container(request
);
101 r
= sd_bus_message_append(request
, "us", 0, NULL
);
105 r
= sd_bus_call(call
->bus
, request
, 0, e
, &reply
);
107 /* Treat no PK available as access denied */
108 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
)) {
109 sd_bus_error_free(e
);
116 r
= sd_bus_message_enter_container(reply
, 'r', "bba{ss}");
120 r
= sd_bus_message_read(reply
, "bb", &authorized
, &challenge
);
128 *_challenge
= challenge
;
139 typedef struct AsyncPolkitQuery
{
140 sd_bus_message
*request
, *reply
;
141 sd_bus_message_handler_t callback
;
147 static void async_polkit_query_free(AsyncPolkitQuery
*q
) {
152 sd_bus_slot_unref(q
->slot
);
154 if (q
->registry
&& q
->request
)
155 hashmap_remove(q
->registry
, q
->request
);
157 sd_bus_message_unref(q
->request
);
158 sd_bus_message_unref(q
->reply
);
163 static int async_polkit_callback(sd_bus_message
*reply
, void *userdata
, sd_bus_error
*error
) {
164 _cleanup_(sd_bus_error_free
) sd_bus_error error_buffer
= SD_BUS_ERROR_NULL
;
165 AsyncPolkitQuery
*q
= userdata
;
171 q
->slot
= sd_bus_slot_unref(q
->slot
);
172 q
->reply
= sd_bus_message_ref(reply
);
174 r
= sd_bus_message_rewind(q
->request
, true);
176 r
= sd_bus_reply_method_errno(q
->request
, r
, NULL
);
180 r
= q
->callback(q
->request
, q
->userdata
, &error_buffer
);
181 r
= bus_maybe_reply_error(q
->request
, r
, &error_buffer
);
184 async_polkit_query_free(q
);
191 int bus_verify_polkit_async(
192 sd_bus_message
*call
,
195 const char **details
,
199 sd_bus_error
*error
) {
202 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pk
= NULL
;
204 const char *sender
, **k
, **v
;
205 sd_bus_message_handler_t callback
;
215 r
= check_good_user(call
, good_user
);
220 q
= hashmap_get(*registry
, call
);
222 int authorized
, challenge
;
224 /* This is the second invocation of this function, and
225 * there's already a response from polkit, let's
229 if (sd_bus_message_is_method_error(q
->reply
, NULL
)) {
230 const sd_bus_error
*e
;
232 e
= sd_bus_message_get_error(q
->reply
);
234 /* Treat no PK available as access denied */
235 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
) ||
236 sd_bus_error_has_name(e
, SD_BUS_ERROR_NAME_HAS_NO_OWNER
))
239 /* Copy error from polkit reply */
240 sd_bus_error_copy(error
, e
);
241 return -sd_bus_error_get_errno(e
);
244 r
= sd_bus_message_enter_container(q
->reply
, 'r', "bba{ss}");
246 r
= sd_bus_message_read(q
->reply
, "bb", &authorized
, &challenge
);
254 return sd_bus_error_set(error
, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, "Interactive authentication required.");
260 r
= sd_bus_query_sender_privilege(call
, capability
);
267 if (sd_bus_get_current_message(call
->bus
) != call
)
270 callback
= sd_bus_get_current_handler(call
->bus
);
274 userdata
= sd_bus_get_current_userdata(call
->bus
);
276 sender
= sd_bus_message_get_sender(call
);
280 c
= sd_bus_message_get_allow_interactive_authorization(call
);
286 r
= hashmap_ensure_allocated(registry
, NULL
);
290 r
= sd_bus_message_new_method_call(
293 "org.freedesktop.PolicyKit1",
294 "/org/freedesktop/PolicyKit1/Authority",
295 "org.freedesktop.PolicyKit1.Authority",
296 "CheckAuthorization");
300 r
= sd_bus_message_append(
303 "system-bus-name", 1, "name", "s", sender
,
308 r
= sd_bus_message_open_container(pk
, 'a', "{ss}");
312 STRV_FOREACH_PAIR(k
, v
, details
) {
313 r
= sd_bus_message_append(pk
, "{ss}", *k
, *v
);
318 r
= sd_bus_message_close_container(pk
);
322 r
= sd_bus_message_append(pk
, "us", interactive
, NULL
);
326 q
= new0(AsyncPolkitQuery
, 1);
330 q
->request
= sd_bus_message_ref(call
);
331 q
->callback
= callback
;
332 q
->userdata
= userdata
;
334 r
= hashmap_put(*registry
, call
, q
);
336 async_polkit_query_free(q
);
340 q
->registry
= *registry
;
342 r
= sd_bus_call_async(call
->bus
, &q
->slot
, pk
, async_polkit_callback
, q
, 0);
344 async_polkit_query_free(q
);
354 void bus_verify_polkit_async_registry_free(Hashmap
*registry
) {
356 hashmap_free_with_destructor(registry
, async_polkit_query_free
);