2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_VALGRIND_MEMCHECK_H
21 #include <valgrind/memcheck.h>
29 #include "alloc-util.h"
30 #include "bus-bloom.h"
31 #include "bus-control.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
35 #include "capability-util.h"
36 #include "stdio-util.h"
37 #include "string-util.h"
39 #include "user-util.h"
41 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
44 assert_return(bus, -EINVAL);
45 assert_return(unique, -EINVAL);
46 assert_return(!bus_pid_changed(bus), -ECHILD);
51 r = bus_ensure_running(bus);
55 *unique = bus->unique_name;
59 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
68 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
69 n = alloca0_align(size, 8);
71 n->flags = request_name_flags_to_kdbus(flags);
73 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
74 n->items[0].type = KDBUS_ITEM_NAME;
75 memcpy(n->items[0].str, name, l);
77 #ifdef HAVE_VALGRIND_MEMCHECK_H
78 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
81 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
85 if (n->return_flags & KDBUS_NAME_IN_QUEUE)
91 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
92 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
93 uint32_t ret, param = 0;
99 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
100 param |= BUS_NAME_ALLOW_REPLACEMENT;
101 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
102 param |= BUS_NAME_REPLACE_EXISTING;
103 if (!(flags & SD_BUS_NAME_QUEUE))
104 param |= BUS_NAME_DO_NOT_QUEUE;
106 r = sd_bus_call_method(
108 "org.freedesktop.DBus",
109 "/org/freedesktop/DBus",
110 "org.freedesktop.DBus",
120 r = sd_bus_message_read(reply, "u", &ret);
124 if (ret == BUS_NAME_ALREADY_OWNER)
126 else if (ret == BUS_NAME_EXISTS)
128 else if (ret == BUS_NAME_IN_QUEUE)
130 else if (ret == BUS_NAME_PRIMARY_OWNER)
136 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
137 assert_return(bus, -EINVAL);
138 assert_return(name, -EINVAL);
139 assert_return(!bus_pid_changed(bus), -ECHILD);
140 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
141 assert_return(service_name_is_valid(name), -EINVAL);
142 assert_return(name[0] != ':', -EINVAL);
144 if (!bus->bus_client)
147 /* Don't allow requesting the special driver and local names */
148 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
151 if (!BUS_IS_OPEN(bus->state))
155 return bus_request_name_kernel(bus, name, flags);
157 return bus_request_name_dbus1(bus, name, flags);
160 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
168 l = strlen(name) + 1;
169 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
170 n = alloca0_align(size, 8);
173 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
174 n->items[0].type = KDBUS_ITEM_NAME;
175 memcpy(n->items[0].str, name, l);
177 #ifdef HAVE_VALGRIND_MEMCHECK_H
178 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
180 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
187 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
188 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
195 r = sd_bus_call_method(
197 "org.freedesktop.DBus",
198 "/org/freedesktop/DBus",
199 "org.freedesktop.DBus",
208 r = sd_bus_message_read(reply, "u", &ret);
211 if (ret == BUS_NAME_NON_EXISTENT)
213 if (ret == BUS_NAME_NOT_OWNER)
215 if (ret == BUS_NAME_RELEASED)
221 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
222 assert_return(bus, -EINVAL);
223 assert_return(name, -EINVAL);
224 assert_return(!bus_pid_changed(bus), -ECHILD);
225 assert_return(service_name_is_valid(name), -EINVAL);
226 assert_return(name[0] != ':', -EINVAL);
228 if (!bus->bus_client)
231 /* Don't allow releasing the special driver and local names */
232 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
235 if (!BUS_IS_OPEN(bus->state))
239 return bus_release_name_kernel(bus, name);
241 return bus_release_name_dbus1(bus, name);
244 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
245 struct kdbus_cmd_list cmd = {
249 struct kdbus_info *name_list, *name;
250 uint64_t previous_id = 0;
253 /* Caller will free half-constructed list on failure... */
255 r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
259 name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
261 KDBUS_FOREACH(name, name_list, cmd.list_size) {
262 struct kdbus_item *item;
264 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) {
267 #pragma GCC diagnostic push
268 #pragma GCC diagnostic ignored "-Wformat"
269 if (asprintf(&n, ":1.%llu", name->id) < 0) {
273 #pragma GCC diagnostic pop
275 r = strv_consume(x, n);
279 previous_id = name->id;
282 KDBUS_ITEM_FOREACH(item, name, items) {
283 if (item->type == KDBUS_ITEM_OWNED_NAME) {
284 if (service_name_is_valid(item->name.name)) {
285 r = strv_extend(x, item->name.name);
298 bus_kernel_cmd_free(bus, cmd.offset);
302 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
303 _cleanup_strv_free_ char **x = NULL, **y = NULL;
307 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
313 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
329 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
330 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
331 _cleanup_strv_free_ char **x = NULL, **y = NULL;
335 r = sd_bus_call_method(
337 "org.freedesktop.DBus",
338 "/org/freedesktop/DBus",
339 "org.freedesktop.DBus",
347 r = sd_bus_message_read_strv(reply, &x);
351 reply = sd_bus_message_unref(reply);
355 r = sd_bus_call_method(
357 "org.freedesktop.DBus",
358 "/org/freedesktop/DBus",
359 "org.freedesktop.DBus",
360 "ListActivatableNames",
367 r = sd_bus_message_read_strv(reply, &y);
383 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
384 assert_return(bus, -EINVAL);
385 assert_return(acquired || activatable, -EINVAL);
386 assert_return(!bus_pid_changed(bus), -ECHILD);
388 if (!bus->bus_client)
391 if (!BUS_IS_OPEN(bus->state))
395 return bus_list_names_kernel(bus, acquired, activatable);
397 return bus_list_names_dbus1(bus, acquired, activatable);
400 static int bus_populate_creds_from_items(
402 struct kdbus_info *info,
406 struct kdbus_item *item;
414 KDBUS_ITEM_FOREACH(item, info, items) {
416 switch (item->type) {
418 case KDBUS_ITEM_PIDS:
420 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
421 c->pid = (pid_t) item->pids.pid;
422 c->mask |= SD_BUS_CREDS_PID;
425 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
426 c->tid = (pid_t) item->pids.tid;
427 c->mask |= SD_BUS_CREDS_TID;
430 if (mask & SD_BUS_CREDS_PPID) {
431 if (item->pids.ppid > 0) {
432 c->ppid = (pid_t) item->pids.ppid;
433 c->mask |= SD_BUS_CREDS_PPID;
434 } else if (item->pids.pid == 1) {
435 /* The structure doesn't
436 * really distinguish the case
437 * where a process has no
438 * parent and where we don't
439 * know it because it could
440 * not be translated due to
441 * namespaces. However, we
442 * know that PID 1 has no
443 * parent process, hence let's
444 * patch that in, manually. */
446 c->mask |= SD_BUS_CREDS_PPID;
452 case KDBUS_ITEM_CREDS:
454 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
455 c->uid = (uid_t) item->creds.uid;
456 c->mask |= SD_BUS_CREDS_UID;
459 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
460 c->euid = (uid_t) item->creds.euid;
461 c->mask |= SD_BUS_CREDS_EUID;
464 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
465 c->suid = (uid_t) item->creds.suid;
466 c->mask |= SD_BUS_CREDS_SUID;
469 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
470 c->fsuid = (uid_t) item->creds.fsuid;
471 c->mask |= SD_BUS_CREDS_FSUID;
474 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
475 c->gid = (gid_t) item->creds.gid;
476 c->mask |= SD_BUS_CREDS_GID;
479 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
480 c->egid = (gid_t) item->creds.egid;
481 c->mask |= SD_BUS_CREDS_EGID;
484 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
485 c->sgid = (gid_t) item->creds.sgid;
486 c->mask |= SD_BUS_CREDS_SGID;
489 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
490 c->fsgid = (gid_t) item->creds.fsgid;
491 c->mask |= SD_BUS_CREDS_FSGID;
496 case KDBUS_ITEM_PID_COMM:
497 if (mask & SD_BUS_CREDS_COMM) {
498 r = free_and_strdup(&c->comm, item->str);
502 c->mask |= SD_BUS_CREDS_COMM;
506 case KDBUS_ITEM_TID_COMM:
507 if (mask & SD_BUS_CREDS_TID_COMM) {
508 r = free_and_strdup(&c->tid_comm, item->str);
512 c->mask |= SD_BUS_CREDS_TID_COMM;
517 if (mask & SD_BUS_CREDS_EXE) {
518 r = free_and_strdup(&c->exe, item->str);
522 c->mask |= SD_BUS_CREDS_EXE;
526 case KDBUS_ITEM_CMDLINE:
527 if (mask & SD_BUS_CREDS_CMDLINE) {
528 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
529 c->cmdline = memdup(item->data, c->cmdline_size);
533 c->mask |= SD_BUS_CREDS_CMDLINE;
537 case KDBUS_ITEM_CGROUP:
538 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
539 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
540 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
543 r = free_and_strdup(&c->cgroup, item->str);
547 r = bus_get_root_path(bus);
551 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
559 case KDBUS_ITEM_CAPS:
560 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
561 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
564 if (item->caps.last_cap != cap_last_cap() ||
565 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
568 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
576 case KDBUS_ITEM_SECLABEL:
577 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
578 r = free_and_strdup(&c->label, item->str);
582 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
586 case KDBUS_ITEM_AUDIT:
587 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
588 c->audit_session_id = (uint32_t) item->audit.sessionid;
589 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
592 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
593 c->audit_login_uid = (uid_t) item->audit.loginuid;
594 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
598 case KDBUS_ITEM_OWNED_NAME:
599 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
600 r = strv_extend(&c->well_known_names, item->name.name);
604 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
608 case KDBUS_ITEM_CONN_DESCRIPTION:
609 if (mask & SD_BUS_CREDS_DESCRIPTION) {
610 r = free_and_strdup(&c->description, item->str);
614 c->mask |= SD_BUS_CREDS_DESCRIPTION;
618 case KDBUS_ITEM_AUXGROUPS:
619 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
623 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
628 for (i = 0; i < n; i++)
629 g[i] = item->data64[i];
631 free(c->supplementary_gids);
632 c->supplementary_gids = g;
633 c->n_supplementary_gids = n;
635 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
644 int bus_get_name_creds_kdbus(
648 bool allow_activator,
649 sd_bus_creds **creds) {
651 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
652 struct kdbus_cmd_info *cmd;
653 struct kdbus_info *conn_info;
658 if (streq(name, "org.freedesktop.DBus"))
661 r = bus_kernel_parse_unique_name(name, &id);
665 size = offsetof(struct kdbus_cmd_info, items);
666 cmd = alloca0_align(size, 8);
669 l = strlen(name) + 1;
670 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
671 cmd = alloca0_align(size, 8);
672 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
673 cmd->items[0].type = KDBUS_ITEM_NAME;
674 memcpy(cmd->items[0].str, name, l);
677 /* If augmentation is on, and the bus didn't provide us
678 * the bits we want, then ask for the PID/TID so that we
679 * can read the rest from /proc. */
680 if ((mask & SD_BUS_CREDS_AUGMENT) &&
681 (mask & (SD_BUS_CREDS_PPID|
682 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
683 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
684 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
685 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
686 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|
687 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
688 SD_BUS_CREDS_SELINUX_CONTEXT|
689 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
690 mask |= SD_BUS_CREDS_PID;
693 cmd->attach_flags = attach_flags_to_kdbus(mask);
695 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
699 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
701 /* Non-activated names are considered not available */
702 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
716 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
717 #pragma GCC diagnostic push
718 #pragma GCC diagnostic ignored "-Wformat"
719 if (asprintf(&c->unique_name, ":1.%llu", conn_info->id) < 0) {
723 #pragma GCC diagnostic pop
725 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
728 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
729 them in case the service has no names. This does not mean
730 however that the list of owned names could not be
731 acquired. Hence, let's explicitly clarify that the data is
733 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
735 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
739 r = bus_creds_add_more(c, mask, 0, 0);
751 bus_kernel_cmd_free(bus, cmd->offset);
755 static int bus_get_name_creds_dbus1(
759 sd_bus_creds **creds) {
761 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
762 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
763 const char *unique = NULL;
767 /* Only query the owner if the caller wants to know it or if
768 * the caller just wants to check whether a name exists */
769 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
770 r = sd_bus_call_method(
772 "org.freedesktop.DBus",
773 "/org/freedesktop/DBus",
774 "org.freedesktop.DBus",
783 r = sd_bus_message_read(reply_unique, "s", &unique);
793 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
794 c->unique_name = strdup(unique);
798 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
801 if ((mask & SD_BUS_CREDS_PID) ||
802 ((mask & SD_BUS_CREDS_AUGMENT) &&
803 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
804 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
805 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
806 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
807 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|
808 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
809 SD_BUS_CREDS_SELINUX_CONTEXT|
810 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
814 r = sd_bus_call_method(
816 "org.freedesktop.DBus",
817 "/org/freedesktop/DBus",
818 "org.freedesktop.DBus",
819 "GetConnectionUnixProcessID",
823 unique ? unique : name);
827 r = sd_bus_message_read(reply, "u", &u);
832 if (mask & SD_BUS_CREDS_PID) {
834 c->mask |= SD_BUS_CREDS_PID;
837 reply = sd_bus_message_unref(reply);
840 if (mask & SD_BUS_CREDS_EUID) {
843 r = sd_bus_call_method(
845 "org.freedesktop.DBus",
846 "/org/freedesktop/DBus",
847 "org.freedesktop.DBus",
848 "GetConnectionUnixUser",
852 unique ? unique : name);
856 r = sd_bus_message_read(reply, "u", &u);
861 c->mask |= SD_BUS_CREDS_EUID;
863 reply = sd_bus_message_unref(reply);
866 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
867 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
868 const void *p = NULL;
871 r = sd_bus_call_method(
873 "org.freedesktop.DBus",
874 "/org/freedesktop/DBus",
875 "org.freedesktop.DBus",
876 "GetConnectionSELinuxSecurityContext",
880 unique ? unique : name);
882 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
885 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
889 c->label = strndup(p, sz);
893 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
897 r = bus_creds_add_more(c, mask, pid, 0);
910 _public_ int sd_bus_get_name_creds(
914 sd_bus_creds **creds) {
916 assert_return(bus, -EINVAL);
917 assert_return(name, -EINVAL);
918 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
919 assert_return(mask == 0 || creds, -EINVAL);
920 assert_return(!bus_pid_changed(bus), -ECHILD);
921 assert_return(service_name_is_valid(name), -EINVAL);
923 if (!bus->bus_client)
926 if (streq(name, "org.freedesktop.DBus.Local"))
929 if (streq(name, "org.freedesktop.DBus"))
930 return sd_bus_get_owner_creds(bus, mask, creds);
932 if (!BUS_IS_OPEN(bus->state))
936 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
938 return bus_get_name_creds_dbus1(bus, name, mask, creds);
941 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
942 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
943 struct kdbus_cmd_info cmd = {
944 .size = sizeof(struct kdbus_cmd_info),
946 struct kdbus_info *creator_info;
954 /* If augmentation is on, and the bus doesn't didn't allow us
955 * to get the bits we want, then ask for the PID/TID so that we
956 * can read the rest from /proc. */
957 if ((mask & SD_BUS_CREDS_AUGMENT) &&
958 (mask & (SD_BUS_CREDS_PPID|
959 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
960 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
961 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
962 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
963 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|
964 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
965 SD_BUS_CREDS_SELINUX_CONTEXT|
966 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
967 mask |= SD_BUS_CREDS_PID;
969 cmd.attach_flags = attach_flags_to_kdbus(mask);
971 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
975 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
977 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
978 bus_kernel_cmd_free(bus, cmd.offset);
982 r = bus_creds_add_more(c, mask, pid, 0);
991 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
992 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
999 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
1001 /* Avoid allocating anything if we have no chance of returning useful data */
1002 if (!bus->ucred_valid && !do_label)
1005 c = bus_creds_new();
1009 if (bus->ucred_valid) {
1010 if (bus->ucred.pid > 0) {
1011 pid = c->pid = bus->ucred.pid;
1012 c->mask |= SD_BUS_CREDS_PID & mask;
1015 if (bus->ucred.uid != UID_INVALID) {
1016 c->euid = bus->ucred.uid;
1017 c->mask |= SD_BUS_CREDS_EUID & mask;
1020 if (bus->ucred.gid != GID_INVALID) {
1021 c->egid = bus->ucred.gid;
1022 c->mask |= SD_BUS_CREDS_EGID & mask;
1027 c->label = strdup(bus->label);
1031 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1034 r = bus_creds_add_more(c, mask, pid, 0);
1043 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1044 assert_return(bus, -EINVAL);
1045 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1046 assert_return(ret, -EINVAL);
1047 assert_return(!bus_pid_changed(bus), -ECHILD);
1049 if (!BUS_IS_OPEN(bus->state))
1053 return bus_get_owner_creds_kdbus(bus, mask, ret);
1055 return bus_get_owner_creds_dbus1(bus, mask, ret);
1058 static int add_name_change_match(sd_bus *bus,
1061 const char *old_owner,
1062 const char *new_owner) {
1064 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1065 int is_name_id = -1, r;
1066 struct kdbus_item *item;
1070 /* If we encounter a match that could match against
1071 * NameOwnerChanged messages, then we need to create
1072 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1073 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1074 * multiple if the match is underspecified.
1076 * The NameOwnerChanged signals take three parameters with
1077 * unique or well-known names, but only some forms actually
1080 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1081 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1082 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1083 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1084 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1086 * For the latter two the two unique names must be identical.
1091 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1096 if (!isempty(old_owner)) {
1097 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1102 if (is_name_id > 0 && old_owner_id != name_id)
1105 old_owner_id = KDBUS_MATCH_ID_ANY;
1107 if (!isempty(new_owner)) {
1108 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1113 if (is_name_id > 0 && new_owner_id != name_id)
1116 new_owner_id = KDBUS_MATCH_ID_ANY;
1118 if (is_name_id <= 0) {
1119 struct kdbus_cmd_match *m;
1122 /* If the name argument is missing or is a well-known
1123 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1126 l = name ? strlen(name) + 1 : 0;
1128 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1129 offsetof(struct kdbus_item, name_change) +
1130 offsetof(struct kdbus_notify_name_change, name) +
1133 m = alloca0_align(sz, 8);
1139 offsetof(struct kdbus_item, name_change) +
1140 offsetof(struct kdbus_notify_name_change, name) +
1143 item->name_change.old_id.id = old_owner_id;
1144 item->name_change.new_id.id = new_owner_id;
1146 memcpy_safe(item->name_change.name, name, l);
1148 /* If the old name is unset or empty, then
1149 * this can match against added names */
1150 if (isempty(old_owner)) {
1151 item->type = KDBUS_ITEM_NAME_ADD;
1153 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1158 /* If the new name is unset or empty, then
1159 * this can match against removed names */
1160 if (isempty(new_owner)) {
1161 item->type = KDBUS_ITEM_NAME_REMOVE;
1163 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1168 /* The CHANGE match we need in either case, because
1169 * what is reported as a name change by the kernel
1170 * might just be an owner change between starter and
1171 * normal clients. For userspace such a change should
1172 * be considered a removal/addition, hence let's
1173 * subscribe to this unconditionally. */
1174 item->type = KDBUS_ITEM_NAME_CHANGE;
1175 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1180 if (is_name_id != 0) {
1181 struct kdbus_cmd_match *m;
1184 /* If the name argument is missing or is a unique
1185 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1188 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1189 offsetof(struct kdbus_item, id_change) +
1190 sizeof(struct kdbus_notify_id_change));
1192 m = alloca0_align(sz, 8);
1198 offsetof(struct kdbus_item, id_change) +
1199 sizeof(struct kdbus_notify_id_change);
1200 item->id_change.id = name_id;
1202 /* If the old name is unset or empty, then this can
1203 * match against added ids */
1204 if (isempty(old_owner)) {
1205 item->type = KDBUS_ITEM_ID_ADD;
1206 if (!isempty(new_owner))
1207 item->id_change.id = new_owner_id;
1209 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1214 /* If thew new name is unset or empty, then this can
1215 * match against removed ids */
1216 if (isempty(new_owner)) {
1217 item->type = KDBUS_ITEM_ID_REMOVE;
1218 if (!isempty(old_owner))
1219 item->id_change.id = old_owner_id;
1221 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1230 int bus_add_match_internal_kernel(
1232 struct bus_match_component *components,
1233 unsigned n_components,
1236 struct kdbus_cmd_match *m;
1237 struct kdbus_item *item;
1240 const char *sender = NULL;
1241 size_t sender_length = 0;
1242 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1243 bool using_bloom = false;
1245 bool matches_name_change = true;
1246 const char *name_change_arg[3] = {};
1251 /* Monitor streams don't support matches, make this a NOP */
1252 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1255 bloom = alloca0(bus->bloom_size);
1257 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1259 for (i = 0; i < n_components; i++) {
1260 struct bus_match_component *c = &components[i];
1264 case BUS_MATCH_SENDER:
1265 if (!streq(c->value_str, "org.freedesktop.DBus"))
1266 matches_name_change = false;
1268 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1272 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1274 sender = c->value_str;
1275 sender_length = strlen(sender);
1276 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1281 case BUS_MATCH_MESSAGE_TYPE:
1282 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1283 matches_name_change = false;
1285 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1289 case BUS_MATCH_INTERFACE:
1290 if (!streq(c->value_str, "org.freedesktop.DBus"))
1291 matches_name_change = false;
1293 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1297 case BUS_MATCH_MEMBER:
1298 if (!streq(c->value_str, "NameOwnerChanged"))
1299 matches_name_change = false;
1301 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1305 case BUS_MATCH_PATH:
1306 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1307 matches_name_change = false;
1309 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1313 case BUS_MATCH_PATH_NAMESPACE:
1314 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1318 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1319 char buf[sizeof("arg")-1 + 2 + 1];
1321 if (c->type - BUS_MATCH_ARG < 3)
1322 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1324 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1325 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1330 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1331 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1333 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1334 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1339 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1341 * XXX: DBus spec defines arg[0..63]path= matching to be
1342 * a two-way glob. That is, if either string is a prefix
1343 * of the other, it matches.
1344 * This is really hard to realize in bloom-filters, as
1345 * we would have to create a bloom-match for each prefix
1346 * of @c->value_str. This is excessive, hence we just
1347 * ignore all those matches and accept everything from
1348 * the kernel. People should really avoid those matches.
1349 * If they're used in real-life some day, we will have
1350 * to properly support multiple-matches here.
1354 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1355 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1357 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1358 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1363 case BUS_MATCH_DESTINATION:
1365 * Kernel only supports matching on destination IDs, but
1366 * not on destination names. So just skip the
1367 * destination name restriction and verify it in
1368 * user-space on retrieval.
1370 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1374 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1376 /* if not a broadcast, it cannot be a name-change */
1377 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1378 matches_name_change = false;
1382 case BUS_MATCH_ROOT:
1383 case BUS_MATCH_VALUE:
1384 case BUS_MATCH_LEAF:
1385 case _BUS_MATCH_NODE_TYPE_MAX:
1386 case _BUS_MATCH_NODE_TYPE_INVALID:
1387 assert_not_reached("Invalid match type?");
1392 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1394 m = alloca0_align(sz, 8);
1400 if (src_id != KDBUS_MATCH_ID_ANY) {
1401 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1402 item->type = KDBUS_ITEM_ID;
1404 item = KDBUS_ITEM_NEXT(item);
1407 if (dst_id != KDBUS_MATCH_ID_ANY) {
1408 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1409 item->type = KDBUS_ITEM_DST_ID;
1411 item = KDBUS_ITEM_NEXT(item);
1415 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1416 item->type = KDBUS_ITEM_BLOOM_MASK;
1417 memcpy(item->data64, bloom, bus->bloom_size);
1418 item = KDBUS_ITEM_NEXT(item);
1422 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1423 item->type = KDBUS_ITEM_NAME;
1424 memcpy(item->str, sender, sender_length + 1);
1427 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1431 if (matches_name_change) {
1433 /* If this match could theoretically match
1434 * NameOwnerChanged messages, we need to
1435 * install a second non-bloom filter explitly
1438 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1446 #define internal_match(bus, m) \
1447 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1448 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1451 static int bus_add_match_internal_dbus1(
1453 const char *match) {
1460 e = internal_match(bus, match);
1462 return sd_bus_call_method(
1464 "org.freedesktop.DBus",
1465 "/org/freedesktop/DBus",
1466 "org.freedesktop.DBus",
1474 int bus_add_match_internal(
1477 struct bus_match_component *components,
1478 unsigned n_components,
1483 if (!bus->bus_client)
1487 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1489 return bus_add_match_internal_dbus1(bus, match);
1492 int bus_remove_match_internal_kernel(
1496 struct kdbus_cmd_match m = {
1497 .size = offsetof(struct kdbus_cmd_match, items),
1504 /* Monitor streams don't support matches, make this a NOP */
1505 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1508 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1515 static int bus_remove_match_internal_dbus1(
1517 const char *match) {
1524 e = internal_match(bus, match);
1526 return sd_bus_call_method(
1528 "org.freedesktop.DBus",
1529 "/org/freedesktop/DBus",
1530 "org.freedesktop.DBus",
1538 int bus_remove_match_internal(
1545 if (!bus->bus_client)
1549 return bus_remove_match_internal_kernel(bus, cookie);
1551 return bus_remove_match_internal_dbus1(bus, match);
1554 #if 0 /// UNNEEDED by elogind
1555 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1556 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1560 assert_return(bus, -EINVAL);
1561 assert_return(name, -EINVAL);
1562 assert_return(machine, -EINVAL);
1563 assert_return(!bus_pid_changed(bus), -ECHILD);
1564 assert_return(service_name_is_valid(name), -EINVAL);
1566 if (!bus->bus_client)
1569 if (!BUS_IS_OPEN(bus->state))
1572 if (streq_ptr(name, bus->unique_name))
1573 return sd_id128_get_machine(machine);
1575 r = sd_bus_message_new_method_call(
1580 "org.freedesktop.DBus.Peer",
1585 r = sd_bus_message_set_auto_start(m, false);
1589 r = sd_bus_call(bus, m, 0, NULL, &reply);
1593 r = sd_bus_message_read(reply, "s", &mid);
1597 return sd_id128_from_string(mid, machine);