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 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
591 n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
592 g = newdup(gid_t, item->data32, n);
596 free(c->supplementary_gids);
597 c->supplementary_gids = g;
598 c->n_supplementary_gids = n;
600 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
609 int bus_get_name_creds_kdbus(
613 bool allow_activator,
614 sd_bus_creds **creds) {
616 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
617 struct kdbus_cmd_info *cmd;
618 struct kdbus_info *conn_info;
623 if (streq(name, "org.freedesktop.DBus"))
626 r = bus_kernel_parse_unique_name(name, &id);
630 size = offsetof(struct kdbus_cmd_info, items);
631 cmd = alloca0_align(size, 8);
634 l = strlen(name) + 1;
635 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
636 cmd = alloca0_align(size, 8);
637 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
638 cmd->items[0].type = KDBUS_ITEM_NAME;
639 memcpy(cmd->items[0].str, name, l);
642 /* If augmentation is on, and the bus didn't provide us
643 * the bits we want, then ask for the PID/TID so that we
644 * can read the rest from /proc. */
645 if ((mask & SD_BUS_CREDS_AUGMENT) &&
646 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
647 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
648 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
649 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|
650 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
651 SD_BUS_CREDS_SELINUX_CONTEXT|
652 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
653 mask |= SD_BUS_CREDS_PID;
656 cmd->attach_flags = attach_flags_to_kdbus(mask);
658 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
662 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
664 /* Non-activated names are considered not available */
665 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
679 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
680 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
685 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
688 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
689 them in case the service has no names. This does not mean
690 however that the list of owned names could not be
691 acquired. Hence, let's explicitly clarify that the data is
693 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
695 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
699 r = bus_creds_add_more(c, mask, 0, 0);
711 bus_kernel_cmd_free(bus, cmd->offset);
715 static int bus_get_name_creds_dbus1(
719 sd_bus_creds **creds) {
721 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
722 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
723 const char *unique = NULL;
727 /* Only query the owner if the caller wants to know it or if
728 * the caller just wants to check whether a name exists */
729 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
730 r = sd_bus_call_method(
732 "org.freedesktop.DBus",
733 "/org/freedesktop/DBus",
734 "org.freedesktop.DBus",
743 r = sd_bus_message_read(reply_unique, "s", &unique);
753 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
754 c->unique_name = strdup(unique);
758 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
761 if ((mask & SD_BUS_CREDS_PID) ||
762 ((mask & SD_BUS_CREDS_AUGMENT) &&
763 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
764 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
765 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
766 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|
767 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
768 SD_BUS_CREDS_SELINUX_CONTEXT|
769 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
773 r = sd_bus_call_method(
775 "org.freedesktop.DBus",
776 "/org/freedesktop/DBus",
777 "org.freedesktop.DBus",
778 "GetConnectionUnixProcessID",
782 unique ? unique : name);
786 r = sd_bus_message_read(reply, "u", &u);
791 if (mask & SD_BUS_CREDS_PID) {
793 c->mask |= SD_BUS_CREDS_PID;
796 reply = sd_bus_message_unref(reply);
799 if (mask & SD_BUS_CREDS_EUID) {
802 r = sd_bus_call_method(
804 "org.freedesktop.DBus",
805 "/org/freedesktop/DBus",
806 "org.freedesktop.DBus",
807 "GetConnectionUnixUser",
811 unique ? unique : name);
815 r = sd_bus_message_read(reply, "u", &u);
820 c->mask |= SD_BUS_CREDS_EUID;
822 reply = sd_bus_message_unref(reply);
825 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
826 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
827 const void *p = NULL;
830 r = sd_bus_call_method(
832 "org.freedesktop.DBus",
833 "/org/freedesktop/DBus",
834 "org.freedesktop.DBus",
835 "GetConnectionSELinuxSecurityContext",
839 unique ? unique : name);
841 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
844 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
848 c->label = strndup(p, sz);
852 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
856 r = bus_creds_add_more(c, mask, pid, 0);
869 _public_ int sd_bus_get_name_creds(
873 sd_bus_creds **creds) {
875 assert_return(bus, -EINVAL);
876 assert_return(name, -EINVAL);
877 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
878 assert_return(mask == 0 || creds, -EINVAL);
879 assert_return(!bus_pid_changed(bus), -ECHILD);
880 assert_return(service_name_is_valid(name), -EINVAL);
881 assert_return(bus->bus_client, -ENODATA);
883 if (streq(name, "org.freedesktop.DBus.Local"))
886 if (!BUS_IS_OPEN(bus->state))
890 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
892 return bus_get_name_creds_dbus1(bus, name, mask, creds);
895 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
896 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
897 struct kdbus_cmd_info cmd = {
898 .size = sizeof(struct kdbus_cmd_info),
900 struct kdbus_info *creator_info;
908 /* If augmentation is on, and the bus doesn't didn't allow us
909 * to get the bits we want, then ask for the PID/TID so that we
910 * can read the rest from /proc. */
911 if ((mask & SD_BUS_CREDS_AUGMENT) &&
912 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
913 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
914 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
915 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|
916 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
917 SD_BUS_CREDS_SELINUX_CONTEXT|
918 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
919 mask |= SD_BUS_CREDS_PID;
921 cmd.attach_flags = attach_flags_to_kdbus(mask);
923 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
927 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
929 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
930 bus_kernel_cmd_free(bus, cmd.offset);
934 r = bus_creds_add_more(c, mask, pid, 0);
943 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
944 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
948 if (!bus->ucred_valid && !isempty(bus->label))
955 if (bus->ucred_valid) {
956 if (bus->ucred.pid > 0) {
957 pid = c->pid = bus->ucred.pid;
958 c->mask |= SD_BUS_CREDS_PID & mask;
961 if (bus->ucred.uid != UID_INVALID) {
962 c->euid = bus->ucred.uid;
963 c->mask |= SD_BUS_CREDS_EUID & mask;
966 if (bus->ucred.gid != GID_INVALID) {
967 c->egid = bus->ucred.gid;
968 c->mask |= SD_BUS_CREDS_EGID & mask;
972 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
973 c->label = strdup(bus->label);
977 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
980 r = bus_creds_add_more(c, mask, pid, 0);
989 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
990 assert_return(bus, -EINVAL);
991 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
992 assert_return(ret, -EINVAL);
993 assert_return(!bus_pid_changed(bus), -ECHILD);
995 if (!BUS_IS_OPEN(bus->state))
999 return bus_get_owner_creds_kdbus(bus, mask, ret);
1001 return bus_get_owner_creds_dbus1(bus, mask, ret);
1004 static int add_name_change_match(sd_bus *bus,
1007 const char *old_owner,
1008 const char *new_owner) {
1010 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1011 int is_name_id = -1, r;
1012 struct kdbus_item *item;
1016 /* If we encounter a match that could match against
1017 * NameOwnerChanged messages, then we need to create
1018 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1019 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1020 * multiple if the match is underspecified.
1022 * The NameOwnerChanged signals take three parameters with
1023 * unique or well-known names, but only some forms actually
1026 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1027 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1028 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1029 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1030 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1032 * For the latter two the two unique names must be identical.
1037 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1042 if (!isempty(old_owner)) {
1043 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1048 if (is_name_id > 0 && old_owner_id != name_id)
1051 old_owner_id = KDBUS_MATCH_ID_ANY;
1053 if (!isempty(new_owner)) {
1054 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1059 if (is_name_id > 0 && new_owner_id != name_id)
1062 new_owner_id = KDBUS_MATCH_ID_ANY;
1064 if (is_name_id <= 0) {
1065 struct kdbus_cmd_match *m;
1068 /* If the name argument is missing or is a well-known
1069 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1072 l = name ? strlen(name) + 1 : 0;
1074 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1075 offsetof(struct kdbus_item, name_change) +
1076 offsetof(struct kdbus_notify_name_change, name) +
1079 m = alloca0_align(sz, 8);
1085 offsetof(struct kdbus_item, name_change) +
1086 offsetof(struct kdbus_notify_name_change, name) +
1089 item->name_change.old_id.id = old_owner_id;
1090 item->name_change.new_id.id = new_owner_id;
1093 memcpy(item->name_change.name, name, l);
1095 /* If the old name is unset or empty, then
1096 * this can match against added names */
1097 if (!old_owner || old_owner[0] == 0) {
1098 item->type = KDBUS_ITEM_NAME_ADD;
1100 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1105 /* If the new name is unset or empty, then
1106 * this can match against removed names */
1107 if (!new_owner || new_owner[0] == 0) {
1108 item->type = KDBUS_ITEM_NAME_REMOVE;
1110 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1115 /* The CHANGE match we need in either case, because
1116 * what is reported as a name change by the kernel
1117 * might just be an owner change between starter and
1118 * normal clients. For userspace such a change should
1119 * be considered a removal/addition, hence let's
1120 * subscribe to this unconditionally. */
1121 item->type = KDBUS_ITEM_NAME_CHANGE;
1122 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1127 if (is_name_id != 0) {
1128 struct kdbus_cmd_match *m;
1131 /* If the name argument is missing or is a unique
1132 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1135 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1136 offsetof(struct kdbus_item, id_change) +
1137 sizeof(struct kdbus_notify_id_change));
1139 m = alloca0_align(sz, 8);
1145 offsetof(struct kdbus_item, id_change) +
1146 sizeof(struct kdbus_notify_id_change);
1147 item->id_change.id = name_id;
1149 /* If the old name is unset or empty, then this can
1150 * match against added ids */
1151 if (!old_owner || old_owner[0] == 0) {
1152 item->type = KDBUS_ITEM_ID_ADD;
1154 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1159 /* If thew new name is unset or empty, then this can
1160 * match against removed ids */
1161 if (!new_owner || new_owner[0] == 0) {
1162 item->type = KDBUS_ITEM_ID_REMOVE;
1164 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1173 int bus_add_match_internal_kernel(
1175 struct bus_match_component *components,
1176 unsigned n_components,
1179 struct kdbus_cmd_match *m;
1180 struct kdbus_item *item;
1183 const char *sender = NULL;
1184 size_t sender_length = 0;
1185 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1186 bool using_bloom = false;
1188 bool matches_name_change = true;
1189 const char *name_change_arg[3] = {};
1194 /* Monitor streams don't support matches, make this a NOP */
1195 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1198 bloom = alloca0(bus->bloom_size);
1200 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1202 for (i = 0; i < n_components; i++) {
1203 struct bus_match_component *c = &components[i];
1207 case BUS_MATCH_SENDER:
1208 if (!streq(c->value_str, "org.freedesktop.DBus"))
1209 matches_name_change = false;
1211 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1215 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1217 sender = c->value_str;
1218 sender_length = strlen(sender);
1219 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1224 case BUS_MATCH_MESSAGE_TYPE:
1225 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1226 matches_name_change = false;
1228 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1232 case BUS_MATCH_INTERFACE:
1233 if (!streq(c->value_str, "org.freedesktop.DBus"))
1234 matches_name_change = false;
1236 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1240 case BUS_MATCH_MEMBER:
1241 if (!streq(c->value_str, "NameOwnerChanged"))
1242 matches_name_change = false;
1244 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1248 case BUS_MATCH_PATH:
1249 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1250 matches_name_change = false;
1252 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1256 case BUS_MATCH_PATH_NAMESPACE:
1257 if (!streq(c->value_str, "/")) {
1258 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1263 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1264 char buf[sizeof("arg")-1 + 2 + 1];
1266 if (c->type - BUS_MATCH_ARG < 3)
1267 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1269 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1270 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1275 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1276 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1278 xsprintf(buf, "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1279 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1284 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1285 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1287 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1288 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1293 case BUS_MATCH_DESTINATION:
1294 /* The bloom filter does not include
1295 the destination, since it is only
1296 available for broadcast messages
1297 which do not carry a destination
1298 since they are undirected. */
1301 case BUS_MATCH_ROOT:
1302 case BUS_MATCH_VALUE:
1303 case BUS_MATCH_LEAF:
1304 case _BUS_MATCH_NODE_TYPE_MAX:
1305 case _BUS_MATCH_NODE_TYPE_INVALID:
1306 assert_not_reached("Invalid match type?");
1311 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1313 m = alloca0_align(sz, 8);
1319 if (src_id != KDBUS_MATCH_ID_ANY) {
1320 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1321 item->type = KDBUS_ITEM_ID;
1323 item = KDBUS_ITEM_NEXT(item);
1327 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1328 item->type = KDBUS_ITEM_BLOOM_MASK;
1329 memcpy(item->data64, bloom, bus->bloom_size);
1330 item = KDBUS_ITEM_NEXT(item);
1334 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1335 item->type = KDBUS_ITEM_NAME;
1336 memcpy(item->str, sender, sender_length + 1);
1339 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1343 if (matches_name_change) {
1345 /* If this match could theoretically match
1346 * NameOwnerChanged messages, we need to
1347 * install a second non-bloom filter explitly
1350 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1358 #define internal_match(bus, m) \
1359 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1360 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1363 static int bus_add_match_internal_dbus1(
1365 const char *match) {
1372 e = internal_match(bus, match);
1374 return sd_bus_call_method(
1376 "org.freedesktop.DBus",
1377 "/org/freedesktop/DBus",
1378 "org.freedesktop.DBus",
1386 int bus_add_match_internal(
1389 struct bus_match_component *components,
1390 unsigned n_components,
1396 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1398 return bus_add_match_internal_dbus1(bus, match);
1401 int bus_remove_match_internal_kernel(
1405 struct kdbus_cmd_match m = {
1406 .size = offsetof(struct kdbus_cmd_match, items),
1413 /* Monitor streams don't support matches, make this a NOP */
1414 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1417 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1424 static int bus_remove_match_internal_dbus1(
1426 const char *match) {
1433 e = internal_match(bus, match);
1435 return sd_bus_call_method(
1437 "org.freedesktop.DBus",
1438 "/org/freedesktop/DBus",
1439 "org.freedesktop.DBus",
1447 int bus_remove_match_internal(
1455 return bus_remove_match_internal_kernel(bus, cookie);
1457 return bus_remove_match_internal_dbus1(bus, match);
1460 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1461 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1465 assert_return(bus, -EINVAL);
1466 assert_return(name, -EINVAL);
1467 assert_return(machine, -EINVAL);
1468 assert_return(!bus_pid_changed(bus), -ECHILD);
1469 assert_return(service_name_is_valid(name), -EINVAL);
1471 if (!BUS_IS_OPEN(bus->state))
1474 if (streq_ptr(name, bus->unique_name))
1475 return sd_id128_get_machine(machine);
1477 r = sd_bus_message_new_method_call(
1482 "org.freedesktop.DBus.Peer",
1487 r = sd_bus_message_set_auto_start(m, false);
1491 r = sd_bus_call(bus, m, 0, NULL, &reply);
1495 r = sd_bus_message_read(reply, "s", &mid);
1499 return sd_id128_from_string(mid, machine);