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"
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 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
62 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
63 n = alloca0_align(size, 8);
65 n->flags = request_name_flags_to_kdbus(flags);
67 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
68 n->items[0].type = KDBUS_ITEM_NAME;
69 memcpy(n->items[0].str, name, l);
71 #ifdef HAVE_VALGRIND_MEMCHECK_H
72 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
75 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
79 if (n->return_flags & KDBUS_NAME_IN_QUEUE)
85 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
86 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
87 uint32_t ret, param = 0;
93 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
94 param |= BUS_NAME_ALLOW_REPLACEMENT;
95 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
96 param |= BUS_NAME_REPLACE_EXISTING;
97 if (!(flags & SD_BUS_NAME_QUEUE))
98 param |= BUS_NAME_DO_NOT_QUEUE;
100 r = sd_bus_call_method(
102 "org.freedesktop.DBus",
103 "/org/freedesktop/DBus",
104 "org.freedesktop.DBus",
114 r = sd_bus_message_read(reply, "u", &ret);
118 if (ret == BUS_NAME_ALREADY_OWNER)
120 else if (ret == BUS_NAME_EXISTS)
122 else if (ret == BUS_NAME_IN_QUEUE)
124 else if (ret == BUS_NAME_PRIMARY_OWNER)
130 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
131 assert_return(bus, -EINVAL);
132 assert_return(name, -EINVAL);
133 assert_return(bus->bus_client, -EINVAL);
134 assert_return(!bus_pid_changed(bus), -ECHILD);
135 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
136 assert_return(service_name_is_valid(name), -EINVAL);
137 assert_return(name[0] != ':', -EINVAL);
139 /* Don't allow requesting the special driver and local names */
140 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
143 if (!BUS_IS_OPEN(bus->state))
147 return bus_request_name_kernel(bus, name, flags);
149 return bus_request_name_dbus1(bus, name, flags);
152 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
160 l = strlen(name) + 1;
161 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
162 n = alloca0_align(size, 8);
165 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
166 n->items[0].type = KDBUS_ITEM_NAME;
167 memcpy(n->items[0].str, name, l);
169 #ifdef HAVE_VALGRIND_MEMCHECK_H
170 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
172 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
179 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
180 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
187 r = sd_bus_call_method(
189 "org.freedesktop.DBus",
190 "/org/freedesktop/DBus",
191 "org.freedesktop.DBus",
200 r = sd_bus_message_read(reply, "u", &ret);
203 if (ret == BUS_NAME_NON_EXISTENT)
205 if (ret == BUS_NAME_NOT_OWNER)
207 if (ret == BUS_NAME_RELEASED)
213 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
214 assert_return(bus, -EINVAL);
215 assert_return(name, -EINVAL);
216 assert_return(bus->bus_client, -EINVAL);
217 assert_return(!bus_pid_changed(bus), -ECHILD);
218 assert_return(service_name_is_valid(name), -EINVAL);
219 assert_return(name[0] != ':', -EINVAL);
221 /* Don't allow releasing the special driver and local names */
222 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
225 if (!BUS_IS_OPEN(bus->state))
229 return bus_release_name_kernel(bus, name);
231 return bus_release_name_dbus1(bus, name);
234 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
235 struct kdbus_cmd_list cmd = {
239 struct kdbus_info *name_list, *name;
240 uint64_t previous_id = 0;
243 /* Caller will free half-constructed list on failure... */
245 r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
249 name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
251 KDBUS_FOREACH(name, name_list, cmd.list_size) {
253 struct kdbus_item *item;
254 const char *entry_name = NULL;
256 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) {
259 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
264 r = strv_consume(x, n);
268 previous_id = name->id;
271 KDBUS_ITEM_FOREACH(item, name, items)
272 if (item->type == KDBUS_ITEM_OWNED_NAME)
273 entry_name = item->name.name;
275 if (entry_name && service_name_is_valid(entry_name)) {
276 r = strv_extend(x, entry_name);
287 bus_kernel_cmd_free(bus, cmd.offset);
291 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
292 _cleanup_strv_free_ char **x = NULL, **y = NULL;
296 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
302 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
318 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
319 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
320 _cleanup_strv_free_ char **x = NULL, **y = NULL;
324 r = sd_bus_call_method(
326 "org.freedesktop.DBus",
327 "/org/freedesktop/DBus",
328 "org.freedesktop.DBus",
336 r = sd_bus_message_read_strv(reply, &x);
340 reply = sd_bus_message_unref(reply);
344 r = sd_bus_call_method(
346 "org.freedesktop.DBus",
347 "/org/freedesktop/DBus",
348 "org.freedesktop.DBus",
349 "ListActivatableNames",
356 r = sd_bus_message_read_strv(reply, &y);
372 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
373 assert_return(bus, -EINVAL);
374 assert_return(acquired || activatable, -EINVAL);
375 assert_return(!bus_pid_changed(bus), -ECHILD);
377 if (!BUS_IS_OPEN(bus->state))
381 return bus_list_names_kernel(bus, acquired, activatable);
383 return bus_list_names_dbus1(bus, acquired, activatable);
386 static int bus_populate_creds_from_items(
388 struct kdbus_info *info,
392 struct kdbus_item *item;
400 KDBUS_ITEM_FOREACH(item, info, items) {
402 switch (item->type) {
404 case KDBUS_ITEM_PIDS:
406 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
407 c->pid = (pid_t) item->pids.pid;
408 c->mask |= SD_BUS_CREDS_PID;
411 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
412 c->tid = (pid_t) item->pids.tid;
413 c->mask |= SD_BUS_CREDS_TID;
418 case KDBUS_ITEM_CREDS:
420 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
421 c->uid = (uid_t) item->creds.uid;
422 c->mask |= SD_BUS_CREDS_UID;
425 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
426 c->euid = (uid_t) item->creds.euid;
427 c->mask |= SD_BUS_CREDS_EUID;
430 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
431 c->suid = (uid_t) item->creds.suid;
432 c->mask |= SD_BUS_CREDS_SUID;
435 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
436 c->fsuid = (uid_t) item->creds.fsuid;
437 c->mask |= SD_BUS_CREDS_FSUID;
440 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
441 c->gid = (gid_t) item->creds.gid;
442 c->mask |= SD_BUS_CREDS_GID;
445 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
446 c->egid = (gid_t) item->creds.egid;
447 c->mask |= SD_BUS_CREDS_EGID;
450 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
451 c->sgid = (gid_t) item->creds.sgid;
452 c->mask |= SD_BUS_CREDS_SGID;
455 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
456 c->fsgid = (gid_t) item->creds.fsgid;
457 c->mask |= SD_BUS_CREDS_FSGID;
462 case KDBUS_ITEM_PID_COMM:
463 if (mask & SD_BUS_CREDS_COMM) {
464 r = free_and_strdup(&c->comm, item->str);
468 c->mask |= SD_BUS_CREDS_COMM;
472 case KDBUS_ITEM_TID_COMM:
473 if (mask & SD_BUS_CREDS_TID_COMM) {
474 r = free_and_strdup(&c->tid_comm, item->str);
478 c->mask |= SD_BUS_CREDS_TID_COMM;
483 if (mask & SD_BUS_CREDS_EXE) {
484 r = free_and_strdup(&c->exe, item->str);
488 c->mask |= SD_BUS_CREDS_EXE;
492 case KDBUS_ITEM_CMDLINE:
493 if (mask & SD_BUS_CREDS_CMDLINE) {
494 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
495 c->cmdline = memdup(item->data, c->cmdline_size);
499 c->mask |= SD_BUS_CREDS_CMDLINE;
503 case KDBUS_ITEM_CGROUP:
504 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
505 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
506 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
509 r = free_and_strdup(&c->cgroup, item->str);
513 r = bus_get_root_path(bus);
517 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
525 case KDBUS_ITEM_CAPS:
526 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
527 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
530 if (item->caps.last_cap != cap_last_cap() ||
531 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
534 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
542 case KDBUS_ITEM_SECLABEL:
543 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
544 r = free_and_strdup(&c->label, item->str);
548 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
552 case KDBUS_ITEM_AUDIT:
553 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
554 c->audit_session_id = (uint32_t) item->audit.sessionid;
555 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
558 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
559 c->audit_login_uid = (uid_t) item->audit.loginuid;
560 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
564 case KDBUS_ITEM_OWNED_NAME:
565 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
566 r = strv_extend(&c->well_known_names, item->name.name);
570 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
574 case KDBUS_ITEM_CONN_DESCRIPTION:
575 if (mask & SD_BUS_CREDS_DESCRIPTION) {
576 r = free_and_strdup(&c->description, item->str);
580 c->mask |= SD_BUS_CREDS_DESCRIPTION;
584 case KDBUS_ITEM_AUXGROUPS:
585 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
589 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
594 for (i = 0; i < n; i++)
595 g[i] = item->data64[i];
597 free(c->supplementary_gids);
598 c->supplementary_gids = g;
599 c->n_supplementary_gids = n;
601 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
610 int bus_get_name_creds_kdbus(
614 bool allow_activator,
615 sd_bus_creds **creds) {
617 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
618 struct kdbus_cmd_info *cmd;
619 struct kdbus_info *conn_info;
624 if (streq(name, "org.freedesktop.DBus"))
627 r = bus_kernel_parse_unique_name(name, &id);
631 size = offsetof(struct kdbus_cmd_info, items);
632 cmd = alloca0_align(size, 8);
635 l = strlen(name) + 1;
636 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
637 cmd = alloca0_align(size, 8);
638 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
639 cmd->items[0].type = KDBUS_ITEM_NAME;
640 memcpy(cmd->items[0].str, name, l);
643 /* If augmentation is on, and the bus didn't provide us
644 * the bits we want, then ask for the PID/TID so that we
645 * can read the rest from /proc. */
646 if ((mask & SD_BUS_CREDS_AUGMENT) &&
647 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
648 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
649 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
650 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|
651 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
652 SD_BUS_CREDS_SELINUX_CONTEXT|
653 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
654 mask |= SD_BUS_CREDS_PID;
657 cmd->attach_flags = attach_flags_to_kdbus(mask);
659 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
663 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
665 /* Non-activated names are considered not available */
666 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
680 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
681 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
686 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
689 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
690 them in case the service has no names. This does not mean
691 however that the list of owned names could not be
692 acquired. Hence, let's explicitly clarify that the data is
694 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
696 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
700 r = bus_creds_add_more(c, mask, 0, 0);
712 bus_kernel_cmd_free(bus, cmd->offset);
716 static int bus_get_name_creds_dbus1(
720 sd_bus_creds **creds) {
722 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
723 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
724 const char *unique = NULL;
728 /* Only query the owner if the caller wants to know it or if
729 * the caller just wants to check whether a name exists */
730 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
731 r = sd_bus_call_method(
733 "org.freedesktop.DBus",
734 "/org/freedesktop/DBus",
735 "org.freedesktop.DBus",
744 r = sd_bus_message_read(reply_unique, "s", &unique);
754 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
755 c->unique_name = strdup(unique);
759 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
762 if ((mask & SD_BUS_CREDS_PID) ||
763 ((mask & SD_BUS_CREDS_AUGMENT) &&
764 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
765 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
766 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
767 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|
768 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
769 SD_BUS_CREDS_SELINUX_CONTEXT|
770 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
774 r = sd_bus_call_method(
776 "org.freedesktop.DBus",
777 "/org/freedesktop/DBus",
778 "org.freedesktop.DBus",
779 "GetConnectionUnixProcessID",
783 unique ? unique : name);
787 r = sd_bus_message_read(reply, "u", &u);
792 if (mask & SD_BUS_CREDS_PID) {
794 c->mask |= SD_BUS_CREDS_PID;
797 reply = sd_bus_message_unref(reply);
800 if (mask & SD_BUS_CREDS_EUID) {
803 r = sd_bus_call_method(
805 "org.freedesktop.DBus",
806 "/org/freedesktop/DBus",
807 "org.freedesktop.DBus",
808 "GetConnectionUnixUser",
812 unique ? unique : name);
816 r = sd_bus_message_read(reply, "u", &u);
821 c->mask |= SD_BUS_CREDS_EUID;
823 reply = sd_bus_message_unref(reply);
826 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
827 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
828 const void *p = NULL;
831 r = sd_bus_call_method(
833 "org.freedesktop.DBus",
834 "/org/freedesktop/DBus",
835 "org.freedesktop.DBus",
836 "GetConnectionSELinuxSecurityContext",
840 unique ? unique : name);
842 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
845 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
849 c->label = strndup(p, sz);
853 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
857 r = bus_creds_add_more(c, mask, pid, 0);
870 _public_ int sd_bus_get_name_creds(
874 sd_bus_creds **creds) {
876 assert_return(bus, -EINVAL);
877 assert_return(name, -EINVAL);
878 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
879 assert_return(mask == 0 || creds, -EINVAL);
880 assert_return(!bus_pid_changed(bus), -ECHILD);
881 assert_return(service_name_is_valid(name), -EINVAL);
882 assert_return(bus->bus_client, -ENODATA);
884 if (streq(name, "org.freedesktop.DBus.Local"))
887 if (!BUS_IS_OPEN(bus->state))
891 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
893 return bus_get_name_creds_dbus1(bus, name, mask, creds);
896 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
897 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
898 struct kdbus_cmd_info cmd = {
899 .size = sizeof(struct kdbus_cmd_info),
901 struct kdbus_info *creator_info;
909 /* If augmentation is on, and the bus doesn't didn't allow us
910 * to get the bits we want, then ask for the PID/TID so that we
911 * can read the rest from /proc. */
912 if ((mask & SD_BUS_CREDS_AUGMENT) &&
913 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
914 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
915 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
916 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|
917 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
918 SD_BUS_CREDS_SELINUX_CONTEXT|
919 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
920 mask |= SD_BUS_CREDS_PID;
922 cmd.attach_flags = attach_flags_to_kdbus(mask);
924 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
928 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
930 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
931 bus_kernel_cmd_free(bus, cmd.offset);
935 r = bus_creds_add_more(c, mask, pid, 0);
944 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
945 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
949 if (!bus->ucred_valid && !isempty(bus->label))
956 if (bus->ucred_valid) {
957 if (bus->ucred.pid > 0) {
958 pid = c->pid = bus->ucred.pid;
959 c->mask |= SD_BUS_CREDS_PID & mask;
962 if (bus->ucred.uid != UID_INVALID) {
963 c->euid = bus->ucred.uid;
964 c->mask |= SD_BUS_CREDS_EUID & mask;
967 if (bus->ucred.gid != GID_INVALID) {
968 c->egid = bus->ucred.gid;
969 c->mask |= SD_BUS_CREDS_EGID & mask;
973 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
974 c->label = strdup(bus->label);
978 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
981 r = bus_creds_add_more(c, mask, pid, 0);
990 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
991 assert_return(bus, -EINVAL);
992 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
993 assert_return(ret, -EINVAL);
994 assert_return(!bus_pid_changed(bus), -ECHILD);
996 if (!BUS_IS_OPEN(bus->state))
1000 return bus_get_owner_creds_kdbus(bus, mask, ret);
1002 return bus_get_owner_creds_dbus1(bus, mask, ret);
1005 static int add_name_change_match(sd_bus *bus,
1008 const char *old_owner,
1009 const char *new_owner) {
1011 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1012 int is_name_id = -1, r;
1013 struct kdbus_item *item;
1017 /* If we encounter a match that could match against
1018 * NameOwnerChanged messages, then we need to create
1019 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1020 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1021 * multiple if the match is underspecified.
1023 * The NameOwnerChanged signals take three parameters with
1024 * unique or well-known names, but only some forms actually
1027 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1028 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1029 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1030 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1031 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1033 * For the latter two the two unique names must be identical.
1038 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1043 if (!isempty(old_owner)) {
1044 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1049 if (is_name_id > 0 && old_owner_id != name_id)
1052 old_owner_id = KDBUS_MATCH_ID_ANY;
1054 if (!isempty(new_owner)) {
1055 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1060 if (is_name_id > 0 && new_owner_id != name_id)
1063 new_owner_id = KDBUS_MATCH_ID_ANY;
1065 if (is_name_id <= 0) {
1066 struct kdbus_cmd_match *m;
1069 /* If the name argument is missing or is a well-known
1070 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1073 l = name ? strlen(name) + 1 : 0;
1075 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1076 offsetof(struct kdbus_item, name_change) +
1077 offsetof(struct kdbus_notify_name_change, name) +
1080 m = alloca0_align(sz, 8);
1086 offsetof(struct kdbus_item, name_change) +
1087 offsetof(struct kdbus_notify_name_change, name) +
1090 item->name_change.old_id.id = old_owner_id;
1091 item->name_change.new_id.id = new_owner_id;
1094 memcpy(item->name_change.name, name, l);
1096 /* If the old name is unset or empty, then
1097 * this can match against added names */
1098 if (!old_owner || old_owner[0] == 0) {
1099 item->type = KDBUS_ITEM_NAME_ADD;
1101 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1106 /* If the new name is unset or empty, then
1107 * this can match against removed names */
1108 if (!new_owner || new_owner[0] == 0) {
1109 item->type = KDBUS_ITEM_NAME_REMOVE;
1111 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1116 /* The CHANGE match we need in either case, because
1117 * what is reported as a name change by the kernel
1118 * might just be an owner change between starter and
1119 * normal clients. For userspace such a change should
1120 * be considered a removal/addition, hence let's
1121 * subscribe to this unconditionally. */
1122 item->type = KDBUS_ITEM_NAME_CHANGE;
1123 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1128 if (is_name_id != 0) {
1129 struct kdbus_cmd_match *m;
1132 /* If the name argument is missing or is a unique
1133 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1136 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1137 offsetof(struct kdbus_item, id_change) +
1138 sizeof(struct kdbus_notify_id_change));
1140 m = alloca0_align(sz, 8);
1146 offsetof(struct kdbus_item, id_change) +
1147 sizeof(struct kdbus_notify_id_change);
1148 item->id_change.id = name_id;
1150 /* If the old name is unset or empty, then this can
1151 * match against added ids */
1152 if (!old_owner || old_owner[0] == 0) {
1153 item->type = KDBUS_ITEM_ID_ADD;
1155 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1160 /* If thew new name is unset or empty, then this can
1161 * match against removed ids */
1162 if (!new_owner || new_owner[0] == 0) {
1163 item->type = KDBUS_ITEM_ID_REMOVE;
1165 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1174 int bus_add_match_internal_kernel(
1176 struct bus_match_component *components,
1177 unsigned n_components,
1180 struct kdbus_cmd_match *m;
1181 struct kdbus_item *item;
1184 const char *sender = NULL;
1185 size_t sender_length = 0;
1186 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1187 bool using_bloom = false;
1189 bool matches_name_change = true;
1190 const char *name_change_arg[3] = {};
1195 /* Monitor streams don't support matches, make this a NOP */
1196 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1199 bloom = alloca0(bus->bloom_size);
1201 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1203 for (i = 0; i < n_components; i++) {
1204 struct bus_match_component *c = &components[i];
1208 case BUS_MATCH_SENDER:
1209 if (!streq(c->value_str, "org.freedesktop.DBus"))
1210 matches_name_change = false;
1212 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1216 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1218 sender = c->value_str;
1219 sender_length = strlen(sender);
1220 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1225 case BUS_MATCH_MESSAGE_TYPE:
1226 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1227 matches_name_change = false;
1229 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1233 case BUS_MATCH_INTERFACE:
1234 if (!streq(c->value_str, "org.freedesktop.DBus"))
1235 matches_name_change = false;
1237 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1241 case BUS_MATCH_MEMBER:
1242 if (!streq(c->value_str, "NameOwnerChanged"))
1243 matches_name_change = false;
1245 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1249 case BUS_MATCH_PATH:
1250 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1251 matches_name_change = false;
1253 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1257 case BUS_MATCH_PATH_NAMESPACE:
1258 if (!streq(c->value_str, "/")) {
1259 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1264 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1265 char buf[sizeof("arg")-1 + 2 + 1];
1267 if (c->type - BUS_MATCH_ARG < 3)
1268 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1270 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1271 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1276 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1277 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1279 xsprintf(buf, "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1280 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1285 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1286 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1288 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1289 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1294 case BUS_MATCH_DESTINATION:
1295 /* The bloom filter does not include
1296 the destination, since it is only
1297 available for broadcast messages
1298 which do not carry a destination
1299 since they are undirected. */
1302 case BUS_MATCH_ROOT:
1303 case BUS_MATCH_VALUE:
1304 case BUS_MATCH_LEAF:
1305 case _BUS_MATCH_NODE_TYPE_MAX:
1306 case _BUS_MATCH_NODE_TYPE_INVALID:
1307 assert_not_reached("Invalid match type?");
1312 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1314 m = alloca0_align(sz, 8);
1320 if (src_id != KDBUS_MATCH_ID_ANY) {
1321 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1322 item->type = KDBUS_ITEM_ID;
1324 item = KDBUS_ITEM_NEXT(item);
1328 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1329 item->type = KDBUS_ITEM_BLOOM_MASK;
1330 memcpy(item->data64, bloom, bus->bloom_size);
1331 item = KDBUS_ITEM_NEXT(item);
1335 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1336 item->type = KDBUS_ITEM_NAME;
1337 memcpy(item->str, sender, sender_length + 1);
1340 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1344 if (matches_name_change) {
1346 /* If this match could theoretically match
1347 * NameOwnerChanged messages, we need to
1348 * install a second non-bloom filter explitly
1351 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1359 #define internal_match(bus, m) \
1360 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1361 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1364 static int bus_add_match_internal_dbus1(
1366 const char *match) {
1373 e = internal_match(bus, match);
1375 return sd_bus_call_method(
1377 "org.freedesktop.DBus",
1378 "/org/freedesktop/DBus",
1379 "org.freedesktop.DBus",
1387 int bus_add_match_internal(
1390 struct bus_match_component *components,
1391 unsigned n_components,
1397 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1399 return bus_add_match_internal_dbus1(bus, match);
1402 int bus_remove_match_internal_kernel(
1406 struct kdbus_cmd_match m = {
1407 .size = offsetof(struct kdbus_cmd_match, items),
1414 /* Monitor streams don't support matches, make this a NOP */
1415 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1418 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1425 static int bus_remove_match_internal_dbus1(
1427 const char *match) {
1434 e = internal_match(bus, match);
1436 return sd_bus_call_method(
1438 "org.freedesktop.DBus",
1439 "/org/freedesktop/DBus",
1440 "org.freedesktop.DBus",
1448 int bus_remove_match_internal(
1456 return bus_remove_match_internal_kernel(bus, cookie);
1458 return bus_remove_match_internal_dbus1(bus, match);
1461 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1462 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1466 assert_return(bus, -EINVAL);
1467 assert_return(name, -EINVAL);
1468 assert_return(machine, -EINVAL);
1469 assert_return(!bus_pid_changed(bus), -ECHILD);
1470 assert_return(service_name_is_valid(name), -EINVAL);
1472 if (!BUS_IS_OPEN(bus->state))
1475 if (streq_ptr(name, bus->unique_name))
1476 return sd_id128_get_machine(machine);
1478 r = sd_bus_message_new_method_call(
1483 "org.freedesktop.DBus.Peer",
1488 r = sd_bus_message_set_auto_start(m, false);
1492 r = sd_bus_call(bus, m, 0, NULL, &reply);
1496 r = sd_bus_message_read(reply, "s", &mid);
1500 return sd_id128_from_string(mid, machine);