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 _public_ int sd_bus_get_owner(
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 assert_return(bus, -EINVAL);
277 assert_return(name, -EINVAL);
278 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
279 assert_return(mask == 0 || creds, -EINVAL);
280 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
281 assert_return(!bus_pid_changed(bus), -ECHILD);
283 /* Only query the owner if the caller wants to know it or if
284 * the caller just wants to check whether a name exists */
285 if (owner || mask == 0) {
288 r = sd_bus_call_method(
290 "org.freedesktop.DBus",
292 "org.freedesktop.DBus",
301 r = sd_bus_message_read(reply, "s", &found);
305 unique = strdup(found);
309 reply = sd_bus_message_unref(reply);
317 if ((mask & SD_BUS_CREDS_PID) ||
318 mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
321 r = sd_bus_call_method(
323 "org.freedesktop.DBus",
325 "org.freedesktop.DBus",
326 "GetConnectionUnixProcessID",
334 r = sd_bus_message_read(reply, "u", &u);
339 if (mask & SD_BUS_CREDS_PID) {
341 c->mask |= SD_BUS_CREDS_PID;
344 reply = sd_bus_message_unref(reply);
347 if (mask & SD_BUS_CREDS_UID) {
350 r = sd_bus_call_method(
352 "org.freedesktop.DBus",
354 "org.freedesktop.DBus",
355 "GetConnectionUnixUser",
363 r = sd_bus_message_read(reply, "u", &u);
368 c->mask |= SD_BUS_CREDS_UID;
370 reply = sd_bus_message_unref(reply);
373 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
377 r = sd_bus_call_method(
379 "org.freedesktop.DBus",
381 "org.freedesktop.DBus",
382 "GetConnectionSELinuxSecurityContext",
390 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
394 c->label = strndup(p, sz);
398 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
401 r = bus_creds_add_more(c, mask, pid, 0);
419 static int add_name_change_match(sd_bus *bus,
422 const char *old_owner,
423 const char *new_owner) {
425 uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
426 int is_name_id = -1, r;
427 struct kdbus_item *item;
431 /* If we encounter a match that could match against
432 * NameOwnerChanged messages, then we need to create
433 * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
434 * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
435 * multiple if the match is underspecified.
437 * The NameOwnerChanged signals take three parameters with
438 * unique or well-known names, but only some forms actually
441 * WELLKNOWN, "", UNIQUE → KDBUS_MATCH_NAME_ADD
442 * WELLKNOWN, UNIQUE, "" → KDBUS_MATCH_NAME_REMOVE
443 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_MATCH_NAME_CHANGE
444 * UNIQUE, "", UNIQUE → KDBUS_MATCH_ID_ADD
445 * UNIQUE, UNIQUE, "" → KDBUS_MATCH_ID_REMOVE
447 * For the latter two the two unique names must be identical.
452 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
458 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
463 if (is_name_id > 0 && old_owner_id != name_id)
468 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
473 if (is_name_id > 0 && new_owner_id != name_id)
477 if (is_name_id <= 0) {
480 /* If the name argument is missing or is a well-known
481 * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
484 l = name ? strlen(name) : 0;
486 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
487 offsetof(struct kdbus_item, name_change) +
488 offsetof(struct kdbus_notify_name_change, name) +
494 struct kdbus_cmd_match match;
500 m.match.cookie = cookie;
501 m.match.src_id = KDBUS_SRC_ID_KERNEL;
503 item = m.match.items;
505 offsetof(struct kdbus_item, name_change) +
506 offsetof(struct kdbus_notify_name_change, name) +
509 item->name_change.old_id = old_owner_id;
510 item->name_change.new_id = new_owner_id;
513 strcpy(item->name_change.name, name);
515 /* If the old name is unset or empty, then
516 * this can match against added names */
517 if (!old_owner || old_owner[0] == 0) {
518 item->type = KDBUS_MATCH_NAME_ADD;
520 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
525 /* If the new name is unset or empty, then
526 * this can match against removed names */
527 if (!new_owner || new_owner[0] == 0) {
528 item->type = KDBUS_MATCH_NAME_REMOVE;
530 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
535 /* If the neither name is explicitly set to
536 * the empty string, then this can match
537 * agains changed names */
538 if (!(old_owner && old_owner[0] == 0) &&
539 !(new_owner && new_owner[0] == 0)) {
540 item->type = KDBUS_MATCH_NAME_CHANGE;
542 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
549 if (is_name_id != 0) {
551 ALIGN8(offsetof(struct kdbus_cmd_match, items) +
552 offsetof(struct kdbus_item, id_change));
555 struct kdbus_cmd_match match;
558 /* If the name argument is missing or is a unique
559 * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
565 m.match.cookie = cookie;
566 m.match.src_id = KDBUS_SRC_ID_KERNEL;
568 item = m.match.items;
569 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
570 item->id_change.id = name_id;
572 /* If the old name is unset or empty, then this can
573 * match against added ids */
574 if (!old_owner || old_owner[0] == 0) {
575 item->type = KDBUS_MATCH_ID_ADD;
577 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
582 /* If thew new name is unset or empty, then this can
583 match against removed ids */
584 if (!new_owner || new_owner[0] == 0) {
585 item->type = KDBUS_MATCH_ID_REMOVE;
587 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
596 int bus_add_match_internal(
599 struct bus_match_component *components,
600 unsigned n_components,
608 if (bus->is_kernel) {
609 struct kdbus_cmd_match *m;
610 struct kdbus_item *item;
611 uint64_t bloom[BLOOM_SIZE/8];
613 const char *sender = NULL;
614 size_t sender_length = 0;
615 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
616 bool using_bloom = false;
618 bool matches_name_change = true;
619 const char *name_change_arg[3] = {};
623 sz = offsetof(struct kdbus_cmd_match, items);
625 for (i = 0; i < n_components; i++) {
626 struct bus_match_component *c = &components[i];
630 case BUS_MATCH_SENDER:
631 if (!streq(c->value_str, "org.freedesktop.DBus"))
632 matches_name_change = false;
634 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
639 sender = c->value_str;
640 sender_length = strlen(sender);
641 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
646 case BUS_MATCH_MESSAGE_TYPE:
647 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
648 matches_name_change = false;
650 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
654 case BUS_MATCH_INTERFACE:
655 if (!streq(c->value_str, "org.freedesktop.DBus"))
656 matches_name_change = false;
658 bloom_add_pair(bloom, "interface", c->value_str);
662 case BUS_MATCH_MEMBER:
663 if (!streq(c->value_str, "NameOwnerChanged"))
664 matches_name_change = false;
666 bloom_add_pair(bloom, "member", c->value_str);
671 if (!streq(c->value_str, "/org/freedesktop/DBus"))
672 matches_name_change = false;
674 bloom_add_pair(bloom, "path", c->value_str);
678 case BUS_MATCH_PATH_NAMESPACE:
679 if (!streq(c->value_str, "/")) {
680 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
685 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
686 char buf[sizeof("arg")-1 + 2 + 1];
688 if (c->type - BUS_MATCH_ARG < 3)
689 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
691 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
692 bloom_add_pair(bloom, buf, c->value_str);
697 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
698 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
700 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
701 bloom_add_pair(bloom, buf, c->value_str);
706 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
707 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
709 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
710 bloom_add_pair(bloom, buf, c->value_str);
715 case BUS_MATCH_DESTINATION:
716 /* The bloom filter does not include
717 the destination, since it is only
718 available for broadcast messages
719 which do not carry a destination
720 since they are undirected. */
724 case BUS_MATCH_VALUE:
726 case _BUS_MATCH_NODE_TYPE_MAX:
727 case _BUS_MATCH_NODE_TYPE_INVALID:
728 assert_not_reached("Invalid match type?");
733 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
743 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
744 item->type = KDBUS_MATCH_BLOOM;
745 memcpy(item->data64, bloom, BLOOM_SIZE);
747 item = KDBUS_PART_NEXT(item);
751 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
752 item->type = KDBUS_MATCH_SRC_NAME;
753 memcpy(item->str, sender, sender_length + 1);
756 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
760 if (matches_name_change) {
762 /* If this match could theoretically match
763 * NameOwnerChanged messages, we need to
764 * install a second non-bloom filter explitly
767 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
774 return sd_bus_call_method(
776 "org.freedesktop.DBus",
778 "org.freedesktop.DBus",
786 int bus_remove_match_internal(
796 if (bus->is_kernel) {
797 struct kdbus_cmd_match m;
800 m.size = offsetof(struct kdbus_cmd_match, items);
803 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
810 return sd_bus_call_method(
812 "org.freedesktop.DBus",
814 "org.freedesktop.DBus",
823 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
824 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
828 assert_return(bus, -EINVAL);
829 assert_return(name, -EINVAL);
830 assert_return(machine, -EINVAL);
831 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
832 assert_return(!bus_pid_changed(bus), -ECHILD);
834 if (streq_ptr(name, bus->unique_name))
835 return sd_id128_get_machine(machine);
837 r = sd_bus_message_new_method_call(
841 "org.freedesktop.DBus.Peer",
846 r = sd_bus_message_set_no_auto_start(m, true);
850 r = sd_bus_call(bus, m, 0, NULL, &reply);
854 r = sd_bus_message_read(reply, "s", &mid);
858 return sd_id128_from_string(mid, machine);