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>
23 #include <sys/capability.h>
33 #include "bus-error.h"
34 #include "bus-message.h"
36 #include "bus-internal.h"
38 static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
39 sd_event *e = userdata;
49 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
50 _cleanup_free_ char *match = NULL;
58 /* We unregister the name here and then wait for the
59 * NameOwnerChanged signal for this event to arrive before we
60 * quit. We do this in order to make sure that any queued
61 * requests are still processed before we really exit. */
63 r = sd_bus_get_unique_name(bus, &unique);
68 "sender='org.freedesktop.DBus',"
70 "interface='org.freedesktop.DBus',"
71 "member='NameOwnerChanged',"
72 "path='/org/freedesktop/DBus',"
75 "arg2=''", name, unique);
79 r = sd_bus_add_match(bus, match, name_owner_change_callback, e);
83 r = sd_bus_release_name(bus, name);
90 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
99 r = sd_event_get_state(e);
103 if (r == SD_EVENT_FINISHED)
106 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
110 if (r == 0 && !exiting) {
111 r = bus_async_unregister_and_exit(e, bus, name);
119 r = sd_event_get_exit_code(e, &code);
126 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
127 _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
128 int r, has_owner = 0;
133 r = sd_bus_call_method(c,
134 "org.freedesktop.DBus",
135 "/org/freedesktop/dbus",
136 "org.freedesktop.DBus",
145 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
147 return sd_bus_error_set_errno(error, r);
152 int bus_verify_polkit(
160 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
168 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
172 r = sd_bus_creds_get_uid(creds, &uid);
181 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
182 int authorized = false, challenge = false;
185 sender = sd_bus_message_get_sender(m);
189 r = sd_bus_call_method(
191 "org.freedesktop.PolicyKit1",
192 "/org/freedesktop/PolicyKit1/Authority",
193 "org.freedesktop.PolicyKit1.Authority",
194 "CheckAuthorization",
198 "system-bus-name", 1, "name", "s", sender,
205 /* Treat no PK available as access denied */
206 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
207 sd_bus_error_free(e);
214 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
218 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
226 *_challenge = challenge;
237 typedef struct AsyncPolkitQuery {
238 sd_bus_message *request, *reply;
239 sd_bus_message_handler_t callback;
245 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
250 if (q->serial > 0 && b)
251 sd_bus_call_async_cancel(b, q->serial);
253 if (q->registry && q->request)
254 hashmap_remove(q->registry, q->request);
256 sd_bus_message_unref(q->request);
257 sd_bus_message_unref(q->reply);
262 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
263 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
264 AsyncPolkitQuery *q = userdata;
271 q->reply = sd_bus_message_ref(reply);
274 r = sd_bus_message_rewind(q->request, true);
276 r = sd_bus_reply_method_errno(q->request, r, NULL);
280 r = q->callback(bus, q->request, q->userdata, &error_buffer);
281 r = bus_maybe_reply_error(q->request, r, &error_buffer);
284 async_polkit_query_free(bus, q);
290 int bus_verify_polkit_async(
297 sd_bus_message_handler_t callback,
301 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
305 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
315 q = hashmap_get(*registry, m);
317 int authorized, challenge;
319 /* This is the second invocation of this function, and
320 * there's already a response from polkit, let's
324 if (sd_bus_message_is_method_error(q->reply, NULL)) {
325 const sd_bus_error *e;
327 /* Copy error from polkit reply */
328 e = sd_bus_message_get_error(q->reply);
329 sd_bus_error_copy(error, e);
331 /* Treat no PK available as access denied */
332 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
335 return -sd_bus_error_get_errno(e);
338 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
340 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
352 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
356 r = sd_bus_creds_get_uid(creds, &uid);
364 sender = sd_bus_message_get_sender(m);
368 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
372 r = sd_bus_message_new_method_call(
374 "org.freedesktop.PolicyKit1",
375 "/org/freedesktop/PolicyKit1/Authority",
376 "org.freedesktop.PolicyKit1.Authority",
377 "CheckAuthorization",
382 r = sd_bus_message_append(
385 "system-bus-name", 1, "name", "s", sender,
393 q = new0(AsyncPolkitQuery, 1);
397 q->request = sd_bus_message_ref(m);
398 q->callback = callback;
399 q->userdata = userdata;
401 r = hashmap_put(*registry, m, q);
403 async_polkit_query_free(bus, q);
407 q->registry = *registry;
409 r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
411 async_polkit_query_free(bus, q);
421 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
425 while ((q = hashmap_steal_first(registry)))
426 async_polkit_query_free(bus, q);
428 hashmap_free(registry);
432 int bus_check_peercred(sd_bus *c) {
439 fd = sd_bus_get_fd(c);
443 l = sizeof(struct ucred);
444 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
447 if (l != sizeof(struct ucred))
450 if (ucred.uid != 0 && ucred.uid != geteuid())
456 int bus_open_system_systemd(sd_bus **_bus) {
457 _cleanup_bus_unref_ sd_bus *bus = NULL;
463 return sd_bus_open_system(_bus);
465 /* If we are root and kdbus is not available, then let's talk
466 * directly to the system instance, instead of going via the
470 r = sd_bus_new(&bus);
474 r = sd_bus_set_address(bus, "kernel:path=/dev/kdbus/0-system/bus");
478 bus->bus_client = true;
480 r = sd_bus_start(bus);
487 bus = sd_bus_unref(bus);
490 r = sd_bus_new(&bus);
494 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
498 r = sd_bus_start(bus);
500 return sd_bus_open_system(_bus);
502 r = bus_check_peercred(bus);
512 int bus_open_user_systemd(sd_bus **_bus) {
513 _cleanup_bus_unref_ sd_bus *bus = NULL;
514 _cleanup_free_ char *ee = NULL;
518 /* Try via kdbus first, and then directly */
523 r = sd_bus_new(&bus);
527 if (asprintf(&bus->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid()) < 0)
530 bus->bus_client = true;
532 r = sd_bus_start(bus);
539 bus = sd_bus_unref(bus);
542 e = secure_getenv("XDG_RUNTIME_DIR");
544 return sd_bus_open_system(_bus);
546 ee = bus_address_escape(e);
550 r = sd_bus_new(&bus);
554 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
558 r = sd_bus_start(bus);
560 return sd_bus_open_system(_bus);
562 r = bus_check_peercred(bus);
572 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
574 const char *contents;
580 r = sd_bus_message_peek_type(property, &type, &contents);
586 case SD_BUS_TYPE_STRING: {
589 r = sd_bus_message_read_basic(property, type, &s);
593 if (all || !isempty(s))
594 printf("%s=%s\n", name, s);
599 case SD_BUS_TYPE_BOOLEAN: {
602 r = sd_bus_message_read_basic(property, type, &b);
606 printf("%s=%s\n", name, yes_no(b));
611 case SD_BUS_TYPE_UINT64: {
614 r = sd_bus_message_read_basic(property, type, &u);
618 /* Yes, heuristics! But we can change this check
619 * should it turn out to not be sufficient */
621 if (endswith(name, "Timestamp")) {
622 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
624 t = format_timestamp(timestamp, sizeof(timestamp), u);
626 printf("%s=%s\n", name, strempty(t));
628 } else if (strstr(name, "USec")) {
629 char timespan[FORMAT_TIMESPAN_MAX];
631 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
633 printf("%s=%llu\n", name, (unsigned long long) u);
638 case SD_BUS_TYPE_UINT32: {
641 r = sd_bus_message_read_basic(property, type, &u);
645 if (strstr(name, "UMask") || strstr(name, "Mode"))
646 printf("%s=%04o\n", name, u);
648 printf("%s=%u\n", name, (unsigned) u);
653 case SD_BUS_TYPE_INT32: {
656 r = sd_bus_message_read_basic(property, type, &i);
660 printf("%s=%i\n", name, (int) i);
664 case SD_BUS_TYPE_DOUBLE: {
667 r = sd_bus_message_read_basic(property, type, &d);
671 printf("%s=%g\n", name, d);
675 case SD_BUS_TYPE_ARRAY:
676 if (streq(contents, "s")) {
680 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
684 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
688 printf("%s%s", first ? "" : " ", str);
700 r = sd_bus_message_exit_container(property);
706 } else if (streq(contents, "y")) {
710 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
719 for (i = 0; i < n; i++)
720 printf("%02x", u[i]);
727 } else if (streq(contents, "u")) {
731 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
740 for (i = 0; i < n; i++)
741 printf("%08x", u[i]);
755 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
756 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
757 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
763 r = sd_bus_call_method(bus,
766 "org.freedesktop.DBus.Properties",
774 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
778 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
780 const char *contents;
782 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
786 if (!filter || strv_find(filter, name)) {
787 r = sd_bus_message_peek_type(reply, NULL, &contents);
791 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
795 r = bus_print_property(name, reply, all);
800 printf("%s=[unprintable]\n", name);
801 /* skip what we didn't read */
802 r = sd_bus_message_skip(reply, contents);
807 r = sd_bus_message_exit_container(reply);
811 r = sd_bus_message_skip(reply, "v");
816 r = sd_bus_message_exit_container(reply);
823 r = sd_bus_message_exit_container(reply);
830 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
831 sd_id128_t *p = userdata;
836 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
843 memcpy((*p).bytes, v, n);
850 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
854 r = sd_bus_message_peek_type(m, &type, NULL);
859 case SD_BUS_TYPE_STRING: {
864 r = sd_bus_message_read_basic(m, type, &s);
882 case SD_BUS_TYPE_ARRAY: {
883 _cleanup_strv_free_ char **l = NULL;
884 char ***p = userdata;
886 r = bus_message_read_strv_extend(m, &l);
897 case SD_BUS_TYPE_BOOLEAN: {
901 r = sd_bus_message_read_basic(m, type, &b);
910 case SD_BUS_TYPE_UINT32: {
912 uint32_t *p = userdata;
914 r = sd_bus_message_read_basic(m, type, &u);
923 case SD_BUS_TYPE_UINT64: {
925 uint64_t *p = userdata;
927 r = sd_bus_message_read_basic(m, type, &t);
943 int bus_map_all_properties(sd_bus *bus,
944 const char *destination,
946 const struct bus_properties_map *map,
948 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
949 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
957 r = sd_bus_call_method(
961 "org.freedesktop.DBus.Properties",
969 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
973 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
974 const struct bus_properties_map *prop;
976 const char *contents;
980 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
984 for (i = 0, prop = NULL; map[i].member; i++)
985 if (streq(map[i].member, member)) {
991 r = sd_bus_message_peek_type(m, NULL, &contents);
995 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
999 v = (uint8_t *)userdata + prop->offset;
1001 r = prop->set(bus, member, m, &error, v);
1003 r = map_basic(bus, member, m, &error, v);
1007 r = sd_bus_message_exit_container(m);
1011 r = sd_bus_message_skip(m, "v");
1016 r = sd_bus_message_exit_container(m);
1024 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1027 assert(transport >= 0);
1028 assert(transport < _BUS_TRANSPORT_MAX);
1031 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1032 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1034 switch (transport) {
1036 case BUS_TRANSPORT_LOCAL:
1038 r = sd_bus_default_user(bus);
1040 r = sd_bus_default_system(bus);
1044 case BUS_TRANSPORT_REMOTE:
1045 r = sd_bus_open_system_remote(host, bus);
1048 case BUS_TRANSPORT_CONTAINER:
1049 r = sd_bus_open_system_container(host, bus);
1053 assert_not_reached("Hmm, unknown transport type.");
1059 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1062 assert(transport >= 0);
1063 assert(transport < _BUS_TRANSPORT_MAX);
1066 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1067 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1069 switch (transport) {
1071 case BUS_TRANSPORT_LOCAL:
1073 r = bus_open_user_systemd(bus);
1075 r = bus_open_system_systemd(bus);
1079 case BUS_TRANSPORT_REMOTE:
1080 r = sd_bus_open_system_remote(host, bus);
1083 case BUS_TRANSPORT_CONTAINER:
1084 r = sd_bus_open_system_container(host, bus);
1088 assert_not_reached("Hmm, unknown transport type.");
1094 int bus_property_get_tristate(
1097 const char *interface,
1098 const char *property,
1099 sd_bus_message *reply,
1101 sd_bus_error *error) {
1103 int *tristate = userdata;
1105 return sd_bus_message_append(reply, "b", *tristate > 0);
1108 int bus_property_get_bool(
1111 const char *interface,
1112 const char *property,
1113 sd_bus_message *reply,
1115 sd_bus_error *error) {
1117 int b = *(bool*) userdata;
1119 return sd_bus_message_append_basic(reply, 'b', &b);
1122 #if __SIZEOF_SIZE_T__ != 8
1123 int bus_property_get_size(
1126 const char *interface,
1127 const char *property,
1128 sd_bus_message *reply,
1130 sd_bus_error *error) {
1132 uint64_t sz = *(size_t*) userdata;
1134 return sd_bus_message_append_basic(reply, 't', &sz);
1138 #if __SIZEOF_LONG__ != 8
1139 int bus_property_get_long(
1142 const char *interface,
1143 const char *property,
1144 sd_bus_message *reply,
1146 sd_bus_error *error) {
1148 int64_t l = *(long*) userdata;
1150 return sd_bus_message_append_basic(reply, 'x', &l);
1153 int bus_property_get_ulong(
1156 const char *interface,
1157 const char *property,
1158 sd_bus_message *reply,
1160 sd_bus_error *error) {
1162 uint64_t ul = *(unsigned long*) userdata;
1164 return sd_bus_message_append_basic(reply, 't', &ul);
1168 int bus_log_parse_error(int r) {
1169 log_error("Failed to parse message: %s", strerror(-r));
1173 int bus_log_create_error(int r) {
1174 log_error("Failed to create message: %s", strerror(-r));
1178 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1182 return sd_bus_message_read(
1197 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1201 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1202 sd_bus_reply_method_errno(m, r, error);
1204 } else if (sd_bus_error_is_set(error)) {
1205 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1206 sd_bus_reply_method_error(m, error);
1210 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1211 bus_message_type_to_string(m->header->type),
1214 strna(m->interface),
1216 strna(m->root_container.signature),
1217 bus_error_message(error, r));