@@ -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+
185187typedef 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
195202static 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+
228290static 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