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>
32 #include "bus-error.h"
33 #include "bus-message.h"
37 static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
38 sd_event *e = userdata;
44 sd_event_request_quit(e);
48 int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
49 _cleanup_free_ char *match = NULL;
56 r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
60 r = sd_bus_add_match(bus, match, quit_callback, e);
64 r = sd_bus_release_name(bus, name);
68 if (r != SD_BUS_NAME_RELEASED)
74 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
83 r = sd_event_get_state(e);
87 if (r == SD_EVENT_FINISHED)
90 r = sd_event_run(e, exiting ? (uint64_t) -1 : timeout);
94 if (r == 0 && !exiting) {
95 r = bus_async_unregister_and_quit(e, bus, name);
106 int bus_property_get_tristate(
109 const char *interface,
110 const char *property,
111 sd_bus_message *reply,
115 int *tristate = userdata;
118 r = sd_bus_message_append(reply, "b", *tristate > 0);
125 int bus_verify_polkit(
141 sender = sd_bus_message_get_sender(m);
145 r = sd_bus_get_owner_uid(bus, sender, &uid);
154 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
155 int authorized = false, challenge = false;
157 r = sd_bus_call_method(
159 "org.freedesktop.PolicyKit1",
160 "/org/freedesktop/PolicyKit1/Authority",
161 "org.freedesktop.PolicyKit1.Authority",
162 "CheckAuthorization",
166 "system-bus-name", 1, "name", "s", sender,
173 /* Treat no PK available as access denied */
174 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
175 sd_bus_error_free(e);
182 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
184 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
190 *_challenge = challenge;
201 typedef struct AsyncPolkitQuery {
202 sd_bus_message *request, *reply;
203 sd_bus_message_handler_t callback;
208 static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
209 AsyncPolkitQuery *q = userdata;
210 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
217 q->reply = sd_bus_message_ref(reply);
220 m = sd_bus_message_ref(q->request);
222 r = sd_bus_message_rewind(m, true);
226 r = q->callback(bus, m, q->userdata);
233 static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
238 if (q->serial > 0 && b)
239 sd_bus_send_with_reply_cancel(b, q->serial);
241 sd_bus_message_unref(q->request);
242 sd_bus_message_unref(q->reply);
248 int bus_verify_polkit_async(
255 sd_bus_message_handler_t callback,
259 _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
272 q = hashmap_remove(*registry, m);
274 int authorized, challenge;
276 /* This is the second invocation of this function, and
277 * there's already a response from polkit, let's
281 if (sd_bus_message_is_method_error(q->reply, NULL)) {
282 const sd_bus_error *e;
284 /* Treat no PK available as access denied */
285 if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
286 async_polkit_query_free(bus, q);
290 e = sd_bus_message_get_error(q->reply);
291 sd_bus_error_copy(error, e);
292 r = sd_bus_error_get_errno(e);
294 async_polkit_query_free(bus, q);
298 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
300 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
302 async_polkit_query_free(bus, q);
314 sender = sd_bus_message_get_sender(m);
318 r = sd_bus_get_owner_uid(bus, sender, &uid);
326 r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
330 r = sd_bus_message_new_method_call(
332 "org.freedesktop.PolicyKit1",
333 "/org/freedesktop/PolicyKit1/Authority",
334 "org.freedesktop.PolicyKit1.Authority",
335 "CheckAuthorization",
340 r = sd_bus_message_append(
343 "system-bus-name", 1, "name", "s", sender,
351 q = new0(AsyncPolkitQuery, 1);
355 q->request = sd_bus_message_ref(m);
356 q->callback = callback;
357 q->userdata = userdata;
359 r = hashmap_put(*registry, m, q);
361 async_polkit_query_free(bus, q);
365 r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
375 void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
379 while ((q = hashmap_steal_first(registry)))
380 async_polkit_query_free(bus, q);
382 hashmap_free(registry);
386 static int bus_check_peercred(sd_bus *c) {
393 fd = sd_bus_get_fd(c);
397 l = sizeof(struct ucred);
398 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
401 if (l != sizeof(struct ucred))
404 if (ucred.uid != 0 && ucred.uid != geteuid())
410 int bus_open_system_systemd(sd_bus **_bus) {
411 _cleanup_bus_unref_ sd_bus *bus = NULL;
417 return sd_bus_open_system(_bus);
419 /* If we are root, then let's talk directly to the system
420 * instance, instead of going via the bus */
422 r = sd_bus_new(&bus);
426 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
430 r = sd_bus_start(bus);
434 r = bus_check_peercred(bus);
444 int bus_open_user_systemd(sd_bus **_bus) {
445 _cleanup_bus_unref_ sd_bus *bus = NULL;
446 _cleanup_free_ char *p = NULL;
450 /* If we are supposed to talk to the instance, try via
451 * XDG_RUNTIME_DIR first, then fallback to normal bus
456 e = secure_getenv("XDG_RUNTIME_DIR");
458 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
462 r = sd_bus_new(&bus);
466 r = sd_bus_set_address(bus, p);
470 r = sd_bus_start(bus);
474 r = bus_check_peercred(bus);
484 int bus_print_property(const char *name, sd_bus_message *property, bool all) {
486 const char *contents;
492 r = sd_bus_message_peek_type(property, &type, &contents);
498 case SD_BUS_TYPE_STRING: {
501 r = sd_bus_message_read_basic(property, type, &s);
505 if (all || !isempty(s))
506 printf("%s=%s\n", name, s);
511 case SD_BUS_TYPE_BOOLEAN: {
514 r = sd_bus_message_read_basic(property, type, &b);
518 printf("%s=%s\n", name, yes_no(b));
523 case SD_BUS_TYPE_UINT64: {
526 r = sd_bus_message_read_basic(property, type, &u);
530 /* Yes, heuristics! But we can change this check
531 * should it turn out to not be sufficient */
533 if (endswith(name, "Timestamp")) {
534 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
536 t = format_timestamp(timestamp, sizeof(timestamp), u);
538 printf("%s=%s\n", name, strempty(t));
540 } else if (strstr(name, "USec")) {
541 char timespan[FORMAT_TIMESPAN_MAX];
543 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
545 printf("%s=%llu\n", name, (unsigned long long) u);
550 case SD_BUS_TYPE_UINT32: {
553 r = sd_bus_message_read_basic(property, type, &u);
557 if (strstr(name, "UMask") || strstr(name, "Mode"))
558 printf("%s=%04o\n", name, u);
560 printf("%s=%u\n", name, (unsigned) u);
565 case SD_BUS_TYPE_INT32: {
568 r = sd_bus_message_read_basic(property, type, &i);
572 printf("%s=%i\n", name, (int) i);
576 case SD_BUS_TYPE_DOUBLE: {
579 r = sd_bus_message_read_basic(property, type, &d);
583 printf("%s=%g\n", name, d);
587 case SD_BUS_TYPE_ARRAY:
588 if (streq(contents, "s")) {
592 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
596 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
600 printf("%s%s", first ? "" : " ", str);
612 r = sd_bus_message_exit_container(property);
618 } else if (streq(contents, "y")) {
622 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
631 for (i = 0; i < n; i++)
632 printf("%02x", u[i]);
639 } else if (streq(contents, "u")) {
643 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
652 for (i = 0; i < n; i++)
653 printf("%08x", u[i]);
667 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
668 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
669 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
675 r = sd_bus_call_method(bus,
678 "org.freedesktop.DBus.Properties",
686 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
690 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
692 const char *contents;
694 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
698 if (!filter || strv_find(filter, name)) {
699 r = sd_bus_message_peek_type(reply, NULL, &contents);
703 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
707 r = bus_print_property(name, reply, all);
712 printf("%s=[unprintable]\n", name);
713 /* skip what we didn't read */
714 r = sd_bus_message_skip(reply, contents);
719 r = sd_bus_message_exit_container(reply);
723 r = sd_bus_message_skip(reply, "v");
728 r = sd_bus_message_exit_container(reply);
735 r = sd_bus_message_exit_container(reply);
742 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
743 sd_id128_t *p = userdata;
748 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
755 memcpy((*p).bytes, v, n);
762 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
766 r = sd_bus_message_peek_type(m, &type, NULL);
771 case SD_BUS_TYPE_STRING: {
776 r = sd_bus_message_read_basic(m, type, &s);
794 case SD_BUS_TYPE_ARRAY: {
795 _cleanup_strv_free_ char **l = NULL;
796 char ***p = userdata;
798 r = bus_message_read_strv_extend(m, &l);
809 case SD_BUS_TYPE_BOOLEAN: {
813 r = sd_bus_message_read_basic(m, type, &b);
822 case SD_BUS_TYPE_UINT32: {
824 uint32_t *p = userdata;
826 r = sd_bus_message_read_basic(m, type, &u);
835 case SD_BUS_TYPE_UINT64: {
837 uint64_t *p = userdata;
839 r = sd_bus_message_read_basic(m, type, &t);
855 int bus_map_all_properties(sd_bus *bus,
856 const char *destination,
858 const struct bus_properties_map *map,
860 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
861 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
869 r = sd_bus_call_method( bus,
872 "org.freedesktop.DBus.Properties",
880 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
884 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
885 const struct bus_properties_map *prop;
887 const char *contents;
891 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
895 for (i = 0, prop = NULL; map[i].member; i++)
896 if (streq(map[i].member, member)) {
902 r = sd_bus_message_peek_type(m, NULL, &contents);
906 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
910 v = (uint8_t *)userdata + prop->offset;
912 r = prop->set(bus, member, m, &error, v);
914 r = map_basic(bus, member, m, &error, v);
916 r = sd_bus_message_exit_container(m);
920 r = sd_bus_message_skip(m, "v");
925 r = sd_bus_message_exit_container(m);
933 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
936 assert(transport >= 0);
937 assert(transport < _BUS_TRANSPORT_MAX);
940 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
941 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
945 case BUS_TRANSPORT_LOCAL:
947 r = sd_bus_open_user(bus);
949 r = sd_bus_open_system(bus);
953 case BUS_TRANSPORT_REMOTE:
954 r = sd_bus_open_system_remote(host, bus);
957 case BUS_TRANSPORT_CONTAINER:
958 r = sd_bus_open_system_container(host, bus);
962 assert_not_reached("Hmm, unknown transport type.");
968 int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
971 assert(transport >= 0);
972 assert(transport < _BUS_TRANSPORT_MAX);
975 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
976 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
980 case BUS_TRANSPORT_LOCAL:
982 r = bus_open_user_systemd(bus);
984 r = bus_open_system_systemd(bus);
988 case BUS_TRANSPORT_REMOTE:
989 r = sd_bus_open_system_remote(host, bus);
992 case BUS_TRANSPORT_CONTAINER:
993 r = sd_bus_open_system_container(host, bus);
997 assert_not_reached("Hmm, unknown transport type.");
1003 int bus_property_get_bool(
1006 const char *interface,
1007 const char *property,
1008 sd_bus_message *reply,
1009 sd_bus_error *error,
1012 int b = *(bool*) userdata;
1014 return sd_bus_message_append_basic(reply, 'b', &b);
1017 int bus_property_get_uid(
1020 const char *interface,
1021 const char *property,
1022 sd_bus_message *reply,
1023 sd_bus_error *error,
1026 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
1027 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
1028 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
1030 return sd_bus_message_append_basic(reply, 'u', userdata);
1033 int bus_log_parse_error(int r) {
1034 log_error("Failed to parse message: %s", strerror(-r));
1038 int bus_log_create_error(int r) {
1039 log_error("Failed to create message: %s", strerror(-r));
1043 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
1047 return sd_bus_message_read(