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) {
260 struct kdbus_item *item;
261 const char *entry_name = NULL;
263 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) {
266 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
271 r = strv_consume(x, n);
275 previous_id = name->id;
278 KDBUS_ITEM_FOREACH(item, name, items)
279 if (item->type == KDBUS_ITEM_OWNED_NAME)
280 entry_name = item->name.name;
282 if (entry_name && service_name_is_valid(entry_name)) {
283 r = strv_extend(x, entry_name);
294 bus_kernel_cmd_free(bus, cmd.offset);
298 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
299 _cleanup_strv_free_ char **x = NULL, **y = NULL;
303 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
309 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
325 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
326 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
327 _cleanup_strv_free_ char **x = NULL, **y = NULL;
331 r = sd_bus_call_method(
333 "org.freedesktop.DBus",
334 "/org/freedesktop/DBus",
335 "org.freedesktop.DBus",
343 r = sd_bus_message_read_strv(reply, &x);
347 reply = sd_bus_message_unref(reply);
351 r = sd_bus_call_method(
353 "org.freedesktop.DBus",
354 "/org/freedesktop/DBus",
355 "org.freedesktop.DBus",
356 "ListActivatableNames",
363 r = sd_bus_message_read_strv(reply, &y);
379 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
380 assert_return(bus, -EINVAL);
381 assert_return(acquired || activatable, -EINVAL);
382 assert_return(!bus_pid_changed(bus), -ECHILD);
384 if (!bus->bus_client)
387 if (!BUS_IS_OPEN(bus->state))
391 return bus_list_names_kernel(bus, acquired, activatable);
393 return bus_list_names_dbus1(bus, acquired, activatable);
396 static int bus_populate_creds_from_items(
398 struct kdbus_info *info,
402 struct kdbus_item *item;
410 KDBUS_ITEM_FOREACH(item, info, items) {
412 switch (item->type) {
414 case KDBUS_ITEM_PIDS:
416 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
417 c->pid = (pid_t) item->pids.pid;
418 c->mask |= SD_BUS_CREDS_PID;
421 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
422 c->tid = (pid_t) item->pids.tid;
423 c->mask |= SD_BUS_CREDS_TID;
426 if (mask & SD_BUS_CREDS_PPID && item->pids.ppid > 0) {
427 c->ppid = (pid_t) item->pids.ppid;
428 c->mask |= SD_BUS_CREDS_PPID;
433 case KDBUS_ITEM_CREDS:
435 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
436 c->uid = (uid_t) item->creds.uid;
437 c->mask |= SD_BUS_CREDS_UID;
440 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
441 c->euid = (uid_t) item->creds.euid;
442 c->mask |= SD_BUS_CREDS_EUID;
445 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
446 c->suid = (uid_t) item->creds.suid;
447 c->mask |= SD_BUS_CREDS_SUID;
450 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
451 c->fsuid = (uid_t) item->creds.fsuid;
452 c->mask |= SD_BUS_CREDS_FSUID;
455 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
456 c->gid = (gid_t) item->creds.gid;
457 c->mask |= SD_BUS_CREDS_GID;
460 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
461 c->egid = (gid_t) item->creds.egid;
462 c->mask |= SD_BUS_CREDS_EGID;
465 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
466 c->sgid = (gid_t) item->creds.sgid;
467 c->mask |= SD_BUS_CREDS_SGID;
470 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
471 c->fsgid = (gid_t) item->creds.fsgid;
472 c->mask |= SD_BUS_CREDS_FSGID;
477 case KDBUS_ITEM_PID_COMM:
478 if (mask & SD_BUS_CREDS_COMM) {
479 r = free_and_strdup(&c->comm, item->str);
483 c->mask |= SD_BUS_CREDS_COMM;
487 case KDBUS_ITEM_TID_COMM:
488 if (mask & SD_BUS_CREDS_TID_COMM) {
489 r = free_and_strdup(&c->tid_comm, item->str);
493 c->mask |= SD_BUS_CREDS_TID_COMM;
498 if (mask & SD_BUS_CREDS_EXE) {
499 r = free_and_strdup(&c->exe, item->str);
503 c->mask |= SD_BUS_CREDS_EXE;
507 case KDBUS_ITEM_CMDLINE:
508 if (mask & SD_BUS_CREDS_CMDLINE) {
509 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
510 c->cmdline = memdup(item->data, c->cmdline_size);
514 c->mask |= SD_BUS_CREDS_CMDLINE;
518 case KDBUS_ITEM_CGROUP:
519 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
520 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
521 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
524 r = free_and_strdup(&c->cgroup, item->str);
528 r = bus_get_root_path(bus);
532 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
540 case KDBUS_ITEM_CAPS:
541 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
542 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
545 if (item->caps.last_cap != cap_last_cap() ||
546 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
549 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
557 case KDBUS_ITEM_SECLABEL:
558 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
559 r = free_and_strdup(&c->label, item->str);
563 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
567 case KDBUS_ITEM_AUDIT:
568 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
569 c->audit_session_id = (uint32_t) item->audit.sessionid;
570 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
573 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
574 c->audit_login_uid = (uid_t) item->audit.loginuid;
575 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
579 case KDBUS_ITEM_OWNED_NAME:
580 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
581 r = strv_extend(&c->well_known_names, item->name.name);
585 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
589 case KDBUS_ITEM_CONN_DESCRIPTION:
590 if (mask & SD_BUS_CREDS_DESCRIPTION) {
591 r = free_and_strdup(&c->description, item->str);
595 c->mask |= SD_BUS_CREDS_DESCRIPTION;
599 case KDBUS_ITEM_AUXGROUPS:
600 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
604 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
609 for (i = 0; i < n; i++)
610 g[i] = item->data64[i];
612 free(c->supplementary_gids);
613 c->supplementary_gids = g;
614 c->n_supplementary_gids = n;
616 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
625 int bus_get_name_creds_kdbus(
629 bool allow_activator,
630 sd_bus_creds **creds) {
632 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
633 struct kdbus_cmd_info *cmd;
634 struct kdbus_info *conn_info;
639 if (streq(name, "org.freedesktop.DBus"))
642 r = bus_kernel_parse_unique_name(name, &id);
646 size = offsetof(struct kdbus_cmd_info, items);
647 cmd = alloca0_align(size, 8);
650 l = strlen(name) + 1;
651 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
652 cmd = alloca0_align(size, 8);
653 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
654 cmd->items[0].type = KDBUS_ITEM_NAME;
655 memcpy(cmd->items[0].str, name, l);
658 /* If augmentation is on, and the bus didn't provide us
659 * the bits we want, then ask for the PID/TID so that we
660 * can read the rest from /proc. */
661 if ((mask & SD_BUS_CREDS_AUGMENT) &&
662 (mask & (SD_BUS_CREDS_PPID|
663 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
664 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
665 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
666 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|
667 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
668 SD_BUS_CREDS_SELINUX_CONTEXT|
669 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
670 mask |= SD_BUS_CREDS_PID;
673 cmd->attach_flags = attach_flags_to_kdbus(mask);
675 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
679 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
681 /* Non-activated names are considered not available */
682 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
696 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
697 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
702 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
705 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
706 them in case the service has no names. This does not mean
707 however that the list of owned names could not be
708 acquired. Hence, let's explicitly clarify that the data is
710 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
712 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
716 r = bus_creds_add_more(c, mask, 0, 0);
728 bus_kernel_cmd_free(bus, cmd->offset);
732 static int bus_get_name_creds_dbus1(
736 sd_bus_creds **creds) {
738 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
739 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
740 const char *unique = NULL;
744 /* Only query the owner if the caller wants to know it or if
745 * the caller just wants to check whether a name exists */
746 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
747 r = sd_bus_call_method(
749 "org.freedesktop.DBus",
750 "/org/freedesktop/DBus",
751 "org.freedesktop.DBus",
760 r = sd_bus_message_read(reply_unique, "s", &unique);
770 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
771 c->unique_name = strdup(unique);
775 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
778 if ((mask & SD_BUS_CREDS_PID) ||
779 ((mask & SD_BUS_CREDS_AUGMENT) &&
780 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
781 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
782 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
783 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|
784 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
785 SD_BUS_CREDS_SELINUX_CONTEXT|
786 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
790 r = sd_bus_call_method(
792 "org.freedesktop.DBus",
793 "/org/freedesktop/DBus",
794 "org.freedesktop.DBus",
795 "GetConnectionUnixProcessID",
799 unique ? unique : name);
803 r = sd_bus_message_read(reply, "u", &u);
808 if (mask & SD_BUS_CREDS_PID) {
810 c->mask |= SD_BUS_CREDS_PID;
813 reply = sd_bus_message_unref(reply);
816 if (mask & SD_BUS_CREDS_EUID) {
819 r = sd_bus_call_method(
821 "org.freedesktop.DBus",
822 "/org/freedesktop/DBus",
823 "org.freedesktop.DBus",
824 "GetConnectionUnixUser",
828 unique ? unique : name);
832 r = sd_bus_message_read(reply, "u", &u);
837 c->mask |= SD_BUS_CREDS_EUID;
839 reply = sd_bus_message_unref(reply);
842 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
843 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
844 const void *p = NULL;
847 r = sd_bus_call_method(
849 "org.freedesktop.DBus",
850 "/org/freedesktop/DBus",
851 "org.freedesktop.DBus",
852 "GetConnectionSELinuxSecurityContext",
856 unique ? unique : name);
858 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
861 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
865 c->label = strndup(p, sz);
869 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
873 r = bus_creds_add_more(c, mask, pid, 0);
886 _public_ int sd_bus_get_name_creds(
890 sd_bus_creds **creds) {
892 assert_return(bus, -EINVAL);
893 assert_return(name, -EINVAL);
894 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
895 assert_return(mask == 0 || creds, -EINVAL);
896 assert_return(!bus_pid_changed(bus), -ECHILD);
897 assert_return(service_name_is_valid(name), -EINVAL);
899 if (!bus->bus_client)
902 if (streq(name, "org.freedesktop.DBus.Local"))
905 if (!BUS_IS_OPEN(bus->state))
909 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
911 return bus_get_name_creds_dbus1(bus, name, mask, creds);
914 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
915 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
916 struct kdbus_cmd_info cmd = {
917 .size = sizeof(struct kdbus_cmd_info),
919 struct kdbus_info *creator_info;
927 /* If augmentation is on, and the bus doesn't didn't allow us
928 * to get the bits we want, then ask for the PID/TID so that we
929 * can read the rest from /proc. */
930 if ((mask & SD_BUS_CREDS_AUGMENT) &&
931 (mask & (SD_BUS_CREDS_PPID|
932 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
933 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
934 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
935 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|
936 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
937 SD_BUS_CREDS_SELINUX_CONTEXT|
938 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
939 mask |= SD_BUS_CREDS_PID;
941 cmd.attach_flags = attach_flags_to_kdbus(mask);
943 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
947 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
949 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
950 bus_kernel_cmd_free(bus, cmd.offset);
954 r = bus_creds_add_more(c, mask, pid, 0);
963 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
964 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
968 if (!bus->ucred_valid && !isempty(bus->label))
975 if (bus->ucred_valid) {
976 if (bus->ucred.pid > 0) {
977 pid = c->pid = bus->ucred.pid;
978 c->mask |= SD_BUS_CREDS_PID & mask;
981 if (bus->ucred.uid != UID_INVALID) {
982 c->euid = bus->ucred.uid;
983 c->mask |= SD_BUS_CREDS_EUID & mask;
986 if (bus->ucred.gid != GID_INVALID) {
987 c->egid = bus->ucred.gid;
988 c->mask |= SD_BUS_CREDS_EGID & mask;
992 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
993 c->label = strdup(bus->label);
997 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1000 r = bus_creds_add_more(c, mask, pid, 0);
1009 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1010 assert_return(bus, -EINVAL);
1011 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1012 assert_return(ret, -EINVAL);
1013 assert_return(!bus_pid_changed(bus), -ECHILD);
1015 if (!BUS_IS_OPEN(bus->state))
1019 return bus_get_owner_creds_kdbus(bus, mask, ret);
1021 return bus_get_owner_creds_dbus1(bus, mask, ret);
1024 static int add_name_change_match(sd_bus *bus,
1027 const char *old_owner,
1028 const char *new_owner) {
1030 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1031 int is_name_id = -1, r;
1032 struct kdbus_item *item;
1036 /* If we encounter a match that could match against
1037 * NameOwnerChanged messages, then we need to create
1038 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1039 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1040 * multiple if the match is underspecified.
1042 * The NameOwnerChanged signals take three parameters with
1043 * unique or well-known names, but only some forms actually
1046 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1047 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1048 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1049 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1050 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1052 * For the latter two the two unique names must be identical.
1057 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1062 if (!isempty(old_owner)) {
1063 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1068 if (is_name_id > 0 && old_owner_id != name_id)
1071 old_owner_id = KDBUS_MATCH_ID_ANY;
1073 if (!isempty(new_owner)) {
1074 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1079 if (is_name_id > 0 && new_owner_id != name_id)
1082 new_owner_id = KDBUS_MATCH_ID_ANY;
1084 if (is_name_id <= 0) {
1085 struct kdbus_cmd_match *m;
1088 /* If the name argument is missing or is a well-known
1089 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1092 l = name ? strlen(name) + 1 : 0;
1094 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1095 offsetof(struct kdbus_item, name_change) +
1096 offsetof(struct kdbus_notify_name_change, name) +
1099 m = alloca0_align(sz, 8);
1105 offsetof(struct kdbus_item, name_change) +
1106 offsetof(struct kdbus_notify_name_change, name) +
1109 item->name_change.old_id.id = old_owner_id;
1110 item->name_change.new_id.id = new_owner_id;
1113 memcpy(item->name_change.name, name, l);
1115 /* If the old name is unset or empty, then
1116 * this can match against added names */
1117 if (!old_owner || old_owner[0] == 0) {
1118 item->type = KDBUS_ITEM_NAME_ADD;
1120 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1125 /* If the new name is unset or empty, then
1126 * this can match against removed names */
1127 if (!new_owner || new_owner[0] == 0) {
1128 item->type = KDBUS_ITEM_NAME_REMOVE;
1130 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1135 /* The CHANGE match we need in either case, because
1136 * what is reported as a name change by the kernel
1137 * might just be an owner change between starter and
1138 * normal clients. For userspace such a change should
1139 * be considered a removal/addition, hence let's
1140 * subscribe to this unconditionally. */
1141 item->type = KDBUS_ITEM_NAME_CHANGE;
1142 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1147 if (is_name_id != 0) {
1148 struct kdbus_cmd_match *m;
1151 /* If the name argument is missing or is a unique
1152 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1155 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1156 offsetof(struct kdbus_item, id_change) +
1157 sizeof(struct kdbus_notify_id_change));
1159 m = alloca0_align(sz, 8);
1165 offsetof(struct kdbus_item, id_change) +
1166 sizeof(struct kdbus_notify_id_change);
1167 item->id_change.id = name_id;
1169 /* If the old name is unset or empty, then this can
1170 * match against added ids */
1171 if (!old_owner || old_owner[0] == 0) {
1172 item->type = KDBUS_ITEM_ID_ADD;
1174 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1179 /* If thew new name is unset or empty, then this can
1180 * match against removed ids */
1181 if (!new_owner || new_owner[0] == 0) {
1182 item->type = KDBUS_ITEM_ID_REMOVE;
1184 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1193 int bus_add_match_internal_kernel(
1195 struct bus_match_component *components,
1196 unsigned n_components,
1199 struct kdbus_cmd_match *m;
1200 struct kdbus_item *item;
1203 const char *sender = NULL;
1204 size_t sender_length = 0;
1205 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1206 bool using_bloom = false;
1208 bool matches_name_change = true;
1209 const char *name_change_arg[3] = {};
1214 /* Monitor streams don't support matches, make this a NOP */
1215 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1218 bloom = alloca0(bus->bloom_size);
1220 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1222 for (i = 0; i < n_components; i++) {
1223 struct bus_match_component *c = &components[i];
1227 case BUS_MATCH_SENDER:
1228 if (!streq(c->value_str, "org.freedesktop.DBus"))
1229 matches_name_change = false;
1231 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1235 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1237 sender = c->value_str;
1238 sender_length = strlen(sender);
1239 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1244 case BUS_MATCH_MESSAGE_TYPE:
1245 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1246 matches_name_change = false;
1248 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1252 case BUS_MATCH_INTERFACE:
1253 if (!streq(c->value_str, "org.freedesktop.DBus"))
1254 matches_name_change = false;
1256 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1260 case BUS_MATCH_MEMBER:
1261 if (!streq(c->value_str, "NameOwnerChanged"))
1262 matches_name_change = false;
1264 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1268 case BUS_MATCH_PATH:
1269 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1270 matches_name_change = false;
1272 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1276 case BUS_MATCH_PATH_NAMESPACE:
1277 if (!streq(c->value_str, "/")) {
1278 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1283 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1284 char buf[sizeof("arg")-1 + 2 + 1];
1286 if (c->type - BUS_MATCH_ARG < 3)
1287 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1289 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1290 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1295 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1296 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1298 xsprintf(buf, "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1299 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1304 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1305 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1307 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1308 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1313 case BUS_MATCH_DESTINATION:
1314 /* The bloom filter does not include
1315 the destination, since it is only
1316 available for broadcast messages
1317 which do not carry a destination
1318 since they are undirected. */
1321 case BUS_MATCH_ROOT:
1322 case BUS_MATCH_VALUE:
1323 case BUS_MATCH_LEAF:
1324 case _BUS_MATCH_NODE_TYPE_MAX:
1325 case _BUS_MATCH_NODE_TYPE_INVALID:
1326 assert_not_reached("Invalid match type?");
1331 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1333 m = alloca0_align(sz, 8);
1339 if (src_id != KDBUS_MATCH_ID_ANY) {
1340 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1341 item->type = KDBUS_ITEM_ID;
1343 item = KDBUS_ITEM_NEXT(item);
1347 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1348 item->type = KDBUS_ITEM_BLOOM_MASK;
1349 memcpy(item->data64, bloom, bus->bloom_size);
1350 item = KDBUS_ITEM_NEXT(item);
1354 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1355 item->type = KDBUS_ITEM_NAME;
1356 memcpy(item->str, sender, sender_length + 1);
1359 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1363 if (matches_name_change) {
1365 /* If this match could theoretically match
1366 * NameOwnerChanged messages, we need to
1367 * install a second non-bloom filter explitly
1370 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1378 #define internal_match(bus, m) \
1379 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1380 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1383 static int bus_add_match_internal_dbus1(
1385 const char *match) {
1392 e = internal_match(bus, match);
1394 return sd_bus_call_method(
1396 "org.freedesktop.DBus",
1397 "/org/freedesktop/DBus",
1398 "org.freedesktop.DBus",
1406 int bus_add_match_internal(
1409 struct bus_match_component *components,
1410 unsigned n_components,
1415 if (!bus->bus_client)
1419 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1421 return bus_add_match_internal_dbus1(bus, match);
1424 int bus_remove_match_internal_kernel(
1428 struct kdbus_cmd_match m = {
1429 .size = offsetof(struct kdbus_cmd_match, items),
1436 /* Monitor streams don't support matches, make this a NOP */
1437 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1440 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1447 static int bus_remove_match_internal_dbus1(
1449 const char *match) {
1456 e = internal_match(bus, match);
1458 return sd_bus_call_method(
1460 "org.freedesktop.DBus",
1461 "/org/freedesktop/DBus",
1462 "org.freedesktop.DBus",
1470 int bus_remove_match_internal(
1477 if (!bus->bus_client)
1481 return bus_remove_match_internal_kernel(bus, cookie);
1483 return bus_remove_match_internal_dbus1(bus, match);
1486 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1487 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1491 assert_return(bus, -EINVAL);
1492 assert_return(name, -EINVAL);
1493 assert_return(machine, -EINVAL);
1494 assert_return(!bus_pid_changed(bus), -ECHILD);
1495 assert_return(service_name_is_valid(name), -EINVAL);
1497 if (!bus->bus_client)
1500 if (!BUS_IS_OPEN(bus->state))
1503 if (streq_ptr(name, bus->unique_name))
1504 return sd_id128_get_machine(machine);
1506 r = sd_bus_message_new_method_call(
1511 "org.freedesktop.DBus.Peer",
1516 r = sd_bus_message_set_auto_start(m, false);
1520 r = sd_bus_call(bus, m, 0, NULL, &reply);
1524 r = sd_bus_message_read(reply, "s", &mid);
1528 return sd_id128_from_string(mid, machine);