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_print_property(const char *name, sd_bus_message *property, bool all) {
445 const char *contents;
451 r = sd_bus_message_peek_type(property, &type, &contents);
457 case SD_BUS_TYPE_STRING: {
460 r = sd_bus_message_read_basic(property, type, &s);
464 if (all || !isempty(s))
465 printf("%s=%s\n", name, s);
470 case SD_BUS_TYPE_BOOLEAN: {
473 r = sd_bus_message_read_basic(property, type, &b);
477 printf("%s=%s\n", name, yes_no(b));
482 case SD_BUS_TYPE_UINT64: {
485 r = sd_bus_message_read_basic(property, type, &u);
489 /* Yes, heuristics! But we can change this check
490 * should it turn out to not be sufficient */
492 if (endswith(name, "Timestamp")) {
493 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
495 t = format_timestamp(timestamp, sizeof(timestamp), u);
497 printf("%s=%s\n", name, strempty(t));
499 } else if (strstr(name, "USec")) {
500 char timespan[FORMAT_TIMESPAN_MAX];
502 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
504 printf("%s=%llu\n", name, (unsigned long long) u);
509 case SD_BUS_TYPE_UINT32: {
512 r = sd_bus_message_read_basic(property, type, &u);
516 if (strstr(name, "UMask") || strstr(name, "Mode"))
517 printf("%s=%04o\n", name, u);
519 printf("%s=%u\n", name, (unsigned) u);
524 case SD_BUS_TYPE_INT32: {
527 r = sd_bus_message_read_basic(property, type, &i);
531 printf("%s=%i\n", name, (int) i);
535 case SD_BUS_TYPE_DOUBLE: {
538 r = sd_bus_message_read_basic(property, type, &d);
542 printf("%s=%g\n", name, d);
546 case SD_BUS_TYPE_ARRAY:
547 if (streq(contents, "s")) {
552 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
556 r = sd_bus_message_peek_type(property, &tp, &cnt);
565 while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) >= 0) {
566 printf("%s%s", space ? " " : "", str);
576 r = sd_bus_message_exit_container(property);
582 } else if (streq(contents, "y")) {
586 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
595 for (i = 0; i < n; i++)
596 printf("%02x", u[i]);
603 } else if (streq(contents, "u")) {
607 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
616 for (i = 0; i < n; i++)
617 printf("%08x", u[i]);
631 int bus_print_all_properties(sd_bus *bus, const char *path, char **filter, bool all) {
632 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
633 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
639 r = sd_bus_call_method(bus,
640 "org.freedesktop.machine1",
642 "org.freedesktop.DBus.Properties",
650 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
654 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
656 const char *contents;
658 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
662 if (!filter || strv_find(filter, name)) {
663 r = sd_bus_message_peek_type(reply, NULL, &contents);
667 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
671 r = bus_print_property(name, reply, all);
675 printf("%s=[unprintable]\n", name);
677 r = sd_bus_message_exit_container(reply);
681 r = sd_bus_message_skip(reply, "v");
686 r = sd_bus_message_exit_container(reply);
693 r = sd_bus_message_exit_container(reply);
700 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
701 sd_id128_t *p = userdata;
706 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
713 memcpy((*p).bytes, v, n);
720 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
724 r = sd_bus_message_peek_type(m, &type, NULL);
729 case SD_BUS_TYPE_STRING: {
734 r = sd_bus_message_read_basic(m, type, &s);
752 case SD_BUS_TYPE_ARRAY: {
753 _cleanup_strv_free_ char **l = NULL;
754 char ***p = userdata;
756 r = bus_message_read_strv_extend(m, &l);
767 case SD_BUS_TYPE_BOOLEAN: {
771 r = sd_bus_message_read_basic(m, type, &b);
780 case SD_BUS_TYPE_UINT32: {
782 uint32_t *p = userdata;
784 r = sd_bus_message_read_basic(m, type, &u);
793 case SD_BUS_TYPE_UINT64: {
795 uint64_t *p = userdata;
797 r = sd_bus_message_read_basic(m, type, &t);
813 int bus_map_all_properties(sd_bus *bus,
814 const char *destination,
816 const struct bus_properties_map *map,
818 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
819 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
827 r = sd_bus_call_method( bus,
830 "org.freedesktop.DBus.Properties",
838 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
842 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
843 const struct bus_properties_map *prop;
845 const char *contents;
849 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
853 for (i = 0, prop = NULL; map[i].member; i++)
854 if (streq(map[i].member, member)) {
860 r = sd_bus_message_peek_type(m, NULL, &contents);
864 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
868 v = (uint8_t *)userdata + prop->offset;
870 r = prop->set(bus, member, m, &error, v);
872 r = map_basic(bus, member, m, &error, v);
874 r = sd_bus_message_exit_container(m);
878 r = sd_bus_message_skip(m, "v");
883 r = sd_bus_message_exit_container(m);
891 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
894 assert(transport >= 0);
895 assert(transport < _BUS_TRANSPORT_MAX);
898 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
899 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
903 case BUS_TRANSPORT_LOCAL:
905 r = sd_bus_open_user(bus);
907 r = sd_bus_open_system(bus);
911 case BUS_TRANSPORT_REMOTE:
912 r = sd_bus_open_system_remote(host, bus);
915 case BUS_TRANSPORT_CONTAINER:
916 r = sd_bus_open_system_container(host, bus);
920 assert_not_reached("Hmm, unknown transport type.");
926 int bus_property_get_bool(
929 const char *interface,
930 const char *property,
931 sd_bus_message *reply,
935 int b = *(bool*) userdata;
937 return sd_bus_message_append_basic(reply, 'b', &b);
940 int bus_property_get_uid(
943 const char *interface,
944 const char *property,
945 sd_bus_message *reply,
949 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
950 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
951 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
953 return sd_bus_message_append_basic(reply, 'u', userdata);