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/>.
22 #include <sys/socket.h>
33 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
34 sd_event *e = userdata;
40 sd_event_request_quit(e);
44 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
45 _cleanup_free_ char *match = NULL;
52 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
56 r = sd_bus_add_match(bus, match, quit_callback, e);
60 r = sd_bus_release_name(bus, name);
64 if (r != SD_BUS_NAME_RELEASED)
70 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
79 r = sd_event_get_state(e);
83 if (r == SD_EVENT_FINISHED)
86 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
90 if (r == 0 && !exiting) {
91 r = bus_async_unregister_and_quit(e, bus, name);
102 int bus_property_get_tristate(
105 const char *interface,
106 const char *property,
107 sd_bus_message *reply,
111 int *tristate = userdata;
114 r = sd_bus_message_append(reply, "b", *tristate > 0);
121 int bus_verify_polkit(
137 sender = sd_bus_message_get_sender(m);
141 r = sd_bus_get_owner_uid(bus, sender, &uid);
150 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
151 unsigned authorized = false, challenge = false;
153 r = sd_bus_call_method(
155 "org.freedesktop.PolicyKit1",
156 "/org/freedesktop/PolicyKit1/Authority",
157 "org.freedesktop.PolicyKit1.Authority",
158 "CheckAuthorization",
162 "system-bus-name", 1, "name", "s", sender,
169 /* Treat no PK available as access denied */
170 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
171 sd_bus_error_free(e);
178 r = sd_bus_message_read(reply, "(bb)", &authorized, &challenge);
186 *_challenge = challenge;
197 typedef struct AsyncPolkitQuery {
198 sd_bus_message *request, *reply;
199 sd_bus_message_handler_t callback;
204 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
205 AsyncPolkitQuery *q = userdata;
206 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
213 q->reply = sd_bus_message_ref(reply);
216 m = sd_bus_message_ref(q->request);
218 r = sd_bus_message_rewind(m, true);
222 r = q->callback(bus, m, q->userdata);
229 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
234 if (q->serial > 0 && b)
235 sd_bus_send_with_reply_cancel(b, q->serial);
237 sd_bus_message_unref(q->request);
238 sd_bus_message_unref(q->reply);
244 int bus_verify_polkit_async(
251 sd_bus_message_handler_t callback,
255 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
268 q = hashmap_remove(*registry, m);
270 unsigned authorized, challenge;
272 /* This is the second invocation of this function, and
273 * there's already a response from polkit, let's
277 if (sd_bus_message_is_method_error(q->reply, NULL)) {
278 const sd_bus_error *e;
280 /* Treat no PK available as access denied */
281 if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
282 async_polkit_query_free(bus, q);
286 e = sd_bus_message_get_error(q->reply);
287 sd_bus_error_copy(error, e);
288 r = sd_bus_error_get_errno(e);
290 async_polkit_query_free(bus, q);
294 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
296 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
298 async_polkit_query_free(bus, q);
310 sender = sd_bus_message_get_sender(m);
314 r = sd_bus_get_owner_uid(bus, sender, &uid);
322 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
326 r = sd_bus_message_new_method_call(
328 "org.freedesktop.PolicyKit1",
329 "/org/freedesktop/PolicyKit1/Authority",
330 "org.freedesktop.PolicyKit1.Authority",
331 "CheckAuthorization",
336 r = sd_bus_message_append(
339 "system-bus-name", 1, "name", "s", sender,
347 q = new0(AsyncPolkitQuery, 1);
351 q->request = sd_bus_message_ref(m);
352 q->callback = callback;
353 q->userdata = userdata;
355 r = hashmap_put(*registry, m, q);
357 async_polkit_query_free(bus, q);
361 r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
371 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
375 while ((q = hashmap_steal_first(registry)))
376 async_polkit_query_free(bus, q);
378 hashmap_free(registry);
382 static int bus_check_peercred(sd_bus *c) {
389 fd = sd_bus_get_fd(c);
393 l = sizeof(struct ucred);
394 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
397 if (l != sizeof(struct ucred))
400 if (ucred.uid != 0 && ucred.uid != geteuid())
406 int bus_open_system_systemd(sd_bus **_bus) {
407 _cleanup_bus_unref_ sd_bus *bus = NULL;
413 return sd_bus_open_system(_bus);
415 /* If we are root, then let's talk directly to the system
416 * instance, instead of going via the bus */
418 r = sd_bus_new(&bus);
422 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
426 r = sd_bus_start(bus);
430 r = bus_check_peercred(bus);
440 int bus_generic_print_property(const char *name, sd_bus_message *property, bool all) {
442 const char *contents;
447 sd_bus_message_peek_type(property, &type, &contents);
451 case SD_BUS_TYPE_STRING: {
453 sd_bus_message_read_basic(property, type, &s);
455 if (all || !isempty(s))
456 printf("%s=%s\n", name, s);
461 case SD_BUS_TYPE_BOOLEAN: {
464 sd_bus_message_read_basic(property, type, &b);
465 printf("%s=%s\n", name, yes_no(b));
470 case SD_BUS_TYPE_UINT64: {
473 sd_bus_message_read_basic(property, type, &u);
475 /* Yes, heuristics! But we can change this check
476 * should it turn out to not be sufficient */
478 if (endswith(name, "Timestamp")) {
479 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
481 t = format_timestamp(timestamp, sizeof(timestamp), u);
483 printf("%s=%s\n", name, strempty(t));
485 } else if (strstr(name, "USec")) {
486 char timespan[FORMAT_TIMESPAN_MAX];
488 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
490 printf("%s=%llu\n", name, (unsigned long long) u);
495 case SD_BUS_TYPE_UINT32: {
498 sd_bus_message_read_basic(property, type, &u);
500 if (strstr(name, "UMask") || strstr(name, "Mode"))
501 printf("%s=%04o\n", name, u);
503 printf("%s=%u\n", name, (unsigned) u);
508 case SD_BUS_TYPE_INT32: {
511 sd_bus_message_read_basic(property, type, &i);
513 printf("%s=%i\n", name, (int) i);
517 case SD_BUS_TYPE_DOUBLE: {
520 sd_bus_message_read_basic(property, type, &d);
522 printf("%s=%g\n", name, d);
526 case SD_BUS_TYPE_ARRAY:
528 if (streq(contents, "s")) {
533 sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
535 sd_bus_message_peek_type(property, &tp, &cnt);
542 while(sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) {
543 printf("%s%s", space ? " " : "", str);
551 sd_bus_message_exit_container(property);
555 } else if (streq(contents, "y")) {
559 sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
565 for (i = 0; i < n; i++)
566 printf("%02x", u[i]);
573 } else if (streq(contents, "u")) {
577 sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
583 for (i = 0; i < n; i++)
584 printf("%08x", u[i]);
598 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
601 assert(transport >= 0);
602 assert(transport < _BUS_TRANSPORT_MAX);
605 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
606 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
610 case BUS_TRANSPORT_LOCAL:
612 r = sd_bus_open_user(bus);
614 r = sd_bus_open_system(bus);
618 case BUS_TRANSPORT_REMOTE:
619 r = sd_bus_open_system_remote(host, bus);
622 case BUS_TRANSPORT_CONTAINER:
623 r = sd_bus_open_system_container(host, bus);
627 assert_not_reached("Hmm, unknown transport type.");