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;
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_names *names = NULL;
178 struct kdbus_cmd_name *name;
181 /* assume 8k size first. If that doesn't suffice, kdbus will tell us
182 * how big the buffer needs to be. */
186 names = realloc(names, size);
191 names->flags = KDBUS_NAME_LIST_UNIQUE_NAMES;
193 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, names);
195 if (errno == ENOBUFS && size != names->size) {
206 KDBUS_PART_FOREACH(name, names, names) {
209 if (name->size > sizeof(*name))
212 asprintf(&n, ":1.%llu", (unsigned long long) name->id);
214 r = strv_extend(&x, n);
221 r = sd_bus_call_method(
223 "org.freedesktop.DBus",
225 "org.freedesktop.DBus",
233 r = sd_bus_call_method(
235 "org.freedesktop.DBus",
237 "org.freedesktop.DBus",
238 "ListActivatableNames",
245 r = bus_message_read_strv_extend(reply1, &x);
251 r = bus_message_read_strv_extend(reply2, &x);
263 static int sd_bus_get_owner_dbus(
268 sd_bus_creds **creds) {
270 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
271 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
272 _cleanup_free_ char *unique = NULL;
276 /* Only query the owner if the caller wants to know it or if
277 * the caller just wants to check whether a name exists */
278 if (owner || mask == 0) {
281 r = sd_bus_call_method(
283 "org.freedesktop.DBus",
285 "org.freedesktop.DBus",
294 r = sd_bus_message_read(reply, "s", &found);
298 unique = strdup(found);
302 reply = sd_bus_message_unref(reply);
310 if ((mask & SD_BUS_CREDS_PID) ||
311 mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
314 r = sd_bus_call_method(
316 "org.freedesktop.DBus",
318 "org.freedesktop.DBus",
319 "GetConnectionUnixProcessID",
327 r = sd_bus_message_read(reply, "u", &u);
332 if (mask & SD_BUS_CREDS_PID) {
334 c->mask |= SD_BUS_CREDS_PID;
337 reply = sd_bus_message_unref(reply);
340 if (mask & SD_BUS_CREDS_UID) {
343 r = sd_bus_call_method(
345 "org.freedesktop.DBus",
347 "org.freedesktop.DBus",
348 "GetConnectionUnixUser",
356 r = sd_bus_message_read(reply, "u", &u);
361 c->mask |= SD_BUS_CREDS_UID;
363 reply = sd_bus_message_unref(reply);
366 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
370 r = sd_bus_call_method(
372 "org.freedesktop.DBus",
374 "org.freedesktop.DBus",
375 "GetConnectionSELinuxSecurityContext",
383 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
387 c->label = strndup(p, sz);
391 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
394 r = bus_creds_add_more(c, mask, pid, 0);
412 static int add_name_change_match(sd_bus *bus,
415 const char *old_owner,
416 const char *new_owner) {
418 uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
419 int is_name_id = -1, r;
420 struct kdbus_item *item;
424 /* If we encounter a match that could match against
425 * NameOwnerChanged messages, then we need to create
426 * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
427 * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
428 * multiple if the match is underspecified.
430 * The NameOwnerChanged signals take three parameters with
431 * unique or well-known names, but only some forms actually
434 * WELLKNOWN, "", UNIQUE → KDBUS_MATCH_NAME_ADD
435 * WELLKNOWN, UNIQUE, "" → KDBUS_MATCH_NAME_REMOVE
436 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_MATCH_NAME_CHANGE
437 * UNIQUE, "", UNIQUE → KDBUS_MATCH_ID_ADD
438 * UNIQUE, UNIQUE, "" → KDBUS_MATCH_ID_REMOVE
440 * For the latter two the two unique names must be identical.
445 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
451 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
456 if (is_name_id > 0 && old_owner_id != name_id)
461 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
466 if (is_name_id > 0 && new_owner_id != name_id)
470 if (is_name_id <= 0) {
473 /* If the name argument is missing or is a well-known
474 * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
477 l = name ? strlen(name) : 0;
479 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
480 offsetof(struct kdbus_item, name_change) +
481 offsetof(struct kdbus_notify_name_change, name) +
487 struct kdbus_cmd_match match;
493 m.match.cookie = cookie;
494 m.match.src_id = KDBUS_SRC_ID_KERNEL;
496 item = m.match.items;
498 offsetof(struct kdbus_item, name_change) +
499 offsetof(struct kdbus_notify_name_change, name) +
502 item->name_change.old_id = old_owner_id;
503 item->name_change.new_id = new_owner_id;
506 strcpy(item->name_change.name, name);
508 /* If the old name is unset or empty, then
509 * this can match against added names */
510 if (!old_owner || old_owner[0] == 0) {
511 item->type = KDBUS_MATCH_NAME_ADD;
513 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
518 /* If the new name is unset or empty, then
519 * this can match against removed names */
520 if (!new_owner || new_owner[0] == 0) {
521 item->type = KDBUS_MATCH_NAME_REMOVE;
523 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
528 /* If the neither name is explicitly set to
529 * the empty string, then this can match
530 * agains changed names */
531 if (!(old_owner && old_owner[0] == 0) &&
532 !(new_owner && new_owner[0] == 0)) {
533 item->type = KDBUS_MATCH_NAME_CHANGE;
535 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
542 if (is_name_id != 0) {
544 ALIGN8(offsetof(struct kdbus_cmd_match, items) +
545 offsetof(struct kdbus_item, id_change) +
546 sizeof(struct kdbus_notify_id_change));
549 struct kdbus_cmd_match match;
552 /* If the name argument is missing or is a unique
553 * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
559 m.match.cookie = cookie;
560 m.match.src_id = KDBUS_SRC_ID_KERNEL;
562 item = m.match.items;
563 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
564 item->id_change.id = name_id;
566 /* If the old name is unset or empty, then this can
567 * match against added ids */
568 if (!old_owner || old_owner[0] == 0) {
569 item->type = KDBUS_MATCH_ID_ADD;
571 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
576 /* If thew new name is unset or empty, then this can
577 match against removed ids */
578 if (!new_owner || new_owner[0] == 0) {
579 item->type = KDBUS_MATCH_ID_REMOVE;
581 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
590 static int kdbus_name_query(
595 sd_bus_creds **creds) {
597 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
598 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
599 _cleanup_free_ char *unique = NULL;
600 struct kdbus_cmd_name_info *name_info = NULL;
601 struct kdbus_item *item;
602 uint64_t attach_flags, m;
606 r = kdbus_translate_attach_flags(mask, &attach_flags);
610 slen = strlen(name) + 1;
613 * The structure is used for both directions. Start with 8k buffer size and
614 * expand to the size kdbus reports in case we fail.
619 name_info = realloc(name_info, size);
623 memset(name_info, 0, size);
625 name_info->size = size;
626 name_info->attach_flags = attach_flags;
628 item = name_info->items;
629 item->type = KDBUS_NAME_INFO_ITEM_NAME;
630 item->size = KDBUS_ITEM_SIZE(slen);
631 strcpy(item->str, name);
633 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_QUERY, name_info);
635 if (errno == ENOBUFS && size != name_info->size) {
636 size = name_info->size;
646 asprintf(&unique, ":1.%llu", (unsigned long long) name_info->id);
652 KDBUS_PART_FOREACH(item, name_info, items) {
653 switch (item->type) {
654 case KDBUS_ITEM_CREDS:
655 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
656 SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
659 c->uid = item->creds.uid;
660 c->pid = item->creds.pid;
661 c->gid = item->creds.gid;
662 c->tid = item->creds.tid;
663 c->pid_starttime = item->creds.starttime;
668 case KDBUS_ITEM_PID_COMM:
669 if (mask & SD_BUS_CREDS_COMM) {
670 c->comm = strdup(item->str);
674 c->mask |= SD_BUS_CREDS_COMM;
678 case KDBUS_ITEM_TID_COMM:
679 if (mask & SD_BUS_CREDS_TID_COMM) {
680 c->tid_comm = strdup(item->str);
684 c->mask |= SD_BUS_CREDS_TID_COMM;
689 if (mask & SD_BUS_CREDS_EXE) {
690 c->exe = strdup(item->str);
694 c->mask |= SD_BUS_CREDS_EXE;
698 case KDBUS_ITEM_CMDLINE:
699 if (mask & SD_BUS_CREDS_CMDLINE) {
700 c->cmdline_length = item->size - KDBUS_PART_HEADER_SIZE;
701 c->cmdline = memdup(item->data, c->cmdline_length);
705 c->mask |= SD_BUS_CREDS_CMDLINE;
709 case KDBUS_ITEM_CGROUP:
710 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
711 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
712 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
715 c->cgroup = strdup(item->str);
723 case KDBUS_ITEM_CAPS:
724 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
725 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
728 c->capability_size = item->size - KDBUS_PART_HEADER_SIZE;
729 c->capability = memdup(item->data, c->capability_size);
737 case KDBUS_ITEM_SECLABEL:
738 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
739 c->label = strdup(item->str);
743 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
747 case KDBUS_ITEM_AUDIT:
748 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
751 c->audit_session_id = item->audit.sessionid;
752 c->audit_login_uid = item->audit.loginuid;
772 _public_ int sd_bus_get_owner(
777 sd_bus_creds **creds) {
779 assert_return(bus, -EINVAL);
780 assert_return(name, -EINVAL);
781 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
782 assert_return(mask == 0 || creds, -EINVAL);
783 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
784 assert_return(!bus_pid_changed(bus), -ECHILD);
787 return kdbus_name_query(bus, name, mask, owner, creds);
789 return sd_bus_get_owner_dbus(bus, name, mask, owner, creds);
792 int bus_add_match_internal(
795 struct bus_match_component *components,
796 unsigned n_components,
804 if (bus->is_kernel) {
805 struct kdbus_cmd_match *m;
806 struct kdbus_item *item;
807 uint64_t bloom[BLOOM_SIZE/8];
809 const char *sender = NULL;
810 size_t sender_length = 0;
811 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
812 bool using_bloom = false;
814 bool matches_name_change = true;
815 const char *name_change_arg[3] = {};
819 sz = offsetof(struct kdbus_cmd_match, items);
821 for (i = 0; i < n_components; i++) {
822 struct bus_match_component *c = &components[i];
826 case BUS_MATCH_SENDER:
827 if (!streq(c->value_str, "org.freedesktop.DBus"))
828 matches_name_change = false;
830 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
835 sender = c->value_str;
836 sender_length = strlen(sender);
837 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
842 case BUS_MATCH_MESSAGE_TYPE:
843 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
844 matches_name_change = false;
846 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
850 case BUS_MATCH_INTERFACE:
851 if (!streq(c->value_str, "org.freedesktop.DBus"))
852 matches_name_change = false;
854 bloom_add_pair(bloom, "interface", c->value_str);
858 case BUS_MATCH_MEMBER:
859 if (!streq(c->value_str, "NameOwnerChanged"))
860 matches_name_change = false;
862 bloom_add_pair(bloom, "member", c->value_str);
867 if (!streq(c->value_str, "/org/freedesktop/DBus"))
868 matches_name_change = false;
870 bloom_add_pair(bloom, "path", c->value_str);
874 case BUS_MATCH_PATH_NAMESPACE:
875 if (!streq(c->value_str, "/")) {
876 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
881 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
882 char buf[sizeof("arg")-1 + 2 + 1];
884 if (c->type - BUS_MATCH_ARG < 3)
885 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
887 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
888 bloom_add_pair(bloom, buf, c->value_str);
893 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
894 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
896 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
897 bloom_add_pair(bloom, buf, c->value_str);
902 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
903 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
905 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
906 bloom_add_pair(bloom, buf, c->value_str);
911 case BUS_MATCH_DESTINATION:
912 /* The bloom filter does not include
913 the destination, since it is only
914 available for broadcast messages
915 which do not carry a destination
916 since they are undirected. */
920 case BUS_MATCH_VALUE:
922 case _BUS_MATCH_NODE_TYPE_MAX:
923 case _BUS_MATCH_NODE_TYPE_INVALID:
924 assert_not_reached("Invalid match type?");
929 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
939 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
940 item->type = KDBUS_MATCH_BLOOM;
941 memcpy(item->data64, bloom, BLOOM_SIZE);
943 item = KDBUS_PART_NEXT(item);
947 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
948 item->type = KDBUS_MATCH_SRC_NAME;
949 memcpy(item->str, sender, sender_length + 1);
952 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
956 if (matches_name_change) {
958 /* If this match could theoretically match
959 * NameOwnerChanged messages, we need to
960 * install a second non-bloom filter explitly
963 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
970 return sd_bus_call_method(
972 "org.freedesktop.DBus",
974 "org.freedesktop.DBus",
982 int bus_remove_match_internal(
992 if (bus->is_kernel) {
993 struct kdbus_cmd_match m;
996 m.size = offsetof(struct kdbus_cmd_match, items);
999 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1006 return sd_bus_call_method(
1008 "org.freedesktop.DBus",
1010 "org.freedesktop.DBus",
1019 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1020 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1024 assert_return(bus, -EINVAL);
1025 assert_return(name, -EINVAL);
1026 assert_return(machine, -EINVAL);
1027 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1028 assert_return(!bus_pid_changed(bus), -ECHILD);
1030 if (streq_ptr(name, bus->unique_name))
1031 return sd_id128_get_machine(machine);
1033 r = sd_bus_message_new_method_call(
1037 "org.freedesktop.DBus.Peer",
1038 "GetMachineId", &m);
1042 r = sd_bus_message_set_no_auto_start(m, true);
1046 r = sd_bus_call(bus, m, 0, NULL, &reply);
1050 r = sd_bus_message_read(reply, "s", &mid);
1054 return sd_id128_from_string(mid, machine);