bus-control.c revision 6ad4a4fc43e12c8c36f85abbb36e8791ec507519
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/***
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen This file is part of systemd.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Copyright 2013 Lennart Poettering
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is free software; you can redistribute it and/or modify it
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen under the terms of the GNU Lesser General Public License as published by
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen (at your option) any later version.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is distributed in the hope that it will be useful, but
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Lesser General Public License for more details.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen You should have received a copy of the GNU Lesser General Public License
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen***/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#ifdef HAVE_VALGRIND_MEMCHECK_H
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <valgrind/memcheck.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#endif
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <stddef.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "strv.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-bus.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "bus-internal.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "bus-message.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "bus-control.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "bus-bloom.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "bus-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "capability.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(unique, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(!bus_pid_changed(bus), -ECHILD);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = bus_ensure_running(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *unique = bus->unique_name;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_cmd *n;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen size_t size, l;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen l = strlen(name) + 1;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n = alloca0_align(size, 8);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->size = size;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->flags = request_name_flags_to_kdbus(flags);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->items[0].type = KDBUS_ITEM_NAME;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen memcpy(n->items[0].str, name, l);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#ifdef HAVE_VALGRIND_MEMCHECK_H
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen VALGRIND_MAKE_MEM_DEFINED(n, n->size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#endif
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (n->return_flags & KDBUS_NAME_IN_QUEUE)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 1;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen uint32_t ret, param = 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen param |= BUS_NAME_ALLOW_REPLACEMENT;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (flags & SD_BUS_NAME_REPLACE_EXISTING)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen param |= BUS_NAME_REPLACE_EXISTING;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!(flags & SD_BUS_NAME_QUEUE))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen param |= BUS_NAME_DO_NOT_QUEUE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_call_method(
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen bus,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "/org/freedesktop/DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "RequestName",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen NULL,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen &reply,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "su",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen name,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen param);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_message_read(reply, "u", &ret);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (ret == BUS_NAME_ALREADY_OWNER)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EALREADY;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else if (ret == BUS_NAME_EXISTS)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EEXIST;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else if (ret == BUS_NAME_IN_QUEUE)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else if (ret == BUS_NAME_PRIMARY_OWNER)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 1;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EIO;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(name, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus->bus_client, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(!bus_pid_changed(bus), -ECHILD);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(service_name_is_valid(name), -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(name[0] != ':', -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Don't allow requesting the special driver and local names */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EINVAL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!BUS_IS_OPEN(bus->state))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -ENOTCONN;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (bus->is_kernel)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_request_name_kernel(bus, name, flags);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_request_name_dbus1(bus, name, flags);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_release_name_kernel(sd_bus *bus, const char *name) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_cmd *n;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen size_t size, l;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen l = strlen(name) + 1;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n = alloca0_align(size, 8);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->size = size;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n->items[0].type = KDBUS_ITEM_NAME;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen memcpy(n->items[0].str, name, l);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#ifdef HAVE_VALGRIND_MEMCHECK_H
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen VALGRIND_MAKE_MEM_DEFINED(n, n->size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#endif
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_release_name_dbus1(sd_bus *bus, const char *name) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen uint32_t ret;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann assert(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_call_method(
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen bus,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "/org/freedesktop/DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "ReleaseName",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen NULL,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen &reply,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_message_read(reply, "u", &ret);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (ret == BUS_NAME_NON_EXISTENT)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -ESRCH;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (ret == BUS_NAME_NOT_OWNER)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EADDRINUSE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (ret == BUS_NAME_RELEASED)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EINVAL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(name, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus->bus_client, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(!bus_pid_changed(bus), -ECHILD);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(service_name_is_valid(name), -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(name[0] != ':', -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Don't allow releasing the special driver and local names */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EINVAL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!BUS_IS_OPEN(bus->state))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -ENOTCONN;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (bus->is_kernel)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_release_name_kernel(bus, name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_release_name_dbus1(bus, name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_cmd_list cmd = {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .size = sizeof(cmd),
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .flags = flags,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen };
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_info *name_list, *name;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen uint64_t previous_id = 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Caller will free half-constructed list on failure... */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen KDBUS_FOREACH(name, name_list, cmd.list_size) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_item *item;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen const char *entry_name = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen char *n;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = -ENOMEM;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen goto fail;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = strv_consume(x, n);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen goto fail;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen previous_id = name->id;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen KDBUS_ITEM_FOREACH(item, name, items)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (item->type == KDBUS_ITEM_OWNED_NAME)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen entry_name = item->name.name;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (entry_name && service_name_is_valid(entry_name)) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = strv_extend(x, entry_name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = -ENOMEM;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen goto fail;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenfail:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen bus_kernel_cmd_free(bus, cmd.offset);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_strv_free_ char **x = NULL, **y = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (acquired) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (activatable) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *activatable = y;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen y = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (acquired) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *acquired = x;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen x = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann _cleanup_strv_free_ char **x = NULL, **y = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (acquired) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_call_method(
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen bus,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "/org/freedesktop/DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "ListNames",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen NULL,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen &reply,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen NULL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_message_read_strv(reply, &x);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen reply = sd_bus_message_unref(reply);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (activatable) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_call_method(
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen bus,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "/org/freedesktop/DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "org.freedesktop.DBus",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "ListActivatableNames",
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann NULL,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen &reply,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen NULL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sd_bus_message_read_strv(reply, &y);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *activatable = y;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen y = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (acquired) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *acquired = x;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen x = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(bus, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(acquired || activatable, -EINVAL);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_return(!bus_pid_changed(bus), -ECHILD);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!BUS_IS_OPEN(bus->state))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -ENOTCONN;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (bus->is_kernel)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_list_names_kernel(bus, acquired, activatable);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return bus_list_names_dbus1(bus, acquired, activatable);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int bus_populate_creds_from_items(
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen sd_bus *bus,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_info *info,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen uint64_t mask,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen sd_bus_creds *c) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct kdbus_item *item;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen uint64_t m;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(info);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(c);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen KDBUS_ITEM_FOREACH(item, info, items) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen switch (item->type) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_PIDS:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->pid = (pid_t) item->pids.pid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_PID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->tid = (pid_t) item->pids.tid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_TID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_CREDS:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->uid = (uid_t) item->creds.uid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_UID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->euid = (uid_t) item->creds.euid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_EUID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->suid = (uid_t) item->creds.suid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_SUID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->fsuid = (uid_t) item->creds.fsuid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_FSUID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->gid = (gid_t) item->creds.gid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_GID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->egid = (gid_t) item->creds.egid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_EGID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->sgid = (gid_t) item->creds.sgid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_SGID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->fsgid = (gid_t) item->creds.fsgid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_FSGID;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_PID_COMM:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_COMM) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = free_and_strdup(&c->comm, item->str);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_COMM;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_TID_COMM:
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poettering if (mask & SD_BUS_CREDS_TID_COMM) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = free_and_strdup(&c->tid_comm, item->str);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_TID_COMM;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_EXE:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_EXE) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = free_and_strdup(&c->exe, item->str);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_EXE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_CMDLINE:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (mask & SD_BUS_CREDS_CMDLINE) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->cmdline = memdup(item->data, c->cmdline_size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!c->cmdline)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -ENOMEM;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= SD_BUS_CREDS_CMDLINE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_CGROUP:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (m) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = free_and_strdup(&c->cgroup, item->str);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = bus_get_root_path(bus);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen c->mask |= m;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case KDBUS_ITEM_CAPS:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (m) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (item->caps.last_cap != cap_last_cap() ||
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
return -EBADMSG;
c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
if (!c->capability)
return -ENOMEM;
c->mask |= m;
}
break;
case KDBUS_ITEM_SECLABEL:
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
r = free_and_strdup(&c->label, item->str);
if (r < 0)
return r;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
break;
case KDBUS_ITEM_AUDIT:
if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
c->audit_session_id = (uint32_t) item->audit.sessionid;
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
}
if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
c->audit_login_uid = (uid_t) item->audit.loginuid;
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
break;
case KDBUS_ITEM_OWNED_NAME:
if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
r = strv_extend(&c->well_known_names, item->name.name);
if (r < 0)
return r;
c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
}
break;
case KDBUS_ITEM_CONN_DESCRIPTION:
if (mask & SD_BUS_CREDS_DESCRIPTION) {
r = free_and_strdup(&c->description, item->str);
if (r < 0)
return r;
c->mask |= SD_BUS_CREDS_DESCRIPTION;
}
break;
case KDBUS_ITEM_AUXGROUPS:
if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
size_t n;
uid_t *g;
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
g = newdup(gid_t, item->data32, n);
if (!g)
return -ENOMEM;
free(c->supplementary_gids);
c->supplementary_gids = g;
c->n_supplementary_gids = n;
c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
break;
}
}
return 0;
}
int bus_get_name_creds_kdbus(
sd_bus *bus,
const char *name,
uint64_t mask,
bool allow_activator,
sd_bus_creds **creds) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
struct kdbus_cmd_info *cmd;
struct kdbus_info *conn_info;
size_t size, l;
uint64_t id;
int r;
if (streq(name, "org.freedesktop.DBus"))
return -ENOTSUP;
r = bus_kernel_parse_unique_name(name, &id);
if (r < 0)
return r;
if (r > 0) {
size = offsetof(struct kdbus_cmd_info, items);
cmd = alloca0_align(size, 8);
cmd->id = id;
} else {
l = strlen(name) + 1;
size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
cmd = alloca0_align(size, 8);
cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
cmd->items[0].type = KDBUS_ITEM_NAME;
memcpy(cmd->items[0].str, name, l);
}
/* If augmentation is on, and the bus didn't provide us
* the bits we want, then ask for the PID/TID so that we
* can read the rest from /proc. */
if ((mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
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|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
SD_BUS_CREDS_SELINUX_CONTEXT|
SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
mask |= SD_BUS_CREDS_PID;
cmd->size = size;
cmd->attach_flags = attach_flags_to_kdbus(mask);
r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
if (r < 0)
return -errno;
conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
/* Non-activated names are considered not available */
if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
if (name[0] == ':')
r = -ENXIO;
else
r = -ESRCH;
goto fail;
}
c = bus_creds_new();
if (!c) {
r = -ENOMEM;
goto fail;
}
if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
r = -ENOMEM;
goto fail;
}
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
/* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
them in case the service has no names. This does not mean
however that the list of owned names could not be
acquired. Hence, let's explicitly clarify that the data is
complete. */
c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
r = bus_populate_creds_from_items(bus, conn_info, mask, c);
if (r < 0)
goto fail;
r = bus_creds_add_more(c, mask, 0, 0);
if (r < 0)
goto fail;
if (creds) {
*creds = c;
c = NULL;
}
r = 0;
fail:
bus_kernel_cmd_free(bus, cmd->offset);
return r;
}
static int bus_get_name_creds_dbus1(
sd_bus *bus,
const char *name,
uint64_t mask,
sd_bus_creds **creds) {
_cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
const char *unique = NULL;
pid_t pid = 0;
int r;
/* Only query the owner if the caller wants to know it or if
* the caller just wants to check whether a name exists */
if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
NULL,
&reply_unique,
"s",
name);
if (r < 0)
return r;
r = sd_bus_message_read(reply_unique, "s", &unique);
if (r < 0)
return r;
}
if (mask != 0) {
c = bus_creds_new();
if (!c)
return -ENOMEM;
if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
c->unique_name = strdup(unique);
if (!c->unique_name)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
if ((mask & SD_BUS_CREDS_PID) ||
((mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
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|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
SD_BUS_CREDS_SELINUX_CONTEXT|
SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
uint32_t u;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixProcessID",
NULL,
&reply,
"s",
unique ? unique : name);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &u);
if (r < 0)
return r;
pid = u;
if (mask & SD_BUS_CREDS_PID) {
c->pid = u;
c->mask |= SD_BUS_CREDS_PID;
}
reply = sd_bus_message_unref(reply);
}
if (mask & SD_BUS_CREDS_EUID) {
uint32_t u;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixUser",
NULL,
&reply,
"s",
unique ? unique : name);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &u);
if (r < 0)
return r;
c->euid = u;
c->mask |= SD_BUS_CREDS_EUID;
reply = sd_bus_message_unref(reply);
}
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const void *p = NULL;
size_t sz = 0;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionSELinuxSecurityContext",
&error,
&reply,
"s",
unique ? unique : name);
if (r < 0) {
if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
return r;
} else {
r = sd_bus_message_read_array(reply, 'y', &p, &sz);
if (r < 0)
return r;
c->label = strndup(p, sz);
if (!c->label)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
}
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0)
return r;
}
if (creds) {
*creds = c;
c = NULL;
}
return 0;
}
_public_ int sd_bus_get_name_creds(
sd_bus *bus,
const char *name,
uint64_t mask,
sd_bus_creds **creds) {
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
assert_return(mask == 0 || creds, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
assert_return(bus->bus_client, -ENODATA);
if (streq(name, "org.freedesktop.DBus.Local"))
return -EINVAL;
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
if (bus->is_kernel)
return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
else
return bus_get_name_creds_dbus1(bus, name, mask, creds);
}
static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
struct kdbus_cmd_info cmd = {
.size = sizeof(struct kdbus_cmd_info),
};
struct kdbus_info *creator_info;
pid_t pid = 0;
int r;
c = bus_creds_new();
if (!c)
return -ENOMEM;
/* If augmentation is on, and the bus doesn't didn't allow us
* to get the bits we want, then ask for the PID/TID so that we
* can read the rest from /proc. */
if ((mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
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|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
SD_BUS_CREDS_SELINUX_CONTEXT|
SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
mask |= SD_BUS_CREDS_PID;
cmd.attach_flags = attach_flags_to_kdbus(mask);
r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
if (r < 0)
return -errno;
creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
r = bus_populate_creds_from_items(bus, creator_info, mask, c);
bus_kernel_cmd_free(bus, cmd.offset);
if (r < 0)
return r;
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0)
return r;
*ret = c;
c = NULL;
return 0;
}
static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
pid_t pid = 0;
int r;
if (!bus->ucred_valid && !isempty(bus->label))
return -ENODATA;
c = bus_creds_new();
if (!c)
return -ENOMEM;
if (bus->ucred_valid) {
if (bus->ucred.pid > 0) {
pid = c->pid = bus->ucred.pid;
c->mask |= SD_BUS_CREDS_PID & mask;
}
if (bus->ucred.uid != UID_INVALID) {
c->euid = bus->ucred.uid;
c->mask |= SD_BUS_CREDS_EUID & mask;
}
if (bus->ucred.gid != GID_INVALID) {
c->egid = bus->ucred.gid;
c->mask |= SD_BUS_CREDS_EGID & mask;
}
}
if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
c->label = strdup(bus->label);
if (!c->label)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0)
return r;
*ret = c;
c = NULL;
return 0;
}
_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
assert_return(bus, -EINVAL);
assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
assert_return(ret, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
if (bus->is_kernel)
return bus_get_owner_creds_kdbus(bus, mask, ret);
else
return bus_get_owner_creds_dbus1(bus, mask, ret);
}
static int add_name_change_match(sd_bus *bus,
uint64_t cookie,
const char *name,
const char *old_owner,
const char *new_owner) {
uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
int is_name_id = -1, r;
struct kdbus_item *item;
assert(bus);
/* If we encounter a match that could match against
* NameOwnerChanged messages, then we need to create
* KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
* KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
* multiple if the match is underspecified.
*
* The NameOwnerChanged signals take three parameters with
* unique or well-known names, but only some forms actually
* exist:
*
* WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
* WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
* WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
* UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
* UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
*
* For the latter two the two unique names must be identical.
*
* */
if (name) {
is_name_id = bus_kernel_parse_unique_name(name, &name_id);
if (is_name_id < 0)
return 0;
}
if (!isempty(old_owner)) {
r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
if (r < 0)
return 0;
if (r == 0)
return 0;
if (is_name_id > 0 && old_owner_id != name_id)
return 0;
} else
old_owner_id = KDBUS_MATCH_ID_ANY;
if (!isempty(new_owner)) {
r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
if (r < 0)
return r;
if (r == 0)
return 0;
if (is_name_id > 0 && new_owner_id != name_id)
return 0;
} else
new_owner_id = KDBUS_MATCH_ID_ANY;
if (is_name_id <= 0) {
struct kdbus_cmd_match *m;
size_t sz, l;
/* If the name argument is missing or is a well-known
* name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
* matches for it */
l = name ? strlen(name) + 1 : 0;
sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
offsetof(struct kdbus_item, name_change) +
offsetof(struct kdbus_notify_name_change, name) +
l);
m = alloca0_align(sz, 8);
m->size = sz;
m->cookie = cookie;
item = m->items;
item->size =
offsetof(struct kdbus_item, name_change) +
offsetof(struct kdbus_notify_name_change, name) +
l;
item->name_change.old_id.id = old_owner_id;
item->name_change.new_id.id = new_owner_id;
if (name)
memcpy(item->name_change.name, name, l);
/* If the old name is unset or empty, then
* this can match against added names */
if (!old_owner || old_owner[0] == 0) {
item->type = KDBUS_ITEM_NAME_ADD;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
}
/* If the new name is unset or empty, then
* this can match against removed names */
if (!new_owner || new_owner[0] == 0) {
item->type = KDBUS_ITEM_NAME_REMOVE;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
}
/* The CHANGE match we need in either case, because
* what is reported as a name change by the kernel
* might just be an owner change between starter and
* normal clients. For userspace such a change should
* be considered a removal/addition, hence let's
* subscribe to this unconditionally. */
item->type = KDBUS_ITEM_NAME_CHANGE;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
}
if (is_name_id != 0) {
struct kdbus_cmd_match *m;
uint64_t sz;
/* If the name argument is missing or is a unique
* name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
* for it */
sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
offsetof(struct kdbus_item, id_change) +
sizeof(struct kdbus_notify_id_change));
m = alloca0_align(sz, 8);
m->size = sz;
m->cookie = cookie;
item = m->items;
item->size =
offsetof(struct kdbus_item, id_change) +
sizeof(struct kdbus_notify_id_change);
item->id_change.id = name_id;
/* If the old name is unset or empty, then this can
* match against added ids */
if (!old_owner || old_owner[0] == 0) {
item->type = KDBUS_ITEM_ID_ADD;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
}
/* If thew new name is unset or empty, then this can
* match against removed ids */
if (!new_owner || new_owner[0] == 0) {
item->type = KDBUS_ITEM_ID_REMOVE;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
}
}
return 0;
}
int bus_add_match_internal_kernel(
sd_bus *bus,
struct bus_match_component *components,
unsigned n_components,
uint64_t cookie) {
struct kdbus_cmd_match *m;
struct kdbus_item *item;
uint64_t *bloom;
size_t sz;
const char *sender = NULL;
size_t sender_length = 0;
uint64_t src_id = KDBUS_MATCH_ID_ANY;
bool using_bloom = false;
unsigned i;
bool matches_name_change = true;
const char *name_change_arg[3] = {};
int r;
assert(bus);
/* Monitor streams don't support matches, make this a NOP */
if (bus->hello_flags & KDBUS_HELLO_MONITOR)
return 0;
bloom = alloca0(bus->bloom_size);
sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
for (i = 0; i < n_components; i++) {
struct bus_match_component *c = &components[i];
switch (c->type) {
case BUS_MATCH_SENDER:
if (!streq(c->value_str, "org.freedesktop.DBus"))
matches_name_change = false;
r = bus_kernel_parse_unique_name(c->value_str, &src_id);
if (r < 0)
return r;
else if (r > 0)
sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
else {
sender = c->value_str;
sender_length = strlen(sender);
sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
}
break;
case BUS_MATCH_MESSAGE_TYPE:
if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
matches_name_change = false;
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
using_bloom = true;
break;
case BUS_MATCH_INTERFACE:
if (!streq(c->value_str, "org.freedesktop.DBus"))
matches_name_change = false;
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
using_bloom = true;
break;
case BUS_MATCH_MEMBER:
if (!streq(c->value_str, "NameOwnerChanged"))
matches_name_change = false;
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
using_bloom = true;
break;
case BUS_MATCH_PATH:
if (!streq(c->value_str, "/org/freedesktop/DBus"))
matches_name_change = false;
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
using_bloom = true;
break;
case BUS_MATCH_PATH_NAMESPACE:
if (!streq(c->value_str, "/")) {
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
using_bloom = true;
}
break;
case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
char buf[sizeof("arg")-1 + 2 + 1];
if (c->type - BUS_MATCH_ARG < 3)
name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
using_bloom = true;
break;
}
case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
xsprintf(buf, "arg%i-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
using_bloom = true;
break;
}
case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
using_bloom = true;
break;
}
case BUS_MATCH_DESTINATION:
/* The bloom filter does not include
the destination, since it is only
available for broadcast messages
which do not carry a destination
since they are undirected. */
break;
case BUS_MATCH_ROOT:
case BUS_MATCH_VALUE:
case BUS_MATCH_LEAF:
case _BUS_MATCH_NODE_TYPE_MAX:
case _BUS_MATCH_NODE_TYPE_INVALID:
assert_not_reached("Invalid match type?");
}
}
if (using_bloom)
sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
m = alloca0_align(sz, 8);
m->size = sz;
m->cookie = cookie;
item = m->items;
if (src_id != KDBUS_MATCH_ID_ANY) {
item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
item->type = KDBUS_ITEM_ID;
item->id = src_id;
item = KDBUS_ITEM_NEXT(item);
}
if (using_bloom) {
item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
item->type = KDBUS_ITEM_BLOOM_MASK;
memcpy(item->data64, bloom, bus->bloom_size);
item = KDBUS_ITEM_NEXT(item);
}
if (sender) {
item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
item->type = KDBUS_ITEM_NAME;
memcpy(item->str, sender, sender_length + 1);
}
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
return -errno;
if (matches_name_change) {
/* If this match could theoretically match
* NameOwnerChanged messages, we need to
* install a second non-bloom filter explitly
* for it */
r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
if (r < 0)
return r;
}
return 0;
}
#define internal_match(bus, m) \
((bus)->hello_flags & KDBUS_HELLO_MONITOR \
? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
: (m))
static int bus_add_match_internal_dbus1(
sd_bus *bus,
const char *match) {
const char *e;
assert(bus);
assert(match);
e = internal_match(bus, match);
return sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"AddMatch",
NULL,
NULL,
"s",
e);
}
int bus_add_match_internal(
sd_bus *bus,
const char *match,
struct bus_match_component *components,
unsigned n_components,
uint64_t cookie) {
assert(bus);
if (bus->is_kernel)
return bus_add_match_internal_kernel(bus, components, n_components, cookie);
else
return bus_add_match_internal_dbus1(bus, match);
}
int bus_remove_match_internal_kernel(
sd_bus *bus,
uint64_t cookie) {
struct kdbus_cmd_match m = {
.size = offsetof(struct kdbus_cmd_match, items),
.cookie = cookie,
};
int r;
assert(bus);
/* Monitor streams don't support matches, make this a NOP */
if (bus->hello_flags & KDBUS_HELLO_MONITOR)
return 0;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
if (r < 0)
return -errno;
return 0;
}
static int bus_remove_match_internal_dbus1(
sd_bus *bus,
const char *match) {
const char *e;
assert(bus);
assert(match);
e = internal_match(bus, match);
return sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RemoveMatch",
NULL,
NULL,
"s",
e);
}
int bus_remove_match_internal(
sd_bus *bus,
const char *match,
uint64_t cookie) {
assert(bus);
if (bus->is_kernel)
return bus_remove_match_internal_kernel(bus, cookie);
else
return bus_remove_match_internal_dbus1(bus, match);
}
_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
const char *mid;
int r;
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
assert_return(machine, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
if (streq_ptr(name, bus->unique_name))
return sd_id128_get_machine(machine);
r = sd_bus_message_new_method_call(
bus,
&m,
name,
"/",
"org.freedesktop.DBus.Peer",
"GetMachineId");
if (r < 0)
return r;
r = sd_bus_message_set_auto_start(m, false);
if (r < 0)
return r;
r = sd_bus_call(bus, m, 0, NULL, &reply);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "s", &mid);
if (r < 0)
return r;
return sd_id128_from_string(mid, machine);
}