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 const void *p = NULL;
803 r = sd_bus_call_method(
805 "org.freedesktop.DBus",
806 "/org/freedesktop/DBus",
807 "org.freedesktop.DBus",
808 "GetConnectionSELinuxSecurityContext",
812 unique ? unique : name);
816 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
820 c->label = strndup(p, sz);
824 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
827 r = bus_creds_add_more(c, mask, pid, 0);
840 _public_ int sd_bus_get_name_creds(
844 sd_bus_creds **creds) {
846 assert_return(bus, -EINVAL);
847 assert_return(name, -EINVAL);
848 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
849 assert_return(mask == 0 || creds, -EINVAL);
850 assert_return(!bus_pid_changed(bus), -ECHILD);
851 assert_return(service_name_is_valid(name), -EINVAL);
852 assert_return(bus->bus_client, -ENODATA);
854 if (!BUS_IS_OPEN(bus->state))
858 return bus_get_name_creds_kdbus(bus, name, mask, creds);
860 return bus_get_name_creds_dbus1(bus, name, mask, creds);
863 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
864 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
868 assert_return(bus, -EINVAL);
869 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
870 assert_return(ret, -EINVAL);
871 assert_return(!bus_pid_changed(bus), -ECHILD);
873 if (!BUS_IS_OPEN(bus->state))
876 if (!bus->ucred_valid && !isempty(bus->label))
883 if (bus->ucred_valid) {
884 pid = c->pid = bus->ucred.pid;
885 c->uid = bus->ucred.uid;
886 c->gid = bus->ucred.gid;
888 c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
891 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
892 c->label = strdup(bus->label);
896 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
899 if (bus->is_kernel) {
900 struct kdbus_cmd_info cmd = {};
901 struct kdbus_info *creator_info;
903 cmd.size = sizeof(cmd);
904 kdbus_translate_attach_flags(mask, (uint64_t*) &cmd.flags);
906 /* If augmentation is on, and the bus doesn't didn't allow us
907 * to get the bits we want, then ask for the PID/TID so that we
908 * can read the rest from /proc. */
909 if ((mask & SD_BUS_CREDS_AUGMENT) &&
910 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
911 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
912 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
913 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|
914 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
915 SD_BUS_CREDS_SELINUX_CONTEXT|
916 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
917 cmd.flags |= KDBUS_ATTACH_PIDS;
919 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
923 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
925 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
926 kernel_cmd_free(bus, cmd.offset);
932 r = bus_creds_add_more(c, mask, pid, 0);
941 static int add_name_change_match(sd_bus *bus,
944 const char *old_owner,
945 const char *new_owner) {
947 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
948 int is_name_id = -1, r;
949 struct kdbus_item *item;
953 /* If we encounter a match that could match against
954 * NameOwnerChanged messages, then we need to create
955 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
956 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
957 * multiple if the match is underspecified.
959 * The NameOwnerChanged signals take three parameters with
960 * unique or well-known names, but only some forms actually
963 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
964 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
965 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
966 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
967 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
969 * For the latter two the two unique names must be identical.
974 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
979 if (!isempty(old_owner)) {
980 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
985 if (is_name_id > 0 && old_owner_id != name_id)
988 old_owner_id = KDBUS_MATCH_ID_ANY;
990 if (!isempty(new_owner)) {
991 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
996 if (is_name_id > 0 && new_owner_id != name_id)
999 new_owner_id = KDBUS_MATCH_ID_ANY;
1001 if (is_name_id <= 0) {
1002 struct kdbus_cmd_match *m;
1005 /* If the name argument is missing or is a well-known
1006 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1009 l = name ? strlen(name) + 1 : 0;
1011 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1012 offsetof(struct kdbus_item, name_change) +
1013 offsetof(struct kdbus_notify_name_change, name) +
1016 m = alloca0_align(sz, 8);
1022 offsetof(struct kdbus_item, name_change) +
1023 offsetof(struct kdbus_notify_name_change, name) +
1026 item->name_change.old_id.id = old_owner_id;
1027 item->name_change.new_id.id = new_owner_id;
1030 memcpy(item->name_change.name, name, l);
1032 /* If the old name is unset or empty, then
1033 * this can match against added names */
1034 if (!old_owner || old_owner[0] == 0) {
1035 item->type = KDBUS_ITEM_NAME_ADD;
1037 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1042 /* If the new name is unset or empty, then
1043 * this can match against removed names */
1044 if (!new_owner || new_owner[0] == 0) {
1045 item->type = KDBUS_ITEM_NAME_REMOVE;
1047 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1052 /* The CHANGE match we need in either case, because
1053 * what is reported as a name change by the kernel
1054 * might just be an owner change between starter and
1055 * normal clients. For userspace such a change should
1056 * be considered a removal/addition, hence let's
1057 * subscribe to this unconditionally. */
1058 item->type = KDBUS_ITEM_NAME_CHANGE;
1059 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1064 if (is_name_id != 0) {
1065 struct kdbus_cmd_match *m;
1068 /* If the name argument is missing or is a unique
1069 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1072 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1073 offsetof(struct kdbus_item, id_change) +
1074 sizeof(struct kdbus_notify_id_change));
1076 m = alloca0_align(sz, 8);
1082 offsetof(struct kdbus_item, id_change) +
1083 sizeof(struct kdbus_notify_id_change);
1084 item->id_change.id = name_id;
1086 /* If the old name is unset or empty, then this can
1087 * match against added ids */
1088 if (!old_owner || old_owner[0] == 0) {
1089 item->type = KDBUS_ITEM_ID_ADD;
1091 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1096 /* If thew new name is unset or empty, then this can
1097 * match against removed ids */
1098 if (!new_owner || new_owner[0] == 0) {
1099 item->type = KDBUS_ITEM_ID_REMOVE;
1101 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1110 int bus_add_match_internal_kernel(
1112 struct bus_match_component *components,
1113 unsigned n_components,
1116 struct kdbus_cmd_match *m;
1117 struct kdbus_item *item;
1120 const char *sender = NULL;
1121 size_t sender_length = 0;
1122 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1123 bool using_bloom = false;
1125 bool matches_name_change = true;
1126 const char *name_change_arg[3] = {};
1131 bloom = alloca0(bus->bloom_size);
1133 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1135 for (i = 0; i < n_components; i++) {
1136 struct bus_match_component *c = &components[i];
1140 case BUS_MATCH_SENDER:
1141 if (!streq(c->value_str, "org.freedesktop.DBus"))
1142 matches_name_change = false;
1144 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1148 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1150 sender = c->value_str;
1151 sender_length = strlen(sender);
1152 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1157 case BUS_MATCH_MESSAGE_TYPE:
1158 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1159 matches_name_change = false;
1161 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1165 case BUS_MATCH_INTERFACE:
1166 if (!streq(c->value_str, "org.freedesktop.DBus"))
1167 matches_name_change = false;
1169 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1173 case BUS_MATCH_MEMBER:
1174 if (!streq(c->value_str, "NameOwnerChanged"))
1175 matches_name_change = false;
1177 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1181 case BUS_MATCH_PATH:
1182 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1183 matches_name_change = false;
1185 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1189 case BUS_MATCH_PATH_NAMESPACE:
1190 if (!streq(c->value_str, "/")) {
1191 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1196 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1197 char buf[sizeof("arg")-1 + 2 + 1];
1199 if (c->type - BUS_MATCH_ARG < 3)
1200 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1202 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1203 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1208 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1209 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1211 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1212 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1217 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1218 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1220 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1221 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1226 case BUS_MATCH_DESTINATION:
1227 /* The bloom filter does not include
1228 the destination, since it is only
1229 available for broadcast messages
1230 which do not carry a destination
1231 since they are undirected. */
1234 case BUS_MATCH_ROOT:
1235 case BUS_MATCH_VALUE:
1236 case BUS_MATCH_LEAF:
1237 case _BUS_MATCH_NODE_TYPE_MAX:
1238 case _BUS_MATCH_NODE_TYPE_INVALID:
1239 assert_not_reached("Invalid match type?");
1244 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1246 m = alloca0_align(sz, 8);
1252 if (src_id != KDBUS_MATCH_ID_ANY) {
1253 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1254 item->type = KDBUS_ITEM_ID;
1256 item = KDBUS_ITEM_NEXT(item);
1260 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1261 item->type = KDBUS_ITEM_BLOOM_MASK;
1262 memcpy(item->data64, bloom, bus->bloom_size);
1263 item = KDBUS_ITEM_NEXT(item);
1267 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1268 item->type = KDBUS_ITEM_NAME;
1269 memcpy(item->str, sender, sender_length + 1);
1272 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1276 if (matches_name_change) {
1278 /* If this match could theoretically match
1279 * NameOwnerChanged messages, we need to
1280 * install a second non-bloom filter explitly
1283 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1291 #define internal_match(bus, m) \
1292 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1293 ? (isempty(m) ? "eavesdrop='true'" : strappenda((m), ",eavesdrop='true'")) \
1296 static int bus_add_match_internal_dbus1(
1298 const char *match) {
1305 e = internal_match(bus, match);
1307 return sd_bus_call_method(
1309 "org.freedesktop.DBus",
1310 "/org/freedesktop/DBus",
1311 "org.freedesktop.DBus",
1319 int bus_add_match_internal(
1322 struct bus_match_component *components,
1323 unsigned n_components,
1329 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1331 return bus_add_match_internal_dbus1(bus, match);
1334 int bus_remove_match_internal_kernel(
1338 struct kdbus_cmd_match m;
1344 m.size = offsetof(struct kdbus_cmd_match, items);
1347 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1354 static int bus_remove_match_internal_dbus1(
1356 const char *match) {
1363 e = internal_match(bus, match);
1365 return sd_bus_call_method(
1367 "org.freedesktop.DBus",
1368 "/org/freedesktop/DBus",
1369 "org.freedesktop.DBus",
1377 int bus_remove_match_internal(
1385 return bus_remove_match_internal_kernel(bus, cookie);
1387 return bus_remove_match_internal_dbus1(bus, match);
1390 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1391 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1395 assert_return(bus, -EINVAL);
1396 assert_return(name, -EINVAL);
1397 assert_return(machine, -EINVAL);
1398 assert_return(!bus_pid_changed(bus), -ECHILD);
1399 assert_return(service_name_is_valid(name), -EINVAL);
1401 if (!BUS_IS_OPEN(bus->state))
1404 if (streq_ptr(name, bus->unique_name))
1405 return sd_id128_get_machine(machine);
1407 r = sd_bus_message_new_method_call(
1412 "org.freedesktop.DBus.Peer",
1417 r = sd_bus_message_set_auto_start(m, false);
1421 r = sd_bus_call(bus, m, 0, NULL, &reply);
1425 r = sd_bus_message_read(reply, "s", &mid);
1429 return sd_id128_from_string(mid, machine);