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"
37 #include "cgroup-util.h"
39 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
42 assert_return(bus, -EINVAL);
43 assert_return(unique, -EINVAL);
44 assert_return(!bus_pid_changed(bus), -ECHILD);
46 r = bus_ensure_running(bus);
50 *unique = bus->unique_name;
54 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
55 struct kdbus_cmd_name *n;
63 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
64 n = alloca0_align(size, 8);
66 n->flags = request_name_flags_to_kdbus(flags);
68 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
69 n->items[0].type = KDBUS_ITEM_NAME;
70 memcpy(n->items[0].str, name, l);
72 #ifdef HAVE_VALGRIND_MEMCHECK_H
73 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
76 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
80 if (n->flags & KDBUS_NAME_IN_QUEUE)
86 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
87 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
88 uint32_t ret, param = 0;
94 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
95 param |= BUS_NAME_ALLOW_REPLACEMENT;
96 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
97 param |= BUS_NAME_REPLACE_EXISTING;
98 if (!(flags & SD_BUS_NAME_QUEUE))
99 param |= BUS_NAME_DO_NOT_QUEUE;
101 r = sd_bus_call_method(
103 "org.freedesktop.DBus",
104 "/org/freedesktop/DBus",
105 "org.freedesktop.DBus",
115 r = sd_bus_message_read(reply, "u", &ret);
119 if (ret == BUS_NAME_ALREADY_OWNER)
121 else if (ret == BUS_NAME_EXISTS)
123 else if (ret == BUS_NAME_IN_QUEUE)
125 else if (ret == BUS_NAME_PRIMARY_OWNER)
131 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
132 assert_return(bus, -EINVAL);
133 assert_return(name, -EINVAL);
134 assert_return(bus->bus_client, -EINVAL);
135 assert_return(!bus_pid_changed(bus), -ECHILD);
136 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
137 assert_return(service_name_is_valid(name), -EINVAL);
138 assert_return(name[0] != ':', -EINVAL);
140 if (!BUS_IS_OPEN(bus->state))
144 return bus_request_name_kernel(bus, name, flags);
146 return bus_request_name_dbus1(bus, name, flags);
149 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
150 struct kdbus_cmd_name *n;
157 l = strlen(name) + 1;
158 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
159 n = alloca0_align(size, 8);
162 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
163 n->items[0].type = KDBUS_ITEM_NAME;
164 memcpy(n->items[0].str, name, l);
166 #ifdef HAVE_VALGRIND_MEMCHECK_H
167 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
169 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
176 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
177 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
184 r = sd_bus_call_method(
186 "org.freedesktop.DBus",
187 "/org/freedesktop/DBus",
188 "org.freedesktop.DBus",
197 r = sd_bus_message_read(reply, "u", &ret);
200 if (ret == BUS_NAME_NON_EXISTENT)
202 if (ret == BUS_NAME_NOT_OWNER)
204 if (ret == BUS_NAME_RELEASED)
210 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
211 assert_return(bus, -EINVAL);
212 assert_return(name, -EINVAL);
213 assert_return(bus->bus_client, -EINVAL);
214 assert_return(!bus_pid_changed(bus), -ECHILD);
215 assert_return(service_name_is_valid(name), -EINVAL);
216 assert_return(name[0] != ':', -EINVAL);
218 if (!BUS_IS_OPEN(bus->state))
222 return bus_release_name_kernel(bus, name);
224 return bus_release_name_dbus1(bus, name);
227 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
228 struct kdbus_cmd_name_list cmd = {};
229 struct kdbus_name_list *name_list;
230 struct kdbus_name_info *name;
231 uint64_t previous_id = 0;
234 /* Caller will free half-constructed list on failure... */
236 cmd.size = sizeof(cmd);
239 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
243 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
245 KDBUS_ITEM_FOREACH(name, name_list, names) {
247 struct kdbus_item *item;
248 const char *entry_name = NULL;
250 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
253 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
258 r = strv_consume(x, n);
262 previous_id = name->owner_id;
265 KDBUS_ITEM_FOREACH(item, name, items)
266 if (item->type == KDBUS_ITEM_OWNED_NAME)
267 entry_name = item->name.name;
269 if (entry_name && service_name_is_valid(entry_name)) {
270 r = strv_extend(x, entry_name);
281 bus_kernel_cmd_free(bus, cmd.offset);
285 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
286 _cleanup_strv_free_ char **x = NULL, **y = NULL;
290 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
296 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
312 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
313 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
314 _cleanup_strv_free_ char **x = NULL, **y = NULL;
318 r = sd_bus_call_method(
320 "org.freedesktop.DBus",
321 "/org/freedesktop/DBus",
322 "org.freedesktop.DBus",
330 r = sd_bus_message_read_strv(reply, &x);
334 reply = sd_bus_message_unref(reply);
338 r = sd_bus_call_method(
340 "org.freedesktop.DBus",
341 "/org/freedesktop/DBus",
342 "org.freedesktop.DBus",
343 "ListActivatableNames",
350 r = sd_bus_message_read_strv(reply, &y);
366 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
367 assert_return(bus, -EINVAL);
368 assert_return(acquired || activatable, -EINVAL);
369 assert_return(!bus_pid_changed(bus), -ECHILD);
371 if (!BUS_IS_OPEN(bus->state))
375 return bus_list_names_kernel(bus, acquired, activatable);
377 return bus_list_names_dbus1(bus, acquired, activatable);
380 static int bus_populate_creds_from_items(
382 struct kdbus_info *info,
386 struct kdbus_item *item;
394 KDBUS_ITEM_FOREACH(item, info, items) {
396 switch (item->type) {
398 case KDBUS_ITEM_PIDS:
400 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
401 c->pid = (pid_t) item->pids.pid;
402 c->mask |= SD_BUS_CREDS_PID;
405 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
406 c->tid = (pid_t) item->pids.tid;
407 c->mask |= SD_BUS_CREDS_TID;
412 case KDBUS_ITEM_CREDS:
414 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
415 c->uid = (uid_t) item->creds.uid;
416 c->mask |= SD_BUS_CREDS_UID;
419 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
420 c->euid = (uid_t) item->creds.euid;
421 c->mask |= SD_BUS_CREDS_EUID;
424 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
425 c->suid = (uid_t) item->creds.suid;
426 c->mask |= SD_BUS_CREDS_SUID;
429 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
430 c->fsuid = (uid_t) item->creds.fsuid;
431 c->mask |= SD_BUS_CREDS_FSUID;
434 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
435 c->gid = (gid_t) item->creds.gid;
436 c->mask |= SD_BUS_CREDS_GID;
439 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
440 c->egid = (gid_t) item->creds.egid;
441 c->mask |= SD_BUS_CREDS_EGID;
444 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
445 c->sgid = (gid_t) item->creds.sgid;
446 c->mask |= SD_BUS_CREDS_SGID;
449 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
450 c->fsgid = (gid_t) item->creds.fsgid;
451 c->mask |= SD_BUS_CREDS_FSGID;
456 case KDBUS_ITEM_PID_COMM:
457 if (mask & SD_BUS_CREDS_COMM) {
458 r = free_and_strdup(&c->comm, item->str);
462 c->mask |= SD_BUS_CREDS_COMM;
466 case KDBUS_ITEM_TID_COMM:
467 if (mask & SD_BUS_CREDS_TID_COMM) {
468 r = free_and_strdup(&c->tid_comm, item->str);
472 c->mask |= SD_BUS_CREDS_TID_COMM;
477 if (mask & SD_BUS_CREDS_EXE) {
478 r = free_and_strdup(&c->exe, item->str);
482 c->mask |= SD_BUS_CREDS_EXE;
486 case KDBUS_ITEM_CMDLINE:
487 if (mask & SD_BUS_CREDS_CMDLINE) {
488 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
489 c->cmdline = memdup(item->data, c->cmdline_size);
493 c->mask |= SD_BUS_CREDS_CMDLINE;
497 case KDBUS_ITEM_CGROUP:
498 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
499 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
500 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
503 r = free_and_strdup(&c->cgroup, item->str);
507 r = bus_get_root_path(bus);
511 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
519 case KDBUS_ITEM_CAPS:
520 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
521 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
524 if (item->caps.last_cap != cap_last_cap() ||
525 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
528 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
536 case KDBUS_ITEM_SECLABEL:
537 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
538 r = free_and_strdup(&c->label, item->str);
542 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
546 case KDBUS_ITEM_AUDIT:
547 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
548 c->audit_session_id = (uint32_t) item->audit.sessionid;
549 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
552 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
553 c->audit_login_uid = (uid_t) item->audit.loginuid;
554 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
558 case KDBUS_ITEM_OWNED_NAME:
559 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
560 r = strv_extend(&c->well_known_names, item->name.name);
564 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
568 case KDBUS_ITEM_CONN_DESCRIPTION:
569 if (mask & SD_BUS_CREDS_DESCRIPTION) {
570 r = free_and_strdup(&c->description, item->str);
574 c->mask |= SD_BUS_CREDS_DESCRIPTION;
578 case KDBUS_ITEM_AUXGROUPS:
579 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
583 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
585 n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
586 g = newdup(gid_t, item->data32, n);
590 free(c->supplementary_gids);
591 c->supplementary_gids = g;
592 c->n_supplementary_gids = n;
594 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
603 int bus_get_name_creds_kdbus(
607 bool allow_activator,
608 sd_bus_creds **creds) {
610 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
611 struct kdbus_cmd_info *cmd;
612 struct kdbus_info *conn_info;
617 r = bus_kernel_parse_unique_name(name, &id);
621 size = offsetof(struct kdbus_cmd_info, items);
622 cmd = alloca0_align(size, 8);
625 l = strlen(name) + 1;
626 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
627 cmd = alloca0_align(size, 8);
628 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
629 cmd->items[0].type = KDBUS_ITEM_NAME;
630 memcpy(cmd->items[0].str, name, l);
634 cmd->flags = attach_flags_to_kdbus(mask);
636 /* If augmentation is on, and the bus doesn't didn't allow us
637 * to get the bits we want, then ask for the PID/TID so that we
638 * can read the rest from /proc. */
639 if ((mask & SD_BUS_CREDS_AUGMENT) &&
640 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
641 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
642 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
643 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|
644 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
645 SD_BUS_CREDS_SELINUX_CONTEXT|
646 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
647 cmd->flags |= KDBUS_ATTACH_PIDS;
649 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
653 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
655 /* Non-activated names are considered not available */
656 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
670 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
671 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
676 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
679 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
680 them in case the service has no names. This does not mean
681 however that the list of owned names could not be
682 acquired. Hence, let's explicitly clarify that the data is
684 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
686 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
690 r = bus_creds_add_more(c, mask, 0, 0);
702 bus_kernel_cmd_free(bus, cmd->offset);
706 static int bus_get_name_creds_dbus1(
710 sd_bus_creds **creds) {
712 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
713 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
714 const char *unique = NULL;
718 /* Only query the owner if the caller wants to know it or if
719 * the caller just wants to check whether a name exists */
720 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
721 r = sd_bus_call_method(
723 "org.freedesktop.DBus",
724 "/org/freedesktop/DBus",
725 "org.freedesktop.DBus",
734 r = sd_bus_message_read(reply_unique, "s", &unique);
744 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
745 c->unique_name = strdup(unique);
749 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
752 if ((mask & SD_BUS_CREDS_PID) ||
753 ((mask & SD_BUS_CREDS_AUGMENT) &&
754 (mask & (SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
755 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
756 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
757 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|
758 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
759 SD_BUS_CREDS_SELINUX_CONTEXT|
760 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
764 r = sd_bus_call_method(
766 "org.freedesktop.DBus",
767 "/org/freedesktop/DBus",
768 "org.freedesktop.DBus",
769 "GetConnectionUnixProcessID",
773 unique ? unique : name);
777 r = sd_bus_message_read(reply, "u", &u);
782 if (mask & SD_BUS_CREDS_PID) {
784 c->mask |= SD_BUS_CREDS_PID;
787 reply = sd_bus_message_unref(reply);
790 if (mask & SD_BUS_CREDS_UID) {
793 r = sd_bus_call_method(
795 "org.freedesktop.DBus",
796 "/org/freedesktop/DBus",
797 "org.freedesktop.DBus",
798 "GetConnectionUnixUser",
802 unique ? unique : name);
806 r = sd_bus_message_read(reply, "u", &u);
811 c->mask |= SD_BUS_CREDS_UID;
813 reply = sd_bus_message_unref(reply);
816 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
817 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
818 const void *p = NULL;
821 r = sd_bus_call_method(
823 "org.freedesktop.DBus",
824 "/org/freedesktop/DBus",
825 "org.freedesktop.DBus",
826 "GetConnectionSELinuxSecurityContext",
830 unique ? unique : name);
832 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
835 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
839 c->label = strndup(p, sz);
843 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
847 r = bus_creds_add_more(c, mask, pid, 0);
860 _public_ int sd_bus_get_name_creds(
864 sd_bus_creds **creds) {
866 assert_return(bus, -EINVAL);
867 assert_return(name, -EINVAL);
868 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
869 assert_return(mask == 0 || creds, -EINVAL);
870 assert_return(!bus_pid_changed(bus), -ECHILD);
871 assert_return(service_name_is_valid(name), -EINVAL);
872 assert_return(bus->bus_client, -ENODATA);
874 if (!BUS_IS_OPEN(bus->state))
878 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
880 return bus_get_name_creds_dbus1(bus, name, mask, creds);
883 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
884 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
885 struct kdbus_cmd_info cmd = {
886 .size = sizeof(struct kdbus_cmd_info)
888 struct kdbus_info *creator_info;
896 cmd.flags = attach_flags_to_kdbus(mask);
898 /* If augmentation is on, and the bus doesn't didn't allow us
899 * to get the bits we want, then ask for the PID/TID so that we
900 * can read the rest from /proc. */
901 if ((mask & SD_BUS_CREDS_AUGMENT) &&
902 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
903 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
904 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
905 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|
906 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
907 SD_BUS_CREDS_SELINUX_CONTEXT|
908 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
909 cmd.flags |= KDBUS_ATTACH_PIDS;
911 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
915 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
917 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
918 bus_kernel_cmd_free(bus, cmd.offset);
922 r = bus_creds_add_more(c, mask, pid, 0);
931 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
932 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
936 if (!bus->ucred_valid && !isempty(bus->label))
943 if (bus->ucred_valid) {
944 if (bus->ucred.pid > 0) {
945 pid = c->pid = bus->ucred.pid;
946 c->mask |= SD_BUS_CREDS_PID & mask;
949 if (bus->ucred.uid != UID_INVALID) {
950 c->uid = bus->ucred.uid;
951 c->mask |= SD_BUS_CREDS_UID & mask;
954 if (bus->ucred.gid != GID_INVALID) {
955 c->gid = bus->ucred.gid;
956 c->mask |= SD_BUS_CREDS_GID & mask;
960 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
961 c->label = strdup(bus->label);
965 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
968 r = bus_creds_add_more(c, mask, pid, 0);
977 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
978 assert_return(bus, -EINVAL);
979 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
980 assert_return(ret, -EINVAL);
981 assert_return(!bus_pid_changed(bus), -ECHILD);
983 if (!BUS_IS_OPEN(bus->state))
987 return bus_get_owner_creds_kdbus(bus, mask, ret);
989 return bus_get_owner_creds_dbus1(bus, mask, ret);
992 static int add_name_change_match(sd_bus *bus,
995 const char *old_owner,
996 const char *new_owner) {
998 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
999 int is_name_id = -1, r;
1000 struct kdbus_item *item;
1004 /* If we encounter a match that could match against
1005 * NameOwnerChanged messages, then we need to create
1006 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1007 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1008 * multiple if the match is underspecified.
1010 * The NameOwnerChanged signals take three parameters with
1011 * unique or well-known names, but only some forms actually
1014 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1015 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1016 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1017 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1018 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1020 * For the latter two the two unique names must be identical.
1025 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1030 if (!isempty(old_owner)) {
1031 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1036 if (is_name_id > 0 && old_owner_id != name_id)
1039 old_owner_id = KDBUS_MATCH_ID_ANY;
1041 if (!isempty(new_owner)) {
1042 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1047 if (is_name_id > 0 && new_owner_id != name_id)
1050 new_owner_id = KDBUS_MATCH_ID_ANY;
1052 if (is_name_id <= 0) {
1053 struct kdbus_cmd_match *m;
1056 /* If the name argument is missing or is a well-known
1057 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1060 l = name ? strlen(name) + 1 : 0;
1062 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1063 offsetof(struct kdbus_item, name_change) +
1064 offsetof(struct kdbus_notify_name_change, name) +
1067 m = alloca0_align(sz, 8);
1073 offsetof(struct kdbus_item, name_change) +
1074 offsetof(struct kdbus_notify_name_change, name) +
1077 item->name_change.old_id.id = old_owner_id;
1078 item->name_change.new_id.id = new_owner_id;
1081 memcpy(item->name_change.name, name, l);
1083 /* If the old name is unset or empty, then
1084 * this can match against added names */
1085 if (!old_owner || old_owner[0] == 0) {
1086 item->type = KDBUS_ITEM_NAME_ADD;
1088 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1093 /* If the new name is unset or empty, then
1094 * this can match against removed names */
1095 if (!new_owner || new_owner[0] == 0) {
1096 item->type = KDBUS_ITEM_NAME_REMOVE;
1098 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1103 /* The CHANGE match we need in either case, because
1104 * what is reported as a name change by the kernel
1105 * might just be an owner change between starter and
1106 * normal clients. For userspace such a change should
1107 * be considered a removal/addition, hence let's
1108 * subscribe to this unconditionally. */
1109 item->type = KDBUS_ITEM_NAME_CHANGE;
1110 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1115 if (is_name_id != 0) {
1116 struct kdbus_cmd_match *m;
1119 /* If the name argument is missing or is a unique
1120 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1123 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1124 offsetof(struct kdbus_item, id_change) +
1125 sizeof(struct kdbus_notify_id_change));
1127 m = alloca0_align(sz, 8);
1133 offsetof(struct kdbus_item, id_change) +
1134 sizeof(struct kdbus_notify_id_change);
1135 item->id_change.id = name_id;
1137 /* If the old name is unset or empty, then this can
1138 * match against added ids */
1139 if (!old_owner || old_owner[0] == 0) {
1140 item->type = KDBUS_ITEM_ID_ADD;
1142 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1147 /* If thew new name is unset or empty, then this can
1148 * match against removed ids */
1149 if (!new_owner || new_owner[0] == 0) {
1150 item->type = KDBUS_ITEM_ID_REMOVE;
1152 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1161 int bus_add_match_internal_kernel(
1163 struct bus_match_component *components,
1164 unsigned n_components,
1167 struct kdbus_cmd_match *m;
1168 struct kdbus_item *item;
1171 const char *sender = NULL;
1172 size_t sender_length = 0;
1173 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1174 bool using_bloom = false;
1176 bool matches_name_change = true;
1177 const char *name_change_arg[3] = {};
1182 /* Monitor streams don't support matches, make this a NOP */
1183 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1186 bloom = alloca0(bus->bloom_size);
1188 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1190 for (i = 0; i < n_components; i++) {
1191 struct bus_match_component *c = &components[i];
1195 case BUS_MATCH_SENDER:
1196 if (!streq(c->value_str, "org.freedesktop.DBus"))
1197 matches_name_change = false;
1199 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1203 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1205 sender = c->value_str;
1206 sender_length = strlen(sender);
1207 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1212 case BUS_MATCH_MESSAGE_TYPE:
1213 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1214 matches_name_change = false;
1216 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1220 case BUS_MATCH_INTERFACE:
1221 if (!streq(c->value_str, "org.freedesktop.DBus"))
1222 matches_name_change = false;
1224 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1228 case BUS_MATCH_MEMBER:
1229 if (!streq(c->value_str, "NameOwnerChanged"))
1230 matches_name_change = false;
1232 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1236 case BUS_MATCH_PATH:
1237 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1238 matches_name_change = false;
1240 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1244 case BUS_MATCH_PATH_NAMESPACE:
1245 if (!streq(c->value_str, "/")) {
1246 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1251 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1252 char buf[sizeof("arg")-1 + 2 + 1];
1254 if (c->type - BUS_MATCH_ARG < 3)
1255 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1257 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1258 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1263 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1264 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1266 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1267 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1272 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1273 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1275 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1276 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1281 case BUS_MATCH_DESTINATION:
1282 /* The bloom filter does not include
1283 the destination, since it is only
1284 available for broadcast messages
1285 which do not carry a destination
1286 since they are undirected. */
1289 case BUS_MATCH_ROOT:
1290 case BUS_MATCH_VALUE:
1291 case BUS_MATCH_LEAF:
1292 case _BUS_MATCH_NODE_TYPE_MAX:
1293 case _BUS_MATCH_NODE_TYPE_INVALID:
1294 assert_not_reached("Invalid match type?");
1299 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1301 m = alloca0_align(sz, 8);
1307 if (src_id != KDBUS_MATCH_ID_ANY) {
1308 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1309 item->type = KDBUS_ITEM_ID;
1311 item = KDBUS_ITEM_NEXT(item);
1315 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1316 item->type = KDBUS_ITEM_BLOOM_MASK;
1317 memcpy(item->data64, bloom, bus->bloom_size);
1318 item = KDBUS_ITEM_NEXT(item);
1322 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1323 item->type = KDBUS_ITEM_NAME;
1324 memcpy(item->str, sender, sender_length + 1);
1327 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1331 if (matches_name_change) {
1333 /* If this match could theoretically match
1334 * NameOwnerChanged messages, we need to
1335 * install a second non-bloom filter explitly
1338 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1346 #define internal_match(bus, m) \
1347 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1348 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1351 static int bus_add_match_internal_dbus1(
1353 const char *match) {
1360 e = internal_match(bus, match);
1362 return sd_bus_call_method(
1364 "org.freedesktop.DBus",
1365 "/org/freedesktop/DBus",
1366 "org.freedesktop.DBus",
1374 int bus_add_match_internal(
1377 struct bus_match_component *components,
1378 unsigned n_components,
1384 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1386 return bus_add_match_internal_dbus1(bus, match);
1389 int bus_remove_match_internal_kernel(
1393 struct kdbus_cmd_match m;
1398 /* Monitor streams don't support matches, make this a NOP */
1399 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1403 m.size = offsetof(struct kdbus_cmd_match, items);
1406 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1413 static int bus_remove_match_internal_dbus1(
1415 const char *match) {
1422 e = internal_match(bus, match);
1424 return sd_bus_call_method(
1426 "org.freedesktop.DBus",
1427 "/org/freedesktop/DBus",
1428 "org.freedesktop.DBus",
1436 int bus_remove_match_internal(
1444 return bus_remove_match_internal_kernel(bus, cookie);
1446 return bus_remove_match_internal_dbus1(bus, match);
1449 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1450 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1454 assert_return(bus, -EINVAL);
1455 assert_return(name, -EINVAL);
1456 assert_return(machine, -EINVAL);
1457 assert_return(!bus_pid_changed(bus), -ECHILD);
1458 assert_return(service_name_is_valid(name), -EINVAL);
1460 if (!BUS_IS_OPEN(bus->state))
1463 if (streq_ptr(name, bus->unique_name))
1464 return sd_id128_get_machine(machine);
1466 r = sd_bus_message_new_method_call(
1471 "org.freedesktop.DBus.Peer",
1476 r = sd_bus_message_set_auto_start(m, false);
1480 r = sd_bus_call(bus, m, 0, NULL, &reply);
1484 r = sd_bus_message_read(reply, "s", &mid);
1488 return sd_id128_from_string(mid, machine);