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 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
272 r = strv_consume(x, n);
276 previous_id = name->id;
279 KDBUS_ITEM_FOREACH(item, name, items) {
280 if (item->type == KDBUS_ITEM_OWNED_NAME) {
281 if (service_name_is_valid(item->name.name)) {
282 r = strv_extend(x, item->name.name);
295 bus_kernel_cmd_free(bus, cmd.offset);
299 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
300 _cleanup_strv_free_ char **x = NULL, **y = NULL;
304 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
310 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
326 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
327 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
328 _cleanup_strv_free_ char **x = NULL, **y = NULL;
332 r = sd_bus_call_method(
334 "org.freedesktop.DBus",
335 "/org/freedesktop/DBus",
336 "org.freedesktop.DBus",
344 r = sd_bus_message_read_strv(reply, &x);
348 reply = sd_bus_message_unref(reply);
352 r = sd_bus_call_method(
354 "org.freedesktop.DBus",
355 "/org/freedesktop/DBus",
356 "org.freedesktop.DBus",
357 "ListActivatableNames",
364 r = sd_bus_message_read_strv(reply, &y);
380 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
381 assert_return(bus, -EINVAL);
382 assert_return(acquired || activatable, -EINVAL);
383 assert_return(!bus_pid_changed(bus), -ECHILD);
385 if (!bus->bus_client)
388 if (!BUS_IS_OPEN(bus->state))
392 return bus_list_names_kernel(bus, acquired, activatable);
394 return bus_list_names_dbus1(bus, acquired, activatable);
397 static int bus_populate_creds_from_items(
399 struct kdbus_info *info,
403 struct kdbus_item *item;
411 KDBUS_ITEM_FOREACH(item, info, items) {
413 switch (item->type) {
415 case KDBUS_ITEM_PIDS:
417 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
418 c->pid = (pid_t) item->pids.pid;
419 c->mask |= SD_BUS_CREDS_PID;
422 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
423 c->tid = (pid_t) item->pids.tid;
424 c->mask |= SD_BUS_CREDS_TID;
427 if (mask & SD_BUS_CREDS_PPID) {
428 if (item->pids.ppid > 0) {
429 c->ppid = (pid_t) item->pids.ppid;
430 c->mask |= SD_BUS_CREDS_PPID;
431 } else if (item->pids.pid == 1) {
432 /* The structure doesn't
433 * really distinguish the case
434 * where a process has no
435 * parent and where we don't
436 * know it because it could
437 * not be translated due to
438 * namespaces. However, we
439 * know that PID 1 has no
440 * parent process, hence let's
441 * patch that in, manually. */
443 c->mask |= SD_BUS_CREDS_PPID;
449 case KDBUS_ITEM_CREDS:
451 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
452 c->uid = (uid_t) item->creds.uid;
453 c->mask |= SD_BUS_CREDS_UID;
456 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
457 c->euid = (uid_t) item->creds.euid;
458 c->mask |= SD_BUS_CREDS_EUID;
461 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
462 c->suid = (uid_t) item->creds.suid;
463 c->mask |= SD_BUS_CREDS_SUID;
466 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
467 c->fsuid = (uid_t) item->creds.fsuid;
468 c->mask |= SD_BUS_CREDS_FSUID;
471 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
472 c->gid = (gid_t) item->creds.gid;
473 c->mask |= SD_BUS_CREDS_GID;
476 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
477 c->egid = (gid_t) item->creds.egid;
478 c->mask |= SD_BUS_CREDS_EGID;
481 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
482 c->sgid = (gid_t) item->creds.sgid;
483 c->mask |= SD_BUS_CREDS_SGID;
486 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
487 c->fsgid = (gid_t) item->creds.fsgid;
488 c->mask |= SD_BUS_CREDS_FSGID;
493 case KDBUS_ITEM_PID_COMM:
494 if (mask & SD_BUS_CREDS_COMM) {
495 r = free_and_strdup(&c->comm, item->str);
499 c->mask |= SD_BUS_CREDS_COMM;
503 case KDBUS_ITEM_TID_COMM:
504 if (mask & SD_BUS_CREDS_TID_COMM) {
505 r = free_and_strdup(&c->tid_comm, item->str);
509 c->mask |= SD_BUS_CREDS_TID_COMM;
514 if (mask & SD_BUS_CREDS_EXE) {
515 r = free_and_strdup(&c->exe, item->str);
519 c->mask |= SD_BUS_CREDS_EXE;
523 case KDBUS_ITEM_CMDLINE:
524 if (mask & SD_BUS_CREDS_CMDLINE) {
525 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
526 c->cmdline = memdup(item->data, c->cmdline_size);
530 c->mask |= SD_BUS_CREDS_CMDLINE;
534 case KDBUS_ITEM_CGROUP:
535 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
536 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
537 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
540 r = free_and_strdup(&c->cgroup, item->str);
544 r = bus_get_root_path(bus);
548 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
556 case KDBUS_ITEM_CAPS:
557 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
558 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
561 if (item->caps.last_cap != cap_last_cap() ||
562 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
565 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
573 case KDBUS_ITEM_SECLABEL:
574 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
575 r = free_and_strdup(&c->label, item->str);
579 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
583 case KDBUS_ITEM_AUDIT:
584 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
585 c->audit_session_id = (uint32_t) item->audit.sessionid;
586 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
589 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
590 c->audit_login_uid = (uid_t) item->audit.loginuid;
591 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
595 case KDBUS_ITEM_OWNED_NAME:
596 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
597 r = strv_extend(&c->well_known_names, item->name.name);
601 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
605 case KDBUS_ITEM_CONN_DESCRIPTION:
606 if (mask & SD_BUS_CREDS_DESCRIPTION) {
607 r = free_and_strdup(&c->description, item->str);
611 c->mask |= SD_BUS_CREDS_DESCRIPTION;
615 case KDBUS_ITEM_AUXGROUPS:
616 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
620 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
625 for (i = 0; i < n; i++)
626 g[i] = item->data64[i];
628 free(c->supplementary_gids);
629 c->supplementary_gids = g;
630 c->n_supplementary_gids = n;
632 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
641 int bus_get_name_creds_kdbus(
645 bool allow_activator,
646 sd_bus_creds **creds) {
648 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
649 struct kdbus_cmd_info *cmd;
650 struct kdbus_info *conn_info;
655 if (streq(name, "org.freedesktop.DBus"))
658 r = bus_kernel_parse_unique_name(name, &id);
662 size = offsetof(struct kdbus_cmd_info, items);
663 cmd = alloca0_align(size, 8);
666 l = strlen(name) + 1;
667 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
668 cmd = alloca0_align(size, 8);
669 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
670 cmd->items[0].type = KDBUS_ITEM_NAME;
671 memcpy(cmd->items[0].str, name, l);
674 /* If augmentation is on, and the bus didn't provide us
675 * the bits we want, then ask for the PID/TID so that we
676 * can read the rest from /proc. */
677 if ((mask & SD_BUS_CREDS_AUGMENT) &&
678 (mask & (SD_BUS_CREDS_PPID|
679 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
680 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
681 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
682 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|
683 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
684 SD_BUS_CREDS_SELINUX_CONTEXT|
685 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
686 mask |= SD_BUS_CREDS_PID;
689 cmd->attach_flags = attach_flags_to_kdbus(mask);
691 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
695 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
697 /* Non-activated names are considered not available */
698 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
712 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
713 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
718 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
721 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
722 them in case the service has no names. This does not mean
723 however that the list of owned names could not be
724 acquired. Hence, let's explicitly clarify that the data is
726 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
728 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
732 r = bus_creds_add_more(c, mask, 0, 0);
744 bus_kernel_cmd_free(bus, cmd->offset);
748 static int bus_get_name_creds_dbus1(
752 sd_bus_creds **creds) {
754 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
755 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
756 const char *unique = NULL;
760 /* Only query the owner if the caller wants to know it or if
761 * the caller just wants to check whether a name exists */
762 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
763 r = sd_bus_call_method(
765 "org.freedesktop.DBus",
766 "/org/freedesktop/DBus",
767 "org.freedesktop.DBus",
776 r = sd_bus_message_read(reply_unique, "s", &unique);
786 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
787 c->unique_name = strdup(unique);
791 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
794 if ((mask & SD_BUS_CREDS_PID) ||
795 ((mask & SD_BUS_CREDS_AUGMENT) &&
796 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
797 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
798 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
799 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|
800 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
801 SD_BUS_CREDS_SELINUX_CONTEXT|
802 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
806 r = sd_bus_call_method(
808 "org.freedesktop.DBus",
809 "/org/freedesktop/DBus",
810 "org.freedesktop.DBus",
811 "GetConnectionUnixProcessID",
815 unique ? unique : name);
819 r = sd_bus_message_read(reply, "u", &u);
824 if (mask & SD_BUS_CREDS_PID) {
826 c->mask |= SD_BUS_CREDS_PID;
829 reply = sd_bus_message_unref(reply);
832 if (mask & SD_BUS_CREDS_EUID) {
835 r = sd_bus_call_method(
837 "org.freedesktop.DBus",
838 "/org/freedesktop/DBus",
839 "org.freedesktop.DBus",
840 "GetConnectionUnixUser",
844 unique ? unique : name);
848 r = sd_bus_message_read(reply, "u", &u);
853 c->mask |= SD_BUS_CREDS_EUID;
855 reply = sd_bus_message_unref(reply);
858 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
859 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
860 const void *p = NULL;
863 r = sd_bus_call_method(
865 "org.freedesktop.DBus",
866 "/org/freedesktop/DBus",
867 "org.freedesktop.DBus",
868 "GetConnectionSELinuxSecurityContext",
872 unique ? unique : name);
874 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
877 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
881 c->label = strndup(p, sz);
885 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
889 r = bus_creds_add_more(c, mask, pid, 0);
902 _public_ int sd_bus_get_name_creds(
906 sd_bus_creds **creds) {
908 assert_return(bus, -EINVAL);
909 assert_return(name, -EINVAL);
910 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
911 assert_return(mask == 0 || creds, -EINVAL);
912 assert_return(!bus_pid_changed(bus), -ECHILD);
913 assert_return(service_name_is_valid(name), -EINVAL);
915 if (!bus->bus_client)
918 if (streq(name, "org.freedesktop.DBus.Local"))
921 if (!BUS_IS_OPEN(bus->state))
925 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
927 return bus_get_name_creds_dbus1(bus, name, mask, creds);
930 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
931 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
932 struct kdbus_cmd_info cmd = {
933 .size = sizeof(struct kdbus_cmd_info),
935 struct kdbus_info *creator_info;
943 /* If augmentation is on, and the bus doesn't didn't allow us
944 * to get the bits we want, then ask for the PID/TID so that we
945 * can read the rest from /proc. */
946 if ((mask & SD_BUS_CREDS_AUGMENT) &&
947 (mask & (SD_BUS_CREDS_PPID|
948 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
949 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
950 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
951 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|
952 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
953 SD_BUS_CREDS_SELINUX_CONTEXT|
954 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
955 mask |= SD_BUS_CREDS_PID;
957 cmd.attach_flags = attach_flags_to_kdbus(mask);
959 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
963 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
965 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
966 bus_kernel_cmd_free(bus, cmd.offset);
970 r = bus_creds_add_more(c, mask, pid, 0);
979 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
980 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
987 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
989 /* Avoid allocating anything if we have no chance of returning useful data */
990 if (!bus->ucred_valid && !do_label)
997 if (bus->ucred_valid) {
998 if (bus->ucred.pid > 0) {
999 pid = c->pid = bus->ucred.pid;
1000 c->mask |= SD_BUS_CREDS_PID & mask;
1003 if (bus->ucred.uid != UID_INVALID) {
1004 c->euid = bus->ucred.uid;
1005 c->mask |= SD_BUS_CREDS_EUID & mask;
1008 if (bus->ucred.gid != GID_INVALID) {
1009 c->egid = bus->ucred.gid;
1010 c->mask |= SD_BUS_CREDS_EGID & mask;
1015 c->label = strdup(bus->label);
1019 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1022 r = bus_creds_add_more(c, mask, pid, 0);
1031 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1032 assert_return(bus, -EINVAL);
1033 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1034 assert_return(ret, -EINVAL);
1035 assert_return(!bus_pid_changed(bus), -ECHILD);
1037 if (!BUS_IS_OPEN(bus->state))
1041 return bus_get_owner_creds_kdbus(bus, mask, ret);
1043 return bus_get_owner_creds_dbus1(bus, mask, ret);
1046 static int add_name_change_match(sd_bus *bus,
1049 const char *old_owner,
1050 const char *new_owner) {
1052 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1053 int is_name_id = -1, r;
1054 struct kdbus_item *item;
1058 /* If we encounter a match that could match against
1059 * NameOwnerChanged messages, then we need to create
1060 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1061 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1062 * multiple if the match is underspecified.
1064 * The NameOwnerChanged signals take three parameters with
1065 * unique or well-known names, but only some forms actually
1068 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1069 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1070 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1071 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1072 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1074 * For the latter two the two unique names must be identical.
1079 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1084 if (!isempty(old_owner)) {
1085 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1090 if (is_name_id > 0 && old_owner_id != name_id)
1093 old_owner_id = KDBUS_MATCH_ID_ANY;
1095 if (!isempty(new_owner)) {
1096 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1101 if (is_name_id > 0 && new_owner_id != name_id)
1104 new_owner_id = KDBUS_MATCH_ID_ANY;
1106 if (is_name_id <= 0) {
1107 struct kdbus_cmd_match *m;
1110 /* If the name argument is missing or is a well-known
1111 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1114 l = name ? strlen(name) + 1 : 0;
1116 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1117 offsetof(struct kdbus_item, name_change) +
1118 offsetof(struct kdbus_notify_name_change, name) +
1121 m = alloca0_align(sz, 8);
1127 offsetof(struct kdbus_item, name_change) +
1128 offsetof(struct kdbus_notify_name_change, name) +
1131 item->name_change.old_id.id = old_owner_id;
1132 item->name_change.new_id.id = new_owner_id;
1134 memcpy_safe(item->name_change.name, name, l);
1136 /* If the old name is unset or empty, then
1137 * this can match against added names */
1138 if (isempty(old_owner)) {
1139 item->type = KDBUS_ITEM_NAME_ADD;
1141 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1146 /* If the new name is unset or empty, then
1147 * this can match against removed names */
1148 if (isempty(new_owner)) {
1149 item->type = KDBUS_ITEM_NAME_REMOVE;
1151 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1156 /* The CHANGE match we need in either case, because
1157 * what is reported as a name change by the kernel
1158 * might just be an owner change between starter and
1159 * normal clients. For userspace such a change should
1160 * be considered a removal/addition, hence let's
1161 * subscribe to this unconditionally. */
1162 item->type = KDBUS_ITEM_NAME_CHANGE;
1163 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1168 if (is_name_id != 0) {
1169 struct kdbus_cmd_match *m;
1172 /* If the name argument is missing or is a unique
1173 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1176 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1177 offsetof(struct kdbus_item, id_change) +
1178 sizeof(struct kdbus_notify_id_change));
1180 m = alloca0_align(sz, 8);
1186 offsetof(struct kdbus_item, id_change) +
1187 sizeof(struct kdbus_notify_id_change);
1188 item->id_change.id = name_id;
1190 /* If the old name is unset or empty, then this can
1191 * match against added ids */
1192 if (isempty(old_owner)) {
1193 item->type = KDBUS_ITEM_ID_ADD;
1194 if (!isempty(new_owner))
1195 item->id_change.id = new_owner_id;
1197 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1202 /* If thew new name is unset or empty, then this can
1203 * match against removed ids */
1204 if (isempty(new_owner)) {
1205 item->type = KDBUS_ITEM_ID_REMOVE;
1206 if (!isempty(old_owner))
1207 item->id_change.id = old_owner_id;
1209 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1218 int bus_add_match_internal_kernel(
1220 struct bus_match_component *components,
1221 unsigned n_components,
1224 struct kdbus_cmd_match *m;
1225 struct kdbus_item *item;
1228 const char *sender = NULL;
1229 size_t sender_length = 0;
1230 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1231 bool using_bloom = false;
1233 bool matches_name_change = true;
1234 const char *name_change_arg[3] = {};
1239 /* Monitor streams don't support matches, make this a NOP */
1240 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1243 bloom = alloca0(bus->bloom_size);
1245 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1247 for (i = 0; i < n_components; i++) {
1248 struct bus_match_component *c = &components[i];
1252 case BUS_MATCH_SENDER:
1253 if (!streq(c->value_str, "org.freedesktop.DBus"))
1254 matches_name_change = false;
1256 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1260 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1262 sender = c->value_str;
1263 sender_length = strlen(sender);
1264 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1269 case BUS_MATCH_MESSAGE_TYPE:
1270 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1271 matches_name_change = false;
1273 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1277 case BUS_MATCH_INTERFACE:
1278 if (!streq(c->value_str, "org.freedesktop.DBus"))
1279 matches_name_change = false;
1281 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1285 case BUS_MATCH_MEMBER:
1286 if (!streq(c->value_str, "NameOwnerChanged"))
1287 matches_name_change = false;
1289 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1293 case BUS_MATCH_PATH:
1294 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1295 matches_name_change = false;
1297 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1301 case BUS_MATCH_PATH_NAMESPACE:
1302 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1306 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1307 char buf[sizeof("arg")-1 + 2 + 1];
1309 if (c->type - BUS_MATCH_ARG < 3)
1310 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1312 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1313 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1318 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1319 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1321 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1322 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1327 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1329 * XXX: DBus spec defines arg[0..63]path= matching to be
1330 * a two-way glob. That is, if either string is a prefix
1331 * of the other, it matches.
1332 * This is really hard to realize in bloom-filters, as
1333 * we would have to create a bloom-match for each prefix
1334 * of @c->value_str. This is excessive, hence we just
1335 * ignore all those matches and accept everything from
1336 * the kernel. People should really avoid those matches.
1337 * If they're used in real-life some day, we will have
1338 * to properly support multiple-matches here.
1342 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1343 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1345 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1346 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1351 case BUS_MATCH_DESTINATION:
1353 * Kernel only supports matching on destination IDs, but
1354 * not on destination names. So just skip the
1355 * destination name restriction and verify it in
1356 * user-space on retrieval.
1358 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1362 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1364 /* if not a broadcast, it cannot be a name-change */
1365 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1366 matches_name_change = false;
1370 case BUS_MATCH_ROOT:
1371 case BUS_MATCH_VALUE:
1372 case BUS_MATCH_LEAF:
1373 case _BUS_MATCH_NODE_TYPE_MAX:
1374 case _BUS_MATCH_NODE_TYPE_INVALID:
1375 assert_not_reached("Invalid match type?");
1380 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1382 m = alloca0_align(sz, 8);
1388 if (src_id != KDBUS_MATCH_ID_ANY) {
1389 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1390 item->type = KDBUS_ITEM_ID;
1392 item = KDBUS_ITEM_NEXT(item);
1395 if (dst_id != KDBUS_MATCH_ID_ANY) {
1396 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1397 item->type = KDBUS_ITEM_DST_ID;
1399 item = KDBUS_ITEM_NEXT(item);
1403 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1404 item->type = KDBUS_ITEM_BLOOM_MASK;
1405 memcpy(item->data64, bloom, bus->bloom_size);
1406 item = KDBUS_ITEM_NEXT(item);
1410 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1411 item->type = KDBUS_ITEM_NAME;
1412 memcpy(item->str, sender, sender_length + 1);
1415 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1419 if (matches_name_change) {
1421 /* If this match could theoretically match
1422 * NameOwnerChanged messages, we need to
1423 * install a second non-bloom filter explitly
1426 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1434 #define internal_match(bus, m) \
1435 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1436 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1439 static int bus_add_match_internal_dbus1(
1441 const char *match) {
1448 e = internal_match(bus, match);
1450 return sd_bus_call_method(
1452 "org.freedesktop.DBus",
1453 "/org/freedesktop/DBus",
1454 "org.freedesktop.DBus",
1462 int bus_add_match_internal(
1465 struct bus_match_component *components,
1466 unsigned n_components,
1471 if (!bus->bus_client)
1475 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1477 return bus_add_match_internal_dbus1(bus, match);
1480 int bus_remove_match_internal_kernel(
1484 struct kdbus_cmd_match m = {
1485 .size = offsetof(struct kdbus_cmd_match, items),
1492 /* Monitor streams don't support matches, make this a NOP */
1493 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1496 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1503 static int bus_remove_match_internal_dbus1(
1505 const char *match) {
1512 e = internal_match(bus, match);
1514 return sd_bus_call_method(
1516 "org.freedesktop.DBus",
1517 "/org/freedesktop/DBus",
1518 "org.freedesktop.DBus",
1526 int bus_remove_match_internal(
1533 if (!bus->bus_client)
1537 return bus_remove_match_internal_kernel(bus, cookie);
1539 return bus_remove_match_internal_dbus1(bus, match);
1542 #if 0 /// UNNEEDED by elogind
1543 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1544 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1548 assert_return(bus, -EINVAL);
1549 assert_return(name, -EINVAL);
1550 assert_return(machine, -EINVAL);
1551 assert_return(!bus_pid_changed(bus), -ECHILD);
1552 assert_return(service_name_is_valid(name), -EINVAL);
1554 if (!bus->bus_client)
1557 if (!BUS_IS_OPEN(bus->state))
1560 if (streq_ptr(name, bus->unique_name))
1561 return sd_id128_get_machine(machine);
1563 r = sd_bus_message_new_method_call(
1568 "org.freedesktop.DBus.Peer",
1573 r = sd_bus_message_set_auto_start(m, false);
1577 r = sd_bus_call(bus, m, 0, NULL, &reply);
1581 r = sd_bus_message_read(reply, "s", &mid);
1585 return sd_id128_from_string(mid, machine);