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 _public_ int sd_bus_get_owner(
595 sd_bus_creds **creds) {
597 assert_return(bus, -EINVAL);
598 assert_return(name, -EINVAL);
599 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
600 assert_return(mask == 0 || creds, -EINVAL);
601 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
602 assert_return(!bus_pid_changed(bus), -ECHILD);
604 return sd_bus_get_owner_dbus(bus, name, mask, owner, creds);
607 int bus_add_match_internal(
610 struct bus_match_component *components,
611 unsigned n_components,
619 if (bus->is_kernel) {
620 struct kdbus_cmd_match *m;
621 struct kdbus_item *item;
622 uint64_t bloom[BLOOM_SIZE/8];
624 const char *sender = NULL;
625 size_t sender_length = 0;
626 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
627 bool using_bloom = false;
629 bool matches_name_change = true;
630 const char *name_change_arg[3] = {};
634 sz = offsetof(struct kdbus_cmd_match, items);
636 for (i = 0; i < n_components; i++) {
637 struct bus_match_component *c = &components[i];
641 case BUS_MATCH_SENDER:
642 if (!streq(c->value_str, "org.freedesktop.DBus"))
643 matches_name_change = false;
645 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
650 sender = c->value_str;
651 sender_length = strlen(sender);
652 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
657 case BUS_MATCH_MESSAGE_TYPE:
658 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
659 matches_name_change = false;
661 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
665 case BUS_MATCH_INTERFACE:
666 if (!streq(c->value_str, "org.freedesktop.DBus"))
667 matches_name_change = false;
669 bloom_add_pair(bloom, "interface", c->value_str);
673 case BUS_MATCH_MEMBER:
674 if (!streq(c->value_str, "NameOwnerChanged"))
675 matches_name_change = false;
677 bloom_add_pair(bloom, "member", c->value_str);
682 if (!streq(c->value_str, "/org/freedesktop/DBus"))
683 matches_name_change = false;
685 bloom_add_pair(bloom, "path", c->value_str);
689 case BUS_MATCH_PATH_NAMESPACE:
690 if (!streq(c->value_str, "/")) {
691 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
696 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
697 char buf[sizeof("arg")-1 + 2 + 1];
699 if (c->type - BUS_MATCH_ARG < 3)
700 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
702 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
703 bloom_add_pair(bloom, buf, c->value_str);
708 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
709 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
711 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
712 bloom_add_pair(bloom, buf, c->value_str);
717 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
718 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
720 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
721 bloom_add_pair(bloom, buf, c->value_str);
726 case BUS_MATCH_DESTINATION:
727 /* The bloom filter does not include
728 the destination, since it is only
729 available for broadcast messages
730 which do not carry a destination
731 since they are undirected. */
735 case BUS_MATCH_VALUE:
737 case _BUS_MATCH_NODE_TYPE_MAX:
738 case _BUS_MATCH_NODE_TYPE_INVALID:
739 assert_not_reached("Invalid match type?");
744 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
754 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
755 item->type = KDBUS_MATCH_BLOOM;
756 memcpy(item->data64, bloom, BLOOM_SIZE);
758 item = KDBUS_PART_NEXT(item);
762 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
763 item->type = KDBUS_MATCH_SRC_NAME;
764 memcpy(item->str, sender, sender_length + 1);
767 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
771 if (matches_name_change) {
773 /* If this match could theoretically match
774 * NameOwnerChanged messages, we need to
775 * install a second non-bloom filter explitly
778 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
785 return sd_bus_call_method(
787 "org.freedesktop.DBus",
789 "org.freedesktop.DBus",
797 int bus_remove_match_internal(
807 if (bus->is_kernel) {
808 struct kdbus_cmd_match m;
811 m.size = offsetof(struct kdbus_cmd_match, items);
814 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
821 return sd_bus_call_method(
823 "org.freedesktop.DBus",
825 "org.freedesktop.DBus",
834 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
835 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
839 assert_return(bus, -EINVAL);
840 assert_return(name, -EINVAL);
841 assert_return(machine, -EINVAL);
842 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
843 assert_return(!bus_pid_changed(bus), -ECHILD);
845 if (streq_ptr(name, bus->unique_name))
846 return sd_id128_get_machine(machine);
848 r = sd_bus_message_new_method_call(
852 "org.freedesktop.DBus.Peer",
857 r = sd_bus_message_set_no_auto_start(m, true);
861 r = sd_bus_call(bus, m, 0, NULL, &reply);
865 r = sd_bus_message_read(reply, "s", &mid);
869 return sd_id128_from_string(mid, machine);