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 *dest, 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,
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);
676 printf("%s=[unprintable]\n", name);
677 /* skip what we didn't read */
678 r = sd_bus_message_skip(reply, contents);
683 r = sd_bus_message_exit_container(reply);
687 r = sd_bus_message_skip(reply, "v");
692 r = sd_bus_message_exit_container(reply);
699 r = sd_bus_message_exit_container(reply);
706 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
707 sd_id128_t *p = userdata;
712 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
719 memcpy((*p).bytes, v, n);
726 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
730 r = sd_bus_message_peek_type(m, &type, NULL);
735 case SD_BUS_TYPE_STRING: {
740 r = sd_bus_message_read_basic(m, type, &s);
758 case SD_BUS_TYPE_ARRAY: {
759 _cleanup_strv_free_ char **l = NULL;
760 char ***p = userdata;
762 r = bus_message_read_strv_extend(m, &l);
773 case SD_BUS_TYPE_BOOLEAN: {
777 r = sd_bus_message_read_basic(m, type, &b);
786 case SD_BUS_TYPE_UINT32: {
788 uint32_t *p = userdata;
790 r = sd_bus_message_read_basic(m, type, &u);
799 case SD_BUS_TYPE_UINT64: {
801 uint64_t *p = userdata;
803 r = sd_bus_message_read_basic(m, type, &t);
819 int bus_map_all_properties(sd_bus *bus,
820 const char *destination,
822 const struct bus_properties_map *map,
824 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
825 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
833 r = sd_bus_call_method( bus,
836 "org.freedesktop.DBus.Properties",
844 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
848 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
849 const struct bus_properties_map *prop;
851 const char *contents;
855 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
859 for (i = 0, prop = NULL; map[i].member; i++)
860 if (streq(map[i].member, member)) {
866 r = sd_bus_message_peek_type(m, NULL, &contents);
870 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
874 v = (uint8_t *)userdata + prop->offset;
876 r = prop->set(bus, member, m, &error, v);
878 r = map_basic(bus, member, m, &error, v);
880 r = sd_bus_message_exit_container(m);
884 r = sd_bus_message_skip(m, "v");
889 r = sd_bus_message_exit_container(m);
897 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
900 assert(transport >= 0);
901 assert(transport < _BUS_TRANSPORT_MAX);
904 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
905 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
909 case BUS_TRANSPORT_LOCAL:
911 r = sd_bus_open_user(bus);
913 r = sd_bus_open_system(bus);
917 case BUS_TRANSPORT_REMOTE:
918 r = sd_bus_open_system_remote(host, bus);
921 case BUS_TRANSPORT_CONTAINER:
922 r = sd_bus_open_system_container(host, bus);
926 assert_not_reached("Hmm, unknown transport type.");
932 int bus_property_get_bool(
935 const char *interface,
936 const char *property,
937 sd_bus_message *reply,
941 int b = *(bool*) userdata;
943 return sd_bus_message_append_basic(reply, 'b', &b);
946 int bus_property_get_uid(
949 const char *interface,
950 const char *property,
951 sd_bus_message *reply,
955 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
956 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
957 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
959 return sd_bus_message_append_basic(reply, 'u', userdata);