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 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35 #include "bus-bloom.h"
38 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
41 assert_return(bus, -EINVAL);
42 assert_return(unique, -EINVAL);
43 assert_return(!bus_pid_changed(bus), -ECHILD);
45 r = bus_ensure_running(bus);
49 *unique = bus->unique_name;
53 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
54 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
58 assert_return(bus, -EINVAL);
59 assert_return(name, -EINVAL);
60 assert_return(bus->bus_client, -EINVAL);
61 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
62 assert_return(!bus_pid_changed(bus), -ECHILD);
65 struct kdbus_cmd_name *n;
69 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
70 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
71 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
72 memcpy(n->name, name, l+1);
74 #ifdef HAVE_VALGRIND_MEMCHECK_H
75 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
78 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
80 if (errno == -EALREADY)
81 return SD_BUS_NAME_ALREADY_OWNER;
84 return SD_BUS_NAME_EXISTS;
89 if (n->flags & KDBUS_NAME_IN_QUEUE)
90 return SD_BUS_NAME_IN_QUEUE;
92 return SD_BUS_NAME_PRIMARY_OWNER;
94 r = sd_bus_call_method(
96 "org.freedesktop.DBus",
98 "org.freedesktop.DBus",
108 r = sd_bus_message_read(reply, "u", &ret);
116 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
117 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
121 assert_return(bus, -EINVAL);
122 assert_return(name, -EINVAL);
123 assert_return(bus->bus_client, -EINVAL);
124 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
125 assert_return(!bus_pid_changed(bus), -ECHILD);
127 if (bus->is_kernel) {
128 struct kdbus_cmd_name *n;
132 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
133 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
134 memcpy(n->name, name, l+1);
136 #ifdef HAVE_VALGRIND_MEMCHECK_H
137 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
139 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
145 r = sd_bus_call_method(
147 "org.freedesktop.DBus",
149 "org.freedesktop.DBus",
158 r = sd_bus_message_read(reply, "u", &ret);
166 _public_ int sd_bus_list_names(sd_bus *bus, char ***l) {
167 _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
171 assert_return(bus, -EINVAL);
172 assert_return(l, -EINVAL);
173 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
174 assert_return(!bus_pid_changed(bus), -ECHILD);
176 if (bus->is_kernel) {
177 _cleanup_free_ struct kdbus_cmd_name_list *cmd = NULL;
178 struct kdbus_name_list *name_list;
179 struct kdbus_cmd_name *name;
181 cmd = malloc0(sizeof(struct kdbus_cmd_name_list *));
185 cmd->flags = KDBUS_NAME_LIST_UNIQUE_NAMES;
187 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, cmd);
191 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
193 KDBUS_PART_FOREACH(name, name_list, names) {
196 if (name->size > sizeof(*name))
199 asprintf(&n, ":1.%llu", (unsigned long long) name->id);
201 r = strv_extend(&x, n);
206 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd->offset);
212 r = sd_bus_call_method(
214 "org.freedesktop.DBus",
216 "org.freedesktop.DBus",
224 r = sd_bus_call_method(
226 "org.freedesktop.DBus",
228 "org.freedesktop.DBus",
229 "ListActivatableNames",
236 r = bus_message_read_strv_extend(reply1, &x);
242 r = bus_message_read_strv_extend(reply2, &x);
254 static int bus_get_owner_dbus(
258 sd_bus_creds **creds) {
260 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
261 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
262 const char *unique = NULL;
266 /* Only query the owner if the caller wants to know it or if
267 * the caller just wants to check whether a name exists */
268 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
269 r = sd_bus_call_method(
271 "org.freedesktop.DBus",
273 "org.freedesktop.DBus",
282 r = sd_bus_message_read(reply_unique, "s", &unique);
292 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
293 c->unique_name = strdup(unique);
297 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
300 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
301 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
302 SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
303 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
304 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
307 r = sd_bus_call_method(
309 "org.freedesktop.DBus",
311 "org.freedesktop.DBus",
312 "GetConnectionUnixProcessID",
316 unique ? unique : name);
320 r = sd_bus_message_read(reply, "u", &u);
325 if (mask & SD_BUS_CREDS_PID) {
327 c->mask |= SD_BUS_CREDS_PID;
330 reply = sd_bus_message_unref(reply);
333 if (mask & SD_BUS_CREDS_UID) {
336 r = sd_bus_call_method(
338 "org.freedesktop.DBus",
340 "org.freedesktop.DBus",
341 "GetConnectionUnixUser",
345 unique ? unique : name);
349 r = sd_bus_message_read(reply, "u", &u);
354 c->mask |= SD_BUS_CREDS_UID;
356 reply = sd_bus_message_unref(reply);
359 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
363 r = sd_bus_call_method(
365 "org.freedesktop.DBus",
367 "org.freedesktop.DBus",
368 "GetConnectionSELinuxSecurityContext",
372 unique ? unique : name);
376 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
380 c->label = strndup(p, sz);
384 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
387 r = bus_creds_add_more(c, mask, pid, 0);
400 static int bus_get_owner_kdbus(
404 sd_bus_creds **creds) {
406 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
407 struct kdbus_cmd_name_info *cmd;
408 struct kdbus_name_info *name_info;
409 struct kdbus_item *item;
414 r = bus_kernel_parse_unique_name(name, &id);
418 size = offsetof(struct kdbus_cmd_name_info, name);
422 size = offsetof(struct kdbus_cmd_name_info, name) + strlen(name) + 1;
424 strcpy(cmd->name, name);
428 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_INFO, cmd);
432 name_info = (struct kdbus_name_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
438 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
439 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) name_info->id) < 0)
442 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
445 KDBUS_PART_FOREACH(item, name_info, items) {
447 switch (item->type) {
449 case KDBUS_ITEM_CREDS:
450 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
451 SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
454 c->uid = item->creds.uid;
455 c->pid = item->creds.pid;
456 c->gid = item->creds.gid;
457 c->tid = item->creds.tid;
458 c->pid_starttime = item->creds.starttime;
463 case KDBUS_ITEM_PID_COMM:
464 if (mask & SD_BUS_CREDS_COMM) {
465 c->comm = strdup(item->str);
471 c->mask |= SD_BUS_CREDS_COMM;
475 case KDBUS_ITEM_TID_COMM:
476 if (mask & SD_BUS_CREDS_TID_COMM) {
477 c->tid_comm = strdup(item->str);
483 c->mask |= SD_BUS_CREDS_TID_COMM;
488 if (mask & SD_BUS_CREDS_EXE) {
489 c->exe = strdup(item->str);
495 c->mask |= SD_BUS_CREDS_EXE;
499 case KDBUS_ITEM_CMDLINE:
500 if (mask & SD_BUS_CREDS_CMDLINE) {
501 c->cmdline_size = item->size - KDBUS_PART_HEADER_SIZE;
502 c->cmdline = memdup(item->data, c->cmdline_size);
508 c->mask |= SD_BUS_CREDS_CMDLINE;
512 case KDBUS_ITEM_CGROUP:
513 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
514 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
515 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
518 c->cgroup = strdup(item->str);
528 case KDBUS_ITEM_CAPS:
529 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
530 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
533 c->capability_size = item->size - KDBUS_PART_HEADER_SIZE;
534 c->capability = memdup(item->data, c->capability_size);
535 if (!c->capability) {
544 case KDBUS_ITEM_SECLABEL:
545 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
546 c->label = strdup(item->str);
552 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
556 case KDBUS_ITEM_AUDIT:
557 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
560 c->audit_session_id = item->audit.sessionid;
561 c->audit_login_uid = item->audit.loginuid;
566 case KDBUS_ITEM_NAMES:
567 if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
568 c->well_known_names_size = item->size - KDBUS_PART_HEADER_SIZE;
569 c->well_known_names = memdup(item->data, c->well_known_names_size);
570 if (!c->well_known_names) {
575 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
589 ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
593 _public_ int sd_bus_get_owner(
597 sd_bus_creds **creds) {
599 assert_return(bus, -EINVAL);
600 assert_return(name, -EINVAL);
601 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
602 assert_return(mask == 0 || creds, -EINVAL);
603 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
604 assert_return(!bus_pid_changed(bus), -ECHILD);
607 return bus_get_owner_kdbus(bus, name, mask, creds);
609 return bus_get_owner_dbus(bus, name, mask, creds);
612 static int add_name_change_match(sd_bus *bus,
615 const char *old_owner,
616 const char *new_owner) {
618 uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
619 int is_name_id = -1, r;
620 struct kdbus_item *item;
624 /* If we encounter a match that could match against
625 * NameOwnerChanged messages, then we need to create
626 * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
627 * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
628 * multiple if the match is underspecified.
630 * The NameOwnerChanged signals take three parameters with
631 * unique or well-known names, but only some forms actually
634 * WELLKNOWN, "", UNIQUE → KDBUS_MATCH_NAME_ADD
635 * WELLKNOWN, UNIQUE, "" → KDBUS_MATCH_NAME_REMOVE
636 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_MATCH_NAME_CHANGE
637 * UNIQUE, "", UNIQUE → KDBUS_MATCH_ID_ADD
638 * UNIQUE, UNIQUE, "" → KDBUS_MATCH_ID_REMOVE
640 * For the latter two the two unique names must be identical.
645 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
651 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
656 if (is_name_id > 0 && old_owner_id != name_id)
661 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
666 if (is_name_id > 0 && new_owner_id != name_id)
670 if (is_name_id <= 0) {
673 /* If the name argument is missing or is a well-known
674 * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
677 l = name ? strlen(name) : 0;
679 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
680 offsetof(struct kdbus_item, name_change) +
681 offsetof(struct kdbus_notify_name_change, name) +
687 struct kdbus_cmd_match match;
693 m.match.cookie = cookie;
694 m.match.src_id = KDBUS_SRC_ID_KERNEL;
696 item = m.match.items;
698 offsetof(struct kdbus_item, name_change) +
699 offsetof(struct kdbus_notify_name_change, name) +
702 item->name_change.old_id = old_owner_id;
703 item->name_change.new_id = new_owner_id;
706 strcpy(item->name_change.name, name);
708 /* If the old name is unset or empty, then
709 * this can match against added names */
710 if (!old_owner || old_owner[0] == 0) {
711 item->type = KDBUS_MATCH_NAME_ADD;
713 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
718 /* If the new name is unset or empty, then
719 * this can match against removed names */
720 if (!new_owner || new_owner[0] == 0) {
721 item->type = KDBUS_MATCH_NAME_REMOVE;
723 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
728 /* If the neither name is explicitly set to
729 * the empty string, then this can match
730 * agains changed names */
731 if (!(old_owner && old_owner[0] == 0) &&
732 !(new_owner && new_owner[0] == 0)) {
733 item->type = KDBUS_MATCH_NAME_CHANGE;
735 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
742 if (is_name_id != 0) {
744 ALIGN8(offsetof(struct kdbus_cmd_match, items) +
745 offsetof(struct kdbus_item, id_change) +
746 sizeof(struct kdbus_notify_id_change));
749 struct kdbus_cmd_match match;
752 /* If the name argument is missing or is a unique
753 * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
759 m.match.cookie = cookie;
760 m.match.src_id = KDBUS_SRC_ID_KERNEL;
762 item = m.match.items;
763 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
764 item->id_change.id = name_id;
766 /* If the old name is unset or empty, then this can
767 * match against added ids */
768 if (!old_owner || old_owner[0] == 0) {
769 item->type = KDBUS_MATCH_ID_ADD;
771 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
776 /* If thew new name is unset or empty, then this can
777 match against removed ids */
778 if (!new_owner || new_owner[0] == 0) {
779 item->type = KDBUS_MATCH_ID_REMOVE;
781 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
790 int bus_add_match_internal(
793 struct bus_match_component *components,
794 unsigned n_components,
802 if (bus->is_kernel) {
803 struct kdbus_cmd_match *m;
804 struct kdbus_item *item;
805 uint64_t bloom[BLOOM_SIZE/8];
807 const char *sender = NULL;
808 size_t sender_length = 0;
809 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
810 bool using_bloom = false;
812 bool matches_name_change = true;
813 const char *name_change_arg[3] = {};
817 sz = offsetof(struct kdbus_cmd_match, items);
819 for (i = 0; i < n_components; i++) {
820 struct bus_match_component *c = &components[i];
824 case BUS_MATCH_SENDER:
825 if (!streq(c->value_str, "org.freedesktop.DBus"))
826 matches_name_change = false;
828 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
833 sender = c->value_str;
834 sender_length = strlen(sender);
835 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
840 case BUS_MATCH_MESSAGE_TYPE:
841 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
842 matches_name_change = false;
844 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
848 case BUS_MATCH_INTERFACE:
849 if (!streq(c->value_str, "org.freedesktop.DBus"))
850 matches_name_change = false;
852 bloom_add_pair(bloom, "interface", c->value_str);
856 case BUS_MATCH_MEMBER:
857 if (!streq(c->value_str, "NameOwnerChanged"))
858 matches_name_change = false;
860 bloom_add_pair(bloom, "member", c->value_str);
865 if (!streq(c->value_str, "/org/freedesktop/DBus"))
866 matches_name_change = false;
868 bloom_add_pair(bloom, "path", c->value_str);
872 case BUS_MATCH_PATH_NAMESPACE:
873 if (!streq(c->value_str, "/")) {
874 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
879 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
880 char buf[sizeof("arg")-1 + 2 + 1];
882 if (c->type - BUS_MATCH_ARG < 3)
883 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
885 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
886 bloom_add_pair(bloom, buf, c->value_str);
891 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
892 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
894 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
895 bloom_add_pair(bloom, buf, c->value_str);
900 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
901 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
903 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
904 bloom_add_pair(bloom, buf, c->value_str);
909 case BUS_MATCH_DESTINATION:
910 /* The bloom filter does not include
911 the destination, since it is only
912 available for broadcast messages
913 which do not carry a destination
914 since they are undirected. */
918 case BUS_MATCH_VALUE:
920 case _BUS_MATCH_NODE_TYPE_MAX:
921 case _BUS_MATCH_NODE_TYPE_INVALID:
922 assert_not_reached("Invalid match type?");
927 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
937 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
938 item->type = KDBUS_MATCH_BLOOM;
939 memcpy(item->data64, bloom, BLOOM_SIZE);
941 item = KDBUS_PART_NEXT(item);
945 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
946 item->type = KDBUS_MATCH_SRC_NAME;
947 memcpy(item->str, sender, sender_length + 1);
950 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
954 if (matches_name_change) {
956 /* If this match could theoretically match
957 * NameOwnerChanged messages, we need to
958 * install a second non-bloom filter explitly
961 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
968 return sd_bus_call_method(
970 "org.freedesktop.DBus",
972 "org.freedesktop.DBus",
980 int bus_remove_match_internal(
990 if (bus->is_kernel) {
991 struct kdbus_cmd_match m;
994 m.size = offsetof(struct kdbus_cmd_match, items);
997 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1004 return sd_bus_call_method(
1006 "org.freedesktop.DBus",
1008 "org.freedesktop.DBus",
1017 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1018 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1022 assert_return(bus, -EINVAL);
1023 assert_return(name, -EINVAL);
1024 assert_return(machine, -EINVAL);
1025 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1026 assert_return(!bus_pid_changed(bus), -ECHILD);
1028 if (streq_ptr(name, bus->unique_name))
1029 return sd_id128_get_machine(machine);
1031 r = sd_bus_message_new_method_call(
1035 "org.freedesktop.DBus.Peer",
1036 "GetMachineId", &m);
1040 r = sd_bus_message_set_no_auto_start(m, true);
1044 r = sd_bus_call(bus, m, 0, NULL, &reply);
1048 r = sd_bus_message_read(reply, "s", &mid);
1052 return sd_id128_from_string(mid, machine);