Skip to content

Commit 959301c

Browse files
committed
bus-polkit: parse reply from polkit on receive
... and store just the result.
1 parent c71901b commit 959301c

File tree

1 file changed

+77
-44
lines changed

1 file changed

+77
-44
lines changed

src/shared/bus-polkit.c

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,21 @@ static AsyncPolkitQueryAction *async_polkit_query_action_free(AsyncPolkitQueryAc
182182
return mfree(a);
183183
}
184184

185+
DEFINE_TRIVIAL_CLEANUP_FUNC(AsyncPolkitQueryAction*, async_polkit_query_action_free);
186+
185187
typedef struct AsyncPolkitQuery {
186188
AsyncPolkitQueryAction *action;
187189

188-
sd_bus_message *request, *reply;
190+
sd_bus_message *request;
189191
sd_bus_slot *slot;
190192

191193
Hashmap *registry;
192194
sd_event_source *defer_event_source;
195+
196+
AsyncPolkitQueryAction *authorized_action;
197+
AsyncPolkitQueryAction *denied_action;
198+
AsyncPolkitQueryAction *error_action;
199+
sd_bus_error error;
193200
} AsyncPolkitQuery;
194201

195202
static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) {
@@ -202,12 +209,17 @@ static AsyncPolkitQuery *async_polkit_query_free(AsyncPolkitQuery *q) {
202209
hashmap_remove(q->registry, q->request);
203210

204211
sd_bus_message_unref(q->request);
205-
sd_bus_message_unref(q->reply);
206212

207213
async_polkit_query_action_free(q->action);
208214

209215
sd_event_source_disable_unref(q->defer_event_source);
210216

217+
async_polkit_query_action_free(q->authorized_action);
218+
async_polkit_query_action_free(q->denied_action);
219+
async_polkit_query_action_free(q->error_action);
220+
221+
sd_bus_error_free(&q->error);
222+
211223
return mfree(q);
212224
}
213225

@@ -225,6 +237,56 @@ static int async_polkit_defer(sd_event_source *s, void *userdata) {
225237
return 0;
226238
}
227239

240+
static int async_polkit_read_reply(sd_bus_message *reply, AsyncPolkitQuery *q) {
241+
_cleanup_(async_polkit_query_action_freep) AsyncPolkitQueryAction *a = NULL;
242+
int authorized, challenge, r;
243+
244+
assert(reply);
245+
assert(q);
246+
247+
assert(q->action);
248+
a = TAKE_PTR(q->action);
249+
250+
if (sd_bus_message_is_method_error(reply, NULL)) {
251+
const sd_bus_error *e;
252+
253+
e = sd_bus_message_get_error(reply);
254+
255+
/* Save error from polkit reply, so it can be returned when the same authorization is
256+
* attempted for second time */
257+
if (!bus_error_is_unknown_service(e)) {
258+
q->error_action = TAKE_PTR(a);
259+
return sd_bus_error_copy(&q->error, e);
260+
}
261+
262+
/* Treat no PK available as access denied */
263+
q->denied_action = TAKE_PTR(a);
264+
265+
return 0;
266+
}
267+
268+
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
269+
if (r >= 0)
270+
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
271+
if (r < 0)
272+
return r;
273+
274+
assert(!q->authorized_action);
275+
assert(!q->denied_action);
276+
assert(!q->error_action);
277+
assert(!sd_bus_error_is_set(&q->error));
278+
279+
if (authorized)
280+
q->authorized_action = TAKE_PTR(a);
281+
else if (challenge) {
282+
q->error_action = TAKE_PTR(a);
283+
return sd_bus_error_set(&q->error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
284+
} else
285+
q->denied_action = TAKE_PTR(a);
286+
287+
return 0;
288+
}
289+
228290
static int async_polkit_process_reply(sd_bus_message *reply, AsyncPolkitQuery *q) {
229291
int r;
230292

@@ -234,8 +296,9 @@ static int async_polkit_process_reply(sd_bus_message *reply, AsyncPolkitQuery *q
234296
assert(q->slot);
235297
q->slot = sd_bus_slot_unref(q->slot);
236298

237-
assert(!q->reply);
238-
q->reply = sd_bus_message_ref(reply);
299+
r = async_polkit_read_reply(reply, q);
300+
if (r < 0)
301+
return r;
239302

240303
/* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the
241304
* whole message processing again, and thus re-validating and re-retrieving the "userdata" field
@@ -283,56 +346,26 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
283346
return r;
284347
}
285348

286-
static int process_polkit_response(
349+
_pure_ static int async_polkit_query_check_action(
287350
AsyncPolkitQuery *q,
288-
sd_bus_message *call,
289351
const char *action,
290352
const char **details,
291353
sd_bus_error *ret_error) {
292354

293-
int authorized, challenge, r;
294-
295355
assert(q);
296-
assert(call);
297356
assert(action);
298357
assert(ret_error);
299358

300-
assert(q->action);
301-
assert(q->action->action);
302-
assert(q->reply);
303-
304-
/* If the operation we want to authenticate changed between the first and the second time,
305-
* let's not use this authentication, it might be out of date as the object and context we
306-
* operate on might have changed. */
307-
if (!streq(q->action->action, action) || !strv_equal(q->action->details, (char**) details))
308-
return -ESTALE;
309-
310-
if (sd_bus_message_is_method_error(q->reply, NULL)) {
311-
const sd_bus_error *e;
312-
313-
e = sd_bus_message_get_error(q->reply);
314-
315-
/* Treat no PK available as access denied */
316-
if (bus_error_is_unknown_service(e))
317-
return -EACCES;
318-
319-
/* Copy error from polkit reply */
320-
sd_bus_error_copy(ret_error, e);
321-
return -sd_bus_error_get_errno(e);
322-
}
323-
324-
r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
325-
if (r >= 0)
326-
r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
327-
if (r < 0)
328-
return r;
329-
330-
if (authorized)
331-
return 1;
359+
if (q->authorized_action)
360+
/* If the operation we want to authenticate changed between the first and the second time,
361+
* let's not use this authentication, it might be out of date as the object and context we
362+
* operate on might have changed. */
363+
return streq(q->authorized_action->action, action) && strv_equal(q->action->details, (char**) details) ? 1 : -ESTALE;
332364

333-
if (challenge)
334-
return sd_bus_error_set(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
365+
if (q->error_action)
366+
return sd_bus_error_copy(ret_error, &q->error);
335367

368+
assert(q->denied_action);
336369
return -EACCES;
337370
}
338371

@@ -437,7 +470,7 @@ int bus_verify_polkit_async(
437470
/* This is the second invocation of this function, and there's already a response from
438471
* polkit, let's process it */
439472
if (q)
440-
return process_polkit_response(q, call, action, details, ret_error);
473+
return async_polkit_query_check_action(q, action, details, ret_error);
441474
#endif
442475

443476
r = sd_bus_query_sender_privilege(call, capability);

0 commit comments

Comments
 (0)