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>
31 #include "bus-error.h"
32 #include "bus-message.h"
36 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
37 sd_event *e = userdata;
43 sd_event_request_quit(e);
47 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
48 _cleanup_free_ char *match = NULL;
55 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
59 r = sd_bus_add_match(bus, match, quit_callback, e);
63 r = sd_bus_release_name(bus, name);
67 if (r != SD_BUS_NAME_RELEASED)
73 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
82 r = sd_event_get_state(e);
86 if (r == SD_EVENT_FINISHED)
89 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
93 if (r == 0 && !exiting) {
94 r = bus_async_unregister_and_quit(e, bus, name);
105 int bus_property_get_tristate(
108 const char *interface,
109 const char *property,
110 sd_bus_message *reply,
114 int *tristate = userdata;
117 r = sd_bus_message_append(reply, "b", *tristate > 0);
124 int bus_verify_polkit(
140 sender = sd_bus_message_get_sender(m);
144 r = sd_bus_get_owner_uid(bus, sender, &uid);
153 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
154 int authorized = false, challenge = false;
156 r = sd_bus_call_method(
158 "org.freedesktop.PolicyKit1",
159 "/org/freedesktop/PolicyKit1/Authority",
160 "org.freedesktop.PolicyKit1.Authority",
161 "CheckAuthorization",
165 "system-bus-name", 1, "name", "s", sender,
172 /* Treat no PK available as access denied */
173 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
174 sd_bus_error_free(e);
181 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
183 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
189 *_challenge = challenge;
200 typedef struct AsyncPolkitQuery {
201 sd_bus_message *request, *reply;
202 sd_bus_message_handler_t callback;
207 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
208 AsyncPolkitQuery *q = userdata;
209 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
216 q->reply = sd_bus_message_ref(reply);
219 m = sd_bus_message_ref(q->request);
221 r = sd_bus_message_rewind(m, true);
225 r = q->callback(bus, m, q->userdata);
232 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
237 if (q->serial > 0 && b)
238 sd_bus_send_with_reply_cancel(b, q->serial);
240 sd_bus_message_unref(q->request);
241 sd_bus_message_unref(q->reply);
247 int bus_verify_polkit_async(
254 sd_bus_message_handler_t callback,
258 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
271 q = hashmap_remove(*registry, m);
273 int authorized, challenge;
275 /* This is the second invocation of this function, and
276 * there's already a response from polkit, let's
280 if (sd_bus_message_is_method_error(q->reply, NULL)) {
281 const sd_bus_error *e;
283 /* Treat no PK available as access denied */
284 if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
285 async_polkit_query_free(bus, q);
289 e = sd_bus_message_get_error(q->reply);
290 sd_bus_error_copy(error, e);
291 r = sd_bus_error_get_errno(e);
293 async_polkit_query_free(bus, q);
297 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
299 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
301 async_polkit_query_free(bus, q);
313 sender = sd_bus_message_get_sender(m);
317 r = sd_bus_get_owner_uid(bus, sender, &uid);
325 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
329 r = sd_bus_message_new_method_call(
331 "org.freedesktop.PolicyKit1",
332 "/org/freedesktop/PolicyKit1/Authority",
333 "org.freedesktop.PolicyKit1.Authority",
334 "CheckAuthorization",
339 r = sd_bus_message_append(
342 "system-bus-name", 1, "name", "s", sender,
350 q = new0(AsyncPolkitQuery, 1);
354 q->request = sd_bus_message_ref(m);
355 q->callback = callback;
356 q->userdata = userdata;
358 r = hashmap_put(*registry, m, q);
360 async_polkit_query_free(bus, q);
364 r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
374 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
378 while ((q = hashmap_steal_first(registry)))
379 async_polkit_query_free(bus, q);
381 hashmap_free(registry);
385 static int bus_check_peercred(sd_bus *c) {
392 fd = sd_bus_get_fd(c);
396 l = sizeof(struct ucred);
397 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
400 if (l != sizeof(struct ucred))
403 if (ucred.uid != 0 && ucred.uid != geteuid())
409 int bus_open_system_systemd(sd_bus **_bus) {
410 _cleanup_bus_unref_ sd_bus *bus = NULL;
416 return sd_bus_open_system(_bus);
418 /* If we are root, then let's talk directly to the system
419 * instance, instead of going via the bus */
421 r = sd_bus_new(&bus);
425 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
429 r = sd_bus_start(bus);
433 r = bus_check_peercred(bus);
443 int bus_open_user_systemd(sd_bus **_bus) {
444 _cleanup_bus_unref_ sd_bus *bus = NULL;
445 _cleanup_free_ char *p = NULL;
449 /* If we are supposed to talk to the instance, try via
450 * XDG_RUNTIME_DIR first, then fallback to normal bus
455 e = secure_getenv("XDG_RUNTIME_DIR");
457 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
461 r = sd_bus_new(&bus);
465 r = sd_bus_set_address(bus, p);
469 r = sd_bus_start(bus);
473 r = bus_check_peercred(bus);
483 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
485 const char *contents;
491 r = sd_bus_message_peek_type(property, &type, &contents);
497 case SD_BUS_TYPE_STRING: {
500 r = sd_bus_message_read_basic(property, type, &s);
504 if (all || !isempty(s))
505 printf("%s=%s\n", name, s);
510 case SD_BUS_TYPE_BOOLEAN: {
513 r = sd_bus_message_read_basic(property, type, &b);
517 printf("%s=%s\n", name, yes_no(b));
522 case SD_BUS_TYPE_UINT64: {
525 r = sd_bus_message_read_basic(property, type, &u);
529 /* Yes, heuristics! But we can change this check
530 * should it turn out to not be sufficient */
532 if (endswith(name, "Timestamp")) {
533 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
535 t = format_timestamp(timestamp, sizeof(timestamp), u);
537 printf("%s=%s\n", name, strempty(t));
539 } else if (strstr(name, "USec")) {
540 char timespan[FORMAT_TIMESPAN_MAX];
542 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
544 printf("%s=%llu\n", name, (unsigned long long) u);
549 case SD_BUS_TYPE_UINT32: {
552 r = sd_bus_message_read_basic(property, type, &u);
556 if (strstr(name, "UMask") || strstr(name, "Mode"))
557 printf("%s=%04o\n", name, u);
559 printf("%s=%u\n", name, (unsigned) u);
564 case SD_BUS_TYPE_INT32: {
567 r = sd_bus_message_read_basic(property, type, &i);
571 printf("%s=%i\n", name, (int) i);
575 case SD_BUS_TYPE_DOUBLE: {
578 r = sd_bus_message_read_basic(property, type, &d);
582 printf("%s=%g\n", name, d);
586 case SD_BUS_TYPE_ARRAY:
587 if (streq(contents, "s")) {
591 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
595 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
599 printf("%s%s", first ? "" : " ", str);
611 r = sd_bus_message_exit_container(property);
617 } else if (streq(contents, "y")) {
621 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
630 for (i = 0; i < n; i++)
631 printf("%02x", u[i]);
638 } else if (streq(contents, "u")) {
642 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
651 for (i = 0; i < n; i++)
652 printf("%08x", u[i]);
666 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
667 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
668 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
674 r = sd_bus_call_method(bus,
677 "org.freedesktop.DBus.Properties",
685 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
689 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
691 const char *contents;
693 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
697 if (!filter || strv_find(filter, name)) {
698 r = sd_bus_message_peek_type(reply, NULL, &contents);
702 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
706 r = bus_print_property(name, reply, all);
711 printf("%s=[unprintable]\n", name);
712 /* skip what we didn't read */
713 r = sd_bus_message_skip(reply, contents);
718 r = sd_bus_message_exit_container(reply);
722 r = sd_bus_message_skip(reply, "v");
727 r = sd_bus_message_exit_container(reply);
734 r = sd_bus_message_exit_container(reply);
741 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
742 sd_id128_t *p = userdata;
747 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
754 memcpy((*p).bytes, v, n);
761 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
765 r = sd_bus_message_peek_type(m, &type, NULL);
770 case SD_BUS_TYPE_STRING: {
775 r = sd_bus_message_read_basic(m, type, &s);
793 case SD_BUS_TYPE_ARRAY: {
794 _cleanup_strv_free_ char **l = NULL;
795 char ***p = userdata;
797 r = bus_message_read_strv_extend(m, &l);
808 case SD_BUS_TYPE_BOOLEAN: {
812 r = sd_bus_message_read_basic(m, type, &b);
821 case SD_BUS_TYPE_UINT32: {
823 uint32_t *p = userdata;
825 r = sd_bus_message_read_basic(m, type, &u);
834 case SD_BUS_TYPE_UINT64: {
836 uint64_t *p = userdata;
838 r = sd_bus_message_read_basic(m, type, &t);
854 int bus_map_all_properties(sd_bus *bus,
855 const char *destination,
857 const struct bus_properties_map *map,
859 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
860 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
868 r = sd_bus_call_method( bus,
871 "org.freedesktop.DBus.Properties",
879 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
883 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
884 const struct bus_properties_map *prop;
886 const char *contents;
890 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
894 for (i = 0, prop = NULL; map[i].member; i++)
895 if (streq(map[i].member, member)) {
901 r = sd_bus_message_peek_type(m, NULL, &contents);
905 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
909 v = (uint8_t *)userdata + prop->offset;
911 r = prop->set(bus, member, m, &error, v);
913 r = map_basic(bus, member, m, &error, v);
915 r = sd_bus_message_exit_container(m);
919 r = sd_bus_message_skip(m, "v");
924 r = sd_bus_message_exit_container(m);
932 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
935 assert(transport >= 0);
936 assert(transport < _BUS_TRANSPORT_MAX);
939 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
940 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
944 case BUS_TRANSPORT_LOCAL:
946 r = sd_bus_open_user(bus);
948 r = sd_bus_open_system(bus);
952 case BUS_TRANSPORT_REMOTE:
953 r = sd_bus_open_system_remote(host, bus);
956 case BUS_TRANSPORT_CONTAINER:
957 r = sd_bus_open_system_container(host, bus);
961 assert_not_reached("Hmm, unknown transport type.");
967 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
970 assert(transport >= 0);
971 assert(transport < _BUS_TRANSPORT_MAX);
974 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
975 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
979 case BUS_TRANSPORT_LOCAL:
981 r = bus_open_user_systemd(bus);
983 r = bus_open_system_systemd(bus);
987 case BUS_TRANSPORT_REMOTE:
988 r = sd_bus_open_system_remote(host, bus);
991 case BUS_TRANSPORT_CONTAINER:
992 r = sd_bus_open_system_container(host, bus);
996 assert_not_reached("Hmm, unknown transport type.");
1002 int bus_property_get_bool(
1005 const char *interface,
1006 const char *property,
1007 sd_bus_message *reply,
1008 sd_bus_error *error,
1011 int b = *(bool*) userdata;
1013 return sd_bus_message_append_basic(reply, 'b', &b);
1016 int bus_property_get_uid(
1019 const char *interface,
1020 const char *property,
1021 sd_bus_message *reply,
1022 sd_bus_error *error,
1025 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
1026 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
1027 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
1029 return sd_bus_message_append_basic(reply, 'u', userdata);
1032 int bus_log_parse_error(int r) {
1033 log_error("Failed to parse message: %s", strerror(-r));
1037 int bus_log_create_error(int r) {
1038 log_error("Failed to create message: %s", strerror(-r));
1042 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1046 return sd_bus_message_read(