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... */
237 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
241 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
243 KDBUS_ITEM_FOREACH(name, name_list, names) {
245 struct kdbus_item *item;
246 const char *entry_name = NULL;
248 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
251 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
256 r = strv_consume(x, n);
260 previous_id = name->owner_id;
263 KDBUS_ITEM_FOREACH(item, name, items)
264 if (item->type == KDBUS_ITEM_OWNED_NAME)
265 entry_name = item->name.name;
267 if (entry_name && service_name_is_valid(entry_name)) {
268 r = strv_extend(x, entry_name);
279 bus_kernel_cmd_free(bus, cmd.offset);
283 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
284 _cleanup_strv_free_ char **x = NULL, **y = NULL;
288 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
294 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
310 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
311 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
312 _cleanup_strv_free_ char **x = NULL, **y = NULL;
316 r = sd_bus_call_method(
318 "org.freedesktop.DBus",
319 "/org/freedesktop/DBus",
320 "org.freedesktop.DBus",
328 r = sd_bus_message_read_strv(reply, &x);
332 reply = sd_bus_message_unref(reply);
336 r = sd_bus_call_method(
338 "org.freedesktop.DBus",
339 "/org/freedesktop/DBus",
340 "org.freedesktop.DBus",
341 "ListActivatableNames",
348 r = sd_bus_message_read_strv(reply, &y);
364 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
365 assert_return(bus, -EINVAL);
366 assert_return(acquired || activatable, -EINVAL);
367 assert_return(!bus_pid_changed(bus), -ECHILD);
369 if (!BUS_IS_OPEN(bus->state))
373 return bus_list_names_kernel(bus, acquired, activatable);
375 return bus_list_names_dbus1(bus, acquired, activatable);
378 static int bus_populate_creds_from_items(
380 struct kdbus_info *info,
384 struct kdbus_item *item;
392 KDBUS_ITEM_FOREACH(item, info, items) {
394 switch (item->type) {
396 case KDBUS_ITEM_PIDS:
398 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
399 c->pid = (pid_t) item->pids.pid;
400 c->mask |= SD_BUS_CREDS_PID;
403 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
404 c->tid = (pid_t) item->pids.tid;
405 c->mask |= SD_BUS_CREDS_TID;
410 case KDBUS_ITEM_CREDS:
412 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
413 c->uid = (uid_t) item->creds.uid;
414 c->mask |= SD_BUS_CREDS_UID;
417 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
418 c->euid = (uid_t) item->creds.euid;
419 c->mask |= SD_BUS_CREDS_EUID;
422 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
423 c->suid = (uid_t) item->creds.suid;
424 c->mask |= SD_BUS_CREDS_SUID;
427 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
428 c->fsuid = (uid_t) item->creds.fsuid;
429 c->mask |= SD_BUS_CREDS_FSUID;
432 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
433 c->gid = (gid_t) item->creds.gid;
434 c->mask |= SD_BUS_CREDS_GID;
437 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
438 c->egid = (gid_t) item->creds.egid;
439 c->mask |= SD_BUS_CREDS_EGID;
442 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
443 c->sgid = (gid_t) item->creds.sgid;
444 c->mask |= SD_BUS_CREDS_SGID;
447 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
448 c->fsgid = (gid_t) item->creds.fsgid;
449 c->mask |= SD_BUS_CREDS_FSGID;
454 case KDBUS_ITEM_PID_COMM:
455 if (mask & SD_BUS_CREDS_COMM) {
456 r = free_and_strdup(&c->comm, item->str);
460 c->mask |= SD_BUS_CREDS_COMM;
464 case KDBUS_ITEM_TID_COMM:
465 if (mask & SD_BUS_CREDS_TID_COMM) {
466 r = free_and_strdup(&c->tid_comm, item->str);
470 c->mask |= SD_BUS_CREDS_TID_COMM;
475 if (mask & SD_BUS_CREDS_EXE) {
476 r = free_and_strdup(&c->exe, item->str);
480 c->mask |= SD_BUS_CREDS_EXE;
484 case KDBUS_ITEM_CMDLINE:
485 if (mask & SD_BUS_CREDS_CMDLINE) {
486 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
487 c->cmdline = memdup(item->data, c->cmdline_size);
491 c->mask |= SD_BUS_CREDS_CMDLINE;
495 case KDBUS_ITEM_CGROUP:
496 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
497 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
498 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
501 r = free_and_strdup(&c->cgroup, item->str);
505 r = bus_get_root_path(bus);
509 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
517 case KDBUS_ITEM_CAPS:
518 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
519 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
522 c->capability_size = item->size - offsetof(struct kdbus_item, caps.caps);
523 c->capability = memdup(item->caps.caps, c->capability_size);
531 case KDBUS_ITEM_SECLABEL:
532 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
533 r = free_and_strdup(&c->label, item->str);
537 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
541 case KDBUS_ITEM_AUDIT:
542 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
543 c->audit_session_id = (uint32_t) item->audit.sessionid;
544 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
547 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
548 c->audit_login_uid = (uid_t) item->audit.loginuid;
549 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
553 case KDBUS_ITEM_OWNED_NAME:
554 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
555 r = strv_extend(&c->well_known_names, item->name.name);
559 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
563 case KDBUS_ITEM_CONN_DESCRIPTION:
564 if (mask & SD_BUS_CREDS_DESCRIPTION) {
565 r = free_and_strdup(&c->description, item->str);
569 c->mask |= SD_BUS_CREDS_DESCRIPTION;
573 case KDBUS_ITEM_AUXGROUPS:
574 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
578 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
580 n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
581 g = newdup(gid_t, item->data32, n);
585 free(c->supplementary_gids);
586 c->supplementary_gids = g;
587 c->n_supplementary_gids = n;
589 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
598 int bus_get_name_creds_kdbus(
602 bool allow_activator,
603 sd_bus_creds **creds) {
605 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
606 struct kdbus_cmd_info *cmd;
607 struct kdbus_info *conn_info;
612 r = bus_kernel_parse_unique_name(name, &id);
616 size = offsetof(struct kdbus_cmd_info, items);
617 cmd = alloca0_align(size, 8);
620 l = strlen(name) + 1;
621 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
622 cmd = alloca0_align(size, 8);
623 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
624 cmd->items[0].type = KDBUS_ITEM_NAME;
625 memcpy(cmd->items[0].str, name, l);
629 cmd->flags = attach_flags_to_kdbus(mask);
631 /* If augmentation is on, and the bus doesn't didn't allow us
632 * to get the bits we want, then ask for the PID/TID so that we
633 * can read the rest from /proc. */
634 if ((mask & SD_BUS_CREDS_AUGMENT) &&
635 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
636 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
637 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
638 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|
639 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
640 SD_BUS_CREDS_SELINUX_CONTEXT|
641 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
642 cmd->flags |= KDBUS_ATTACH_PIDS;
644 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
648 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
650 /* Non-activated names are considered not available */
651 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
665 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
666 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
671 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
674 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
675 them in case the service has no names. This does not mean
676 however that the list of owned names could not be
677 acquired. Hence, let's explicitly clarify that the data is
679 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
681 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
685 r = bus_creds_add_more(c, mask, 0, 0);
697 bus_kernel_cmd_free(bus, cmd->offset);
701 static int bus_get_name_creds_dbus1(
705 sd_bus_creds **creds) {
707 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
708 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
709 const char *unique = NULL;
713 /* Only query the owner if the caller wants to know it or if
714 * the caller just wants to check whether a name exists */
715 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
716 r = sd_bus_call_method(
718 "org.freedesktop.DBus",
719 "/org/freedesktop/DBus",
720 "org.freedesktop.DBus",
729 r = sd_bus_message_read(reply_unique, "s", &unique);
739 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
740 c->unique_name = strdup(unique);
744 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
747 if ((mask & SD_BUS_CREDS_PID) ||
748 ((mask & SD_BUS_CREDS_AUGMENT) &&
749 (mask & (SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
750 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
751 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
752 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|
753 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
754 SD_BUS_CREDS_SELINUX_CONTEXT|
755 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
759 r = sd_bus_call_method(
761 "org.freedesktop.DBus",
762 "/org/freedesktop/DBus",
763 "org.freedesktop.DBus",
764 "GetConnectionUnixProcessID",
768 unique ? unique : name);
772 r = sd_bus_message_read(reply, "u", &u);
777 if (mask & SD_BUS_CREDS_PID) {
779 c->mask |= SD_BUS_CREDS_PID;
782 reply = sd_bus_message_unref(reply);
785 if (mask & SD_BUS_CREDS_UID) {
788 r = sd_bus_call_method(
790 "org.freedesktop.DBus",
791 "/org/freedesktop/DBus",
792 "org.freedesktop.DBus",
793 "GetConnectionUnixUser",
797 unique ? unique : name);
801 r = sd_bus_message_read(reply, "u", &u);
806 c->mask |= SD_BUS_CREDS_UID;
808 reply = sd_bus_message_unref(reply);
811 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
812 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
813 const void *p = NULL;
816 r = sd_bus_call_method(
818 "org.freedesktop.DBus",
819 "/org/freedesktop/DBus",
820 "org.freedesktop.DBus",
821 "GetConnectionSELinuxSecurityContext",
825 unique ? unique : name);
827 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
830 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
834 c->label = strndup(p, sz);
838 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
842 r = bus_creds_add_more(c, mask, pid, 0);
855 _public_ int sd_bus_get_name_creds(
859 sd_bus_creds **creds) {
861 assert_return(bus, -EINVAL);
862 assert_return(name, -EINVAL);
863 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
864 assert_return(mask == 0 || creds, -EINVAL);
865 assert_return(!bus_pid_changed(bus), -ECHILD);
866 assert_return(service_name_is_valid(name), -EINVAL);
867 assert_return(bus->bus_client, -ENODATA);
869 if (!BUS_IS_OPEN(bus->state))
873 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
875 return bus_get_name_creds_dbus1(bus, name, mask, creds);
878 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
879 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
880 struct kdbus_cmd_info cmd = {
881 .size = sizeof(struct kdbus_cmd_info)
883 struct kdbus_info *creator_info;
891 cmd.flags = attach_flags_to_kdbus(mask);
893 /* If augmentation is on, and the bus doesn't didn't allow us
894 * to get the bits we want, then ask for the PID/TID so that we
895 * can read the rest from /proc. */
896 if ((mask & SD_BUS_CREDS_AUGMENT) &&
897 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
898 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
899 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
900 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|
901 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
902 SD_BUS_CREDS_SELINUX_CONTEXT|
903 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
904 cmd.flags |= KDBUS_ATTACH_PIDS;
906 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
910 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
912 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
913 bus_kernel_cmd_free(bus, cmd.offset);
917 r = bus_creds_add_more(c, mask, pid, 0);
926 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
927 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
931 if (!bus->ucred_valid && !isempty(bus->label))
938 if (bus->ucred_valid) {
939 if (bus->ucred.pid > 0) {
940 pid = c->pid = bus->ucred.pid;
941 c->mask |= SD_BUS_CREDS_PID & mask;
944 if (bus->ucred.uid != UID_INVALID) {
945 c->uid = bus->ucred.uid;
946 c->mask |= SD_BUS_CREDS_UID & mask;
949 if (bus->ucred.gid != GID_INVALID) {
950 c->gid = bus->ucred.gid;
951 c->mask |= SD_BUS_CREDS_GID & mask;
955 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
956 c->label = strdup(bus->label);
960 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
963 r = bus_creds_add_more(c, mask, pid, 0);
972 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
973 assert_return(bus, -EINVAL);
974 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
975 assert_return(ret, -EINVAL);
976 assert_return(!bus_pid_changed(bus), -ECHILD);
978 if (!BUS_IS_OPEN(bus->state))
982 return bus_get_owner_creds_kdbus(bus, mask, ret);
984 return bus_get_owner_creds_dbus1(bus, mask, ret);
987 static int add_name_change_match(sd_bus *bus,
990 const char *old_owner,
991 const char *new_owner) {
993 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
994 int is_name_id = -1, r;
995 struct kdbus_item *item;
999 /* If we encounter a match that could match against
1000 * NameOwnerChanged messages, then we need to create
1001 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1002 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1003 * multiple if the match is underspecified.
1005 * The NameOwnerChanged signals take three parameters with
1006 * unique or well-known names, but only some forms actually
1009 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1010 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1011 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1012 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1013 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1015 * For the latter two the two unique names must be identical.
1020 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1025 if (!isempty(old_owner)) {
1026 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1031 if (is_name_id > 0 && old_owner_id != name_id)
1034 old_owner_id = KDBUS_MATCH_ID_ANY;
1036 if (!isempty(new_owner)) {
1037 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1042 if (is_name_id > 0 && new_owner_id != name_id)
1045 new_owner_id = KDBUS_MATCH_ID_ANY;
1047 if (is_name_id <= 0) {
1048 struct kdbus_cmd_match *m;
1051 /* If the name argument is missing or is a well-known
1052 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1055 l = name ? strlen(name) + 1 : 0;
1057 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1058 offsetof(struct kdbus_item, name_change) +
1059 offsetof(struct kdbus_notify_name_change, name) +
1062 m = alloca0_align(sz, 8);
1068 offsetof(struct kdbus_item, name_change) +
1069 offsetof(struct kdbus_notify_name_change, name) +
1072 item->name_change.old_id.id = old_owner_id;
1073 item->name_change.new_id.id = new_owner_id;
1076 memcpy(item->name_change.name, name, l);
1078 /* If the old name is unset or empty, then
1079 * this can match against added names */
1080 if (!old_owner || old_owner[0] == 0) {
1081 item->type = KDBUS_ITEM_NAME_ADD;
1083 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1088 /* If the new name is unset or empty, then
1089 * this can match against removed names */
1090 if (!new_owner || new_owner[0] == 0) {
1091 item->type = KDBUS_ITEM_NAME_REMOVE;
1093 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1098 /* The CHANGE match we need in either case, because
1099 * what is reported as a name change by the kernel
1100 * might just be an owner change between starter and
1101 * normal clients. For userspace such a change should
1102 * be considered a removal/addition, hence let's
1103 * subscribe to this unconditionally. */
1104 item->type = KDBUS_ITEM_NAME_CHANGE;
1105 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1110 if (is_name_id != 0) {
1111 struct kdbus_cmd_match *m;
1114 /* If the name argument is missing or is a unique
1115 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1118 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1119 offsetof(struct kdbus_item, id_change) +
1120 sizeof(struct kdbus_notify_id_change));
1122 m = alloca0_align(sz, 8);
1128 offsetof(struct kdbus_item, id_change) +
1129 sizeof(struct kdbus_notify_id_change);
1130 item->id_change.id = name_id;
1132 /* If the old name is unset or empty, then this can
1133 * match against added ids */
1134 if (!old_owner || old_owner[0] == 0) {
1135 item->type = KDBUS_ITEM_ID_ADD;
1137 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1142 /* If thew new name is unset or empty, then this can
1143 * match against removed ids */
1144 if (!new_owner || new_owner[0] == 0) {
1145 item->type = KDBUS_ITEM_ID_REMOVE;
1147 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1156 int bus_add_match_internal_kernel(
1158 struct bus_match_component *components,
1159 unsigned n_components,
1162 struct kdbus_cmd_match *m;
1163 struct kdbus_item *item;
1166 const char *sender = NULL;
1167 size_t sender_length = 0;
1168 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1169 bool using_bloom = false;
1171 bool matches_name_change = true;
1172 const char *name_change_arg[3] = {};
1177 /* Monitor streams don't support matches, make this a NOP */
1178 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1181 bloom = alloca0(bus->bloom_size);
1183 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1185 for (i = 0; i < n_components; i++) {
1186 struct bus_match_component *c = &components[i];
1190 case BUS_MATCH_SENDER:
1191 if (!streq(c->value_str, "org.freedesktop.DBus"))
1192 matches_name_change = false;
1194 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1198 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1200 sender = c->value_str;
1201 sender_length = strlen(sender);
1202 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1207 case BUS_MATCH_MESSAGE_TYPE:
1208 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1209 matches_name_change = false;
1211 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1215 case BUS_MATCH_INTERFACE:
1216 if (!streq(c->value_str, "org.freedesktop.DBus"))
1217 matches_name_change = false;
1219 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1223 case BUS_MATCH_MEMBER:
1224 if (!streq(c->value_str, "NameOwnerChanged"))
1225 matches_name_change = false;
1227 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1231 case BUS_MATCH_PATH:
1232 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1233 matches_name_change = false;
1235 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1239 case BUS_MATCH_PATH_NAMESPACE:
1240 if (!streq(c->value_str, "/")) {
1241 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1246 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1247 char buf[sizeof("arg")-1 + 2 + 1];
1249 if (c->type - BUS_MATCH_ARG < 3)
1250 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1252 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1253 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1258 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1259 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1261 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1262 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1267 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1268 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1270 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1271 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1276 case BUS_MATCH_DESTINATION:
1277 /* The bloom filter does not include
1278 the destination, since it is only
1279 available for broadcast messages
1280 which do not carry a destination
1281 since they are undirected. */
1284 case BUS_MATCH_ROOT:
1285 case BUS_MATCH_VALUE:
1286 case BUS_MATCH_LEAF:
1287 case _BUS_MATCH_NODE_TYPE_MAX:
1288 case _BUS_MATCH_NODE_TYPE_INVALID:
1289 assert_not_reached("Invalid match type?");
1294 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1296 m = alloca0_align(sz, 8);
1302 if (src_id != KDBUS_MATCH_ID_ANY) {
1303 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1304 item->type = KDBUS_ITEM_ID;
1306 item = KDBUS_ITEM_NEXT(item);
1310 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1311 item->type = KDBUS_ITEM_BLOOM_MASK;
1312 memcpy(item->data64, bloom, bus->bloom_size);
1313 item = KDBUS_ITEM_NEXT(item);
1317 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1318 item->type = KDBUS_ITEM_NAME;
1319 memcpy(item->str, sender, sender_length + 1);
1322 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1326 if (matches_name_change) {
1328 /* If this match could theoretically match
1329 * NameOwnerChanged messages, we need to
1330 * install a second non-bloom filter explitly
1333 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1341 #define internal_match(bus, m) \
1342 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1343 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1346 static int bus_add_match_internal_dbus1(
1348 const char *match) {
1355 e = internal_match(bus, match);
1357 return sd_bus_call_method(
1359 "org.freedesktop.DBus",
1360 "/org/freedesktop/DBus",
1361 "org.freedesktop.DBus",
1369 int bus_add_match_internal(
1372 struct bus_match_component *components,
1373 unsigned n_components,
1379 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1381 return bus_add_match_internal_dbus1(bus, match);
1384 int bus_remove_match_internal_kernel(
1388 struct kdbus_cmd_match m;
1393 /* Monitor streams don't support matches, make this a NOP */
1394 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1398 m.size = offsetof(struct kdbus_cmd_match, items);
1401 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1408 static int bus_remove_match_internal_dbus1(
1410 const char *match) {
1417 e = internal_match(bus, match);
1419 return sd_bus_call_method(
1421 "org.freedesktop.DBus",
1422 "/org/freedesktop/DBus",
1423 "org.freedesktop.DBus",
1431 int bus_remove_match_internal(
1439 return bus_remove_match_internal_kernel(bus, cookie);
1441 return bus_remove_match_internal_dbus1(bus, match);
1444 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1445 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1449 assert_return(bus, -EINVAL);
1450 assert_return(name, -EINVAL);
1451 assert_return(machine, -EINVAL);
1452 assert_return(!bus_pid_changed(bus), -ECHILD);
1453 assert_return(service_name_is_valid(name), -EINVAL);
1455 if (!BUS_IS_OPEN(bus->state))
1458 if (streq_ptr(name, bus->unique_name))
1459 return sd_id128_get_machine(machine);
1461 r = sd_bus_message_new_method_call(
1466 "org.freedesktop.DBus.Peer",
1471 r = sd_bus_message_set_auto_start(m, false);
1475 r = sd_bus_call(bus, m, 0, NULL, &reply);
1479 r = sd_bus_message_read(reply, "s", &mid);
1483 return sd_id128_from_string(mid, machine);