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 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->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_cmd_free(sd_bus *bus, uint64_t offset)
228 struct kdbus_cmd_free cmd;
236 r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
243 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
244 struct kdbus_cmd_name_list cmd = {};
245 struct kdbus_name_list *name_list;
246 struct kdbus_name_info *name;
247 uint64_t previous_id = 0;
250 /* Caller will free half-constructed list on failure... */
254 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
258 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
260 KDBUS_ITEM_FOREACH(name, name_list, names) {
262 struct kdbus_item *item;
263 const char *entry_name = NULL;
265 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
268 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
273 r = strv_consume(x, n);
277 previous_id = name->owner_id;
280 KDBUS_ITEM_FOREACH(item, name, items)
281 if (item->type == KDBUS_ITEM_OWNED_NAME)
282 entry_name = item->name.name;
284 if (entry_name && service_name_is_valid(entry_name)) {
285 r = strv_extend(x, entry_name);
296 kernel_cmd_free(bus, cmd.offset);
300 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
301 _cleanup_strv_free_ char **x = NULL, **y = NULL;
305 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
311 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
327 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
328 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
329 _cleanup_strv_free_ char **x = NULL, **y = NULL;
333 r = sd_bus_call_method(
335 "org.freedesktop.DBus",
336 "/org/freedesktop/DBus",
337 "org.freedesktop.DBus",
345 r = sd_bus_message_read_strv(reply, &x);
349 reply = sd_bus_message_unref(reply);
353 r = sd_bus_call_method(
355 "org.freedesktop.DBus",
356 "/org/freedesktop/DBus",
357 "org.freedesktop.DBus",
358 "ListActivatableNames",
365 r = sd_bus_message_read_strv(reply, &y);
381 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
382 assert_return(bus, -EINVAL);
383 assert_return(acquired || activatable, -EINVAL);
384 assert_return(!bus_pid_changed(bus), -ECHILD);
386 if (!BUS_IS_OPEN(bus->state))
390 return bus_list_names_kernel(bus, acquired, activatable);
392 return bus_list_names_dbus1(bus, acquired, activatable);
395 static int bus_populate_creds_from_items(sd_bus *bus,
396 struct kdbus_info *info,
400 struct kdbus_item *item;
404 KDBUS_ITEM_FOREACH(item, info, items) {
406 switch (item->type) {
408 case KDBUS_ITEM_PIDS:
410 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
411 c->pid = (pid_t) item->pids.pid;
412 c->mask |= SD_BUS_CREDS_PID;
415 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
416 c->tid = (pid_t) item->pids.tid;
417 c->mask |= SD_BUS_CREDS_TID;
420 if (mask & SD_BUS_CREDS_PID_STARTTIME && item->pids.starttime > 0) {
421 c->pid_starttime = item->pids.starttime;
422 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
427 case KDBUS_ITEM_CREDS:
429 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != (uid_t) -1) {
430 c->uid = (uid_t) item->creds.uid;
431 c->mask |= SD_BUS_CREDS_UID;
434 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != (uid_t) -1) {
435 c->euid = (uid_t) item->creds.euid;
436 c->mask |= SD_BUS_CREDS_EUID;
439 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != (uid_t) -1) {
440 c->suid = (uid_t) item->creds.suid;
441 c->mask |= SD_BUS_CREDS_SUID;
444 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != (uid_t) -1) {
445 c->fsuid = (uid_t) item->creds.fsuid;
446 c->mask |= SD_BUS_CREDS_FSUID;
449 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != (gid_t) -1) {
450 c->gid = (gid_t) item->creds.gid;
451 c->mask |= SD_BUS_CREDS_GID;
454 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != (gid_t) -1) {
455 c->egid = (gid_t) item->creds.egid;
456 c->mask |= SD_BUS_CREDS_EGID;
459 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != (gid_t) -1) {
460 c->sgid = (gid_t) item->creds.sgid;
461 c->mask |= SD_BUS_CREDS_SGID;
464 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != (gid_t) -1) {
465 c->fsgid = (gid_t) item->creds.fsgid;
466 c->mask |= SD_BUS_CREDS_FSGID;
471 case KDBUS_ITEM_PID_COMM:
472 if (mask & SD_BUS_CREDS_COMM) {
473 c->comm = strdup(item->str);
477 c->mask |= SD_BUS_CREDS_COMM;
481 case KDBUS_ITEM_TID_COMM:
482 if (mask & SD_BUS_CREDS_TID_COMM) {
483 c->tid_comm = strdup(item->str);
487 c->mask |= SD_BUS_CREDS_TID_COMM;
492 if (mask & SD_BUS_CREDS_EXE) {
493 c->exe = strdup(item->str);
497 c->mask |= SD_BUS_CREDS_EXE;
501 case KDBUS_ITEM_CMDLINE:
502 if (mask & SD_BUS_CREDS_CMDLINE) {
503 c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
504 c->cmdline = memdup(item->data, c->cmdline_size);
508 c->mask |= SD_BUS_CREDS_CMDLINE;
512 case KDBUS_ITEM_CGROUP:
513 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
514 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
515 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
518 c->cgroup = strdup(item->str);
522 r = bus_get_root_path(bus);
526 c->cgroup_root = strdup(bus->cgroup_root);
534 case KDBUS_ITEM_CAPS:
535 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
536 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
539 c->capability_size = item->size - offsetof(struct kdbus_item, caps.caps);
540 c->capability = memdup(item->caps.caps, c->capability_size);
548 case KDBUS_ITEM_SECLABEL:
549 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
550 c->label = strdup(item->str);
554 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
558 case KDBUS_ITEM_AUDIT:
559 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
562 c->audit_session_id = item->audit.sessionid;
563 c->audit_login_uid = item->audit.loginuid;
568 case KDBUS_ITEM_OWNED_NAME:
569 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
570 r = strv_extend(&c->well_known_names, item->name.name);
574 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
578 case KDBUS_ITEM_CONN_DESCRIPTION:
579 if ((mask & SD_BUS_CREDS_DESCRIPTION)) {
580 c->description = strdup(item->str);
584 c->mask |= SD_BUS_CREDS_DESCRIPTION;
593 static int bus_get_name_creds_kdbus(
597 sd_bus_creds **creds) {
599 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
600 struct kdbus_cmd_info *cmd;
601 struct kdbus_info *conn_info;
606 r = bus_kernel_parse_unique_name(name, &id);
610 size = offsetof(struct kdbus_cmd_info, items);
611 cmd = alloca0_align(size, 8);
614 l = strlen(name) + 1;
615 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
616 cmd = alloca0_align(size, 8);
617 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
618 cmd->items[0].type = KDBUS_ITEM_NAME;
619 memcpy(cmd->items[0].str, name, l);
623 kdbus_translate_attach_flags(mask, (uint64_t*) &cmd->flags);
625 /* If augmentation is on, and the bus doesn't didn't allow us
626 * to get the bits we want, then ask for the PID/TID so that we
627 * can read the rest from /proc. */
628 if ((mask & SD_BUS_CREDS_AUGMENT) &&
629 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
630 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
631 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
632 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|
633 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
634 SD_BUS_CREDS_SELINUX_CONTEXT|
635 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
636 cmd->flags |= KDBUS_ATTACH_PIDS;
638 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
642 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
644 /* Non-activated names are considered not available */
645 if (conn_info->flags & KDBUS_HELLO_ACTIVATOR) {
659 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
660 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
665 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
668 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
672 r = bus_creds_add_more(c, mask, 0, 0);
684 kernel_cmd_free(bus, cmd->offset);
688 static int bus_get_name_creds_dbus1(
692 sd_bus_creds **creds) {
694 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
695 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
696 const char *unique = NULL;
700 /* Only query the owner if the caller wants to know it or if
701 * the caller just wants to check whether a name exists */
702 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
703 r = sd_bus_call_method(
705 "org.freedesktop.DBus",
706 "/org/freedesktop/DBus",
707 "org.freedesktop.DBus",
716 r = sd_bus_message_read(reply_unique, "s", &unique);
726 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
727 c->unique_name = strdup(unique);
731 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
734 if ((mask & SD_BUS_CREDS_PID) ||
735 ((mask & SD_BUS_CREDS_AUGMENT) &&
736 (mask & (SD_BUS_CREDS_PID_STARTTIME|
737 SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
738 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
739 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
740 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|
741 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
742 SD_BUS_CREDS_SELINUX_CONTEXT|
743 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
747 r = sd_bus_call_method(
749 "org.freedesktop.DBus",
750 "/org/freedesktop/DBus",
751 "org.freedesktop.DBus",
752 "GetConnectionUnixProcessID",
756 unique ? unique : name);
760 r = sd_bus_message_read(reply, "u", &u);
765 if (mask & SD_BUS_CREDS_PID) {
767 c->mask |= SD_BUS_CREDS_PID;
770 reply = sd_bus_message_unref(reply);
773 if (mask & SD_BUS_CREDS_UID) {
776 r = sd_bus_call_method(
778 "org.freedesktop.DBus",
779 "/org/freedesktop/DBus",
780 "org.freedesktop.DBus",
781 "GetConnectionUnixUser",
785 unique ? unique : name);
789 r = sd_bus_message_read(reply, "u", &u);
794 c->mask |= SD_BUS_CREDS_UID;
796 reply = sd_bus_message_unref(reply);
799 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
800 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
801 const void *p = NULL;
804 r = sd_bus_call_method(
806 "org.freedesktop.DBus",
807 "/org/freedesktop/DBus",
808 "org.freedesktop.DBus",
809 "GetConnectionSELinuxSecurityContext",
813 unique ? unique : name);
815 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
818 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
822 c->label = strndup(p, sz);
826 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
830 r = bus_creds_add_more(c, mask, pid, 0);
843 _public_ int sd_bus_get_name_creds(
847 sd_bus_creds **creds) {
849 assert_return(bus, -EINVAL);
850 assert_return(name, -EINVAL);
851 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
852 assert_return(mask == 0 || creds, -EINVAL);
853 assert_return(!bus_pid_changed(bus), -ECHILD);
854 assert_return(service_name_is_valid(name), -EINVAL);
855 assert_return(bus->bus_client, -ENODATA);
857 if (!BUS_IS_OPEN(bus->state))
861 return bus_get_name_creds_kdbus(bus, name, mask, creds);
863 return bus_get_name_creds_dbus1(bus, name, mask, creds);
866 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
867 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
871 assert_return(bus, -EINVAL);
872 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
873 assert_return(ret, -EINVAL);
874 assert_return(!bus_pid_changed(bus), -ECHILD);
876 if (!BUS_IS_OPEN(bus->state))
879 if (!bus->ucred_valid && !isempty(bus->label))
886 if (bus->ucred_valid) {
887 pid = c->pid = bus->ucred.pid;
888 c->uid = bus->ucred.uid;
889 c->gid = bus->ucred.gid;
891 c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
894 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
895 c->label = strdup(bus->label);
899 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
902 if (bus->is_kernel) {
903 struct kdbus_cmd_info cmd = {};
904 struct kdbus_info *creator_info;
906 cmd.size = sizeof(cmd);
907 kdbus_translate_attach_flags(mask, (uint64_t*) &cmd.flags);
909 /* If augmentation is on, and the bus doesn't didn't allow us
910 * to get the bits we want, then ask for the PID/TID so that we
911 * can read the rest from /proc. */
912 if ((mask & SD_BUS_CREDS_AUGMENT) &&
913 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
914 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
915 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
916 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|
917 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
918 SD_BUS_CREDS_SELINUX_CONTEXT|
919 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
920 cmd.flags |= KDBUS_ATTACH_PIDS;
922 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
926 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
928 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
929 kernel_cmd_free(bus, cmd.offset);
935 r = bus_creds_add_more(c, mask, pid, 0);
944 static int add_name_change_match(sd_bus *bus,
947 const char *old_owner,
948 const char *new_owner) {
950 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
951 int is_name_id = -1, r;
952 struct kdbus_item *item;
956 /* If we encounter a match that could match against
957 * NameOwnerChanged messages, then we need to create
958 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
959 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
960 * multiple if the match is underspecified.
962 * The NameOwnerChanged signals take three parameters with
963 * unique or well-known names, but only some forms actually
966 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
967 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
968 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
969 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
970 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
972 * For the latter two the two unique names must be identical.
977 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
982 if (!isempty(old_owner)) {
983 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
988 if (is_name_id > 0 && old_owner_id != name_id)
991 old_owner_id = KDBUS_MATCH_ID_ANY;
993 if (!isempty(new_owner)) {
994 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
999 if (is_name_id > 0 && new_owner_id != name_id)
1002 new_owner_id = KDBUS_MATCH_ID_ANY;
1004 if (is_name_id <= 0) {
1005 struct kdbus_cmd_match *m;
1008 /* If the name argument is missing or is a well-known
1009 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1012 l = name ? strlen(name) + 1 : 0;
1014 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1015 offsetof(struct kdbus_item, name_change) +
1016 offsetof(struct kdbus_notify_name_change, name) +
1019 m = alloca0_align(sz, 8);
1025 offsetof(struct kdbus_item, name_change) +
1026 offsetof(struct kdbus_notify_name_change, name) +
1029 item->name_change.old_id.id = old_owner_id;
1030 item->name_change.new_id.id = new_owner_id;
1033 memcpy(item->name_change.name, name, l);
1035 /* If the old name is unset or empty, then
1036 * this can match against added names */
1037 if (!old_owner || old_owner[0] == 0) {
1038 item->type = KDBUS_ITEM_NAME_ADD;
1040 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1045 /* If the new name is unset or empty, then
1046 * this can match against removed names */
1047 if (!new_owner || new_owner[0] == 0) {
1048 item->type = KDBUS_ITEM_NAME_REMOVE;
1050 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1055 /* The CHANGE match we need in either case, because
1056 * what is reported as a name change by the kernel
1057 * might just be an owner change between starter and
1058 * normal clients. For userspace such a change should
1059 * be considered a removal/addition, hence let's
1060 * subscribe to this unconditionally. */
1061 item->type = KDBUS_ITEM_NAME_CHANGE;
1062 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1067 if (is_name_id != 0) {
1068 struct kdbus_cmd_match *m;
1071 /* If the name argument is missing or is a unique
1072 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1075 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1076 offsetof(struct kdbus_item, id_change) +
1077 sizeof(struct kdbus_notify_id_change));
1079 m = alloca0_align(sz, 8);
1085 offsetof(struct kdbus_item, id_change) +
1086 sizeof(struct kdbus_notify_id_change);
1087 item->id_change.id = name_id;
1089 /* If the old name is unset or empty, then this can
1090 * match against added ids */
1091 if (!old_owner || old_owner[0] == 0) {
1092 item->type = KDBUS_ITEM_ID_ADD;
1094 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1099 /* If thew new name is unset or empty, then this can
1100 * match against removed ids */
1101 if (!new_owner || new_owner[0] == 0) {
1102 item->type = KDBUS_ITEM_ID_REMOVE;
1104 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1113 int bus_add_match_internal_kernel(
1115 struct bus_match_component *components,
1116 unsigned n_components,
1119 struct kdbus_cmd_match *m;
1120 struct kdbus_item *item;
1123 const char *sender = NULL;
1124 size_t sender_length = 0;
1125 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1126 bool using_bloom = false;
1128 bool matches_name_change = true;
1129 const char *name_change_arg[3] = {};
1134 bloom = alloca0(bus->bloom_size);
1136 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1138 for (i = 0; i < n_components; i++) {
1139 struct bus_match_component *c = &components[i];
1143 case BUS_MATCH_SENDER:
1144 if (!streq(c->value_str, "org.freedesktop.DBus"))
1145 matches_name_change = false;
1147 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1151 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1153 sender = c->value_str;
1154 sender_length = strlen(sender);
1155 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1160 case BUS_MATCH_MESSAGE_TYPE:
1161 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1162 matches_name_change = false;
1164 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1168 case BUS_MATCH_INTERFACE:
1169 if (!streq(c->value_str, "org.freedesktop.DBus"))
1170 matches_name_change = false;
1172 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1176 case BUS_MATCH_MEMBER:
1177 if (!streq(c->value_str, "NameOwnerChanged"))
1178 matches_name_change = false;
1180 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1184 case BUS_MATCH_PATH:
1185 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1186 matches_name_change = false;
1188 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1192 case BUS_MATCH_PATH_NAMESPACE:
1193 if (!streq(c->value_str, "/")) {
1194 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1199 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1200 char buf[sizeof("arg")-1 + 2 + 1];
1202 if (c->type - BUS_MATCH_ARG < 3)
1203 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1205 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1206 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1211 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1212 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1214 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1215 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1220 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1221 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1223 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1224 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1229 case BUS_MATCH_DESTINATION:
1230 /* The bloom filter does not include
1231 the destination, since it is only
1232 available for broadcast messages
1233 which do not carry a destination
1234 since they are undirected. */
1237 case BUS_MATCH_ROOT:
1238 case BUS_MATCH_VALUE:
1239 case BUS_MATCH_LEAF:
1240 case _BUS_MATCH_NODE_TYPE_MAX:
1241 case _BUS_MATCH_NODE_TYPE_INVALID:
1242 assert_not_reached("Invalid match type?");
1247 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1249 m = alloca0_align(sz, 8);
1255 if (src_id != KDBUS_MATCH_ID_ANY) {
1256 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1257 item->type = KDBUS_ITEM_ID;
1259 item = KDBUS_ITEM_NEXT(item);
1263 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1264 item->type = KDBUS_ITEM_BLOOM_MASK;
1265 memcpy(item->data64, bloom, bus->bloom_size);
1266 item = KDBUS_ITEM_NEXT(item);
1270 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1271 item->type = KDBUS_ITEM_NAME;
1272 memcpy(item->str, sender, sender_length + 1);
1275 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1279 if (matches_name_change) {
1281 /* If this match could theoretically match
1282 * NameOwnerChanged messages, we need to
1283 * install a second non-bloom filter explitly
1286 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1294 #define internal_match(bus, m) \
1295 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1296 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1299 static int bus_add_match_internal_dbus1(
1301 const char *match) {
1308 e = internal_match(bus, match);
1310 return sd_bus_call_method(
1312 "org.freedesktop.DBus",
1313 "/org/freedesktop/DBus",
1314 "org.freedesktop.DBus",
1322 int bus_add_match_internal(
1325 struct bus_match_component *components,
1326 unsigned n_components,
1332 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1334 return bus_add_match_internal_dbus1(bus, match);
1337 int bus_remove_match_internal_kernel(
1341 struct kdbus_cmd_match m;
1347 m.size = offsetof(struct kdbus_cmd_match, items);
1350 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1357 static int bus_remove_match_internal_dbus1(
1359 const char *match) {
1366 e = internal_match(bus, match);
1368 return sd_bus_call_method(
1370 "org.freedesktop.DBus",
1371 "/org/freedesktop/DBus",
1372 "org.freedesktop.DBus",
1380 int bus_remove_match_internal(
1388 return bus_remove_match_internal_kernel(bus, cookie);
1390 return bus_remove_match_internal_dbus1(bus, match);
1393 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1394 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1398 assert_return(bus, -EINVAL);
1399 assert_return(name, -EINVAL);
1400 assert_return(machine, -EINVAL);
1401 assert_return(!bus_pid_changed(bus), -ECHILD);
1402 assert_return(service_name_is_valid(name), -EINVAL);
1404 if (!BUS_IS_OPEN(bus->state))
1407 if (streq_ptr(name, bus->unique_name))
1408 return sd_id128_get_machine(machine);
1410 r = sd_bus_message_new_method_call(
1415 "org.freedesktop.DBus.Peer",
1420 r = sd_bus_message_set_auto_start(m, false);
1424 r = sd_bus_call(bus, m, 0, NULL, &reply);
1428 r = sd_bus_message_read(reply, "s", &mid);
1432 return sd_id128_from_string(mid, machine);