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}");
216 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
222 *_challenge = challenge;
233 typedef struct AsyncPolkitQuery {
234 sd_bus_message *request, *reply;
235 sd_bus_message_handler_t callback;
241 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
246 if (q->serial > 0 && b)
247 sd_bus_call_async_cancel(b, q->serial);
249 if (q->registry && q->request)
250 hashmap_remove(q->registry, q->request);
252 sd_bus_message_unref(q->request);
253 sd_bus_message_unref(q->reply);
258 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
259 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
260 AsyncPolkitQuery *q = userdata;
267 q->reply = sd_bus_message_ref(reply);
270 r = sd_bus_message_rewind(q->request, true);
272 r = sd_bus_reply_method_errno(q->request, r, NULL);
276 r = q->callback(bus, q->request, q->userdata, &error_buffer);
277 r = bus_maybe_reply_error(q->request, r, &error_buffer);
280 async_polkit_query_free(bus, q);
286 int bus_verify_polkit_async(
293 sd_bus_message_handler_t callback,
297 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
301 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
311 q = hashmap_get(*registry, m);
313 int authorized, challenge;
315 /* This is the second invocation of this function, and
316 * there's already a response from polkit, let's
320 if (sd_bus_message_is_method_error(q->reply, NULL)) {
321 const sd_bus_error *e;
323 /* Copy error from polkit reply */
324 e = sd_bus_message_get_error(q->reply);
325 sd_bus_error_copy(error, e);
327 /* Treat no PK available as access denied */
328 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
331 return -sd_bus_error_get_errno(e);
334 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
336 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
348 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
352 r = sd_bus_creds_get_uid(creds, &uid);
360 sender = sd_bus_message_get_sender(m);
364 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
368 r = sd_bus_message_new_method_call(
370 "org.freedesktop.PolicyKit1",
371 "/org/freedesktop/PolicyKit1/Authority",
372 "org.freedesktop.PolicyKit1.Authority",
373 "CheckAuthorization",
378 r = sd_bus_message_append(
381 "system-bus-name", 1, "name", "s", sender,
389 q = new0(AsyncPolkitQuery, 1);
393 q->request = sd_bus_message_ref(m);
394 q->callback = callback;
395 q->userdata = userdata;
397 r = hashmap_put(*registry, m, q);
399 async_polkit_query_free(bus, q);
403 q->registry = *registry;
405 r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
407 async_polkit_query_free(bus, q);
417 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
421 while ((q = hashmap_steal_first(registry)))
422 async_polkit_query_free(bus, q);
424 hashmap_free(registry);
428 int bus_check_peercred(sd_bus *c) {
435 fd = sd_bus_get_fd(c);
439 l = sizeof(struct ucred);
440 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
443 if (l != sizeof(struct ucred))
446 if (ucred.uid != 0 && ucred.uid != geteuid())
452 int bus_open_system_systemd(sd_bus **_bus) {
453 _cleanup_bus_unref_ sd_bus *bus = NULL;
459 return sd_bus_open_system(_bus);
461 /* If we are root and kdbus is not available, then let's talk
462 * directly to the system instance, instead of going via the
466 r = sd_bus_new(&bus);
470 r = sd_bus_set_address(bus, "kernel:path=/dev/kdbus/0-system/bus");
474 bus->bus_client = true;
476 r = sd_bus_start(bus);
483 bus = sd_bus_unref(bus);
486 r = sd_bus_new(&bus);
490 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
494 r = sd_bus_start(bus);
496 return sd_bus_open_system(_bus);
498 r = bus_check_peercred(bus);
508 int bus_open_user_systemd(sd_bus **_bus) {
509 _cleanup_bus_unref_ sd_bus *bus = NULL;
510 _cleanup_free_ char *ee = NULL;
514 /* Try via kdbus first, and then directly */
519 r = sd_bus_new(&bus);
523 if (asprintf(&bus->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid()) < 0)
526 bus->bus_client = true;
528 r = sd_bus_start(bus);
535 bus = sd_bus_unref(bus);
538 e = secure_getenv("XDG_RUNTIME_DIR");
540 return sd_bus_open_system(_bus);
542 ee = bus_address_escape(e);
546 r = sd_bus_new(&bus);
550 bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
554 r = sd_bus_start(bus);
556 return sd_bus_open_system(_bus);
558 r = bus_check_peercred(bus);
568 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
570 const char *contents;
576 r = sd_bus_message_peek_type(property, &type, &contents);
582 case SD_BUS_TYPE_STRING: {
585 r = sd_bus_message_read_basic(property, type, &s);
589 if (all || !isempty(s))
590 printf("%s=%s\n", name, s);
595 case SD_BUS_TYPE_BOOLEAN: {
598 r = sd_bus_message_read_basic(property, type, &b);
602 printf("%s=%s\n", name, yes_no(b));
607 case SD_BUS_TYPE_UINT64: {
610 r = sd_bus_message_read_basic(property, type, &u);
614 /* Yes, heuristics! But we can change this check
615 * should it turn out to not be sufficient */
617 if (endswith(name, "Timestamp")) {
618 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
620 t = format_timestamp(timestamp, sizeof(timestamp), u);
622 printf("%s=%s\n", name, strempty(t));
624 } else if (strstr(name, "USec")) {
625 char timespan[FORMAT_TIMESPAN_MAX];
627 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
629 printf("%s=%llu\n", name, (unsigned long long) u);
634 case SD_BUS_TYPE_UINT32: {
637 r = sd_bus_message_read_basic(property, type, &u);
641 if (strstr(name, "UMask") || strstr(name, "Mode"))
642 printf("%s=%04o\n", name, u);
644 printf("%s=%u\n", name, (unsigned) u);
649 case SD_BUS_TYPE_INT32: {
652 r = sd_bus_message_read_basic(property, type, &i);
656 printf("%s=%i\n", name, (int) i);
660 case SD_BUS_TYPE_DOUBLE: {
663 r = sd_bus_message_read_basic(property, type, &d);
667 printf("%s=%g\n", name, d);
671 case SD_BUS_TYPE_ARRAY:
672 if (streq(contents, "s")) {
676 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
680 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
684 printf("%s%s", first ? "" : " ", str);
696 r = sd_bus_message_exit_container(property);
702 } else if (streq(contents, "y")) {
706 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
715 for (i = 0; i < n; i++)
716 printf("%02x", u[i]);
723 } else if (streq(contents, "u")) {
727 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
736 for (i = 0; i < n; i++)
737 printf("%08x", u[i]);
751 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
752 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
753 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
759 r = sd_bus_call_method(bus,
762 "org.freedesktop.DBus.Properties",
770 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
774 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
776 const char *contents;
778 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
782 if (!filter || strv_find(filter, name)) {
783 r = sd_bus_message_peek_type(reply, NULL, &contents);
787 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
791 r = bus_print_property(name, reply, all);
796 printf("%s=[unprintable]\n", name);
797 /* skip what we didn't read */
798 r = sd_bus_message_skip(reply, contents);
803 r = sd_bus_message_exit_container(reply);
807 r = sd_bus_message_skip(reply, "v");
812 r = sd_bus_message_exit_container(reply);
819 r = sd_bus_message_exit_container(reply);
826 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
827 sd_id128_t *p = userdata;
832 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
839 memcpy((*p).bytes, v, n);
846 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
850 r = sd_bus_message_peek_type(m, &type, NULL);
855 case SD_BUS_TYPE_STRING: {
860 r = sd_bus_message_read_basic(m, type, &s);
878 case SD_BUS_TYPE_ARRAY: {
879 _cleanup_strv_free_ char **l = NULL;
880 char ***p = userdata;
882 r = bus_message_read_strv_extend(m, &l);
893 case SD_BUS_TYPE_BOOLEAN: {
897 r = sd_bus_message_read_basic(m, type, &b);
906 case SD_BUS_TYPE_UINT32: {
908 uint32_t *p = userdata;
910 r = sd_bus_message_read_basic(m, type, &u);
919 case SD_BUS_TYPE_UINT64: {
921 uint64_t *p = userdata;
923 r = sd_bus_message_read_basic(m, type, &t);
939 int bus_map_all_properties(sd_bus *bus,
940 const char *destination,
942 const struct bus_properties_map *map,
944 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
945 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
953 r = sd_bus_call_method(
957 "org.freedesktop.DBus.Properties",
965 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
969 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
970 const struct bus_properties_map *prop;
972 const char *contents;
976 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
980 for (i = 0, prop = NULL; map[i].member; i++)
981 if (streq(map[i].member, member)) {
987 r = sd_bus_message_peek_type(m, NULL, &contents);
991 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
995 v = (uint8_t *)userdata + prop->offset;
997 r = prop->set(bus, member, m, &error, v);
999 r = map_basic(bus, member, m, &error, v);
1001 r = sd_bus_message_exit_container(m);
1005 r = sd_bus_message_skip(m, "v");
1010 r = sd_bus_message_exit_container(m);
1018 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1021 assert(transport >= 0);
1022 assert(transport < _BUS_TRANSPORT_MAX);
1025 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1026 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1028 switch (transport) {
1030 case BUS_TRANSPORT_LOCAL:
1032 r = sd_bus_default_user(bus);
1034 r = sd_bus_default_system(bus);
1038 case BUS_TRANSPORT_REMOTE:
1039 r = sd_bus_open_system_remote(host, bus);
1042 case BUS_TRANSPORT_CONTAINER:
1043 r = sd_bus_open_system_container(host, bus);
1047 assert_not_reached("Hmm, unknown transport type.");
1053 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1056 assert(transport >= 0);
1057 assert(transport < _BUS_TRANSPORT_MAX);
1060 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1061 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
1063 switch (transport) {
1065 case BUS_TRANSPORT_LOCAL:
1067 r = bus_open_user_systemd(bus);
1069 r = bus_open_system_systemd(bus);
1073 case BUS_TRANSPORT_REMOTE:
1074 r = sd_bus_open_system_remote(host, bus);
1077 case BUS_TRANSPORT_CONTAINER:
1078 r = sd_bus_open_system_container(host, bus);
1082 assert_not_reached("Hmm, unknown transport type.");
1088 int bus_property_get_tristate(
1091 const char *interface,
1092 const char *property,
1093 sd_bus_message *reply,
1095 sd_bus_error *error) {
1097 int *tristate = userdata;
1099 return sd_bus_message_append(reply, "b", *tristate > 0);
1102 int bus_property_get_bool(
1105 const char *interface,
1106 const char *property,
1107 sd_bus_message *reply,
1109 sd_bus_error *error) {
1111 int b = *(bool*) userdata;
1113 return sd_bus_message_append_basic(reply, 'b', &b);
1116 #if __SIZEOF_SIZE_T__ != 8
1117 int bus_property_get_size(
1120 const char *interface,
1121 const char *property,
1122 sd_bus_message *reply,
1124 sd_bus_error *error) {
1126 uint64_t sz = *(size_t*) userdata;
1128 return sd_bus_message_append_basic(reply, 't', &sz);
1132 #if __SIZEOF_LONG__ != 8
1133 int bus_property_get_long(
1136 const char *interface,
1137 const char *property,
1138 sd_bus_message *reply,
1140 sd_bus_error *error) {
1142 int64_t l = *(long*) userdata;
1144 return sd_bus_message_append_basic(reply, 'x', &l);
1147 int bus_property_get_ulong(
1150 const char *interface,
1151 const char *property,
1152 sd_bus_message *reply,
1154 sd_bus_error *error) {
1156 uint64_t ul = *(unsigned long*) userdata;
1158 return sd_bus_message_append_basic(reply, 't', &ul);
1162 int bus_log_parse_error(int r) {
1163 log_error("Failed to parse message: %s", strerror(-r));
1167 int bus_log_create_error(int r) {
1168 log_error("Failed to create message: %s", strerror(-r));
1172 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1176 return sd_bus_message_read(
1191 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
1195 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1196 sd_bus_reply_method_errno(m, r, error);
1198 } else if (sd_bus_error_is_set(error)) {
1199 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
1200 sd_bus_reply_method_error(m, error);
1204 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
1205 bus_message_type_to_string(m->header->type),
1208 strna(m->interface),
1210 strna(m->root_container.signature),
1211 bus_error_message(error, r));