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 "cgroup-util.h"
38 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
41 assert_return(bus, -EINVAL);
42 assert_return(unique, -EINVAL);
43 assert_return(!bus_pid_changed(bus), -ECHILD);
45 r = bus_ensure_running(bus);
49 *unique = bus->unique_name;
53 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
54 struct kdbus_cmd_name *n;
62 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
63 n = alloca0_align(size, 8);
65 n->flags = request_name_flags_to_kdbus(flags);
67 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
68 n->items[0].type = KDBUS_ITEM_NAME;
69 memcpy(n->items[0].str, name, l);
71 #ifdef HAVE_VALGRIND_MEMCHECK_H
72 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
75 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
79 if (n->flags & KDBUS_NAME_IN_QUEUE)
85 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
86 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
87 uint32_t ret, param = 0;
93 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
94 param |= BUS_NAME_ALLOW_REPLACEMENT;
95 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
96 param |= BUS_NAME_REPLACE_EXISTING;
97 if (!(flags & SD_BUS_NAME_QUEUE))
98 param |= BUS_NAME_DO_NOT_QUEUE;
100 r = sd_bus_call_method(
102 "org.freedesktop.DBus",
103 "/org/freedesktop/DBus",
104 "org.freedesktop.DBus",
114 r = sd_bus_message_read(reply, "u", &ret);
118 if (ret == BUS_NAME_ALREADY_OWNER)
120 else if (ret == BUS_NAME_EXISTS)
122 else if (ret == BUS_NAME_IN_QUEUE)
124 else if (ret == BUS_NAME_PRIMARY_OWNER)
130 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
131 assert_return(bus, -EINVAL);
132 assert_return(name, -EINVAL);
133 assert_return(bus->bus_client, -EINVAL);
134 assert_return(!bus_pid_changed(bus), -ECHILD);
135 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
136 assert_return(service_name_is_valid(name), -EINVAL);
137 assert_return(name[0] != ':', -EINVAL);
139 if (!BUS_IS_OPEN(bus->state))
143 return bus_request_name_kernel(bus, name, flags);
145 return bus_request_name_dbus1(bus, name, flags);
148 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
149 struct kdbus_cmd_name *n;
156 l = strlen(name) + 1;
157 size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
158 n = alloca0_align(size, 8);
161 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
162 n->items[0].type = KDBUS_ITEM_NAME;
163 memcpy(n->items[0].str, name, l);
165 #ifdef HAVE_VALGRIND_MEMCHECK_H
166 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
168 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
175 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
176 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
183 r = sd_bus_call_method(
185 "org.freedesktop.DBus",
186 "/org/freedesktop/DBus",
187 "org.freedesktop.DBus",
196 r = sd_bus_message_read(reply, "u", &ret);
199 if (ret == BUS_NAME_NON_EXISTENT)
201 if (ret == BUS_NAME_NOT_OWNER)
203 if (ret == BUS_NAME_RELEASED)
209 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
210 assert_return(bus, -EINVAL);
211 assert_return(name, -EINVAL);
212 assert_return(bus->bus_client, -EINVAL);
213 assert_return(!bus_pid_changed(bus), -ECHILD);
214 assert_return(service_name_is_valid(name), -EINVAL);
215 assert_return(name[0] != ':', -EINVAL);
217 if (!BUS_IS_OPEN(bus->state))
221 return bus_release_name_kernel(bus, name);
223 return bus_release_name_dbus1(bus, name);
226 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
227 struct kdbus_cmd_name_list cmd = {};
228 struct kdbus_name_list *name_list;
229 struct kdbus_name_info *name;
230 uint64_t previous_id = 0;
233 /* Caller will free half-constructed list on failure... */
235 cmd.size = sizeof(cmd);
238 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
242 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
244 KDBUS_ITEM_FOREACH(name, name_list, names) {
246 struct kdbus_item *item;
247 const char *entry_name = NULL;
249 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
252 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
257 r = strv_consume(x, n);
261 previous_id = name->owner_id;
264 KDBUS_ITEM_FOREACH(item, name, items)
265 if (item->type == KDBUS_ITEM_OWNED_NAME)
266 entry_name = item->name.name;
268 if (entry_name && service_name_is_valid(entry_name)) {
269 r = strv_extend(x, entry_name);
280 bus_kernel_cmd_free(bus, cmd.offset);
284 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
285 _cleanup_strv_free_ char **x = NULL, **y = NULL;
289 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
295 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
311 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
312 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
313 _cleanup_strv_free_ char **x = NULL, **y = NULL;
317 r = sd_bus_call_method(
319 "org.freedesktop.DBus",
320 "/org/freedesktop/DBus",
321 "org.freedesktop.DBus",
329 r = sd_bus_message_read_strv(reply, &x);
333 reply = sd_bus_message_unref(reply);
337 r = sd_bus_call_method(
339 "org.freedesktop.DBus",
340 "/org/freedesktop/DBus",
341 "org.freedesktop.DBus",
342 "ListActivatableNames",
349 r = sd_bus_message_read_strv(reply, &y);
365 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
366 assert_return(bus, -EINVAL);
367 assert_return(acquired || activatable, -EINVAL);
368 assert_return(!bus_pid_changed(bus), -ECHILD);
370 if (!BUS_IS_OPEN(bus->state))
374 return bus_list_names_kernel(bus, acquired, activatable);
376 return bus_list_names_dbus1(bus, acquired, activatable);
379 static int bus_populate_creds_from_items(
381 struct kdbus_info *info,
385 struct kdbus_item *item;
393 KDBUS_ITEM_FOREACH(item, info, items) {
395 switch (item->type) {
397 case KDBUS_ITEM_PIDS:
399 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
400 c->pid = (pid_t) item->pids.pid;
401 c->mask |= SD_BUS_CREDS_PID;
404 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
405 c->tid = (pid_t) item->pids.tid;
406 c->mask |= SD_BUS_CREDS_TID;
411 case KDBUS_ITEM_CREDS:
413 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
414 c->uid = (uid_t) item->creds.uid;
415 c->mask |= SD_BUS_CREDS_UID;
418 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
419 c->euid = (uid_t) item->creds.euid;
420 c->mask |= SD_BUS_CREDS_EUID;
423 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
424 c->suid = (uid_t) item->creds.suid;
425 c->mask |= SD_BUS_CREDS_SUID;
428 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
429 c->fsuid = (uid_t) item->creds.fsuid;
430 c->mask |= SD_BUS_CREDS_FSUID;
433 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
434 c->gid = (gid_t) item->creds.gid;
435 c->mask |= SD_BUS_CREDS_GID;
438 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
439 c->egid = (gid_t) item->creds.egid;
440 c->mask |= SD_BUS_CREDS_EGID;
443 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
444 c->sgid = (gid_t) item->creds.sgid;
445 c->mask |= SD_BUS_CREDS_SGID;
448 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
449 c->fsgid = (gid_t) item->creds.fsgid;
450 c->mask |= SD_BUS_CREDS_FSGID;
455 case KDBUS_ITEM_PID_COMM:
456 if (mask & SD_BUS_CREDS_COMM) {
457 r = free_and_strdup(&c->comm, item->str);
461 c->mask |= SD_BUS_CREDS_COMM;
465 case KDBUS_ITEM_TID_COMM:
466 if (mask & SD_BUS_CREDS_TID_COMM) {
467 r = free_and_strdup(&c->tid_comm, item->str);
471 c->mask |= SD_BUS_CREDS_TID_COMM;
476 if (mask & SD_BUS_CREDS_EXE) {
477 r = free_and_strdup(&c->exe, item->str);
481 c->mask |= SD_BUS_CREDS_EXE;
485 case KDBUS_ITEM_CMDLINE:
486 if (mask & SD_BUS_CREDS_CMDLINE) {
487 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
488 c->cmdline = memdup(item->data, c->cmdline_size);
492 c->mask |= SD_BUS_CREDS_CMDLINE;
496 case KDBUS_ITEM_CGROUP:
497 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
498 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
499 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
502 r = free_and_strdup(&c->cgroup, item->str);
506 r = bus_get_root_path(bus);
510 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
518 case KDBUS_ITEM_CAPS:
519 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
520 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
523 c->capability_size = item->size - offsetof(struct kdbus_item, caps.caps);
524 c->capability = memdup(item->caps.caps, c->capability_size);
532 case KDBUS_ITEM_SECLABEL:
533 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
534 r = free_and_strdup(&c->label, item->str);
538 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
542 case KDBUS_ITEM_AUDIT:
543 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
544 c->audit_session_id = (uint32_t) item->audit.sessionid;
545 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
548 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
549 c->audit_login_uid = (uid_t) item->audit.loginuid;
550 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
554 case KDBUS_ITEM_OWNED_NAME:
555 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
556 r = strv_extend(&c->well_known_names, item->name.name);
560 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
564 case KDBUS_ITEM_CONN_DESCRIPTION:
565 if (mask & SD_BUS_CREDS_DESCRIPTION) {
566 r = free_and_strdup(&c->description, item->str);
570 c->mask |= SD_BUS_CREDS_DESCRIPTION;
574 case KDBUS_ITEM_AUXGROUPS:
575 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
579 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
581 n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
582 g = newdup(gid_t, item->data32, n);
586 free(c->supplementary_gids);
587 c->supplementary_gids = g;
588 c->n_supplementary_gids = n;
590 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
599 int bus_get_name_creds_kdbus(
603 bool allow_activator,
604 sd_bus_creds **creds) {
606 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
607 struct kdbus_cmd_info *cmd;
608 struct kdbus_info *conn_info;
613 r = bus_kernel_parse_unique_name(name, &id);
617 size = offsetof(struct kdbus_cmd_info, items);
618 cmd = alloca0_align(size, 8);
621 l = strlen(name) + 1;
622 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
623 cmd = alloca0_align(size, 8);
624 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
625 cmd->items[0].type = KDBUS_ITEM_NAME;
626 memcpy(cmd->items[0].str, name, l);
630 cmd->flags = attach_flags_to_kdbus(mask);
632 /* If augmentation is on, and the bus doesn't didn't allow us
633 * to get the bits we want, then ask for the PID/TID so that we
634 * can read the rest from /proc. */
635 if ((mask & SD_BUS_CREDS_AUGMENT) &&
636 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
637 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
638 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
639 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|
640 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
641 SD_BUS_CREDS_SELINUX_CONTEXT|
642 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
643 cmd->flags |= KDBUS_ATTACH_PIDS;
645 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
649 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
651 /* Non-activated names are considered not available */
652 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
666 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
667 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
672 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
675 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
676 them in case the service has no names. This does not mean
677 however that the list of owned names could not be
678 acquired. Hence, let's explicitly clarify that the data is
680 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
682 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
686 r = bus_creds_add_more(c, mask, 0, 0);
698 bus_kernel_cmd_free(bus, cmd->offset);
702 static int bus_get_name_creds_dbus1(
706 sd_bus_creds **creds) {
708 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
709 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
710 const char *unique = NULL;
714 /* Only query the owner if the caller wants to know it or if
715 * the caller just wants to check whether a name exists */
716 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
717 r = sd_bus_call_method(
719 "org.freedesktop.DBus",
720 "/org/freedesktop/DBus",
721 "org.freedesktop.DBus",
730 r = sd_bus_message_read(reply_unique, "s", &unique);
740 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
741 c->unique_name = strdup(unique);
745 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
748 if ((mask & SD_BUS_CREDS_PID) ||
749 ((mask & SD_BUS_CREDS_AUGMENT) &&
750 (mask & (SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
751 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
752 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
753 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|
754 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
755 SD_BUS_CREDS_SELINUX_CONTEXT|
756 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
760 r = sd_bus_call_method(
762 "org.freedesktop.DBus",
763 "/org/freedesktop/DBus",
764 "org.freedesktop.DBus",
765 "GetConnectionUnixProcessID",
769 unique ? unique : name);
773 r = sd_bus_message_read(reply, "u", &u);
778 if (mask & SD_BUS_CREDS_PID) {
780 c->mask |= SD_BUS_CREDS_PID;
783 reply = sd_bus_message_unref(reply);
786 if (mask & SD_BUS_CREDS_UID) {
789 r = sd_bus_call_method(
791 "org.freedesktop.DBus",
792 "/org/freedesktop/DBus",
793 "org.freedesktop.DBus",
794 "GetConnectionUnixUser",
798 unique ? unique : name);
802 r = sd_bus_message_read(reply, "u", &u);
807 c->mask |= SD_BUS_CREDS_UID;
809 reply = sd_bus_message_unref(reply);
812 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
813 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
814 const void *p = NULL;
817 r = sd_bus_call_method(
819 "org.freedesktop.DBus",
820 "/org/freedesktop/DBus",
821 "org.freedesktop.DBus",
822 "GetConnectionSELinuxSecurityContext",
826 unique ? unique : name);
828 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
831 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
835 c->label = strndup(p, sz);
839 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
843 r = bus_creds_add_more(c, mask, pid, 0);
856 _public_ int sd_bus_get_name_creds(
860 sd_bus_creds **creds) {
862 assert_return(bus, -EINVAL);
863 assert_return(name, -EINVAL);
864 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
865 assert_return(mask == 0 || creds, -EINVAL);
866 assert_return(!bus_pid_changed(bus), -ECHILD);
867 assert_return(service_name_is_valid(name), -EINVAL);
868 assert_return(bus->bus_client, -ENODATA);
870 if (!BUS_IS_OPEN(bus->state))
874 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
876 return bus_get_name_creds_dbus1(bus, name, mask, creds);
879 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
880 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
881 struct kdbus_cmd_info cmd = {
882 .size = sizeof(struct kdbus_cmd_info)
884 struct kdbus_info *creator_info;
892 cmd.flags = attach_flags_to_kdbus(mask);
894 /* If augmentation is on, and the bus doesn't didn't allow us
895 * to get the bits we want, then ask for the PID/TID so that we
896 * can read the rest from /proc. */
897 if ((mask & SD_BUS_CREDS_AUGMENT) &&
898 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
899 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
900 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
901 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|
902 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
903 SD_BUS_CREDS_SELINUX_CONTEXT|
904 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
905 cmd.flags |= KDBUS_ATTACH_PIDS;
907 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
911 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
913 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
914 bus_kernel_cmd_free(bus, cmd.offset);
918 r = bus_creds_add_more(c, mask, pid, 0);
927 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
928 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
932 if (!bus->ucred_valid && !isempty(bus->label))
939 if (bus->ucred_valid) {
940 if (bus->ucred.pid > 0) {
941 pid = c->pid = bus->ucred.pid;
942 c->mask |= SD_BUS_CREDS_PID & mask;
945 if (bus->ucred.uid != UID_INVALID) {
946 c->uid = bus->ucred.uid;
947 c->mask |= SD_BUS_CREDS_UID & mask;
950 if (bus->ucred.gid != GID_INVALID) {
951 c->gid = bus->ucred.gid;
952 c->mask |= SD_BUS_CREDS_GID & mask;
956 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
957 c->label = strdup(bus->label);
961 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
964 r = bus_creds_add_more(c, mask, pid, 0);
973 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
974 assert_return(bus, -EINVAL);
975 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
976 assert_return(ret, -EINVAL);
977 assert_return(!bus_pid_changed(bus), -ECHILD);
979 if (!BUS_IS_OPEN(bus->state))
983 return bus_get_owner_creds_kdbus(bus, mask, ret);
985 return bus_get_owner_creds_dbus1(bus, mask, ret);
988 static int add_name_change_match(sd_bus *bus,
991 const char *old_owner,
992 const char *new_owner) {
994 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
995 int is_name_id = -1, r;
996 struct kdbus_item *item;
1000 /* If we encounter a match that could match against
1001 * NameOwnerChanged messages, then we need to create
1002 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1003 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1004 * multiple if the match is underspecified.
1006 * The NameOwnerChanged signals take three parameters with
1007 * unique or well-known names, but only some forms actually
1010 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1011 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1012 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1013 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1014 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1016 * For the latter two the two unique names must be identical.
1021 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1026 if (!isempty(old_owner)) {
1027 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1032 if (is_name_id > 0 && old_owner_id != name_id)
1035 old_owner_id = KDBUS_MATCH_ID_ANY;
1037 if (!isempty(new_owner)) {
1038 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1043 if (is_name_id > 0 && new_owner_id != name_id)
1046 new_owner_id = KDBUS_MATCH_ID_ANY;
1048 if (is_name_id <= 0) {
1049 struct kdbus_cmd_match *m;
1052 /* If the name argument is missing or is a well-known
1053 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1056 l = name ? strlen(name) + 1 : 0;
1058 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1059 offsetof(struct kdbus_item, name_change) +
1060 offsetof(struct kdbus_notify_name_change, name) +
1063 m = alloca0_align(sz, 8);
1069 offsetof(struct kdbus_item, name_change) +
1070 offsetof(struct kdbus_notify_name_change, name) +
1073 item->name_change.old_id.id = old_owner_id;
1074 item->name_change.new_id.id = new_owner_id;
1077 memcpy(item->name_change.name, name, l);
1079 /* If the old name is unset or empty, then
1080 * this can match against added names */
1081 if (!old_owner || old_owner[0] == 0) {
1082 item->type = KDBUS_ITEM_NAME_ADD;
1084 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1089 /* If the new name is unset or empty, then
1090 * this can match against removed names */
1091 if (!new_owner || new_owner[0] == 0) {
1092 item->type = KDBUS_ITEM_NAME_REMOVE;
1094 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1099 /* The CHANGE match we need in either case, because
1100 * what is reported as a name change by the kernel
1101 * might just be an owner change between starter and
1102 * normal clients. For userspace such a change should
1103 * be considered a removal/addition, hence let's
1104 * subscribe to this unconditionally. */
1105 item->type = KDBUS_ITEM_NAME_CHANGE;
1106 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1111 if (is_name_id != 0) {
1112 struct kdbus_cmd_match *m;
1115 /* If the name argument is missing or is a unique
1116 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1119 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1120 offsetof(struct kdbus_item, id_change) +
1121 sizeof(struct kdbus_notify_id_change));
1123 m = alloca0_align(sz, 8);
1129 offsetof(struct kdbus_item, id_change) +
1130 sizeof(struct kdbus_notify_id_change);
1131 item->id_change.id = name_id;
1133 /* If the old name is unset or empty, then this can
1134 * match against added ids */
1135 if (!old_owner || old_owner[0] == 0) {
1136 item->type = KDBUS_ITEM_ID_ADD;
1138 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1143 /* If thew new name is unset or empty, then this can
1144 * match against removed ids */
1145 if (!new_owner || new_owner[0] == 0) {
1146 item->type = KDBUS_ITEM_ID_REMOVE;
1148 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1157 int bus_add_match_internal_kernel(
1159 struct bus_match_component *components,
1160 unsigned n_components,
1163 struct kdbus_cmd_match *m;
1164 struct kdbus_item *item;
1167 const char *sender = NULL;
1168 size_t sender_length = 0;
1169 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1170 bool using_bloom = false;
1172 bool matches_name_change = true;
1173 const char *name_change_arg[3] = {};
1178 /* Monitor streams don't support matches, make this a NOP */
1179 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1182 bloom = alloca0(bus->bloom_size);
1184 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1186 for (i = 0; i < n_components; i++) {
1187 struct bus_match_component *c = &components[i];
1191 case BUS_MATCH_SENDER:
1192 if (!streq(c->value_str, "org.freedesktop.DBus"))
1193 matches_name_change = false;
1195 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1199 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1201 sender = c->value_str;
1202 sender_length = strlen(sender);
1203 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1208 case BUS_MATCH_MESSAGE_TYPE:
1209 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1210 matches_name_change = false;
1212 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1216 case BUS_MATCH_INTERFACE:
1217 if (!streq(c->value_str, "org.freedesktop.DBus"))
1218 matches_name_change = false;
1220 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1224 case BUS_MATCH_MEMBER:
1225 if (!streq(c->value_str, "NameOwnerChanged"))
1226 matches_name_change = false;
1228 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1232 case BUS_MATCH_PATH:
1233 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1234 matches_name_change = false;
1236 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1240 case BUS_MATCH_PATH_NAMESPACE:
1241 if (!streq(c->value_str, "/")) {
1242 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1247 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1248 char buf[sizeof("arg")-1 + 2 + 1];
1250 if (c->type - BUS_MATCH_ARG < 3)
1251 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1253 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1254 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1259 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1260 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1262 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1263 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1268 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1269 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1271 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1272 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1277 case BUS_MATCH_DESTINATION:
1278 /* The bloom filter does not include
1279 the destination, since it is only
1280 available for broadcast messages
1281 which do not carry a destination
1282 since they are undirected. */
1285 case BUS_MATCH_ROOT:
1286 case BUS_MATCH_VALUE:
1287 case BUS_MATCH_LEAF:
1288 case _BUS_MATCH_NODE_TYPE_MAX:
1289 case _BUS_MATCH_NODE_TYPE_INVALID:
1290 assert_not_reached("Invalid match type?");
1295 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1297 m = alloca0_align(sz, 8);
1303 if (src_id != KDBUS_MATCH_ID_ANY) {
1304 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1305 item->type = KDBUS_ITEM_ID;
1307 item = KDBUS_ITEM_NEXT(item);
1311 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1312 item->type = KDBUS_ITEM_BLOOM_MASK;
1313 memcpy(item->data64, bloom, bus->bloom_size);
1314 item = KDBUS_ITEM_NEXT(item);
1318 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1319 item->type = KDBUS_ITEM_NAME;
1320 memcpy(item->str, sender, sender_length + 1);
1323 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1327 if (matches_name_change) {
1329 /* If this match could theoretically match
1330 * NameOwnerChanged messages, we need to
1331 * install a second non-bloom filter explitly
1334 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1342 #define internal_match(bus, m) \
1343 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1344 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1347 static int bus_add_match_internal_dbus1(
1349 const char *match) {
1356 e = internal_match(bus, match);
1358 return sd_bus_call_method(
1360 "org.freedesktop.DBus",
1361 "/org/freedesktop/DBus",
1362 "org.freedesktop.DBus",
1370 int bus_add_match_internal(
1373 struct bus_match_component *components,
1374 unsigned n_components,
1380 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1382 return bus_add_match_internal_dbus1(bus, match);
1385 int bus_remove_match_internal_kernel(
1389 struct kdbus_cmd_match m;
1394 /* Monitor streams don't support matches, make this a NOP */
1395 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1399 m.size = offsetof(struct kdbus_cmd_match, items);
1402 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1409 static int bus_remove_match_internal_dbus1(
1411 const char *match) {
1418 e = internal_match(bus, match);
1420 return sd_bus_call_method(
1422 "org.freedesktop.DBus",
1423 "/org/freedesktop/DBus",
1424 "org.freedesktop.DBus",
1432 int bus_remove_match_internal(
1440 return bus_remove_match_internal_kernel(bus, cookie);
1442 return bus_remove_match_internal_dbus1(bus, match);
1445 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1446 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1450 assert_return(bus, -EINVAL);
1451 assert_return(name, -EINVAL);
1452 assert_return(machine, -EINVAL);
1453 assert_return(!bus_pid_changed(bus), -ECHILD);
1454 assert_return(service_name_is_valid(name), -EINVAL);
1456 if (!BUS_IS_OPEN(bus->state))
1459 if (streq_ptr(name, bus->unique_name))
1460 return sd_id128_get_machine(machine);
1462 r = sd_bus_message_new_method_call(
1467 "org.freedesktop.DBus.Peer",
1472 r = sd_bus_message_set_auto_start(m, false);
1476 r = sd_bus_call(bus, m, 0, NULL, &reply);
1480 r = sd_bus_message_read(reply, "s", &mid);
1484 return sd_id128_from_string(mid, machine);