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>
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-control.h"
34 #include "bus-bloom.h"
36 #include "capability.h"
37 #include "cgroup-util.h"
39 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
42 assert_return(bus, -EINVAL);
43 assert_return(unique, -EINVAL);
44 assert_return(!bus_pid_changed(bus), -ECHILD);
46 r = bus_ensure_running(bus);
50 *unique = bus->unique_name;
54 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
55 struct kdbus_cmd_name *n;
63 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
64 n = alloca0_align(size, 8);
66 n->flags = request_name_flags_to_kdbus(flags);
68 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
69 n->items[0].type = KDBUS_ITEM_NAME;
70 memcpy(n->items[0].str, name, l);
72 #ifdef HAVE_VALGRIND_MEMCHECK_H
73 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
76 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
80 if (n->flags & KDBUS_NAME_IN_QUEUE)
86 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
87 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
88 uint32_t ret, param = 0;
94 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
95 param |= BUS_NAME_ALLOW_REPLACEMENT;
96 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
97 param |= BUS_NAME_REPLACE_EXISTING;
98 if (!(flags & SD_BUS_NAME_QUEUE))
99 param |= BUS_NAME_DO_NOT_QUEUE;
101 r = sd_bus_call_method(
103 "org.freedesktop.DBus",
104 "/org/freedesktop/DBus",
105 "org.freedesktop.DBus",
115 r = sd_bus_message_read(reply, "u", &ret);
119 if (ret == BUS_NAME_ALREADY_OWNER)
121 else if (ret == BUS_NAME_EXISTS)
123 else if (ret == BUS_NAME_IN_QUEUE)
125 else if (ret == BUS_NAME_PRIMARY_OWNER)
131 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
132 assert_return(bus, -EINVAL);
133 assert_return(name, -EINVAL);
134 assert_return(bus->bus_client, -EINVAL);
135 assert_return(!bus_pid_changed(bus), -ECHILD);
136 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
137 assert_return(service_name_is_valid(name), -EINVAL);
138 assert_return(name[0] != ':', -EINVAL);
140 /* Don't allow requesting the special driver and local names */
141 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
144 if (!BUS_IS_OPEN(bus->state))
148 return bus_request_name_kernel(bus, name, flags);
150 return bus_request_name_dbus1(bus, name, flags);
153 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
154 struct kdbus_cmd_name *n;
161 l = strlen(name) + 1;
162 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
163 n = alloca0_align(size, 8);
166 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
167 n->items[0].type = KDBUS_ITEM_NAME;
168 memcpy(n->items[0].str, name, l);
170 #ifdef HAVE_VALGRIND_MEMCHECK_H
171 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
173 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
180 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
181 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
188 r = sd_bus_call_method(
190 "org.freedesktop.DBus",
191 "/org/freedesktop/DBus",
192 "org.freedesktop.DBus",
201 r = sd_bus_message_read(reply, "u", &ret);
204 if (ret == BUS_NAME_NON_EXISTENT)
206 if (ret == BUS_NAME_NOT_OWNER)
208 if (ret == BUS_NAME_RELEASED)
214 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
215 assert_return(bus, -EINVAL);
216 assert_return(name, -EINVAL);
217 assert_return(bus->bus_client, -EINVAL);
218 assert_return(!bus_pid_changed(bus), -ECHILD);
219 assert_return(service_name_is_valid(name), -EINVAL);
220 assert_return(name[0] != ':', -EINVAL);
222 /* Don't allow releasing the special driver and local names */
223 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
226 if (!BUS_IS_OPEN(bus->state))
230 return bus_release_name_kernel(bus, name);
232 return bus_release_name_dbus1(bus, name);
235 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
236 struct kdbus_cmd_name_list cmd = {};
237 struct kdbus_name_list *name_list;
238 struct kdbus_name_info *name;
239 uint64_t previous_id = 0;
242 /* Caller will free half-constructed list on failure... */
244 cmd.size = sizeof(cmd);
247 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
251 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
253 KDBUS_ITEM_FOREACH(name, name_list, names) {
255 struct kdbus_item *item;
256 const char *entry_name = NULL;
258 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
261 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
266 r = strv_consume(x, n);
270 previous_id = name->owner_id;
273 KDBUS_ITEM_FOREACH(item, name, items)
274 if (item->type == KDBUS_ITEM_OWNED_NAME)
275 entry_name = item->name.name;
277 if (entry_name && service_name_is_valid(entry_name)) {
278 r = strv_extend(x, entry_name);
289 bus_kernel_cmd_free(bus, cmd.offset);
293 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
294 _cleanup_strv_free_ char **x = NULL, **y = NULL;
298 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
304 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
320 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
321 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
322 _cleanup_strv_free_ char **x = NULL, **y = NULL;
326 r = sd_bus_call_method(
328 "org.freedesktop.DBus",
329 "/org/freedesktop/DBus",
330 "org.freedesktop.DBus",
338 r = sd_bus_message_read_strv(reply, &x);
342 reply = sd_bus_message_unref(reply);
346 r = sd_bus_call_method(
348 "org.freedesktop.DBus",
349 "/org/freedesktop/DBus",
350 "org.freedesktop.DBus",
351 "ListActivatableNames",
358 r = sd_bus_message_read_strv(reply, &y);
374 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
375 assert_return(bus, -EINVAL);
376 assert_return(acquired || activatable, -EINVAL);
377 assert_return(!bus_pid_changed(bus), -ECHILD);
379 if (!BUS_IS_OPEN(bus->state))
383 return bus_list_names_kernel(bus, acquired, activatable);
385 return bus_list_names_dbus1(bus, acquired, activatable);
388 static int bus_populate_creds_from_items(
390 struct kdbus_info *info,
394 struct kdbus_item *item;
402 KDBUS_ITEM_FOREACH(item, info, items) {
404 switch (item->type) {
406 case KDBUS_ITEM_PIDS:
408 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
409 c->pid = (pid_t) item->pids.pid;
410 c->mask |= SD_BUS_CREDS_PID;
413 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
414 c->tid = (pid_t) item->pids.tid;
415 c->mask |= SD_BUS_CREDS_TID;
420 case KDBUS_ITEM_CREDS:
422 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
423 c->uid = (uid_t) item->creds.uid;
424 c->mask |= SD_BUS_CREDS_UID;
427 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
428 c->euid = (uid_t) item->creds.euid;
429 c->mask |= SD_BUS_CREDS_EUID;
432 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
433 c->suid = (uid_t) item->creds.suid;
434 c->mask |= SD_BUS_CREDS_SUID;
437 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
438 c->fsuid = (uid_t) item->creds.fsuid;
439 c->mask |= SD_BUS_CREDS_FSUID;
442 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
443 c->gid = (gid_t) item->creds.gid;
444 c->mask |= SD_BUS_CREDS_GID;
447 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
448 c->egid = (gid_t) item->creds.egid;
449 c->mask |= SD_BUS_CREDS_EGID;
452 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
453 c->sgid = (gid_t) item->creds.sgid;
454 c->mask |= SD_BUS_CREDS_SGID;
457 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
458 c->fsgid = (gid_t) item->creds.fsgid;
459 c->mask |= SD_BUS_CREDS_FSGID;
464 case KDBUS_ITEM_PID_COMM:
465 if (mask & SD_BUS_CREDS_COMM) {
466 r = free_and_strdup(&c->comm, item->str);
470 c->mask |= SD_BUS_CREDS_COMM;
474 case KDBUS_ITEM_TID_COMM:
475 if (mask & SD_BUS_CREDS_TID_COMM) {
476 r = free_and_strdup(&c->tid_comm, item->str);
480 c->mask |= SD_BUS_CREDS_TID_COMM;
485 if (mask & SD_BUS_CREDS_EXE) {
486 r = free_and_strdup(&c->exe, item->str);
490 c->mask |= SD_BUS_CREDS_EXE;
494 case KDBUS_ITEM_CMDLINE:
495 if (mask & SD_BUS_CREDS_CMDLINE) {
496 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
497 c->cmdline = memdup(item->data, c->cmdline_size);
501 c->mask |= SD_BUS_CREDS_CMDLINE;
505 case KDBUS_ITEM_CGROUP:
506 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
507 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
508 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
511 r = free_and_strdup(&c->cgroup, item->str);
515 r = bus_get_root_path(bus);
519 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
527 case KDBUS_ITEM_CAPS:
528 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
529 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
532 if (item->caps.last_cap != cap_last_cap() ||
533 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
536 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
544 case KDBUS_ITEM_SECLABEL:
545 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
546 r = free_and_strdup(&c->label, item->str);
550 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
554 case KDBUS_ITEM_AUDIT:
555 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
556 c->audit_session_id = (uint32_t) item->audit.sessionid;
557 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
560 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
561 c->audit_login_uid = (uid_t) item->audit.loginuid;
562 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
566 case KDBUS_ITEM_OWNED_NAME:
567 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
568 r = strv_extend(&c->well_known_names, item->name.name);
572 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
576 case KDBUS_ITEM_CONN_DESCRIPTION:
577 if (mask & SD_BUS_CREDS_DESCRIPTION) {
578 r = free_and_strdup(&c->description, item->str);
582 c->mask |= SD_BUS_CREDS_DESCRIPTION;
586 case KDBUS_ITEM_AUXGROUPS:
587 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
591 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
593 n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
594 g = newdup(gid_t, item->data32, n);
598 free(c->supplementary_gids);
599 c->supplementary_gids = g;
600 c->n_supplementary_gids = n;
602 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
611 int bus_get_name_creds_kdbus(
615 bool allow_activator,
616 sd_bus_creds **creds) {
618 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
619 struct kdbus_cmd_info *cmd;
620 struct kdbus_info *conn_info;
625 if (streq(name, "org.freedesktop.DBus"))
628 r = bus_kernel_parse_unique_name(name, &id);
632 size = offsetof(struct kdbus_cmd_info, items);
633 cmd = alloca0_align(size, 8);
636 l = strlen(name) + 1;
637 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
638 cmd = alloca0_align(size, 8);
639 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
640 cmd->items[0].type = KDBUS_ITEM_NAME;
641 memcpy(cmd->items[0].str, name, l);
644 /* If augmentation is on, and the bus didn't provide us
645 * the bits we want, then ask for the PID/TID so that we
646 * can read the rest from /proc. */
647 if ((mask & SD_BUS_CREDS_AUGMENT) &&
648 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
649 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
650 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
651 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|
652 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
653 SD_BUS_CREDS_SELINUX_CONTEXT|
654 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
655 mask |= SD_BUS_CREDS_PID;
658 cmd->flags = attach_flags_to_kdbus(mask);
660 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
664 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
666 /* Non-activated names are considered not available */
667 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
681 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
682 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
687 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
690 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
691 them in case the service has no names. This does not mean
692 however that the list of owned names could not be
693 acquired. Hence, let's explicitly clarify that the data is
695 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
697 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
701 r = bus_creds_add_more(c, mask, 0, 0);
713 bus_kernel_cmd_free(bus, cmd->offset);
717 static int bus_get_name_creds_dbus1(
721 sd_bus_creds **creds) {
723 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
724 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
725 const char *unique = NULL;
729 /* Only query the owner if the caller wants to know it or if
730 * the caller just wants to check whether a name exists */
731 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
732 r = sd_bus_call_method(
734 "org.freedesktop.DBus",
735 "/org/freedesktop/DBus",
736 "org.freedesktop.DBus",
745 r = sd_bus_message_read(reply_unique, "s", &unique);
755 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
756 c->unique_name = strdup(unique);
760 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
763 if ((mask & SD_BUS_CREDS_PID) ||
764 ((mask & SD_BUS_CREDS_AUGMENT) &&
765 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
766 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
767 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
768 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|
769 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
770 SD_BUS_CREDS_SELINUX_CONTEXT|
771 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
775 r = sd_bus_call_method(
777 "org.freedesktop.DBus",
778 "/org/freedesktop/DBus",
779 "org.freedesktop.DBus",
780 "GetConnectionUnixProcessID",
784 unique ? unique : name);
788 r = sd_bus_message_read(reply, "u", &u);
793 if (mask & SD_BUS_CREDS_PID) {
795 c->mask |= SD_BUS_CREDS_PID;
798 reply = sd_bus_message_unref(reply);
801 if (mask & SD_BUS_CREDS_EUID) {
804 r = sd_bus_call_method(
806 "org.freedesktop.DBus",
807 "/org/freedesktop/DBus",
808 "org.freedesktop.DBus",
809 "GetConnectionUnixUser",
813 unique ? unique : name);
817 r = sd_bus_message_read(reply, "u", &u);
822 c->mask |= SD_BUS_CREDS_EUID;
824 reply = sd_bus_message_unref(reply);
827 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
828 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
829 const void *p = NULL;
832 r = sd_bus_call_method(
834 "org.freedesktop.DBus",
835 "/org/freedesktop/DBus",
836 "org.freedesktop.DBus",
837 "GetConnectionSELinuxSecurityContext",
841 unique ? unique : name);
843 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
846 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
850 c->label = strndup(p, sz);
854 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
858 r = bus_creds_add_more(c, mask, pid, 0);
871 _public_ int sd_bus_get_name_creds(
875 sd_bus_creds **creds) {
877 assert_return(bus, -EINVAL);
878 assert_return(name, -EINVAL);
879 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
880 assert_return(mask == 0 || creds, -EINVAL);
881 assert_return(!bus_pid_changed(bus), -ECHILD);
882 assert_return(service_name_is_valid(name), -EINVAL);
883 assert_return(bus->bus_client, -ENODATA);
885 if (streq(name, "org.freedesktop.DBus.Local"))
888 if (!BUS_IS_OPEN(bus->state))
892 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
894 return bus_get_name_creds_dbus1(bus, name, mask, creds);
897 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
898 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
899 struct kdbus_cmd_info cmd = {
900 .size = sizeof(struct kdbus_cmd_info)
902 struct kdbus_info *creator_info;
910 /* If augmentation is on, and the bus doesn't didn't allow us
911 * to get the bits we want, then ask for the PID/TID so that we
912 * can read the rest from /proc. */
913 if ((mask & SD_BUS_CREDS_AUGMENT) &&
914 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
915 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
916 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
917 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|
918 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
919 SD_BUS_CREDS_SELINUX_CONTEXT|
920 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
921 mask |= SD_BUS_CREDS_PID;
923 cmd.flags = attach_flags_to_kdbus(mask);
925 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
929 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
931 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
932 bus_kernel_cmd_free(bus, cmd.offset);
936 r = bus_creds_add_more(c, mask, pid, 0);
945 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
946 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
950 if (!bus->ucred_valid && !isempty(bus->label))
957 if (bus->ucred_valid) {
958 if (bus->ucred.pid > 0) {
959 pid = c->pid = bus->ucred.pid;
960 c->mask |= SD_BUS_CREDS_PID & mask;
963 if (bus->ucred.uid != UID_INVALID) {
964 c->euid = bus->ucred.uid;
965 c->mask |= SD_BUS_CREDS_EUID & mask;
968 if (bus->ucred.gid != GID_INVALID) {
969 c->egid = bus->ucred.gid;
970 c->mask |= SD_BUS_CREDS_EGID & mask;
974 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
975 c->label = strdup(bus->label);
979 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
982 r = bus_creds_add_more(c, mask, pid, 0);
991 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
992 assert_return(bus, -EINVAL);
993 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
994 assert_return(ret, -EINVAL);
995 assert_return(!bus_pid_changed(bus), -ECHILD);
997 if (!BUS_IS_OPEN(bus->state))
1001 return bus_get_owner_creds_kdbus(bus, mask, ret);
1003 return bus_get_owner_creds_dbus1(bus, mask, ret);
1006 static int add_name_change_match(sd_bus *bus,
1009 const char *old_owner,
1010 const char *new_owner) {
1012 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1013 int is_name_id = -1, r;
1014 struct kdbus_item *item;
1018 /* If we encounter a match that could match against
1019 * NameOwnerChanged messages, then we need to create
1020 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1021 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1022 * multiple if the match is underspecified.
1024 * The NameOwnerChanged signals take three parameters with
1025 * unique or well-known names, but only some forms actually
1028 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1029 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1030 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1031 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1032 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1034 * For the latter two the two unique names must be identical.
1039 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1044 if (!isempty(old_owner)) {
1045 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1050 if (is_name_id > 0 && old_owner_id != name_id)
1053 old_owner_id = KDBUS_MATCH_ID_ANY;
1055 if (!isempty(new_owner)) {
1056 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1061 if (is_name_id > 0 && new_owner_id != name_id)
1064 new_owner_id = KDBUS_MATCH_ID_ANY;
1066 if (is_name_id <= 0) {
1067 struct kdbus_cmd_match *m;
1070 /* If the name argument is missing or is a well-known
1071 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1074 l = name ? strlen(name) + 1 : 0;
1076 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1077 offsetof(struct kdbus_item, name_change) +
1078 offsetof(struct kdbus_notify_name_change, name) +
1081 m = alloca0_align(sz, 8);
1087 offsetof(struct kdbus_item, name_change) +
1088 offsetof(struct kdbus_notify_name_change, name) +
1091 item->name_change.old_id.id = old_owner_id;
1092 item->name_change.new_id.id = new_owner_id;
1095 memcpy(item->name_change.name, name, l);
1097 /* If the old name is unset or empty, then
1098 * this can match against added names */
1099 if (!old_owner || old_owner[0] == 0) {
1100 item->type = KDBUS_ITEM_NAME_ADD;
1102 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1107 /* If the new name is unset or empty, then
1108 * this can match against removed names */
1109 if (!new_owner || new_owner[0] == 0) {
1110 item->type = KDBUS_ITEM_NAME_REMOVE;
1112 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1117 /* The CHANGE match we need in either case, because
1118 * what is reported as a name change by the kernel
1119 * might just be an owner change between starter and
1120 * normal clients. For userspace such a change should
1121 * be considered a removal/addition, hence let's
1122 * subscribe to this unconditionally. */
1123 item->type = KDBUS_ITEM_NAME_CHANGE;
1124 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1129 if (is_name_id != 0) {
1130 struct kdbus_cmd_match *m;
1133 /* If the name argument is missing or is a unique
1134 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1137 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1138 offsetof(struct kdbus_item, id_change) +
1139 sizeof(struct kdbus_notify_id_change));
1141 m = alloca0_align(sz, 8);
1147 offsetof(struct kdbus_item, id_change) +
1148 sizeof(struct kdbus_notify_id_change);
1149 item->id_change.id = name_id;
1151 /* If the old name is unset or empty, then this can
1152 * match against added ids */
1153 if (!old_owner || old_owner[0] == 0) {
1154 item->type = KDBUS_ITEM_ID_ADD;
1156 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1161 /* If thew new name is unset or empty, then this can
1162 * match against removed ids */
1163 if (!new_owner || new_owner[0] == 0) {
1164 item->type = KDBUS_ITEM_ID_REMOVE;
1166 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1175 int bus_add_match_internal_kernel(
1177 struct bus_match_component *components,
1178 unsigned n_components,
1181 struct kdbus_cmd_match *m;
1182 struct kdbus_item *item;
1185 const char *sender = NULL;
1186 size_t sender_length = 0;
1187 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1188 bool using_bloom = false;
1190 bool matches_name_change = true;
1191 const char *name_change_arg[3] = {};
1196 /* Monitor streams don't support matches, make this a NOP */
1197 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1200 bloom = alloca0(bus->bloom_size);
1202 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1204 for (i = 0; i < n_components; i++) {
1205 struct bus_match_component *c = &components[i];
1209 case BUS_MATCH_SENDER:
1210 if (!streq(c->value_str, "org.freedesktop.DBus"))
1211 matches_name_change = false;
1213 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1217 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1219 sender = c->value_str;
1220 sender_length = strlen(sender);
1221 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1226 case BUS_MATCH_MESSAGE_TYPE:
1227 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1228 matches_name_change = false;
1230 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1234 case BUS_MATCH_INTERFACE:
1235 if (!streq(c->value_str, "org.freedesktop.DBus"))
1236 matches_name_change = false;
1238 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1242 case BUS_MATCH_MEMBER:
1243 if (!streq(c->value_str, "NameOwnerChanged"))
1244 matches_name_change = false;
1246 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1250 case BUS_MATCH_PATH:
1251 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1252 matches_name_change = false;
1254 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1258 case BUS_MATCH_PATH_NAMESPACE:
1259 if (!streq(c->value_str, "/")) {
1260 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1265 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1266 char buf[sizeof("arg")-1 + 2 + 1];
1268 if (c->type - BUS_MATCH_ARG < 3)
1269 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1271 snprintf(buf, sizeof(buf), "arg%i", c->type - BUS_MATCH_ARG);
1272 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1277 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1278 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1280 snprintf(buf, sizeof(buf), "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1281 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1286 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1287 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1289 snprintf(buf, sizeof(buf), "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1290 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1295 case BUS_MATCH_DESTINATION:
1296 /* The bloom filter does not include
1297 the destination, since it is only
1298 available for broadcast messages
1299 which do not carry a destination
1300 since they are undirected. */
1303 case BUS_MATCH_ROOT:
1304 case BUS_MATCH_VALUE:
1305 case BUS_MATCH_LEAF:
1306 case _BUS_MATCH_NODE_TYPE_MAX:
1307 case _BUS_MATCH_NODE_TYPE_INVALID:
1308 assert_not_reached("Invalid match type?");
1313 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1315 m = alloca0_align(sz, 8);
1321 if (src_id != KDBUS_MATCH_ID_ANY) {
1322 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1323 item->type = KDBUS_ITEM_ID;
1325 item = KDBUS_ITEM_NEXT(item);
1329 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1330 item->type = KDBUS_ITEM_BLOOM_MASK;
1331 memcpy(item->data64, bloom, bus->bloom_size);
1332 item = KDBUS_ITEM_NEXT(item);
1336 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1337 item->type = KDBUS_ITEM_NAME;
1338 memcpy(item->str, sender, sender_length + 1);
1341 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1345 if (matches_name_change) {
1347 /* If this match could theoretically match
1348 * NameOwnerChanged messages, we need to
1349 * install a second non-bloom filter explitly
1352 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1360 #define internal_match(bus, m) \
1361 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1362 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1365 static int bus_add_match_internal_dbus1(
1367 const char *match) {
1374 e = internal_match(bus, match);
1376 return sd_bus_call_method(
1378 "org.freedesktop.DBus",
1379 "/org/freedesktop/DBus",
1380 "org.freedesktop.DBus",
1388 int bus_add_match_internal(
1391 struct bus_match_component *components,
1392 unsigned n_components,
1398 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1400 return bus_add_match_internal_dbus1(bus, match);
1403 int bus_remove_match_internal_kernel(
1407 struct kdbus_cmd_match m;
1412 /* Monitor streams don't support matches, make this a NOP */
1413 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1417 m.size = offsetof(struct kdbus_cmd_match, items);
1420 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1427 static int bus_remove_match_internal_dbus1(
1429 const char *match) {
1436 e = internal_match(bus, match);
1438 return sd_bus_call_method(
1440 "org.freedesktop.DBus",
1441 "/org/freedesktop/DBus",
1442 "org.freedesktop.DBus",
1450 int bus_remove_match_internal(
1458 return bus_remove_match_internal_kernel(bus, cookie);
1460 return bus_remove_match_internal_dbus1(bus, match);
1463 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1464 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1468 assert_return(bus, -EINVAL);
1469 assert_return(name, -EINVAL);
1470 assert_return(machine, -EINVAL);
1471 assert_return(!bus_pid_changed(bus), -ECHILD);
1472 assert_return(service_name_is_valid(name), -EINVAL);
1474 if (!BUS_IS_OPEN(bus->state))
1477 if (streq_ptr(name, bus->unique_name))
1478 return sd_id128_get_machine(machine);
1480 r = sd_bus_message_new_method_call(
1485 "org.freedesktop.DBus.Peer",
1490 r = sd_bus_message_set_auto_start(m, false);
1494 r = sd_bus_call(bus, m, 0, NULL, &reply);
1498 r = sd_bus_message_read(reply, "s", &mid);
1502 return sd_id128_from_string(mid, machine);