1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-control.h"
34 #include "bus-bloom.h"
36 #include "capability.h"
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) {
62 size = offsetof(struct kdbus_cmd, 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->return_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 /* Don't allow requesting the special driver and local names */
140 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
143 if (!BUS_IS_OPEN(bus->state))
147 return bus_request_name_kernel(bus, name, flags);
149 return bus_request_name_dbus1(bus, name, flags);
152 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
160 l = strlen(name) + 1;
161 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
162 n = alloca0_align(size, 8);
165 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
166 n->items[0].type = KDBUS_ITEM_NAME;
167 memcpy(n->items[0].str, name, l);
169 #ifdef HAVE_VALGRIND_MEMCHECK_H
170 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
172 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
179 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
180 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
187 r = sd_bus_call_method(
189 "org.freedesktop.DBus",
190 "/org/freedesktop/DBus",
191 "org.freedesktop.DBus",
200 r = sd_bus_message_read(reply, "u", &ret);
203 if (ret == BUS_NAME_NON_EXISTENT)
205 if (ret == BUS_NAME_NOT_OWNER)
207 if (ret == BUS_NAME_RELEASED)
213 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
214 assert_return(bus, -EINVAL);
215 assert_return(name, -EINVAL);
216 assert_return(bus->bus_client, -EINVAL);
217 assert_return(!bus_pid_changed(bus), -ECHILD);
218 assert_return(service_name_is_valid(name), -EINVAL);
219 assert_return(name[0] != ':', -EINVAL);
221 /* Don't allow releasing the special driver and local names */
222 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
225 if (!BUS_IS_OPEN(bus->state))
229 return bus_release_name_kernel(bus, name);
231 return bus_release_name_dbus1(bus, name);
234 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
235 struct kdbus_cmd_list cmd = {
239 struct kdbus_info *name_list, *name;
240 uint64_t previous_id = 0;
243 /* Caller will free half-constructed list on failure... */
245 r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
249 name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
251 KDBUS_FOREACH(name, name_list, cmd.list_size) {
253 struct kdbus_item *item;
254 const char *entry_name = NULL;
256 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) {
259 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
264 r = strv_consume(x, n);
268 previous_id = name->id;
271 KDBUS_ITEM_FOREACH(item, name, items)
272 if (item->type == KDBUS_ITEM_OWNED_NAME)
273 entry_name = item->name.name;
275 if (entry_name && service_name_is_valid(entry_name)) {
276 r = strv_extend(x, entry_name);
287 bus_kernel_cmd_free(bus, cmd.offset);
291 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
292 _cleanup_strv_free_ char **x = NULL, **y = NULL;
296 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
302 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
318 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
319 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
320 _cleanup_strv_free_ char **x = NULL, **y = NULL;
324 r = sd_bus_call_method(
326 "org.freedesktop.DBus",
327 "/org/freedesktop/DBus",
328 "org.freedesktop.DBus",
336 r = sd_bus_message_read_strv(reply, &x);
340 reply = sd_bus_message_unref(reply);
344 r = sd_bus_call_method(
346 "org.freedesktop.DBus",
347 "/org/freedesktop/DBus",
348 "org.freedesktop.DBus",
349 "ListActivatableNames",
356 r = sd_bus_message_read_strv(reply, &y);
372 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
373 assert_return(bus, -EINVAL);
374 assert_return(acquired || activatable, -EINVAL);
375 assert_return(!bus_pid_changed(bus), -ECHILD);
377 if (!BUS_IS_OPEN(bus->state))
381 return bus_list_names_kernel(bus, acquired, activatable);
383 return bus_list_names_dbus1(bus, acquired, activatable);
386 static int bus_populate_creds_from_items(
388 struct kdbus_info *info,
392 struct kdbus_item *item;
400 KDBUS_ITEM_FOREACH(item, info, items) {
402 switch (item->type) {
404 case KDBUS_ITEM_PIDS:
406 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
407 c->pid = (pid_t) item->pids.pid;
408 c->mask |= SD_BUS_CREDS_PID;
411 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
412 c->tid = (pid_t) item->pids.tid;
413 c->mask |= SD_BUS_CREDS_TID;
416 if (mask & SD_BUS_CREDS_PPID && item->pids.ppid > 0) {
417 c->ppid = (pid_t) item->pids.ppid;
418 c->mask |= SD_BUS_CREDS_PPID;
423 case KDBUS_ITEM_CREDS:
425 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
426 c->uid = (uid_t) item->creds.uid;
427 c->mask |= SD_BUS_CREDS_UID;
430 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
431 c->euid = (uid_t) item->creds.euid;
432 c->mask |= SD_BUS_CREDS_EUID;
435 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
436 c->suid = (uid_t) item->creds.suid;
437 c->mask |= SD_BUS_CREDS_SUID;
440 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
441 c->fsuid = (uid_t) item->creds.fsuid;
442 c->mask |= SD_BUS_CREDS_FSUID;
445 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
446 c->gid = (gid_t) item->creds.gid;
447 c->mask |= SD_BUS_CREDS_GID;
450 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
451 c->egid = (gid_t) item->creds.egid;
452 c->mask |= SD_BUS_CREDS_EGID;
455 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
456 c->sgid = (gid_t) item->creds.sgid;
457 c->mask |= SD_BUS_CREDS_SGID;
460 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
461 c->fsgid = (gid_t) item->creds.fsgid;
462 c->mask |= SD_BUS_CREDS_FSGID;
467 case KDBUS_ITEM_PID_COMM:
468 if (mask & SD_BUS_CREDS_COMM) {
469 r = free_and_strdup(&c->comm, item->str);
473 c->mask |= SD_BUS_CREDS_COMM;
477 case KDBUS_ITEM_TID_COMM:
478 if (mask & SD_BUS_CREDS_TID_COMM) {
479 r = free_and_strdup(&c->tid_comm, item->str);
483 c->mask |= SD_BUS_CREDS_TID_COMM;
488 if (mask & SD_BUS_CREDS_EXE) {
489 r = free_and_strdup(&c->exe, item->str);
493 c->mask |= SD_BUS_CREDS_EXE;
497 case KDBUS_ITEM_CMDLINE:
498 if (mask & SD_BUS_CREDS_CMDLINE) {
499 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
500 c->cmdline = memdup(item->data, c->cmdline_size);
504 c->mask |= SD_BUS_CREDS_CMDLINE;
508 case KDBUS_ITEM_CGROUP:
509 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
510 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
511 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
514 r = free_and_strdup(&c->cgroup, item->str);
518 r = bus_get_root_path(bus);
522 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
530 case KDBUS_ITEM_CAPS:
531 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
532 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
535 if (item->caps.last_cap != cap_last_cap() ||
536 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
539 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
547 case KDBUS_ITEM_SECLABEL:
548 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
549 r = free_and_strdup(&c->label, item->str);
553 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
557 case KDBUS_ITEM_AUDIT:
558 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
559 c->audit_session_id = (uint32_t) item->audit.sessionid;
560 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
563 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
564 c->audit_login_uid = (uid_t) item->audit.loginuid;
565 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
569 case KDBUS_ITEM_OWNED_NAME:
570 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
571 r = strv_extend(&c->well_known_names, item->name.name);
575 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
579 case KDBUS_ITEM_CONN_DESCRIPTION:
580 if (mask & SD_BUS_CREDS_DESCRIPTION) {
581 r = free_and_strdup(&c->description, item->str);
585 c->mask |= SD_BUS_CREDS_DESCRIPTION;
589 case KDBUS_ITEM_AUXGROUPS:
590 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
594 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
599 for (i = 0; i < n; i++)
600 g[i] = item->data64[i];
602 free(c->supplementary_gids);
603 c->supplementary_gids = g;
604 c->n_supplementary_gids = n;
606 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
615 int bus_get_name_creds_kdbus(
619 bool allow_activator,
620 sd_bus_creds **creds) {
622 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
623 struct kdbus_cmd_info *cmd;
624 struct kdbus_info *conn_info;
629 if (streq(name, "org.freedesktop.DBus"))
632 r = bus_kernel_parse_unique_name(name, &id);
636 size = offsetof(struct kdbus_cmd_info, items);
637 cmd = alloca0_align(size, 8);
640 l = strlen(name) + 1;
641 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
642 cmd = alloca0_align(size, 8);
643 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
644 cmd->items[0].type = KDBUS_ITEM_NAME;
645 memcpy(cmd->items[0].str, name, l);
648 /* If augmentation is on, and the bus didn't provide us
649 * the bits we want, then ask for the PID/TID so that we
650 * can read the rest from /proc. */
651 if ((mask & SD_BUS_CREDS_AUGMENT) &&
652 (mask & (SD_BUS_CREDS_PPID|
653 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
654 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
655 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
656 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|
657 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
658 SD_BUS_CREDS_SELINUX_CONTEXT|
659 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
660 mask |= SD_BUS_CREDS_PID;
663 cmd->attach_flags = attach_flags_to_kdbus(mask);
665 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
669 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
671 /* Non-activated names are considered not available */
672 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
686 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
687 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
692 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
695 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
696 them in case the service has no names. This does not mean
697 however that the list of owned names could not be
698 acquired. Hence, let's explicitly clarify that the data is
700 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
702 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
706 r = bus_creds_add_more(c, mask, 0, 0);
718 bus_kernel_cmd_free(bus, cmd->offset);
722 static int bus_get_name_creds_dbus1(
726 sd_bus_creds **creds) {
728 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
729 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
730 const char *unique = NULL;
734 /* Only query the owner if the caller wants to know it or if
735 * the caller just wants to check whether a name exists */
736 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
737 r = sd_bus_call_method(
739 "org.freedesktop.DBus",
740 "/org/freedesktop/DBus",
741 "org.freedesktop.DBus",
750 r = sd_bus_message_read(reply_unique, "s", &unique);
760 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
761 c->unique_name = strdup(unique);
765 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
768 if ((mask & SD_BUS_CREDS_PID) ||
769 ((mask & SD_BUS_CREDS_AUGMENT) &&
770 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
771 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
772 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
773 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|
774 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
775 SD_BUS_CREDS_SELINUX_CONTEXT|
776 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
780 r = sd_bus_call_method(
782 "org.freedesktop.DBus",
783 "/org/freedesktop/DBus",
784 "org.freedesktop.DBus",
785 "GetConnectionUnixProcessID",
789 unique ? unique : name);
793 r = sd_bus_message_read(reply, "u", &u);
798 if (mask & SD_BUS_CREDS_PID) {
800 c->mask |= SD_BUS_CREDS_PID;
803 reply = sd_bus_message_unref(reply);
806 if (mask & SD_BUS_CREDS_EUID) {
809 r = sd_bus_call_method(
811 "org.freedesktop.DBus",
812 "/org/freedesktop/DBus",
813 "org.freedesktop.DBus",
814 "GetConnectionUnixUser",
818 unique ? unique : name);
822 r = sd_bus_message_read(reply, "u", &u);
827 c->mask |= SD_BUS_CREDS_EUID;
829 reply = sd_bus_message_unref(reply);
832 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
833 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
834 const void *p = NULL;
837 r = sd_bus_call_method(
839 "org.freedesktop.DBus",
840 "/org/freedesktop/DBus",
841 "org.freedesktop.DBus",
842 "GetConnectionSELinuxSecurityContext",
846 unique ? unique : name);
848 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
851 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
855 c->label = strndup(p, sz);
859 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
863 r = bus_creds_add_more(c, mask, pid, 0);
876 _public_ int sd_bus_get_name_creds(
880 sd_bus_creds **creds) {
882 assert_return(bus, -EINVAL);
883 assert_return(name, -EINVAL);
884 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
885 assert_return(mask == 0 || creds, -EINVAL);
886 assert_return(!bus_pid_changed(bus), -ECHILD);
887 assert_return(service_name_is_valid(name), -EINVAL);
888 assert_return(bus->bus_client, -ENODATA);
890 if (streq(name, "org.freedesktop.DBus.Local"))
893 if (!BUS_IS_OPEN(bus->state))
897 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
899 return bus_get_name_creds_dbus1(bus, name, mask, creds);
902 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
903 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
904 struct kdbus_cmd_info cmd = {
905 .size = sizeof(struct kdbus_cmd_info),
907 struct kdbus_info *creator_info;
915 /* If augmentation is on, and the bus doesn't didn't allow us
916 * to get the bits we want, then ask for the PID/TID so that we
917 * can read the rest from /proc. */
918 if ((mask & SD_BUS_CREDS_AUGMENT) &&
919 (mask & (SD_BUS_CREDS_PPID|
920 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
921 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
922 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
923 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|
924 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
925 SD_BUS_CREDS_SELINUX_CONTEXT|
926 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
927 mask |= SD_BUS_CREDS_PID;
929 cmd.attach_flags = attach_flags_to_kdbus(mask);
931 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
935 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
937 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
938 bus_kernel_cmd_free(bus, cmd.offset);
942 r = bus_creds_add_more(c, mask, pid, 0);
951 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
952 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
956 if (!bus->ucred_valid && !isempty(bus->label))
963 if (bus->ucred_valid) {
964 if (bus->ucred.pid > 0) {
965 pid = c->pid = bus->ucred.pid;
966 c->mask |= SD_BUS_CREDS_PID & mask;
969 if (bus->ucred.uid != UID_INVALID) {
970 c->euid = bus->ucred.uid;
971 c->mask |= SD_BUS_CREDS_EUID & mask;
974 if (bus->ucred.gid != GID_INVALID) {
975 c->egid = bus->ucred.gid;
976 c->mask |= SD_BUS_CREDS_EGID & mask;
980 if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
981 c->label = strdup(bus->label);
985 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
988 r = bus_creds_add_more(c, mask, pid, 0);
997 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
998 assert_return(bus, -EINVAL);
999 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1000 assert_return(ret, -EINVAL);
1001 assert_return(!bus_pid_changed(bus), -ECHILD);
1003 if (!BUS_IS_OPEN(bus->state))
1007 return bus_get_owner_creds_kdbus(bus, mask, ret);
1009 return bus_get_owner_creds_dbus1(bus, mask, ret);
1012 static int add_name_change_match(sd_bus *bus,
1015 const char *old_owner,
1016 const char *new_owner) {
1018 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1019 int is_name_id = -1, r;
1020 struct kdbus_item *item;
1024 /* If we encounter a match that could match against
1025 * NameOwnerChanged messages, then we need to create
1026 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1027 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1028 * multiple if the match is underspecified.
1030 * The NameOwnerChanged signals take three parameters with
1031 * unique or well-known names, but only some forms actually
1034 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1035 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1036 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1037 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1038 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1040 * For the latter two the two unique names must be identical.
1045 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1050 if (!isempty(old_owner)) {
1051 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1056 if (is_name_id > 0 && old_owner_id != name_id)
1059 old_owner_id = KDBUS_MATCH_ID_ANY;
1061 if (!isempty(new_owner)) {
1062 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1067 if (is_name_id > 0 && new_owner_id != name_id)
1070 new_owner_id = KDBUS_MATCH_ID_ANY;
1072 if (is_name_id <= 0) {
1073 struct kdbus_cmd_match *m;
1076 /* If the name argument is missing or is a well-known
1077 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1080 l = name ? strlen(name) + 1 : 0;
1082 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1083 offsetof(struct kdbus_item, name_change) +
1084 offsetof(struct kdbus_notify_name_change, name) +
1087 m = alloca0_align(sz, 8);
1093 offsetof(struct kdbus_item, name_change) +
1094 offsetof(struct kdbus_notify_name_change, name) +
1097 item->name_change.old_id.id = old_owner_id;
1098 item->name_change.new_id.id = new_owner_id;
1101 memcpy(item->name_change.name, name, l);
1103 /* If the old name is unset or empty, then
1104 * this can match against added names */
1105 if (!old_owner || old_owner[0] == 0) {
1106 item->type = KDBUS_ITEM_NAME_ADD;
1108 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1113 /* If the new name is unset or empty, then
1114 * this can match against removed names */
1115 if (!new_owner || new_owner[0] == 0) {
1116 item->type = KDBUS_ITEM_NAME_REMOVE;
1118 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1123 /* The CHANGE match we need in either case, because
1124 * what is reported as a name change by the kernel
1125 * might just be an owner change between starter and
1126 * normal clients. For userspace such a change should
1127 * be considered a removal/addition, hence let's
1128 * subscribe to this unconditionally. */
1129 item->type = KDBUS_ITEM_NAME_CHANGE;
1130 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1135 if (is_name_id != 0) {
1136 struct kdbus_cmd_match *m;
1139 /* If the name argument is missing or is a unique
1140 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1143 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1144 offsetof(struct kdbus_item, id_change) +
1145 sizeof(struct kdbus_notify_id_change));
1147 m = alloca0_align(sz, 8);
1153 offsetof(struct kdbus_item, id_change) +
1154 sizeof(struct kdbus_notify_id_change);
1155 item->id_change.id = name_id;
1157 /* If the old name is unset or empty, then this can
1158 * match against added ids */
1159 if (!old_owner || old_owner[0] == 0) {
1160 item->type = KDBUS_ITEM_ID_ADD;
1162 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1167 /* If thew new name is unset or empty, then this can
1168 * match against removed ids */
1169 if (!new_owner || new_owner[0] == 0) {
1170 item->type = KDBUS_ITEM_ID_REMOVE;
1172 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1181 int bus_add_match_internal_kernel(
1183 struct bus_match_component *components,
1184 unsigned n_components,
1187 struct kdbus_cmd_match *m;
1188 struct kdbus_item *item;
1191 const char *sender = NULL;
1192 size_t sender_length = 0;
1193 uint64_t src_id = KDBUS_MATCH_ID_ANY;
1194 bool using_bloom = false;
1196 bool matches_name_change = true;
1197 const char *name_change_arg[3] = {};
1202 /* Monitor streams don't support matches, make this a NOP */
1203 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1206 bloom = alloca0(bus->bloom_size);
1208 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1210 for (i = 0; i < n_components; i++) {
1211 struct bus_match_component *c = &components[i];
1215 case BUS_MATCH_SENDER:
1216 if (!streq(c->value_str, "org.freedesktop.DBus"))
1217 matches_name_change = false;
1219 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1223 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1225 sender = c->value_str;
1226 sender_length = strlen(sender);
1227 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1232 case BUS_MATCH_MESSAGE_TYPE:
1233 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1234 matches_name_change = false;
1236 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1240 case BUS_MATCH_INTERFACE:
1241 if (!streq(c->value_str, "org.freedesktop.DBus"))
1242 matches_name_change = false;
1244 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1248 case BUS_MATCH_MEMBER:
1249 if (!streq(c->value_str, "NameOwnerChanged"))
1250 matches_name_change = false;
1252 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1256 case BUS_MATCH_PATH:
1257 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1258 matches_name_change = false;
1260 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1264 case BUS_MATCH_PATH_NAMESPACE:
1265 if (!streq(c->value_str, "/")) {
1266 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1271 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1272 char buf[sizeof("arg")-1 + 2 + 1];
1274 if (c->type - BUS_MATCH_ARG < 3)
1275 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1277 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1278 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1283 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1284 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
1286 xsprintf(buf, "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1287 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1292 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1293 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1295 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1296 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1301 case BUS_MATCH_DESTINATION:
1302 /* The bloom filter does not include
1303 the destination, since it is only
1304 available for broadcast messages
1305 which do not carry a destination
1306 since they are undirected. */
1309 case BUS_MATCH_ROOT:
1310 case BUS_MATCH_VALUE:
1311 case BUS_MATCH_LEAF:
1312 case _BUS_MATCH_NODE_TYPE_MAX:
1313 case _BUS_MATCH_NODE_TYPE_INVALID:
1314 assert_not_reached("Invalid match type?");
1319 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1321 m = alloca0_align(sz, 8);
1327 if (src_id != KDBUS_MATCH_ID_ANY) {
1328 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1329 item->type = KDBUS_ITEM_ID;
1331 item = KDBUS_ITEM_NEXT(item);
1335 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1336 item->type = KDBUS_ITEM_BLOOM_MASK;
1337 memcpy(item->data64, bloom, bus->bloom_size);
1338 item = KDBUS_ITEM_NEXT(item);
1342 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1343 item->type = KDBUS_ITEM_NAME;
1344 memcpy(item->str, sender, sender_length + 1);
1347 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1351 if (matches_name_change) {
1353 /* If this match could theoretically match
1354 * NameOwnerChanged messages, we need to
1355 * install a second non-bloom filter explitly
1358 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1366 #define internal_match(bus, m) \
1367 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1368 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1371 static int bus_add_match_internal_dbus1(
1373 const char *match) {
1380 e = internal_match(bus, match);
1382 return sd_bus_call_method(
1384 "org.freedesktop.DBus",
1385 "/org/freedesktop/DBus",
1386 "org.freedesktop.DBus",
1394 int bus_add_match_internal(
1397 struct bus_match_component *components,
1398 unsigned n_components,
1404 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1406 return bus_add_match_internal_dbus1(bus, match);
1409 int bus_remove_match_internal_kernel(
1413 struct kdbus_cmd_match m = {
1414 .size = offsetof(struct kdbus_cmd_match, items),
1421 /* Monitor streams don't support matches, make this a NOP */
1422 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1425 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1432 static int bus_remove_match_internal_dbus1(
1434 const char *match) {
1441 e = internal_match(bus, match);
1443 return sd_bus_call_method(
1445 "org.freedesktop.DBus",
1446 "/org/freedesktop/DBus",
1447 "org.freedesktop.DBus",
1455 int bus_remove_match_internal(
1463 return bus_remove_match_internal_kernel(bus, cookie);
1465 return bus_remove_match_internal_dbus1(bus, match);
1468 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1469 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1473 assert_return(bus, -EINVAL);
1474 assert_return(name, -EINVAL);
1475 assert_return(machine, -EINVAL);
1476 assert_return(!bus_pid_changed(bus), -ECHILD);
1477 assert_return(service_name_is_valid(name), -EINVAL);
1479 if (!BUS_IS_OPEN(bus->state))
1482 if (streq_ptr(name, bus->unique_name))
1483 return sd_id128_get_machine(machine);
1485 r = sd_bus_message_new_method_call(
1490 "org.freedesktop.DBus.Peer",
1495 r = sd_bus_message_set_auto_start(m, false);
1499 r = sd_bus_call(bus, m, 0, NULL, &reply);
1503 r = sd_bus_message_read(reply, "s", &mid);
1507 return sd_id128_from_string(mid, machine);