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);
48 r = bus_ensure_running(bus);
52 *unique = bus->unique_name;
56 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
65 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
66 n = alloca0_align(size, 8);
68 n->flags = request_name_flags_to_kdbus(flags);
70 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
71 n->items[0].type = KDBUS_ITEM_NAME;
72 memcpy(n->items[0].str, name, l);
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);
82 if (n->return_flags & KDBUS_NAME_IN_QUEUE)
88 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
89 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
90 uint32_t ret, param = 0;
96 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
97 param |= BUS_NAME_ALLOW_REPLACEMENT;
98 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
99 param |= BUS_NAME_REPLACE_EXISTING;
100 if (!(flags & SD_BUS_NAME_QUEUE))
101 param |= BUS_NAME_DO_NOT_QUEUE;
103 r = sd_bus_call_method(
105 "org.freedesktop.DBus",
106 "/org/freedesktop/DBus",
107 "org.freedesktop.DBus",
117 r = sd_bus_message_read(reply, "u", &ret);
121 if (ret == BUS_NAME_ALREADY_OWNER)
123 else if (ret == BUS_NAME_EXISTS)
125 else if (ret == BUS_NAME_IN_QUEUE)
127 else if (ret == BUS_NAME_PRIMARY_OWNER)
133 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
134 assert_return(bus, -EINVAL);
135 assert_return(name, -EINVAL);
136 assert_return(!bus_pid_changed(bus), -ECHILD);
137 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
138 assert_return(service_name_is_valid(name), -EINVAL);
139 assert_return(name[0] != ':', -EINVAL);
141 if (!bus->bus_client)
144 /* Don't allow requesting the special driver and local names */
145 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
148 if (!BUS_IS_OPEN(bus->state))
152 return bus_request_name_kernel(bus, name, flags);
154 return bus_request_name_dbus1(bus, name, flags);
157 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
165 l = strlen(name) + 1;
166 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
167 n = alloca0_align(size, 8);
170 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
171 n->items[0].type = KDBUS_ITEM_NAME;
172 memcpy(n->items[0].str, name, l);
174 #ifdef HAVE_VALGRIND_MEMCHECK_H
175 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
177 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
184 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
185 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
192 r = sd_bus_call_method(
194 "org.freedesktop.DBus",
195 "/org/freedesktop/DBus",
196 "org.freedesktop.DBus",
205 r = sd_bus_message_read(reply, "u", &ret);
208 if (ret == BUS_NAME_NON_EXISTENT)
210 if (ret == BUS_NAME_NOT_OWNER)
212 if (ret == BUS_NAME_RELEASED)
218 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
219 assert_return(bus, -EINVAL);
220 assert_return(name, -EINVAL);
221 assert_return(!bus_pid_changed(bus), -ECHILD);
222 assert_return(service_name_is_valid(name), -EINVAL);
223 assert_return(name[0] != ':', -EINVAL);
225 if (!bus->bus_client)
228 /* Don't allow releasing the special driver and local names */
229 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
232 if (!BUS_IS_OPEN(bus->state))
236 return bus_release_name_kernel(bus, name);
238 return bus_release_name_dbus1(bus, name);
241 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
242 struct kdbus_cmd_list cmd = {
246 struct kdbus_info *name_list, *name;
247 uint64_t previous_id = 0;
250 /* Caller will free half-constructed list on failure... */
252 r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
256 name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
258 KDBUS_FOREACH(name, name_list, cmd.list_size) {
259 struct kdbus_item *item;
261 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) {
264 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
269 r = strv_consume(x, n);
273 previous_id = name->id;
276 KDBUS_ITEM_FOREACH(item, name, items) {
277 if (item->type == KDBUS_ITEM_OWNED_NAME) {
278 if (service_name_is_valid(item->name.name)) {
279 r = strv_extend(x, item->name.name);
292 bus_kernel_cmd_free(bus, cmd.offset);
296 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
297 _cleanup_strv_free_ char **x = NULL, **y = NULL;
301 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
307 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
323 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
324 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
325 _cleanup_strv_free_ char **x = NULL, **y = NULL;
329 r = sd_bus_call_method(
331 "org.freedesktop.DBus",
332 "/org/freedesktop/DBus",
333 "org.freedesktop.DBus",
341 r = sd_bus_message_read_strv(reply, &x);
345 reply = sd_bus_message_unref(reply);
349 r = sd_bus_call_method(
351 "org.freedesktop.DBus",
352 "/org/freedesktop/DBus",
353 "org.freedesktop.DBus",
354 "ListActivatableNames",
361 r = sd_bus_message_read_strv(reply, &y);
377 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
378 assert_return(bus, -EINVAL);
379 assert_return(acquired || activatable, -EINVAL);
380 assert_return(!bus_pid_changed(bus), -ECHILD);
382 if (!bus->bus_client)
385 if (!BUS_IS_OPEN(bus->state))
389 return bus_list_names_kernel(bus, acquired, activatable);
391 return bus_list_names_dbus1(bus, acquired, activatable);
394 static int bus_populate_creds_from_items(
396 struct kdbus_info *info,
400 struct kdbus_item *item;
408 KDBUS_ITEM_FOREACH(item, info, items) {
410 switch (item->type) {
412 case KDBUS_ITEM_PIDS:
414 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
415 c->pid = (pid_t) item->pids.pid;
416 c->mask |= SD_BUS_CREDS_PID;
419 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
420 c->tid = (pid_t) item->pids.tid;
421 c->mask |= SD_BUS_CREDS_TID;
424 if (mask & SD_BUS_CREDS_PPID) {
425 if (item->pids.ppid > 0) {
426 c->ppid = (pid_t) item->pids.ppid;
427 c->mask |= SD_BUS_CREDS_PPID;
428 } else if (item->pids.pid == 1) {
429 /* The structure doesn't
430 * really distinguish the case
431 * where a process has no
432 * parent and where we don't
433 * know it because it could
434 * not be translated due to
435 * namespaces. However, we
436 * know that PID 1 has no
437 * parent process, hence let's
438 * patch that in, manually. */
440 c->mask |= SD_BUS_CREDS_PPID;
446 case KDBUS_ITEM_CREDS:
448 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
449 c->uid = (uid_t) item->creds.uid;
450 c->mask |= SD_BUS_CREDS_UID;
453 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
454 c->euid = (uid_t) item->creds.euid;
455 c->mask |= SD_BUS_CREDS_EUID;
458 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
459 c->suid = (uid_t) item->creds.suid;
460 c->mask |= SD_BUS_CREDS_SUID;
463 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
464 c->fsuid = (uid_t) item->creds.fsuid;
465 c->mask |= SD_BUS_CREDS_FSUID;
468 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
469 c->gid = (gid_t) item->creds.gid;
470 c->mask |= SD_BUS_CREDS_GID;
473 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
474 c->egid = (gid_t) item->creds.egid;
475 c->mask |= SD_BUS_CREDS_EGID;
478 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
479 c->sgid = (gid_t) item->creds.sgid;
480 c->mask |= SD_BUS_CREDS_SGID;
483 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
484 c->fsgid = (gid_t) item->creds.fsgid;
485 c->mask |= SD_BUS_CREDS_FSGID;
490 case KDBUS_ITEM_PID_COMM:
491 if (mask & SD_BUS_CREDS_COMM) {
492 r = free_and_strdup(&c->comm, item->str);
496 c->mask |= SD_BUS_CREDS_COMM;
500 case KDBUS_ITEM_TID_COMM:
501 if (mask & SD_BUS_CREDS_TID_COMM) {
502 r = free_and_strdup(&c->tid_comm, item->str);
506 c->mask |= SD_BUS_CREDS_TID_COMM;
511 if (mask & SD_BUS_CREDS_EXE) {
512 r = free_and_strdup(&c->exe, item->str);
516 c->mask |= SD_BUS_CREDS_EXE;
520 case KDBUS_ITEM_CMDLINE:
521 if (mask & SD_BUS_CREDS_CMDLINE) {
522 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
523 c->cmdline = memdup(item->data, c->cmdline_size);
527 c->mask |= SD_BUS_CREDS_CMDLINE;
531 case KDBUS_ITEM_CGROUP:
532 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
533 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
534 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
537 r = free_and_strdup(&c->cgroup, item->str);
541 r = bus_get_root_path(bus);
545 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
553 case KDBUS_ITEM_CAPS:
554 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
555 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
558 if (item->caps.last_cap != cap_last_cap() ||
559 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
562 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
570 case KDBUS_ITEM_SECLABEL:
571 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
572 r = free_and_strdup(&c->label, item->str);
576 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
580 case KDBUS_ITEM_AUDIT:
581 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
582 c->audit_session_id = (uint32_t) item->audit.sessionid;
583 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
586 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
587 c->audit_login_uid = (uid_t) item->audit.loginuid;
588 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
592 case KDBUS_ITEM_OWNED_NAME:
593 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
594 r = strv_extend(&c->well_known_names, item->name.name);
598 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
602 case KDBUS_ITEM_CONN_DESCRIPTION:
603 if (mask & SD_BUS_CREDS_DESCRIPTION) {
604 r = free_and_strdup(&c->description, item->str);
608 c->mask |= SD_BUS_CREDS_DESCRIPTION;
612 case KDBUS_ITEM_AUXGROUPS:
613 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
617 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
622 for (i = 0; i < n; i++)
623 g[i] = item->data64[i];
625 free(c->supplementary_gids);
626 c->supplementary_gids = g;
627 c->n_supplementary_gids = n;
629 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
638 int bus_get_name_creds_kdbus(
642 bool allow_activator,
643 sd_bus_creds **creds) {
645 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
646 struct kdbus_cmd_info *cmd;
647 struct kdbus_info *conn_info;
652 if (streq(name, "org.freedesktop.DBus"))
655 r = bus_kernel_parse_unique_name(name, &id);
659 size = offsetof(struct kdbus_cmd_info, items);
660 cmd = alloca0_align(size, 8);
663 l = strlen(name) + 1;
664 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
665 cmd = alloca0_align(size, 8);
666 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
667 cmd->items[0].type = KDBUS_ITEM_NAME;
668 memcpy(cmd->items[0].str, name, l);
671 /* If augmentation is on, and the bus didn't provide us
672 * the bits we want, then ask for the PID/TID so that we
673 * can read the rest from /proc. */
674 if ((mask & SD_BUS_CREDS_AUGMENT) &&
675 (mask & (SD_BUS_CREDS_PPID|
676 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
677 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
678 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
679 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|
680 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
681 SD_BUS_CREDS_SELINUX_CONTEXT|
682 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
683 mask |= SD_BUS_CREDS_PID;
686 cmd->attach_flags = attach_flags_to_kdbus(mask);
688 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
692 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
694 /* Non-activated names are considered not available */
695 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
709 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
710 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
715 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
718 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
719 them in case the service has no names. This does not mean
720 however that the list of owned names could not be
721 acquired. Hence, let's explicitly clarify that the data is
723 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
725 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
729 r = bus_creds_add_more(c, mask, 0, 0);
741 bus_kernel_cmd_free(bus, cmd->offset);
745 static int bus_get_name_creds_dbus1(
749 sd_bus_creds **creds) {
751 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
752 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
753 const char *unique = NULL;
757 /* Only query the owner if the caller wants to know it or if
758 * the caller just wants to check whether a name exists */
759 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
760 r = sd_bus_call_method(
762 "org.freedesktop.DBus",
763 "/org/freedesktop/DBus",
764 "org.freedesktop.DBus",
773 r = sd_bus_message_read(reply_unique, "s", &unique);
783 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
784 c->unique_name = strdup(unique);
788 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
791 if ((mask & SD_BUS_CREDS_PID) ||
792 ((mask & SD_BUS_CREDS_AUGMENT) &&
793 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
794 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
795 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
796 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|
797 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
798 SD_BUS_CREDS_SELINUX_CONTEXT|
799 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
803 r = sd_bus_call_method(
805 "org.freedesktop.DBus",
806 "/org/freedesktop/DBus",
807 "org.freedesktop.DBus",
808 "GetConnectionUnixProcessID",
812 unique ? unique : name);
816 r = sd_bus_message_read(reply, "u", &u);
821 if (mask & SD_BUS_CREDS_PID) {
823 c->mask |= SD_BUS_CREDS_PID;
826 reply = sd_bus_message_unref(reply);
829 if (mask & SD_BUS_CREDS_EUID) {
832 r = sd_bus_call_method(
834 "org.freedesktop.DBus",
835 "/org/freedesktop/DBus",
836 "org.freedesktop.DBus",
837 "GetConnectionUnixUser",
841 unique ? unique : name);
845 r = sd_bus_message_read(reply, "u", &u);
850 c->mask |= SD_BUS_CREDS_EUID;
852 reply = sd_bus_message_unref(reply);
855 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
856 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
857 const void *p = NULL;
860 r = sd_bus_call_method(
862 "org.freedesktop.DBus",
863 "/org/freedesktop/DBus",
864 "org.freedesktop.DBus",
865 "GetConnectionSELinuxSecurityContext",
869 unique ? unique : name);
871 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
874 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
878 c->label = strndup(p, sz);
882 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
886 r = bus_creds_add_more(c, mask, pid, 0);
899 _public_ int sd_bus_get_name_creds(
903 sd_bus_creds **creds) {
905 assert_return(bus, -EINVAL);
906 assert_return(name, -EINVAL);
907 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
908 assert_return(mask == 0 || creds, -EINVAL);
909 assert_return(!bus_pid_changed(bus), -ECHILD);
910 assert_return(service_name_is_valid(name), -EINVAL);
912 if (!bus->bus_client)
915 if (streq(name, "org.freedesktop.DBus.Local"))
918 if (!BUS_IS_OPEN(bus->state))
922 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
924 return bus_get_name_creds_dbus1(bus, name, mask, creds);
927 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
928 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
929 struct kdbus_cmd_info cmd = {
930 .size = sizeof(struct kdbus_cmd_info),
932 struct kdbus_info *creator_info;
940 /* If augmentation is on, and the bus doesn't didn't allow us
941 * to get the bits we want, then ask for the PID/TID so that we
942 * can read the rest from /proc. */
943 if ((mask & SD_BUS_CREDS_AUGMENT) &&
944 (mask & (SD_BUS_CREDS_PPID|
945 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
946 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
947 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
948 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|
949 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
950 SD_BUS_CREDS_SELINUX_CONTEXT|
951 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
952 mask |= SD_BUS_CREDS_PID;
954 cmd.attach_flags = attach_flags_to_kdbus(mask);
956 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
960 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
962 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
963 bus_kernel_cmd_free(bus, cmd.offset);
967 r = bus_creds_add_more(c, mask, pid, 0);
976 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
977 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
980 bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
982 /* Avoid allocating anything if we have no chance of returning useful data */
983 if (!bus->ucred_valid && !do_label)
990 if (bus->ucred_valid) {
991 if (bus->ucred.pid > 0) {
992 pid = c->pid = bus->ucred.pid;
993 c->mask |= SD_BUS_CREDS_PID & mask;
996 if (bus->ucred.uid != UID_INVALID) {
997 c->euid = bus->ucred.uid;
998 c->mask |= SD_BUS_CREDS_EUID & mask;
1001 if (bus->ucred.gid != GID_INVALID) {
1002 c->egid = bus->ucred.gid;
1003 c->mask |= SD_BUS_CREDS_EGID & mask;
1008 c->label = strdup(bus->label);
1012 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1015 r = bus_creds_add_more(c, mask, pid, 0);
1024 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1025 assert_return(bus, -EINVAL);
1026 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1027 assert_return(ret, -EINVAL);
1028 assert_return(!bus_pid_changed(bus), -ECHILD);
1030 if (!BUS_IS_OPEN(bus->state))
1034 return bus_get_owner_creds_kdbus(bus, mask, ret);
1036 return bus_get_owner_creds_dbus1(bus, mask, ret);
1039 static int add_name_change_match(sd_bus *bus,
1042 const char *old_owner,
1043 const char *new_owner) {
1045 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1046 int is_name_id = -1, r;
1047 struct kdbus_item *item;
1051 /* If we encounter a match that could match against
1052 * NameOwnerChanged messages, then we need to create
1053 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1054 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1055 * multiple if the match is underspecified.
1057 * The NameOwnerChanged signals take three parameters with
1058 * unique or well-known names, but only some forms actually
1061 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1062 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1063 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1064 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1065 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1067 * For the latter two the two unique names must be identical.
1072 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1077 if (!isempty(old_owner)) {
1078 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1083 if (is_name_id > 0 && old_owner_id != name_id)
1086 old_owner_id = KDBUS_MATCH_ID_ANY;
1088 if (!isempty(new_owner)) {
1089 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1094 if (is_name_id > 0 && new_owner_id != name_id)
1097 new_owner_id = KDBUS_MATCH_ID_ANY;
1099 if (is_name_id <= 0) {
1100 struct kdbus_cmd_match *m;
1103 /* If the name argument is missing or is a well-known
1104 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1107 l = name ? strlen(name) + 1 : 0;
1109 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1110 offsetof(struct kdbus_item, name_change) +
1111 offsetof(struct kdbus_notify_name_change, name) +
1114 m = alloca0_align(sz, 8);
1120 offsetof(struct kdbus_item, name_change) +
1121 offsetof(struct kdbus_notify_name_change, name) +
1124 item->name_change.old_id.id = old_owner_id;
1125 item->name_change.new_id.id = new_owner_id;
1128 memcpy(item->name_change.name, name, l);
1130 /* If the old name is unset or empty, then
1131 * this can match against added names */
1132 if (isempty(old_owner)) {
1133 item->type = KDBUS_ITEM_NAME_ADD;
1135 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1140 /* If the new name is unset or empty, then
1141 * this can match against removed names */
1142 if (isempty(new_owner)) {
1143 item->type = KDBUS_ITEM_NAME_REMOVE;
1145 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1150 /* The CHANGE match we need in either case, because
1151 * what is reported as a name change by the kernel
1152 * might just be an owner change between starter and
1153 * normal clients. For userspace such a change should
1154 * be considered a removal/addition, hence let's
1155 * subscribe to this unconditionally. */
1156 item->type = KDBUS_ITEM_NAME_CHANGE;
1157 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1162 if (is_name_id != 0) {
1163 struct kdbus_cmd_match *m;
1166 /* If the name argument is missing or is a unique
1167 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1170 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1171 offsetof(struct kdbus_item, id_change) +
1172 sizeof(struct kdbus_notify_id_change));
1174 m = alloca0_align(sz, 8);
1180 offsetof(struct kdbus_item, id_change) +
1181 sizeof(struct kdbus_notify_id_change);
1182 item->id_change.id = name_id;
1184 /* If the old name is unset or empty, then this can
1185 * match against added ids */
1186 if (isempty(old_owner)) {
1187 item->type = KDBUS_ITEM_ID_ADD;
1188 if (!isempty(new_owner))
1189 item->id_change.id = new_owner_id;
1191 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1196 /* If thew new name is unset or empty, then this can
1197 * match against removed ids */
1198 if (isempty(new_owner)) {
1199 item->type = KDBUS_ITEM_ID_REMOVE;
1200 if (!isempty(old_owner))
1201 item->id_change.id = old_owner_id;
1203 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1212 int bus_add_match_internal_kernel(
1214 struct bus_match_component *components,
1215 unsigned n_components,
1218 struct kdbus_cmd_match *m;
1219 struct kdbus_item *item;
1222 const char *sender = NULL;
1223 size_t sender_length = 0;
1224 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1225 bool using_bloom = false;
1227 bool matches_name_change = true;
1228 const char *name_change_arg[3] = {};
1233 /* Monitor streams don't support matches, make this a NOP */
1234 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1237 bloom = alloca0(bus->bloom_size);
1239 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1241 for (i = 0; i < n_components; i++) {
1242 struct bus_match_component *c = &components[i];
1246 case BUS_MATCH_SENDER:
1247 if (!streq(c->value_str, "org.freedesktop.DBus"))
1248 matches_name_change = false;
1250 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1254 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1256 sender = c->value_str;
1257 sender_length = strlen(sender);
1258 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1263 case BUS_MATCH_MESSAGE_TYPE:
1264 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1265 matches_name_change = false;
1267 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1271 case BUS_MATCH_INTERFACE:
1272 if (!streq(c->value_str, "org.freedesktop.DBus"))
1273 matches_name_change = false;
1275 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1279 case BUS_MATCH_MEMBER:
1280 if (!streq(c->value_str, "NameOwnerChanged"))
1281 matches_name_change = false;
1283 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1287 case BUS_MATCH_PATH:
1288 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1289 matches_name_change = false;
1291 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1295 case BUS_MATCH_PATH_NAMESPACE:
1296 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1300 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1301 char buf[sizeof("arg")-1 + 2 + 1];
1303 if (c->type - BUS_MATCH_ARG < 3)
1304 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1306 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1307 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1312 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1313 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1315 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1316 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1321 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1323 * XXX: DBus spec defines arg[0..63]path= matching to be
1324 * a two-way glob. That is, if either string is a prefix
1325 * of the other, it matches.
1326 * This is really hard to realize in bloom-filters, as
1327 * we would have to create a bloom-match for each prefix
1328 * of @c->value_str. This is excessive, hence we just
1329 * ignore all those matches and accept everything from
1330 * the kernel. People should really avoid those matches.
1331 * If they're used in real-life some day, we will have
1332 * to properly support multiple-matches here.
1336 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1337 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1339 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1340 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1345 case BUS_MATCH_DESTINATION:
1347 * Kernel only supports matching on destination IDs, but
1348 * not on destination names. So just skip the
1349 * destination name restriction and verify it in
1350 * user-space on retrieval.
1352 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1356 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1358 /* if not a broadcast, it cannot be a name-change */
1359 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1360 matches_name_change = false;
1364 case BUS_MATCH_ROOT:
1365 case BUS_MATCH_VALUE:
1366 case BUS_MATCH_LEAF:
1367 case _BUS_MATCH_NODE_TYPE_MAX:
1368 case _BUS_MATCH_NODE_TYPE_INVALID:
1369 assert_not_reached("Invalid match type?");
1374 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1376 m = alloca0_align(sz, 8);
1382 if (src_id != KDBUS_MATCH_ID_ANY) {
1383 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1384 item->type = KDBUS_ITEM_ID;
1386 item = KDBUS_ITEM_NEXT(item);
1389 if (dst_id != KDBUS_MATCH_ID_ANY) {
1390 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1391 item->type = KDBUS_ITEM_DST_ID;
1393 item = KDBUS_ITEM_NEXT(item);
1397 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1398 item->type = KDBUS_ITEM_BLOOM_MASK;
1399 memcpy(item->data64, bloom, bus->bloom_size);
1400 item = KDBUS_ITEM_NEXT(item);
1404 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1405 item->type = KDBUS_ITEM_NAME;
1406 memcpy(item->str, sender, sender_length + 1);
1409 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1413 if (matches_name_change) {
1415 /* If this match could theoretically match
1416 * NameOwnerChanged messages, we need to
1417 * install a second non-bloom filter explitly
1420 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1428 #define internal_match(bus, m) \
1429 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1430 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1433 static int bus_add_match_internal_dbus1(
1435 const char *match) {
1442 e = internal_match(bus, match);
1444 return sd_bus_call_method(
1446 "org.freedesktop.DBus",
1447 "/org/freedesktop/DBus",
1448 "org.freedesktop.DBus",
1456 int bus_add_match_internal(
1459 struct bus_match_component *components,
1460 unsigned n_components,
1465 if (!bus->bus_client)
1469 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1471 return bus_add_match_internal_dbus1(bus, match);
1474 int bus_remove_match_internal_kernel(
1478 struct kdbus_cmd_match m = {
1479 .size = offsetof(struct kdbus_cmd_match, items),
1486 /* Monitor streams don't support matches, make this a NOP */
1487 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1490 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1497 static int bus_remove_match_internal_dbus1(
1499 const char *match) {
1506 e = internal_match(bus, match);
1508 return sd_bus_call_method(
1510 "org.freedesktop.DBus",
1511 "/org/freedesktop/DBus",
1512 "org.freedesktop.DBus",
1520 int bus_remove_match_internal(
1527 if (!bus->bus_client)
1531 return bus_remove_match_internal_kernel(bus, cookie);
1533 return bus_remove_match_internal_dbus1(bus, match);
1536 /// UNNEEDED by elogind
1538 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1539 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1543 assert_return(bus, -EINVAL);
1544 assert_return(name, -EINVAL);
1545 assert_return(machine, -EINVAL);
1546 assert_return(!bus_pid_changed(bus), -ECHILD);
1547 assert_return(service_name_is_valid(name), -EINVAL);
1549 if (!bus->bus_client)
1552 if (!BUS_IS_OPEN(bus->state))
1555 if (streq_ptr(name, bus->unique_name))
1556 return sd_id128_get_machine(machine);
1558 r = sd_bus_message_new_method_call(
1563 "org.freedesktop.DBus.Peer",
1568 r = sd_bus_message_set_auto_start(m, false);
1572 r = sd_bus_call(bus, m, 0, NULL, &reply);
1576 r = sd_bus_message_read(reply, "s", &mid);
1580 return sd_id128_from_string(mid, machine);