1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/ioctl.h>
28 #include <sys/resource.h>
29 #include <sys/socket.h>
32 #include "sd-bus-protocol.h"
34 #include "sd-daemon.h"
38 #include "alloc-util.h"
39 #include "bus-internal.h"
40 #include "bus-label.h"
41 #include "bus-message.h"
44 #include "cgroup-util.h"
49 #include "mount-util.h"
51 #include "parse-util.h"
52 #include "proc-cmdline.h"
53 //#include "rlimit-util.h"
54 #include "stdio-util.h"
56 #include "user-util.h"
58 #if 0 /// UNNEEDED by elogind
59 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
60 sd_event *e = userdata;
65 sd_bus_close(sd_bus_message_get_bus(m));
71 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
80 /* We unregister the name here and then wait for the
81 * NameOwnerChanged signal for this event to arrive before we
82 * quit. We do this in order to make sure that any queued
83 * requests are still processed before we really exit. */
85 r = sd_bus_get_unique_name(bus, &unique);
90 "sender='org.freedesktop.DBus',"
92 "interface='org.freedesktop.DBus',"
93 "member='NameOwnerChanged',"
94 "path='/org/freedesktop/DBus',"
96 "arg1='", unique, "',",
99 r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
103 r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
110 int bus_event_loop_with_idle(
115 check_idle_t check_idle,
117 bool exiting = false;
127 r = sd_event_get_state(e);
130 if (r == SD_EVENT_FINISHED)
134 idle = check_idle(userdata);
138 r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
142 if (r == 0 && !exiting && idle) {
144 r = sd_bus_try_close(bus);
148 /* Fallback for dbus1 connections: we
149 * unregister the name and wait for the
150 * response to come through for it */
151 if (r == -EOPNOTSUPP) {
153 /* Inform the service manager that we
154 * are going down, so that it will
155 * queue all further start requests,
156 * instead of assuming we are already
158 sd_notify(false, "STOPPING=1");
160 r = bus_async_unregister_and_exit(e, bus, name);
176 r = sd_event_get_exit_code(e, &code);
184 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
185 _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
186 int r, has_owner = 0;
191 r = sd_bus_call_method(c,
192 "org.freedesktop.DBus",
193 "/org/freedesktop/dbus",
194 "org.freedesktop.DBus",
203 r = sd_bus_message_read_basic(rep, 'b', &has_owner);
205 return sd_bus_error_set_errno(error, r);
210 static int check_good_user(sd_bus_message *m, uid_t good_user) {
211 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
217 if (good_user == UID_INVALID)
220 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
224 /* Don't trust augmented credentials for authorization */
225 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
227 r = sd_bus_creds_get_euid(creds, &sender_uid);
231 return sender_uid == good_user;
235 sd_bus_message *call,
238 const char **details,
248 /* Tests non-interactively! */
250 r = check_good_user(call, good_user);
254 r = sd_bus_query_sender_privilege(call, capability);
261 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
262 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
263 int authorized = false, challenge = false;
264 const char *sender, **k, **v;
266 sender = sd_bus_message_get_sender(call);
270 r = sd_bus_message_new_method_call(
273 "org.freedesktop.PolicyKit1",
274 "/org/freedesktop/PolicyKit1/Authority",
275 "org.freedesktop.PolicyKit1.Authority",
276 "CheckAuthorization");
280 r = sd_bus_message_append(
283 "system-bus-name", 1, "name", "s", sender,
288 r = sd_bus_message_open_container(request, 'a', "{ss}");
292 STRV_FOREACH_PAIR(k, v, details) {
293 r = sd_bus_message_append(request, "{ss}", *k, *v);
298 r = sd_bus_message_close_container(request);
302 r = sd_bus_message_append(request, "us", 0, NULL);
306 r = sd_bus_call(call->bus, request, 0, e, &reply);
308 /* Treat no PK available as access denied */
309 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
310 sd_bus_error_free(e);
317 r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
321 r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
329 *_challenge = challenge;
340 typedef struct AsyncPolkitQuery {
341 sd_bus_message *request, *reply;
342 sd_bus_message_handler_t callback;
348 static void async_polkit_query_free(AsyncPolkitQuery *q) {
353 sd_bus_slot_unref(q->slot);
355 if (q->registry && q->request)
356 hashmap_remove(q->registry, q->request);
358 sd_bus_message_unref(q->request);
359 sd_bus_message_unref(q->reply);
364 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
365 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
366 AsyncPolkitQuery *q = userdata;
372 q->slot = sd_bus_slot_unref(q->slot);
373 q->reply = sd_bus_message_ref(reply);
375 r = sd_bus_message_rewind(q->request, true);
377 r = sd_bus_reply_method_errno(q->request, r, NULL);
381 r = q->callback(q->request, q->userdata, &error_buffer);
382 r = bus_maybe_reply_error(q->request, r, &error_buffer);
385 async_polkit_query_free(q);
392 int bus_verify_polkit_async(
393 sd_bus_message *call,
396 const char **details,
400 sd_bus_error *error) {
403 _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
405 const char *sender, **k, **v;
406 sd_bus_message_handler_t callback;
416 r = check_good_user(call, good_user);
421 q = hashmap_get(*registry, call);
423 int authorized, challenge;
425 /* This is the second invocation of this function, and
426 * there's already a response from polkit, let's
430 if (sd_bus_message_is_method_error(q->reply, NULL)) {
431 const sd_bus_error *e;
433 /* Copy error from polkit reply */
434 e = sd_bus_message_get_error(q->reply);
435 sd_bus_error_copy(error, e);
437 /* Treat no PK available as access denied */
438 if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
441 return -sd_bus_error_get_errno(e);
444 r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
446 r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
455 return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
461 r = sd_bus_query_sender_privilege(call, capability);
468 if (sd_bus_get_current_message(call->bus) != call)
471 callback = sd_bus_get_current_handler(call->bus);
475 userdata = sd_bus_get_current_userdata(call->bus);
477 sender = sd_bus_message_get_sender(call);
481 c = sd_bus_message_get_allow_interactive_authorization(call);
487 r = hashmap_ensure_allocated(registry, NULL);
491 r = sd_bus_message_new_method_call(
494 "org.freedesktop.PolicyKit1",
495 "/org/freedesktop/PolicyKit1/Authority",
496 "org.freedesktop.PolicyKit1.Authority",
497 "CheckAuthorization");
501 r = sd_bus_message_append(
504 "system-bus-name", 1, "name", "s", sender,
509 r = sd_bus_message_open_container(pk, 'a', "{ss}");
513 STRV_FOREACH_PAIR(k, v, details) {
514 r = sd_bus_message_append(pk, "{ss}", *k, *v);
519 r = sd_bus_message_close_container(pk);
523 r = sd_bus_message_append(pk, "us", !!interactive, NULL);
527 q = new0(AsyncPolkitQuery, 1);
531 q->request = sd_bus_message_ref(call);
532 q->callback = callback;
533 q->userdata = userdata;
535 r = hashmap_put(*registry, call, q);
537 async_polkit_query_free(q);
541 q->registry = *registry;
543 r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
545 async_polkit_query_free(q);
555 void bus_verify_polkit_async_registry_free(Hashmap *registry) {
557 hashmap_free_with_destructor(registry, async_polkit_query_free);
561 #if 0 /// UNNEEDED by elogind
562 int bus_check_peercred(sd_bus *c) {
568 fd = sd_bus_get_fd(c);
572 r = getpeercred(fd, &ucred);
576 if (ucred.uid != 0 && ucred.uid != geteuid())
582 int bus_connect_system_systemd(sd_bus **_bus) {
583 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
589 return sd_bus_default_system(_bus);
591 /* If we are root then let's talk directly to the system
592 * instance, instead of going via the bus */
594 r = sd_bus_new(&bus);
598 r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
602 r = sd_bus_start(bus);
604 return sd_bus_default_system(_bus);
606 r = bus_check_peercred(bus);
616 int bus_connect_user_systemd(sd_bus **_bus) {
617 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
618 _cleanup_free_ char *ee = NULL;
624 e = secure_getenv("XDG_RUNTIME_DIR");
626 return sd_bus_default_user(_bus);
628 ee = bus_address_escape(e);
632 r = sd_bus_new(&bus);
636 bus->address = strjoin("unix:path=", ee, "/systemd/private");
640 r = sd_bus_start(bus);
642 return sd_bus_default_user(_bus);
644 r = bus_check_peercred(bus);
655 #define print_property(name, fmt, ...) \
658 printf(fmt "\n", __VA_ARGS__); \
660 printf("%s=" fmt "\n", name, __VA_ARGS__); \
663 int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
665 const char *contents;
671 r = sd_bus_message_peek_type(property, &type, &contents);
677 case SD_BUS_TYPE_STRING: {
680 r = sd_bus_message_read_basic(property, type, &s);
684 if (all || !isempty(s)) {
687 /* This property has a single value, so we need to take
688 * care not to print a new line, everything else is OK. */
689 good = !strchr(s, '\n');
690 print_property(name, "%s", good ? s : "[unprintable]");
696 case SD_BUS_TYPE_BOOLEAN: {
699 r = sd_bus_message_read_basic(property, type, &b);
703 print_property(name, "%s", yes_no(b));
708 case SD_BUS_TYPE_UINT64: {
711 r = sd_bus_message_read_basic(property, type, &u);
715 /* Yes, heuristics! But we can change this check
716 * should it turn out to not be sufficient */
718 if (endswith(name, "Timestamp")) {
719 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
721 t = format_timestamp(timestamp, sizeof(timestamp), u);
723 print_property(name, "%s", strempty(t));
725 } else if (strstr(name, "USec")) {
726 char timespan[FORMAT_TIMESPAN_MAX];
728 print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
729 } else if (streq(name, "RestrictNamespaces")) {
730 _cleanup_free_ char *s = NULL;
733 if ((u & NAMESPACE_FLAGS_ALL) == 0)
735 else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
738 r = namespace_flag_to_string_many(u, &s);
745 print_property(name, "%s", result);
747 } else if (streq(name, "MountFlags")) {
750 result = mount_propagation_flags_to_string(u);
754 print_property(name, "%s", result);
756 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
757 _cleanup_free_ char *s = NULL;
759 r = capability_set_to_string_alloc(u, &s);
763 print_property(name, "%s", s);
765 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
766 (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
767 (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
768 (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
769 (endswith(name, "NSec") && u == (uint64_t) -1))
771 print_property(name, "%s", "[not set]");
773 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
774 (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
775 (startswith(name, "Limit") && u == (uint64_t) -1) ||
776 (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
778 print_property(name, "%s", "infinity");
780 print_property(name, "%"PRIu64, u);
785 case SD_BUS_TYPE_INT64: {
788 r = sd_bus_message_read_basic(property, type, &i);
792 print_property(name, "%"PRIi64, i);
797 case SD_BUS_TYPE_UINT32: {
800 r = sd_bus_message_read_basic(property, type, &u);
804 if (strstr(name, "UMask") || strstr(name, "Mode"))
805 print_property(name, "%04o", u);
806 else if (streq(name, "UID")) {
807 if (u == UID_INVALID)
808 print_property(name, "%s", "[not set]");
810 print_property(name, "%"PRIu32, u);
811 } else if (streq(name, "GID")) {
812 if (u == GID_INVALID)
813 print_property(name, "%s", "[not set]");
815 print_property(name, "%"PRIu32, u);
817 print_property(name, "%"PRIu32, u);
822 case SD_BUS_TYPE_INT32: {
825 r = sd_bus_message_read_basic(property, type, &i);
829 print_property(name, "%"PRIi32, i);
833 case SD_BUS_TYPE_DOUBLE: {
836 r = sd_bus_message_read_basic(property, type, &d);
840 print_property(name, "%g", d);
844 case SD_BUS_TYPE_ARRAY:
845 if (streq(contents, "s")) {
849 r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
853 while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
859 /* This property has multiple space-separated values, so
860 * neither spaces not newlines can be allowed in a value. */
861 good = str[strcspn(str, " \n")] == '\0';
863 printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
870 if (first && all && !value)
875 r = sd_bus_message_exit_container(property);
881 } else if (streq(contents, "y")) {
885 r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
895 for (i = 0; i < n; i++)
896 printf("%02x", u[i]);
903 } else if (streq(contents, "u")) {
907 r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
917 for (i = 0; i < n; i++)
918 printf("%08x", u[i]);
932 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) {
933 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
934 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
940 r = sd_bus_call_method(bus,
943 "org.freedesktop.DBus.Properties",
951 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
955 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
957 const char *contents;
959 r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
963 if (!filter || strv_find(filter, name)) {
964 r = sd_bus_message_peek_type(reply, NULL, &contents);
968 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
972 r = bus_print_property(name, reply, value, all);
977 printf("%s=[unprintable]\n", name);
978 /* skip what we didn't read */
979 r = sd_bus_message_skip(reply, contents);
984 r = sd_bus_message_exit_container(reply);
988 r = sd_bus_message_skip(reply, "v");
993 r = sd_bus_message_exit_container(reply);
1000 r = sd_bus_message_exit_container(reply);
1007 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1008 sd_id128_t *p = userdata;
1013 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1020 memcpy((*p).bytes, v, n);
1027 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1031 r = sd_bus_message_peek_type(m, &type, NULL);
1037 case SD_BUS_TYPE_STRING: {
1038 char **p = userdata;
1041 r = sd_bus_message_read_basic(m, type, &s);
1048 return free_and_strdup(p, s);
1051 case SD_BUS_TYPE_ARRAY: {
1052 _cleanup_strv_free_ char **l = NULL;
1053 char ***p = userdata;
1055 r = bus_message_read_strv_extend(m, &l);
1065 case SD_BUS_TYPE_BOOLEAN: {
1069 r = sd_bus_message_read_basic(m, type, &b);
1077 case SD_BUS_TYPE_INT32:
1078 case SD_BUS_TYPE_UINT32: {
1079 uint32_t u, *p = userdata;
1081 r = sd_bus_message_read_basic(m, type, &u);
1089 case SD_BUS_TYPE_INT64:
1090 case SD_BUS_TYPE_UINT64: {
1091 uint64_t t, *p = userdata;
1093 r = sd_bus_message_read_basic(m, type, &t);
1101 case SD_BUS_TYPE_DOUBLE: {
1102 double d, *p = userdata;
1104 r = sd_bus_message_read_basic(m, type, &d);
1115 int bus_message_map_all_properties(
1117 const struct bus_properties_map *map,
1118 sd_bus_error *error,
1126 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1130 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1131 const struct bus_properties_map *prop;
1133 const char *contents;
1137 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1141 for (i = 0, prop = NULL; map[i].member; i++)
1142 if (streq(map[i].member, member)) {
1148 r = sd_bus_message_peek_type(m, NULL, &contents);
1152 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1156 v = (uint8_t *)userdata + prop->offset;
1158 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1160 r = map_basic(sd_bus_message_get_bus(m), member, m, error, v);
1164 r = sd_bus_message_exit_container(m);
1168 r = sd_bus_message_skip(m, "v");
1173 r = sd_bus_message_exit_container(m);
1180 return sd_bus_message_exit_container(m);
1183 #if 0 /// UNNEEDED by elogind
1184 int bus_message_map_properties_changed(
1186 const struct bus_properties_map *map,
1187 sd_bus_error *error,
1191 int r, invalidated, i;
1196 r = bus_message_map_all_properties(m, map, error, userdata);
1200 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
1205 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0)
1206 for (i = 0; map[i].member; i++)
1207 if (streq(map[i].member, member)) {
1214 r = sd_bus_message_exit_container(m);
1222 int bus_map_all_properties(
1224 const char *destination,
1226 const struct bus_properties_map *map,
1227 sd_bus_error *error,
1230 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1234 assert(destination);
1238 r = sd_bus_call_method(
1242 "org.freedesktop.DBus.Properties",
1250 return bus_message_map_all_properties(m, map, error, userdata);
1253 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1254 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1257 assert(transport >= 0);
1258 assert(transport < _BUS_TRANSPORT_MAX);
1261 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1262 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1264 switch (transport) {
1266 case BUS_TRANSPORT_LOCAL:
1267 #if 0 /// elogind does not support a user bus
1269 r = sd_bus_default_user(&bus);
1272 r = sd_bus_default_system(&bus);
1276 case BUS_TRANSPORT_REMOTE:
1277 r = sd_bus_open_system_remote(&bus, host);
1280 case BUS_TRANSPORT_MACHINE:
1281 r = sd_bus_open_system_machine(&bus, host);
1285 assert_not_reached("Hmm, unknown transport type.");
1290 r = sd_bus_set_exit_on_disconnect(bus, true);
1300 #if 0 /// UNNEEDED by elogind
1301 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1304 assert(transport >= 0);
1305 assert(transport < _BUS_TRANSPORT_MAX);
1308 assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1309 assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
1311 switch (transport) {
1313 case BUS_TRANSPORT_LOCAL:
1315 r = bus_connect_user_systemd(bus);
1317 r = bus_connect_system_systemd(bus);
1321 case BUS_TRANSPORT_REMOTE:
1322 r = sd_bus_open_system_remote(bus, host);
1325 case BUS_TRANSPORT_MACHINE:
1326 r = sd_bus_open_system_machine(bus, host);
1330 assert_not_reached("Hmm, unknown transport type.");
1337 int bus_property_get_bool(
1340 const char *interface,
1341 const char *property,
1342 sd_bus_message *reply,
1344 sd_bus_error *error) {
1346 int b = *(bool*) userdata;
1348 return sd_bus_message_append_basic(reply, 'b', &b);
1351 #if 0 /// UNNEEDED by elogind
1352 int bus_property_get_id128(
1355 const char *interface,
1356 const char *property,
1357 sd_bus_message *reply,
1359 sd_bus_error *error) {
1361 sd_id128_t *id = userdata;
1363 if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1364 return sd_bus_message_append(reply, "ay", 0);
1366 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1370 #if __SIZEOF_SIZE_T__ != 8
1371 int bus_property_get_size(
1374 const char *interface,
1375 const char *property,
1376 sd_bus_message *reply,
1378 sd_bus_error *error) {
1380 uint64_t sz = *(size_t*) userdata;
1382 return sd_bus_message_append_basic(reply, 't', &sz);
1386 #if __SIZEOF_LONG__ != 8
1387 int bus_property_get_long(
1390 const char *interface,
1391 const char *property,
1392 sd_bus_message *reply,
1394 sd_bus_error *error) {
1396 int64_t l = *(long*) userdata;
1398 return sd_bus_message_append_basic(reply, 'x', &l);
1401 int bus_property_get_ulong(
1404 const char *interface,
1405 const char *property,
1406 sd_bus_message *reply,
1408 sd_bus_error *error) {
1410 uint64_t ul = *(unsigned long*) userdata;
1412 return sd_bus_message_append_basic(reply, 't', &ul);
1416 int bus_log_parse_error(int r) {
1417 return log_error_errno(r, "Failed to parse bus message: %m");
1420 #if 0 /// UNNEEDED by elogind
1421 int bus_log_create_error(int r) {
1422 return log_error_errno(r, "Failed to create bus message: %m");
1426 #if 0 /// UNNEEDED by elogind
1428 * bus_path_encode_unique() - encode unique object path
1429 * @b: bus connection or NULL
1430 * @prefix: object path prefix
1431 * @sender_id: unique-name of client, or NULL
1432 * @external_id: external ID to be chosen by client, or NULL
1433 * @ret_path: storage for encoded object path pointer
1435 * Whenever we provide a bus API that allows clients to create and manage
1436 * server-side objects, we need to provide a unique name for these objects. If
1437 * we let the server choose the name, we suffer from a race condition: If a
1438 * client creates an object asynchronously, it cannot destroy that object until
1439 * it received the method reply. It cannot know the name of the new object,
1440 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1442 * Therefore, many APIs allow the client to choose the unique name for newly
1443 * created objects. There're two problems to solve, though:
1444 * 1) Object names are usually defined via dbus object paths, which are
1445 * usually globally namespaced. Therefore, multiple clients must be able
1446 * to choose unique object names without interference.
1447 * 2) If multiple libraries share the same bus connection, they must be
1448 * able to choose unique object names without interference.
1449 * The first problem is solved easily by prefixing a name with the
1450 * unique-bus-name of a connection. The server side must enforce this and
1451 * reject any other name. The second problem is solved by providing unique
1452 * suffixes from within sd-bus.
1454 * This helper allows clients to create unique object-paths. It uses the
1455 * template '/prefix/sender_id/external_id' and returns the new path in
1456 * @ret_path (must be freed by the caller).
1457 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1458 * NULL, this function allocates a unique suffix via @b (by requesting a new
1459 * cookie). If both @sender_id and @external_id are given, @b can be passed as
1462 * Returns: 0 on success, negative error code on failure.
1464 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1465 _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1466 char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1469 assert_return(b || (sender_id && external_id), -EINVAL);
1470 assert_return(object_path_is_valid(prefix), -EINVAL);
1471 assert_return(ret_path, -EINVAL);
1474 r = sd_bus_get_unique_name(b, &sender_id);
1480 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1481 external_id = external_buf;
1484 sender_label = bus_label_escape(sender_id);
1488 external_label = bus_label_escape(external_id);
1489 if (!external_label)
1492 p = strjoin(prefix, "/", sender_label, "/", external_label);
1501 * bus_path_decode_unique() - decode unique object path
1502 * @path: object path to decode
1503 * @prefix: object path prefix
1504 * @ret_sender: output parameter for sender-id label
1505 * @ret_external: output parameter for external-id label
1507 * This does the reverse of bus_path_encode_unique() (see its description for
1508 * details). Both trailing labels, sender-id and external-id, are unescaped and
1509 * returned in the given output parameters (the caller must free them).
1511 * Note that this function returns 0 if the path does not match the template
1512 * (see bus_path_encode_unique()), 1 if it matched.
1514 * Returns: Negative error code on failure, 0 if the given object path does not
1515 * match the template (return parameters are set to NULL), 1 if it was
1516 * parsed successfully (return parameters contain allocated labels).
1518 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1520 char *sender, *external;
1522 assert(object_path_is_valid(path));
1523 assert(object_path_is_valid(prefix));
1525 assert(ret_external);
1527 p = object_path_startswith(path, prefix);
1530 *ret_external = NULL;
1537 *ret_external = NULL;
1541 sender = bus_label_unescape_n(p, q - p);
1542 external = bus_label_unescape(q + 1);
1543 if (!sender || !external) {
1549 *ret_sender = sender;
1550 *ret_external = external;
1555 #if 0 /// UNNEEDED by elogind
1556 int bus_property_get_rlimit(
1559 const char *interface,
1560 const char *property,
1561 sd_bus_message *reply,
1563 sd_bus_error *error) {
1568 const char *is_soft;
1574 is_soft = endswith(property, "Soft");
1575 rl = *(struct rlimit**) userdata;
1577 x = is_soft ? rl->rlim_cur : rl->rlim_max;
1579 struct rlimit buf = {};
1583 s = is_soft ? strndupa(property, is_soft - property) : property;
1585 z = rlimit_from_string(strstr(s, "Limit"));
1589 x = is_soft ? buf.rlim_cur : buf.rlim_max;
1592 /* rlim_t might have different sizes, let's map
1593 * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
1595 u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1597 return sd_bus_message_append(reply, "t", u);
1600 int bus_track_add_name_many(sd_bus_track *t, char **l) {
1606 /* Continues adding after failure, and returns the first failure. */
1608 STRV_FOREACH(i, l) {
1611 k = sd_bus_track_add_name(t, *i);
1612 if (k < 0 && r >= 0)
1620 int bus_open_system_watch_bind(sd_bus **ret) {
1621 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
1627 /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
1629 r = sd_bus_new(&bus);
1633 e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1635 e = DEFAULT_SYSTEM_BUS_ADDRESS;
1637 r = sd_bus_set_address(bus, e);
1641 r = sd_bus_set_bus_client(bus, true);
1645 r = sd_bus_set_trusted(bus, true);
1649 r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1653 r = sd_bus_set_watch_bind(bus, true);
1657 r = sd_bus_set_connected_signal(bus, true);
1661 r = sd_bus_start(bus);