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);
789 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
790 bool need_pid, need_uid, need_selinux, need_separate_calls;
795 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
796 c->unique_name = strdup(unique);
800 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
803 need_pid = (mask & SD_BUS_CREDS_PID) ||
804 ((mask & SD_BUS_CREDS_AUGMENT) &&
805 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
806 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
807 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
808 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
809 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|
810 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
811 SD_BUS_CREDS_SELINUX_CONTEXT|
812 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
813 need_uid = mask & SD_BUS_CREDS_EUID;
814 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
816 if (need_pid + need_uid + need_selinux > 1) {
818 /* If we need more than one of the credentials, then use GetConnectionCredentials() */
820 r = sd_bus_call_method(
822 "org.freedesktop.DBus",
823 "/org/freedesktop/DBus",
824 "org.freedesktop.DBus",
825 "GetConnectionCredentials",
833 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
836 /* If we got an unknown method error, fall back to the invidual calls... */
837 need_separate_calls = true;
838 sd_bus_error_free(&error);
841 need_separate_calls = false;
843 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
850 r = sd_bus_message_enter_container(reply, 'e', "sv");
856 r = sd_bus_message_read(reply, "s", &m);
860 if (need_uid && streq(m, "UnixUserID")) {
863 r = sd_bus_message_read(reply, "v", "u", &u);
868 c->mask |= SD_BUS_CREDS_EUID;
870 } else if (need_pid && streq(m, "ProcessID")) {
873 r = sd_bus_message_read(reply, "v", "u", &p);
878 if (mask & SD_BUS_CREDS_PID) {
880 c->mask |= SD_BUS_CREDS_PID;
883 } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
884 const void *p = NULL;
887 r = sd_bus_message_enter_container(reply, 'v', "ay");
891 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
896 c->label = strndup(p, sz);
900 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
902 r = sd_bus_message_exit_container(reply);
906 r = sd_bus_message_skip(reply, "v");
911 r = sd_bus_message_exit_container(reply);
916 r = sd_bus_message_exit_container(reply);
920 if (need_pid && pid == 0)
924 } else /* When we only need a single field, then let's use separate calls */
925 need_separate_calls = true;
927 if (need_separate_calls) {
931 r = sd_bus_call_method(
933 "org.freedesktop.DBus",
934 "/org/freedesktop/DBus",
935 "org.freedesktop.DBus",
936 "GetConnectionUnixProcessID",
944 r = sd_bus_message_read(reply, "u", &u);
949 if (mask & SD_BUS_CREDS_PID) {
951 c->mask |= SD_BUS_CREDS_PID;
954 reply = sd_bus_message_unref(reply);
960 r = sd_bus_call_method(
962 "org.freedesktop.DBus",
963 "/org/freedesktop/DBus",
964 "org.freedesktop.DBus",
965 "GetConnectionUnixUser",
969 unique ? unique : name);
973 r = sd_bus_message_read(reply, "u", &u);
978 c->mask |= SD_BUS_CREDS_EUID;
980 reply = sd_bus_message_unref(reply);
984 const void *p = NULL;
987 r = sd_bus_call_method(
989 "org.freedesktop.DBus",
990 "/org/freedesktop/DBus",
991 "org.freedesktop.DBus",
992 "GetConnectionSELinuxSecurityContext",
996 unique ? unique : name);
998 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
1001 /* no data is fine */
1003 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
1007 c->label = strndup(p, sz);
1011 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1016 r = bus_creds_add_more(c, mask, pid, 0);
1029 _public_ int sd_bus_get_name_creds(
1033 sd_bus_creds **creds) {
1035 assert_return(bus, -EINVAL);
1036 assert_return(name, -EINVAL);
1037 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1038 assert_return(mask == 0 || creds, -EINVAL);
1039 assert_return(!bus_pid_changed(bus), -ECHILD);
1040 assert_return(service_name_is_valid(name), -EINVAL);
1042 if (!bus->bus_client)
1045 /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
1046 * going to match. */
1048 mask &= ~SD_BUS_CREDS_AUGMENT;
1050 if (streq(name, "org.freedesktop.DBus.Local"))
1053 if (streq(name, "org.freedesktop.DBus"))
1054 return sd_bus_get_owner_creds(bus, mask, creds);
1056 if (!BUS_IS_OPEN(bus->state))
1060 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
1062 return bus_get_name_creds_dbus1(bus, name, mask, creds);
1065 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1066 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
1067 struct kdbus_cmd_info cmd = {
1068 .size = sizeof(struct kdbus_cmd_info),
1070 struct kdbus_info *creator_info;
1074 c = bus_creds_new();
1078 /* If augmentation is on, and the bus doesn't didn't allow us
1079 * to get the bits we want, then ask for the PID/TID so that we
1080 * can read the rest from /proc. */
1081 if ((mask & SD_BUS_CREDS_AUGMENT) &&
1082 (mask & (SD_BUS_CREDS_PPID|
1083 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
1084 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
1085 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
1086 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
1087 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|
1088 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
1089 SD_BUS_CREDS_SELINUX_CONTEXT|
1090 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
1091 mask |= SD_BUS_CREDS_PID;
1093 cmd.attach_flags = attach_flags_to_kdbus(mask);
1095 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
1099 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
1101 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
1102 bus_kernel_cmd_free(bus, cmd.offset);
1106 r = bus_creds_add_more(c, mask, pid, 0);
1115 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1116 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
1123 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
1125 /* Avoid allocating anything if we have no chance of returning useful data */
1126 if (!bus->ucred_valid && !do_label)
1129 c = bus_creds_new();
1133 if (bus->ucred_valid) {
1134 if (bus->ucred.pid > 0) {
1135 pid = c->pid = bus->ucred.pid;
1136 c->mask |= SD_BUS_CREDS_PID & mask;
1139 if (bus->ucred.uid != UID_INVALID) {
1140 c->euid = bus->ucred.uid;
1141 c->mask |= SD_BUS_CREDS_EUID & mask;
1144 if (bus->ucred.gid != GID_INVALID) {
1145 c->egid = bus->ucred.gid;
1146 c->mask |= SD_BUS_CREDS_EGID & mask;
1151 c->label = strdup(bus->label);
1155 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1158 r = bus_creds_add_more(c, mask, pid, 0);
1167 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1168 assert_return(bus, -EINVAL);
1169 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1170 assert_return(ret, -EINVAL);
1171 assert_return(!bus_pid_changed(bus), -ECHILD);
1173 if (!BUS_IS_OPEN(bus->state))
1177 mask &= ~SD_BUS_CREDS_AUGMENT;
1180 return bus_get_owner_creds_kdbus(bus, mask, ret);
1182 return bus_get_owner_creds_dbus1(bus, mask, ret);
1185 static int add_name_change_match(sd_bus *bus,
1188 const char *old_owner,
1189 const char *new_owner) {
1191 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1192 int is_name_id = -1, r;
1193 struct kdbus_item *item;
1197 /* If we encounter a match that could match against
1198 * NameOwnerChanged messages, then we need to create
1199 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1200 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1201 * multiple if the match is underspecified.
1203 * The NameOwnerChanged signals take three parameters with
1204 * unique or well-known names, but only some forms actually
1207 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1208 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1209 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1210 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1211 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1213 * For the latter two the two unique names must be identical.
1218 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1223 if (!isempty(old_owner)) {
1224 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1229 if (is_name_id > 0 && old_owner_id != name_id)
1232 old_owner_id = KDBUS_MATCH_ID_ANY;
1234 if (!isempty(new_owner)) {
1235 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1240 if (is_name_id > 0 && new_owner_id != name_id)
1243 new_owner_id = KDBUS_MATCH_ID_ANY;
1245 if (is_name_id <= 0) {
1246 struct kdbus_cmd_match *m;
1249 /* If the name argument is missing or is a well-known
1250 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1253 l = name ? strlen(name) + 1 : 0;
1255 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1256 offsetof(struct kdbus_item, name_change) +
1257 offsetof(struct kdbus_notify_name_change, name) +
1260 m = alloca0_align(sz, 8);
1266 offsetof(struct kdbus_item, name_change) +
1267 offsetof(struct kdbus_notify_name_change, name) +
1270 item->name_change.old_id.id = old_owner_id;
1271 item->name_change.new_id.id = new_owner_id;
1273 memcpy_safe(item->name_change.name, name, l);
1275 /* If the old name is unset or empty, then
1276 * this can match against added names */
1277 if (isempty(old_owner)) {
1278 item->type = KDBUS_ITEM_NAME_ADD;
1280 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1285 /* If the new name is unset or empty, then
1286 * this can match against removed names */
1287 if (isempty(new_owner)) {
1288 item->type = KDBUS_ITEM_NAME_REMOVE;
1290 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1295 /* The CHANGE match we need in either case, because
1296 * what is reported as a name change by the kernel
1297 * might just be an owner change between starter and
1298 * normal clients. For userspace such a change should
1299 * be considered a removal/addition, hence let's
1300 * subscribe to this unconditionally. */
1301 item->type = KDBUS_ITEM_NAME_CHANGE;
1302 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1307 if (is_name_id != 0) {
1308 struct kdbus_cmd_match *m;
1311 /* If the name argument is missing or is a unique
1312 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1315 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1316 offsetof(struct kdbus_item, id_change) +
1317 sizeof(struct kdbus_notify_id_change));
1319 m = alloca0_align(sz, 8);
1325 offsetof(struct kdbus_item, id_change) +
1326 sizeof(struct kdbus_notify_id_change);
1327 item->id_change.id = name_id;
1329 /* If the old name is unset or empty, then this can
1330 * match against added ids */
1331 if (isempty(old_owner)) {
1332 item->type = KDBUS_ITEM_ID_ADD;
1333 if (!isempty(new_owner))
1334 item->id_change.id = new_owner_id;
1336 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1341 /* If thew new name is unset or empty, then this can
1342 * match against removed ids */
1343 if (isempty(new_owner)) {
1344 item->type = KDBUS_ITEM_ID_REMOVE;
1345 if (!isempty(old_owner))
1346 item->id_change.id = old_owner_id;
1348 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1357 int bus_add_match_internal_kernel(
1359 struct bus_match_component *components,
1360 unsigned n_components,
1363 struct kdbus_cmd_match *m;
1364 struct kdbus_item *item;
1367 const char *sender = NULL;
1368 size_t sender_length = 0;
1369 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1370 bool using_bloom = false;
1372 bool matches_name_change = true;
1373 const char *name_change_arg[3] = {};
1378 /* Monitor streams don't support matches, make this a NOP */
1379 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1382 bloom = alloca0(bus->bloom_size);
1384 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1386 for (i = 0; i < n_components; i++) {
1387 struct bus_match_component *c = &components[i];
1391 case BUS_MATCH_SENDER:
1392 if (!streq(c->value_str, "org.freedesktop.DBus"))
1393 matches_name_change = false;
1395 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1399 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1401 sender = c->value_str;
1402 sender_length = strlen(sender);
1403 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1408 case BUS_MATCH_MESSAGE_TYPE:
1409 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1410 matches_name_change = false;
1412 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1416 case BUS_MATCH_INTERFACE:
1417 if (!streq(c->value_str, "org.freedesktop.DBus"))
1418 matches_name_change = false;
1420 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1424 case BUS_MATCH_MEMBER:
1425 if (!streq(c->value_str, "NameOwnerChanged"))
1426 matches_name_change = false;
1428 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1432 case BUS_MATCH_PATH:
1433 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1434 matches_name_change = false;
1436 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1440 case BUS_MATCH_PATH_NAMESPACE:
1441 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1445 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1446 char buf[sizeof("arg")-1 + 2 + 1];
1448 if (c->type - BUS_MATCH_ARG < 3)
1449 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1451 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1452 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1457 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1458 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1460 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1461 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1466 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1468 * XXX: DBus spec defines arg[0..63]path= matching to be
1469 * a two-way glob. That is, if either string is a prefix
1470 * of the other, it matches.
1471 * This is really hard to realize in bloom-filters, as
1472 * we would have to create a bloom-match for each prefix
1473 * of @c->value_str. This is excessive, hence we just
1474 * ignore all those matches and accept everything from
1475 * the kernel. People should really avoid those matches.
1476 * If they're used in real-life some day, we will have
1477 * to properly support multiple-matches here.
1481 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1482 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1484 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1485 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1490 case BUS_MATCH_DESTINATION:
1492 * Kernel only supports matching on destination IDs, but
1493 * not on destination names. So just skip the
1494 * destination name restriction and verify it in
1495 * user-space on retrieval.
1497 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1501 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1503 /* if not a broadcast, it cannot be a name-change */
1504 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1505 matches_name_change = false;
1509 case BUS_MATCH_ROOT:
1510 case BUS_MATCH_VALUE:
1511 case BUS_MATCH_LEAF:
1512 case _BUS_MATCH_NODE_TYPE_MAX:
1513 case _BUS_MATCH_NODE_TYPE_INVALID:
1514 assert_not_reached("Invalid match type?");
1519 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1521 m = alloca0_align(sz, 8);
1527 if (src_id != KDBUS_MATCH_ID_ANY) {
1528 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1529 item->type = KDBUS_ITEM_ID;
1531 item = KDBUS_ITEM_NEXT(item);
1534 if (dst_id != KDBUS_MATCH_ID_ANY) {
1535 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1536 item->type = KDBUS_ITEM_DST_ID;
1538 item = KDBUS_ITEM_NEXT(item);
1542 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1543 item->type = KDBUS_ITEM_BLOOM_MASK;
1544 memcpy(item->data64, bloom, bus->bloom_size);
1545 item = KDBUS_ITEM_NEXT(item);
1549 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1550 item->type = KDBUS_ITEM_NAME;
1551 memcpy(item->str, sender, sender_length + 1);
1554 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1558 if (matches_name_change) {
1560 /* If this match could theoretically match
1561 * NameOwnerChanged messages, we need to
1562 * install a second non-bloom filter explitly
1565 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1573 #define internal_match(bus, m) \
1574 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1575 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1578 static int bus_add_match_internal_dbus1(
1580 const char *match) {
1587 e = internal_match(bus, match);
1589 return sd_bus_call_method(
1591 "org.freedesktop.DBus",
1592 "/org/freedesktop/DBus",
1593 "org.freedesktop.DBus",
1601 int bus_add_match_internal(
1604 struct bus_match_component *components,
1605 unsigned n_components,
1610 if (!bus->bus_client)
1614 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1616 return bus_add_match_internal_dbus1(bus, match);
1619 int bus_remove_match_internal_kernel(
1623 struct kdbus_cmd_match m = {
1624 .size = offsetof(struct kdbus_cmd_match, items),
1631 /* Monitor streams don't support matches, make this a NOP */
1632 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1635 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1642 static int bus_remove_match_internal_dbus1(
1644 const char *match) {
1651 e = internal_match(bus, match);
1653 return sd_bus_call_method(
1655 "org.freedesktop.DBus",
1656 "/org/freedesktop/DBus",
1657 "org.freedesktop.DBus",
1665 int bus_remove_match_internal(
1672 if (!bus->bus_client)
1676 return bus_remove_match_internal_kernel(bus, cookie);
1678 return bus_remove_match_internal_dbus1(bus, match);
1681 #if 0 /// UNNEEDED by elogind
1682 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1683 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1687 assert_return(bus, -EINVAL);
1688 assert_return(name, -EINVAL);
1689 assert_return(machine, -EINVAL);
1690 assert_return(!bus_pid_changed(bus), -ECHILD);
1691 assert_return(service_name_is_valid(name), -EINVAL);
1693 if (!bus->bus_client)
1696 if (!BUS_IS_OPEN(bus->state))
1699 if (streq_ptr(name, bus->unique_name))
1700 return sd_id128_get_machine(machine);
1702 r = sd_bus_message_new_method_call(
1707 "org.freedesktop.DBus.Peer",
1712 r = sd_bus_message_set_auto_start(m, false);
1716 r = sd_bus_call(bus, m, 0, NULL, &reply);
1720 r = sd_bus_message_read(reply, "s", &mid);
1724 return sd_id128_from_string(mid, machine);