1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
32 sd_event *e = userdata;
38 sd_event_request_quit(e);
42 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
43 _cleanup_free_ char *match = NULL;
50 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
54 r = sd_bus_add_match(bus, match, quit_callback, e);
58 r = sd_bus_release_name(bus, name);
62 if (r != SD_BUS_NAME_RELEASED)
68 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
77 r = sd_event_get_state(e);
81 if (r == SD_EVENT_FINISHED)
84 r = sd_event_run(e, exiting ? (uint64_t) -1 : 5 * USEC_PER_SEC /* DEFAULT_EXIT_USEC */);
88 if (r == 0 && !exiting) {
89 r = bus_async_unregister_and_quit(e, bus, name);
100 int bus_property_get_tristate(
103 const char *interface,
104 const char *property,
105 sd_bus_message *reply,
109 int *tristate = userdata;
112 r = sd_bus_message_append(reply, "b", *tristate > 0);
119 int bus_verify_polkit(
135 sender = sd_bus_message_get_sender(m);
139 r = sd_bus_get_owner_uid(bus, sender, &uid);
148 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
149 bool authorized = false, challenge = false;
151 r = sd_bus_call_method(
153 "org.freedesktop.PolicyKit1",
154 "/org/freedesktop/PolicyKit1/Authority",
155 "org.freedesktop.PolicyKit1.Authority",
156 "CheckAuthorization",
160 "system-bus-name", 1, "name", "s", sender,
167 /* Treat no PK available as access denied */
168 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
169 sd_bus_error_free(e);
176 r = sd_bus_message_read(reply, "(bb)", &authorized, &challenge);
184 *_challenge = challenge;
195 typedef struct AsyncPolkitQuery {
196 sd_bus_message *request, *reply;
197 sd_bus_message_handler_t callback;
202 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
203 AsyncPolkitQuery *q = userdata;
204 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
211 q->reply = sd_bus_message_ref(reply);
214 m = sd_bus_message_ref(q->request);
216 r = sd_bus_message_rewind(m, true);
220 r = q->callback(bus, m, q->userdata);
227 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
232 if (q->serial > 0 && b)
233 sd_bus_send_with_reply_cancel(b, q->serial);
235 sd_bus_message_unref(q->request);
236 sd_bus_message_unref(q->reply);
242 int bus_verify_polkit_async(
249 sd_bus_message_handler_t callback,
253 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
266 q = hashmap_remove(*registry, m);
268 bool authorized, challenge;
270 /* This is the second invocation of this function, and
271 * there's already a response from polkit, let's
275 if (sd_bus_message_is_method_error(q->reply, NULL)) {
276 const sd_bus_error *e;
278 /* Treat no PK available as access denied */
279 if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
280 async_polkit_query_free(bus, q);
284 e = sd_bus_message_get_error(q->reply);
285 sd_bus_error_copy(error, e);
286 r = sd_bus_error_get_errno(e);
288 async_polkit_query_free(bus, q);
292 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
294 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
296 async_polkit_query_free(bus, q);
308 sender = sd_bus_message_get_sender(m);
312 r = sd_bus_get_owner_uid(bus, sender, &uid);
320 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
324 r = sd_bus_message_new_method_call(
326 "org.freedesktop.PolicyKit1",
327 "/org/freedesktop/PolicyKit1/Authority",
328 "org.freedesktop.PolicyKit1.Authority",
329 "CheckAuthorization",
334 r = sd_bus_message_append(
337 "system-bus-name", 1, "name", "s", sender,
345 q = new0(AsyncPolkitQuery, 1);
349 q->request = sd_bus_message_ref(m);
350 q->callback = callback;
351 q->userdata = userdata;
353 r = hashmap_put(*registry, m, q);
355 async_polkit_query_free(bus, q);
359 r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
369 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
373 while ((q = hashmap_steal_first(registry)))
374 async_polkit_query_free(bus, q);
376 hashmap_free(registry);