bus-control.c revision 455971c1493fc6dc3125d235cf4ea6102cac626d
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include <stddef.h>
#include <errno.h>
#include "strv.h"
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-control.h"
#include "bus-bloom.h"
#include "bus-util.h"
#include "cgroup-util.h"
int r;
r = bus_ensure_running(bus);
if (r < 0)
return r;
return 0;
}
struct kdbus_cmd_name *n;
int r;
#ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_MAKE_MEM_DEFINED(n, n->size);
#endif
if (r < 0)
return -errno;
if (n->flags & KDBUS_NAME_IN_QUEUE)
return 0;
return 1;
}
int r;
if (!(flags & SD_BUS_NAME_QUEUE))
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RequestName",
NULL,
&reply,
"su",
name,
param);
if (r < 0)
return r;
if (r < 0)
return r;
if (ret == BUS_NAME_ALREADY_OWNER)
return -EALREADY;
else if (ret == BUS_NAME_EXISTS)
return -EEXIST;
else if (ret == BUS_NAME_IN_QUEUE)
return 0;
else if (ret == BUS_NAME_PRIMARY_OWNER)
return 1;
return -EIO;
}
assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
return -ENOTCONN;
else
}
struct kdbus_cmd_name *n;
int r;
#ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_MAKE_MEM_DEFINED(n, n->size);
#endif
if (r < 0)
return -errno;
return 0;
}
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"ReleaseName",
NULL,
&reply,
"s",
name);
if (r < 0)
return r;
if (r < 0)
return r;
if (ret == BUS_NAME_NON_EXISTENT)
return -ESRCH;
if (ret == BUS_NAME_NOT_OWNER)
return -EADDRINUSE;
if (ret == BUS_NAME_RELEASED)
return 0;
return -EINVAL;
}
return -ENOTCONN;
else
}
{
struct kdbus_cmd_free cmd;
int r;
if (r < 0)
return -errno;
return 0;
}
struct kdbus_cmd_name_list cmd = {};
struct kdbus_name_list *name_list;
struct kdbus_name_info *name;
uint64_t previous_id = 0;
int r;
/* Caller will free half-constructed list on failure... */
if (r < 0)
return -errno;
struct kdbus_item *item;
const char *entry_name = NULL;
char *n;
r = -ENOMEM;
goto fail;
}
r = strv_consume(x, n);
if (r < 0)
goto fail;
}
r = strv_extend(x, entry_name);
if (r < 0) {
r = -ENOMEM;
goto fail;
}
}
}
r = 0;
fail:
return r;
}
int r;
if (acquired) {
if (r < 0)
return r;
}
if (activatable) {
if (r < 0)
return r;
*activatable = y;
y = NULL;
}
if (acquired) {
*acquired = x;
x = NULL;
}
return 0;
}
int r;
if (acquired) {
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"ListNames",
NULL,
&reply,
NULL);
if (r < 0)
return r;
r = sd_bus_message_read_strv(reply, &x);
if (r < 0)
return r;
}
if (activatable) {
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"ListActivatableNames",
NULL,
&reply,
NULL);
if (r < 0)
return r;
r = sd_bus_message_read_strv(reply, &y);
if (r < 0)
return r;
*activatable = y;
y = NULL;
}
if (acquired) {
*acquired = x;
x = NULL;
}
return 0;
}
return -ENOTCONN;
else
}
struct kdbus_info *info,
sd_bus_creds *c) {
struct kdbus_item *item;
uint64_t m;
int r;
case KDBUS_ITEM_CREDS:
if (m) {
c->mask |= m;
}
c->mask |= SD_BUS_CREDS_TID;
}
c->mask |= SD_BUS_CREDS_PID_STARTTIME;
}
break;
case KDBUS_ITEM_PID_COMM:
if (mask & SD_BUS_CREDS_COMM) {
if (!c->comm)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_COMM;
}
break;
case KDBUS_ITEM_TID_COMM:
if (mask & SD_BUS_CREDS_TID_COMM) {
if (!c->tid_comm)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_TID_COMM;
}
break;
case KDBUS_ITEM_EXE:
if (mask & SD_BUS_CREDS_EXE) {
if (!c->exe)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_EXE;
}
break;
case KDBUS_ITEM_CMDLINE:
if (mask & SD_BUS_CREDS_CMDLINE) {
if (!c->cmdline)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_CMDLINE;
}
break;
case KDBUS_ITEM_CGROUP:
m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
if (m) {
if (!c->cgroup)
return -ENOMEM;
r = bus_get_root_path(bus);
if (r < 0)
return r;
if (!c->cgroup_root)
return -ENOMEM;
c->mask |= m;
}
break;
case KDBUS_ITEM_CAPS:
if (m) {
if (!c->capability)
return -ENOMEM;
c->mask |= m;
}
break;
case KDBUS_ITEM_SECLABEL:
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
if (!c->label)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
break;
case KDBUS_ITEM_AUDIT:
if (m) {
c->mask |= m;
}
break;
case KDBUS_ITEM_OWNED_NAME:
if (r < 0)
return r;
}
break;
if ((mask & SD_BUS_CREDS_DESCRIPTION)) {
if (!c->description)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_DESCRIPTION;
}
break;
}
}
return 0;
}
static int bus_get_name_creds_kdbus(
const char *name,
sd_bus_creds **creds) {
struct kdbus_cmd_info *cmd;
struct kdbus_info *conn_info;
int r;
if (r < 0)
return r;
if (r > 0) {
} else {
}
if (r < 0)
return -errno;
/* Non-activated names are considered not available */
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) {
r = -ENOMEM;
goto fail;
}
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
if (r < 0)
goto fail;
if (creds) {
*creds = c;
c = NULL;
}
r = 0;
fail:
return r;
}
static int bus_get_name_creds_dbus1(
const char *name,
sd_bus_creds **creds) {
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 */
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
NULL,
"s",
name);
if (r < 0)
return r;
if (r < 0)
return r;
}
if (mask != 0) {
c = bus_creds_new();
if (!c)
return -ENOMEM;
if (!c->unique_name)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
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|
uint32_t u;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixProcessID",
NULL,
&reply,
"s",
if (r < 0)
return r;
if (r < 0)
return r;
pid = u;
if (mask & SD_BUS_CREDS_PID) {
c->pid = u;
c->mask |= SD_BUS_CREDS_PID;
}
}
if (mask & SD_BUS_CREDS_UID) {
uint32_t u;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixUser",
NULL,
&reply,
"s",
if (r < 0)
return r;
if (r < 0)
return r;
c->uid = u;
c->mask |= SD_BUS_CREDS_UID;
}
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
const void *p = NULL;
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionSELinuxSecurityContext",
NULL,
&reply,
"s",
if (r < 0)
return r;
if (r < 0)
return r;
if (!c->label)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
if (r < 0)
return r;
}
if (creds) {
*creds = c;
c = NULL;
}
return 0;
}
const char *name,
sd_bus_creds **creds) {
return -ENOTCONN;
else
}
int r;
return -ENOTCONN;
return -ENODATA;
c = bus_creds_new();
if (!c)
return -ENOMEM;
if (bus->ucred_valid) {
}
if (!c->label)
return -ENOMEM;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
struct kdbus_cmd_info cmd = {};
struct kdbus_info *creator_info;
if (r < 0)
return -errno;
if (r < 0)
return r;
} else {
if (r < 0)
return r;
}
*ret = c;
c = NULL;
return 0;
}
const char *name,
const char *old_owner,
const char *new_owner) {
int is_name_id = -1, r;
struct kdbus_item *item;
/* 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) {
if (is_name_id < 0)
return 0;
}
if (r < 0)
return 0;
if (r == 0)
return 0;
return 0;
} else
if (r < 0)
return r;
if (r == 0)
return 0;
return 0;
} else
if (is_name_id <= 0) {
struct kdbus_cmd_match *m;
/* If the name argument is missing or is a well-known
* name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
* matches for it */
l);
l;
if (name)
/* If the old name is unset or empty, then
* this can match against added names */
if (r < 0)
return -errno;
}
/* If the new name is unset or empty, then
* this can match against removed names */
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
* subscribe to this unconditionally. */
if (r < 0)
return -errno;
}
if (is_name_id != 0) {
struct kdbus_cmd_match *m;
/* If the name argument is missing or is a unique
* name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
* for it */
sizeof(struct kdbus_notify_id_change));
sizeof(struct kdbus_notify_id_change);
/* If the old name is unset or empty, then this can
* match against added ids */
if (r < 0)
return -errno;
}
/* If thew new name is unset or empty, then this can
* match against removed ids */
if (r < 0)
return -errno;
}
}
return 0;
}
struct bus_match_component *components,
unsigned n_components,
struct kdbus_cmd_match *m;
struct kdbus_item *item;
size_t sender_length = 0;
bool using_bloom = false;
unsigned i;
bool matches_name_change = true;
const char *name_change_arg[3] = {};
int r;
for (i = 0; i < n_components; i++) {
struct bus_match_component *c = &components[i];
switch (c->type) {
case BUS_MATCH_SENDER:
matches_name_change = false;
if (r < 0)
return r;
else if (r > 0)
else {
}
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:
matches_name_change = false;
using_bloom = true;
break;
case BUS_MATCH_MEMBER:
matches_name_change = false;
using_bloom = true;
break;
case BUS_MATCH_PATH:
matches_name_change = false;
using_bloom = true;
break;
case BUS_MATCH_PATH_NAMESPACE:
using_bloom = true;
}
break;
case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
using_bloom = true;
break;
}
case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
using_bloom = true;
break;
}
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:
assert_not_reached("Invalid match type?");
}
}
if (using_bloom)
if (src_id != KDBUS_MATCH_ID_ANY) {
}
if (using_bloom) {
}
if (sender) {
}
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 */
if (r < 0)
return r;
}
return 0;
}
#define internal_match(bus, m) \
: (m))
static int bus_add_match_internal_dbus1(
const char *match) {
const char *e;
return sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"AddMatch",
NULL,
NULL,
"s",
e);
}
const char *match,
struct bus_match_component *components,
unsigned n_components,
else
}
struct kdbus_cmd_match m;
int r;
zero(m);
if (r < 0)
return -errno;
return 0;
}
static int bus_remove_match_internal_dbus1(
const char *match) {
const char *e;
return sd_bus_call_method(
bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RemoveMatch",
NULL,
NULL,
"s",
e);
}
const char *match,
else
}
const char *mid;
int r;
return -ENOTCONN;
return sd_id128_get_machine(machine);
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;
if (r < 0)
return r;
if (r < 0)
return r;
}