mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #2618 from zonque/busproxy-removal
remove bus-proxyd
This commit is contained in:
commit
8eff97a103
2
.gitignore
vendored
2
.gitignore
vendored
@ -55,7 +55,6 @@
|
||||
/systemd-binfmt
|
||||
/systemd-bootchart
|
||||
/systemd-bootx64.efi
|
||||
/systemd-bus-proxyd
|
||||
/systemd-cat
|
||||
/systemd-cgls
|
||||
/systemd-cgroups-agent
|
||||
@ -150,7 +149,6 @@
|
||||
/test-bus-match
|
||||
/test-bus-objects
|
||||
/test-bus-policy
|
||||
/test-bus-proxy
|
||||
/test-bus-server
|
||||
/test-bus-signature
|
||||
/test-bus-zero-copy
|
||||
|
@ -97,8 +97,6 @@ MANPAGES += \
|
||||
man/systemd-analyze.1 \
|
||||
man/systemd-ask-password-console.service.8 \
|
||||
man/systemd-ask-password.1 \
|
||||
man/systemd-bus-proxyd.8 \
|
||||
man/systemd-bus-proxyd.service.8 \
|
||||
man/systemd-cat.1 \
|
||||
man/systemd-cgls.1 \
|
||||
man/systemd-cgtop.1 \
|
||||
@ -421,7 +419,6 @@ MANPAGES_ALIAS += \
|
||||
man/systemd-ask-password-console.path.8 \
|
||||
man/systemd-ask-password-wall.path.8 \
|
||||
man/systemd-ask-password-wall.service.8 \
|
||||
man/systemd-bus-proxyd.socket.8 \
|
||||
man/systemd-fsck-root.service.8 \
|
||||
man/systemd-fsck.8 \
|
||||
man/systemd-hibernate-resume.8 \
|
||||
@ -751,7 +748,6 @@ man/system.conf.d.5: man/systemd-system.conf.5
|
||||
man/systemd-ask-password-console.path.8: man/systemd-ask-password-console.service.8
|
||||
man/systemd-ask-password-wall.path.8: man/systemd-ask-password-console.service.8
|
||||
man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.service.8
|
||||
man/systemd-bus-proxyd.socket.8: man/systemd-bus-proxyd.service.8
|
||||
man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8
|
||||
man/systemd-fsck.8: man/systemd-fsck@.service.8
|
||||
man/systemd-hibernate-resume.8: man/systemd-hibernate-resume@.service.8
|
||||
@ -1571,9 +1567,6 @@ man/systemd-ask-password-wall.path.html: man/systemd-ask-password-console.servic
|
||||
man/systemd-ask-password-wall.service.html: man/systemd-ask-password-console.service.html
|
||||
$(html-alias)
|
||||
|
||||
man/systemd-bus-proxyd.socket.html: man/systemd-bus-proxyd.service.html
|
||||
$(html-alias)
|
||||
|
||||
man/systemd-fsck-root.service.html: man/systemd-fsck@.service.html
|
||||
$(html-alias)
|
||||
|
||||
@ -2580,8 +2573,6 @@ EXTRA_DIST += \
|
||||
man/systemd-backlight@.service.xml \
|
||||
man/systemd-binfmt.service.xml \
|
||||
man/systemd-bootchart.xml \
|
||||
man/systemd-bus-proxyd.service.xml \
|
||||
man/systemd-bus-proxyd.xml \
|
||||
man/systemd-cat.xml \
|
||||
man/systemd-cgls.xml \
|
||||
man/systemd-cgtop.xml \
|
||||
|
70
Makefile.am
70
Makefile.am
@ -393,7 +393,6 @@ rootlibexec_PROGRAMS = \
|
||||
systemd-ac-power \
|
||||
systemd-sysctl \
|
||||
systemd-sleep \
|
||||
systemd-bus-proxyd \
|
||||
systemd-socket-proxyd \
|
||||
systemd-update-done
|
||||
|
||||
@ -1467,7 +1466,6 @@ tests += \
|
||||
test-ratelimit \
|
||||
test-condition \
|
||||
test-uid-range \
|
||||
test-bus-policy \
|
||||
test-locale-util \
|
||||
test-execute \
|
||||
test-copy \
|
||||
@ -1925,14 +1923,11 @@ test_unaligned_SOURCES = \
|
||||
test_tables_SOURCES = \
|
||||
src/test/test-tables.c \
|
||||
src/shared/test-tables.h \
|
||||
src/bus-proxyd/bus-xml-policy.c \
|
||||
src/bus-proxyd/bus-xml-policy.h \
|
||||
src/journal/journald-server.c \
|
||||
src/journal/journald-server.h
|
||||
|
||||
test_tables_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-I$(top_srcdir)/src/bus-proxyd
|
||||
$(AM_CPPFLAGS)
|
||||
|
||||
test_tables_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
@ -2173,13 +2168,6 @@ test_conf_parser_SOURCES = \
|
||||
test_conf_parser_LDADD = \
|
||||
libshared.la
|
||||
|
||||
test_bus_policy_SOURCES = \
|
||||
src/bus-proxyd/test-bus-xml-policy.c
|
||||
|
||||
test_bus_policy_LDADD = \
|
||||
libbus-proxy-core.la \
|
||||
libshared.la
|
||||
|
||||
test_af_list_SOURCES = \
|
||||
src/test/test-af-list.c
|
||||
|
||||
@ -2944,59 +2932,12 @@ systemd_run_LDADD = \
|
||||
libshared.la
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
noinst_LTLIBRARIES += \
|
||||
libbus-proxy-core.la
|
||||
|
||||
libbus_proxy_core_la_SOURCES = \
|
||||
src/bus-proxyd/bus-xml-policy.c \
|
||||
src/bus-proxyd/bus-xml-policy.h \
|
||||
src/bus-proxyd/driver.c \
|
||||
src/bus-proxyd/driver.h \
|
||||
src/bus-proxyd/proxy.c \
|
||||
src/bus-proxyd/proxy.h \
|
||||
src/bus-proxyd/synthesize.c \
|
||||
src/bus-proxyd/synthesize.h
|
||||
|
||||
libbus_proxy_core_la_LIBADD = \
|
||||
libshared.la
|
||||
|
||||
systemd_bus_proxyd_SOURCES = \
|
||||
src/bus-proxyd/bus-proxyd.c
|
||||
|
||||
systemd_bus_proxyd_LDADD = \
|
||||
libbus-proxy-core.la \
|
||||
libshared.la
|
||||
|
||||
systemd_stdio_bridge_SOURCES = \
|
||||
src/bus-proxyd/stdio-bridge.c
|
||||
src/stdio-bridge/stdio-bridge.c
|
||||
|
||||
systemd_stdio_bridge_LDADD = \
|
||||
libbus-proxy-core.la \
|
||||
libshared.la
|
||||
|
||||
nodist_systemunit_DATA += \
|
||||
units/systemd-bus-proxyd.service
|
||||
|
||||
dist_systemunit_DATA += \
|
||||
units/systemd-bus-proxyd.socket
|
||||
|
||||
nodist_userunit_DATA += \
|
||||
units/user/systemd-bus-proxyd.service
|
||||
|
||||
dist_userunit_DATA += \
|
||||
units/user/systemd-bus-proxyd.socket
|
||||
|
||||
EXTRA_DIST += \
|
||||
units/systemd-bus-proxyd.service.m4.in \
|
||||
units/user/systemd-bus-proxyd.service.in
|
||||
|
||||
if HAVE_SMACK
|
||||
bus-proxyd-set-cap-hook:
|
||||
-$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(rootlibexecdir)/systemd-bus-proxyd
|
||||
|
||||
INSTALL_EXEC_HOOKS += bus-proxyd-set-cap-hook
|
||||
endif
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
systemd_tty_ask_password_agent_SOURCES = \
|
||||
src/tty-ask-password-agent/tty-ask-password-agent.c
|
||||
@ -3159,7 +3100,6 @@ tests += \
|
||||
test-bus-cleanup \
|
||||
test-bus-server \
|
||||
test-bus-match \
|
||||
test-bus-proxy \
|
||||
test-bus-kernel \
|
||||
test-bus-kernel-bloom \
|
||||
test-bus-zero-copy \
|
||||
@ -3252,12 +3192,6 @@ test_bus_match_SOURCES = \
|
||||
test_bus_match_LDADD = \
|
||||
libshared.la
|
||||
|
||||
test_bus_proxy_SOURCES = \
|
||||
src/libsystemd/sd-bus/test-bus-proxy.c
|
||||
|
||||
test_bus_proxy_LDADD = \
|
||||
libshared.la
|
||||
|
||||
test_bus_kernel_SOURCES = \
|
||||
src/libsystemd/sd-bus/test-bus-kernel.c
|
||||
|
||||
|
3
README
3
README
@ -200,9 +200,6 @@ USERS AND GROUPS:
|
||||
Similarly, the name resolution daemon requires the
|
||||
"systemd-resolve" system user and group to exist.
|
||||
|
||||
Similarly, the kdbus dbus1 proxy daemon requires the
|
||||
"systemd-bus-proxy" system user and group to exist.
|
||||
|
||||
Similarly, the coredump support requires the
|
||||
"systemd-coredump" system user and group to exist.
|
||||
|
||||
|
4
TODO
4
TODO
@ -322,10 +322,6 @@ Features:
|
||||
- path escaping
|
||||
- update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now
|
||||
- test bloom filter generation indexes
|
||||
- bus-proxy: when passing messages from kdbus, make sure we properly
|
||||
handle the case where a large number of fds is appended that we
|
||||
cannot pass into sendmsg() of the AF_UNIX sokcet (which only accepts
|
||||
253 messages)
|
||||
- kdbus: introduce a concept of "send-only" connections
|
||||
- kdbus: add counter for refused unicast messages that is passed out via the RECV ioctl. SImilar to the counter for dropped multicast messages we already have.
|
||||
|
||||
|
@ -473,7 +473,6 @@ o "/org/freedesktop/systemd1/job/42684"</programlisting>
|
||||
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
|
||||
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
|
@ -1,80 +0,0 @@
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Zbigniew Jędrzejewski-Szmek
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
-->
|
||||
|
||||
<refentry id="systemd-bus-proxyd.service">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-bus-proxyd.service</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-bus-proxyd.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-bus-proxyd.service</refname>
|
||||
<refname>systemd-bus-proxyd.socket</refname>
|
||||
<refpurpose>Proxy classic D-Bus clients to kdbus</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-bus-proxyd.service</filename></para>
|
||||
<para><filename>systemd-bus-proxyd.socket</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-bus-proxyd.socket</filename> will launch
|
||||
<filename>systemd-bus-proxyd.service</filename> for connections
|
||||
to the classic D-Bus socket in
|
||||
<filename>/var/run/dbus/system_bus_socket</filename>.</para>
|
||||
|
||||
<para><filename>systemd-bus-proxyd.service</filename> is launched
|
||||
for an existing D-Bus connection and will use
|
||||
<command>systemd-bus-proxyd</command> to proxy messages from this
|
||||
connection to the system bus (either kdbus or classic D-Bus).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -1,108 +0,0 @@
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Zbigniew Jędrzejewski-Szmek
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
-->
|
||||
|
||||
<refentry id="systemd-bus-proxyd"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-bus-proxyd</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-bus-proxyd</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-bus-proxyd</refname>
|
||||
<refpurpose>Connect STDIO or a socket to a given bus address</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>/usr/lib/systemd/systemd-bus-proxyd</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="opt"><replaceable>PLACEHOLDER</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-bus-proxyd</command> will proxy D-Bus
|
||||
messages to and from a bus. The will be either the system bus or
|
||||
the bus specified with <option>--address</option> when that option
|
||||
is given. Messages will be proxied to/from standard input and
|
||||
output, or the socket received through socket activation.</para>
|
||||
|
||||
<para>This program can be used to connect a program using classic
|
||||
D-Bus to kdbus.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options and Arguments</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--address=<replaceable>ADDRESS</replaceable><optional>:<replaceable>ADDRESS...</replaceable></optional></option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Connect to the bus specified by
|
||||
<replaceable>ADDRESS</replaceable>. Multiple colon-separated
|
||||
addresses can be specified, in which case
|
||||
<command>systemd-bus-proxyd</command> will attempt to
|
||||
connect to them in turn.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
||||
<para><replaceable>PLACEHOLDER</replaceable>, if given, must be a string
|
||||
of <literal>x</literal> and will be used to display information about
|
||||
the process that <command>systemd-bus-proxyd</command> is forwarding
|
||||
messages for.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -1 +0,0 @@
|
||||
../Makefile
|
@ -1,328 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2013 Daniel Mack
|
||||
Copyright 2014 Kay Sievers
|
||||
Copyright 2015 David Herrmann
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-xml-policy.h"
|
||||
#include "capability-util.h"
|
||||
#include "def.h"
|
||||
#include "fd-util.h"
|
||||
#include "formats-util.h"
|
||||
#include "log.h"
|
||||
#include "proxy.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static char *arg_address = NULL;
|
||||
static char **arg_configuration = NULL;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
SharedPolicy *policy;
|
||||
uid_t bus_uid;
|
||||
} ClientContext;
|
||||
|
||||
static ClientContext *client_context_free(ClientContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
safe_close(c->fd);
|
||||
free(c);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
|
||||
|
||||
static int client_context_new(ClientContext **out) {
|
||||
_cleanup_(client_context_freep) ClientContext *c = NULL;
|
||||
|
||||
c = new0(ClientContext, 1);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
c->fd = -1;
|
||||
|
||||
*out = c;
|
||||
c = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *run_client(void *userdata) {
|
||||
_cleanup_(client_context_freep) ClientContext *c = userdata;
|
||||
_cleanup_(proxy_freep) Proxy *p = NULL;
|
||||
char comm[16];
|
||||
int r;
|
||||
|
||||
r = proxy_new(&p, c->fd, c->fd, arg_address);
|
||||
c->fd = -1;
|
||||
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
/* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
|
||||
r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
|
||||
if (r >= (ssize_t)sizeof(comm))
|
||||
comm[sizeof(comm) - 2] = '*';
|
||||
(void) prctl(PR_SET_NAME, comm);
|
||||
|
||||
r = proxy_set_policy(p, c->policy, arg_configuration);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = proxy_hello_policy(p, c->bus_uid);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = proxy_run(p);
|
||||
|
||||
exit:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int loop_clients(int accept_fd, uid_t bus_uid) {
|
||||
_cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
|
||||
pthread_attr_t attr;
|
||||
int r;
|
||||
|
||||
r = pthread_attr_init(&attr);
|
||||
if (r != 0)
|
||||
return log_error_errno(r, "Cannot initialize pthread attributes: %m");
|
||||
|
||||
r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (r != 0) {
|
||||
r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = shared_policy_new(&sp);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
for (;;) {
|
||||
ClientContext *c;
|
||||
pthread_t tid;
|
||||
int fd;
|
||||
|
||||
fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
|
||||
r = log_error_errno(errno, "accept4() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = client_context_new(&c);
|
||||
if (r < 0) {
|
||||
log_oom();
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
c->fd = fd;
|
||||
c->policy = sp;
|
||||
c->bus_uid = bus_uid;
|
||||
|
||||
r = pthread_create(&tid, &attr, run_client, c);
|
||||
if (r != 0) {
|
||||
log_warning_errno(r, "Cannot spawn thread, ignoring: %m");
|
||||
client_context_free(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
pthread_attr_destroy(&attr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"DBus proxy server.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --configuration=PATH Configuration file or directory\n"
|
||||
" --machine=MACHINE Connect to specified machine\n"
|
||||
" --address=ADDRESS Connect to the bus specified by ADDRESS\n"
|
||||
" (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_ADDRESS,
|
||||
ARG_CONFIGURATION,
|
||||
ARG_MACHINE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "address", required_argument, NULL, ARG_ADDRESS },
|
||||
{ "configuration", required_argument, NULL, ARG_CONFIGURATION },
|
||||
{ "machine", required_argument, NULL, ARG_MACHINE },
|
||||
{},
|
||||
};
|
||||
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_ADDRESS:
|
||||
r = free_and_strdup(&arg_address, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
case ARG_CONFIGURATION:
|
||||
r = strv_extend(&arg_configuration, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
case ARG_MACHINE: {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
char *a;
|
||||
|
||||
e = bus_address_escape(optarg);
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
free(arg_address);
|
||||
arg_address = a;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unhandled option");
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
log_error("Too many arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!arg_address) {
|
||||
arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
|
||||
if (!arg_address)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r, accept_fd;
|
||||
uid_t uid, bus_uid;
|
||||
gid_t gid;
|
||||
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
bus_uid = getuid();
|
||||
|
||||
if (geteuid() == 0) {
|
||||
const char *user = "systemd-bus-proxy";
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot resolve user name %s: %m", user);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot drop privileges: %m");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_listen_fds(0);
|
||||
if (r != 1) {
|
||||
log_error("Illegal number of file descriptors passed");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
accept_fd = SD_LISTEN_FDS_START;
|
||||
|
||||
r = fd_nonblock(accept_fd, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = loop_clients(accept_fd, bus_uid);
|
||||
|
||||
finish:
|
||||
sd_notify(false,
|
||||
"STOPPING=1\n"
|
||||
"STATUS=Shutting down.");
|
||||
|
||||
strv_free(arg_configuration);
|
||||
free(arg_address);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,147 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
|
||||
typedef enum PolicyItemType {
|
||||
_POLICY_ITEM_TYPE_UNSET = 0,
|
||||
POLICY_ITEM_ALLOW,
|
||||
POLICY_ITEM_DENY,
|
||||
_POLICY_ITEM_TYPE_MAX,
|
||||
_POLICY_ITEM_TYPE_INVALID = -1,
|
||||
} PolicyItemType;
|
||||
|
||||
typedef enum PolicyItemClass {
|
||||
_POLICY_ITEM_CLASS_UNSET = 0,
|
||||
POLICY_ITEM_SEND,
|
||||
POLICY_ITEM_RECV,
|
||||
POLICY_ITEM_OWN,
|
||||
POLICY_ITEM_OWN_PREFIX,
|
||||
POLICY_ITEM_USER,
|
||||
POLICY_ITEM_GROUP,
|
||||
POLICY_ITEM_IGNORE,
|
||||
_POLICY_ITEM_CLASS_MAX,
|
||||
_POLICY_ITEM_CLASS_INVALID = -1,
|
||||
} PolicyItemClass;
|
||||
|
||||
typedef struct PolicyItem PolicyItem;
|
||||
|
||||
struct PolicyItem {
|
||||
PolicyItemType type;
|
||||
PolicyItemClass class;
|
||||
char *interface;
|
||||
char *member;
|
||||
char *error;
|
||||
char *path;
|
||||
char *name;
|
||||
uint8_t message_type;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
bool uid_valid, gid_valid;
|
||||
|
||||
LIST_FIELDS(PolicyItem, items);
|
||||
};
|
||||
|
||||
typedef struct Policy {
|
||||
LIST_HEAD(PolicyItem, default_items);
|
||||
LIST_HEAD(PolicyItem, mandatory_items);
|
||||
LIST_HEAD(PolicyItem, on_console_items);
|
||||
LIST_HEAD(PolicyItem, no_console_items);
|
||||
Hashmap *user_items;
|
||||
Hashmap *group_items;
|
||||
} Policy;
|
||||
|
||||
typedef struct SharedPolicy {
|
||||
char **configuration;
|
||||
pthread_mutex_t lock;
|
||||
pthread_rwlock_t rwlock;
|
||||
Policy buffer;
|
||||
Policy *policy;
|
||||
} SharedPolicy;
|
||||
|
||||
/* policy */
|
||||
|
||||
int policy_load(Policy *p, char **files);
|
||||
void policy_free(Policy *p);
|
||||
|
||||
bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name);
|
||||
bool policy_check_hello(Policy *p, uid_t uid, gid_t gid);
|
||||
bool policy_check_one_recv(Policy *p,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
int message_type,
|
||||
const char *name,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member);
|
||||
bool policy_check_recv(Policy *p,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
int message_type,
|
||||
Set *names,
|
||||
char **namesv,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member,
|
||||
bool dbus_to_kernel);
|
||||
bool policy_check_one_send(Policy *p,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
int message_type,
|
||||
const char *name,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member);
|
||||
bool policy_check_send(Policy *p,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
int message_type,
|
||||
Set *names,
|
||||
char **namesv,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member,
|
||||
bool dbus_to_kernel,
|
||||
char **out_used_name);
|
||||
|
||||
void policy_dump(Policy *p);
|
||||
|
||||
const char* policy_item_type_to_string(PolicyItemType t) _const_;
|
||||
PolicyItemType policy_item_type_from_string(const char *s) _pure_;
|
||||
|
||||
const char* policy_item_class_to_string(PolicyItemClass t) _const_;
|
||||
PolicyItemClass policy_item_class_from_string(const char *s) _pure_;
|
||||
|
||||
/* shared policy */
|
||||
|
||||
int shared_policy_new(SharedPolicy **out);
|
||||
SharedPolicy *shared_policy_free(SharedPolicy *sp);
|
||||
|
||||
int shared_policy_reload(SharedPolicy *sp);
|
||||
int shared_policy_preload(SharedPolicy *sp, char **configuration);
|
||||
Policy *shared_policy_acquire(SharedPolicy *sp);
|
||||
void shared_policy_release(SharedPolicy *sp, Policy *p);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free);
|
@ -1,745 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2013 Daniel Mack
|
||||
Copyright 2014 Kay Sievers
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-util.h"
|
||||
#include "driver.h"
|
||||
#include "env-util.h"
|
||||
#include "proxy.h"
|
||||
#include "set.h"
|
||||
#include "strv.h"
|
||||
#include "synthesize.h"
|
||||
#include "util.h"
|
||||
|
||||
static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(name);
|
||||
assert(_creds);
|
||||
|
||||
r = sd_bus_get_name_creds(bus, name, mask, &c);
|
||||
if (r == -ESRCH || r == -ENXIO)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*_creds = c;
|
||||
c = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(m);
|
||||
assert(_creds);
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return get_creds_by_name(bus, name, mask, _creds, error);
|
||||
}
|
||||
|
||||
static int driver_activation(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
ProxyActivation *activation = userdata;
|
||||
|
||||
/*
|
||||
* The org.freedesktop.DBus.Peer.Ping() call returned. We don't care
|
||||
* whether this succeeded, failed, was not implemented or timed out. We
|
||||
* cannot assume that the target reacts to this properly. Hence, just
|
||||
* send the reply to the activation request and be done.
|
||||
*/
|
||||
|
||||
m = activation->request; /* claim reference */
|
||||
|
||||
--activation->proxy->n_activations;
|
||||
LIST_REMOVE(activations_by_proxy, activation->proxy->activations, activation);
|
||||
sd_bus_slot_unref(activation->slot);
|
||||
free(activation);
|
||||
|
||||
return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
|
||||
}
|
||||
|
||||
int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(m);
|
||||
|
||||
if (!a->is_kernel)
|
||||
return 0;
|
||||
|
||||
if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
|
||||
return 0;
|
||||
|
||||
/* The "Hello()" call is is handled in process_hello() */
|
||||
|
||||
if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
|
||||
|
||||
if (!sd_bus_message_has_signature(m, ""))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
return synthetic_reply_method_return(m, "s",
|
||||
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
|
||||
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
"<node>\n"
|
||||
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
|
||||
" <method name=\"Introspect\">\n"
|
||||
" <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
" <interface name=\"org.freedesktop.DBus\">\n"
|
||||
" <method name=\"AddMatch\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"RemoveMatch\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetConnectionCredentials\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"a{sv}\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetConnectionSELinuxSecurityContext\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"ay\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetConnectionUnixProcessID\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetConnectionUnixUser\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetId\">\n"
|
||||
" <arg type=\"s\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetNameOwner\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"s\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"Hello\">\n"
|
||||
" <arg type=\"s\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ListActivatableNames\">\n"
|
||||
" <arg type=\"as\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ListNames\">\n"
|
||||
" <arg type=\"as\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ListQueuedOwners\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"as\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"NameHasOwner\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"b\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ReleaseName\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ReloadConfig\">\n"
|
||||
" </method>\n"
|
||||
" <method name=\"RequestName\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"StartServiceByName\">\n"
|
||||
" <arg type=\"s\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"in\"/>\n"
|
||||
" <arg type=\"u\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"UpdateActivationEnvironment\">\n"
|
||||
" <arg type=\"a{ss}\" direction=\"in\"/>\n"
|
||||
" </method>\n"
|
||||
" <signal name=\"NameAcquired\">\n"
|
||||
" <arg type=\"s\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"NameLost\">\n"
|
||||
" <arg type=\"s\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"NameOwnerChanged\">\n"
|
||||
" <arg type=\"s\"/>\n"
|
||||
" <arg type=\"s\"/>\n"
|
||||
" <arg type=\"s\"/>\n"
|
||||
" </signal>\n"
|
||||
" </interface>\n"
|
||||
"</node>\n");
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
|
||||
const char *match;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &match);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_add_match(a, NULL, match, proxy_match, p);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, NULL);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
|
||||
const char *match;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &match);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = bus_remove_match_by_string(a, match, NULL, NULL);
|
||||
if (r == 0)
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, NULL);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = get_creds_by_message(a, m, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
|
||||
r = sd_bus_message_new_method_return(m, &reply);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "{sv}");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
/* Due to i.e. namespace translations some data might be missing */
|
||||
|
||||
if (creds->mask & SD_BUS_CREDS_PID) {
|
||||
r = sd_bus_message_append(reply, "{sv}", "ProcessID", "u", (uint32_t) creds->pid);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
if (creds->mask & SD_BUS_CREDS_EUID) {
|
||||
r = sd_bus_message_append(reply, "{sv}", "UnixUserID", "u", (uint32_t) creds->euid);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
if (creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
|
||||
r = sd_bus_message_open_container(reply, 'e', "sv");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_append(reply, "s", "LinuxSecurityLabel");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'v', "ay");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_driver_send(m->bus, reply);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
|
||||
if (!(creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
|
||||
return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
|
||||
|
||||
r = sd_bus_message_new_method_return(m, &reply);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_driver_send(m->bus, reply);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
|
||||
if (!(creds->mask & SD_BUS_CREDS_PID))
|
||||
return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
|
||||
if (!(creds->mask & SD_BUS_CREDS_EUID))
|
||||
return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
|
||||
sd_id128_t server_id;
|
||||
char buf[SD_ID128_STRING_MAX];
|
||||
|
||||
if (!sd_bus_message_has_signature(m, ""))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_get_bus_id(a, &server_id);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
|
||||
const char *name;
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (streq(name, "org.freedesktop.DBus"))
|
||||
return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
|
||||
|
||||
r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
|
||||
if (!(creds->mask & SD_BUS_CREDS_UNIQUE_NAME))
|
||||
return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, "s", creds->unique_name);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, ""))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_list_names(a, NULL, &names);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
/* Let's sort the names list to make it stable */
|
||||
strv_sort(names);
|
||||
|
||||
return synthetic_reply_method_return_strv(m, names);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, ""))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_list_names(a, &names, NULL);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = strv_extend(&names, "org.freedesktop.DBus");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
/* Let's sort the names list to make it stable */
|
||||
strv_sort(names);
|
||||
|
||||
return synthetic_reply_method_return_strv(m, names);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
|
||||
struct kdbus_cmd_list cmd = {
|
||||
.flags = KDBUS_LIST_QUEUED,
|
||||
.size = sizeof(cmd),
|
||||
};
|
||||
struct kdbus_info *name_list, *name;
|
||||
_cleanup_strv_free_ char **owners = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
char *arg0;
|
||||
int err = 0;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &arg0);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_get_name_creds(a, arg0, 0, NULL);
|
||||
if (r == -ESRCH || r == -ENXIO) {
|
||||
sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
}
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, -errno, NULL);
|
||||
|
||||
name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
|
||||
|
||||
KDBUS_FOREACH(name, name_list, cmd.list_size) {
|
||||
struct kdbus_item *item;
|
||||
char *n;
|
||||
|
||||
KDBUS_ITEM_FOREACH(item, name, items) {
|
||||
if (item->type == KDBUS_ITEM_OWNED_NAME) {
|
||||
if (!streq_ptr(item->name.name, arg0))
|
||||
continue;
|
||||
|
||||
if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
r = strv_consume(&owners, n);
|
||||
if (r < 0) {
|
||||
err = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
r = bus_kernel_cmd_free(a, cmd.offset);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (err < 0)
|
||||
return synthetic_reply_method_errno(m, err, NULL);
|
||||
|
||||
return synthetic_reply_method_return_strv(m, owners);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
|
||||
const char *name;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (streq(name, "org.freedesktop.DBus"))
|
||||
return synthetic_reply_method_return(m, "b", true);
|
||||
|
||||
r = sd_bus_get_name_creds(a, name, 0, NULL);
|
||||
if (r < 0 && r != -ESRCH && r != -ENXIO)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, "b", r >= 0);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
|
||||
const char *name;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "s"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_release_name(a, name);
|
||||
if (r < 0) {
|
||||
if (r == -ESRCH)
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
|
||||
if (r == -EADDRINUSE)
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
|
||||
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
set_remove(owned_names, (char*) name);
|
||||
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
|
||||
if (!sd_bus_message_has_signature(m, ""))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = shared_policy_reload(sp);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, NULL);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
|
||||
const char *name;
|
||||
uint32_t flags, param;
|
||||
bool in_queue;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "su"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "su", &name, &flags);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (sp) {
|
||||
Policy *policy;
|
||||
bool denied;
|
||||
|
||||
policy = shared_policy_acquire(sp);
|
||||
denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
|
||||
shared_policy_release(sp, policy);
|
||||
if (denied)
|
||||
return synthetic_reply_method_errno(m, -EPERM, NULL);
|
||||
}
|
||||
|
||||
if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
|
||||
return synthetic_reply_method_errno(m, -EINVAL, NULL);
|
||||
|
||||
param = 0;
|
||||
if (flags & BUS_NAME_ALLOW_REPLACEMENT)
|
||||
param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
|
||||
if (flags & BUS_NAME_REPLACE_EXISTING)
|
||||
param |= SD_BUS_NAME_REPLACE_EXISTING;
|
||||
if (!(flags & BUS_NAME_DO_NOT_QUEUE))
|
||||
param |= SD_BUS_NAME_QUEUE;
|
||||
|
||||
r = set_put_strdup(owned_names, name);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_request_name(a, name, param);
|
||||
if (r < 0) {
|
||||
if (r == -EALREADY)
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
|
||||
|
||||
set_remove(owned_names, (char*) name);
|
||||
|
||||
if (r == -EEXIST)
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
in_queue = (r == 0);
|
||||
|
||||
if (in_queue)
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
|
||||
|
||||
return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL;
|
||||
ProxyActivation *activation;
|
||||
const char *name;
|
||||
uint64_t cookie;
|
||||
uint32_t flags;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "su"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_read(m, "su", &name, &flags);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (flags != 0)
|
||||
return synthetic_reply_method_errno(m, -EINVAL, NULL);
|
||||
|
||||
r = sd_bus_get_name_creds(a, name, 0, NULL);
|
||||
if (r >= 0 || streq(name, "org.freedesktop.DBus"))
|
||||
return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
|
||||
if (r != -ESRCH)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (p->n_activations >= PROXY_ACTIVATIONS_MAX)
|
||||
return synthetic_reply_method_errno(m, -EMFILE, NULL);
|
||||
|
||||
r = sd_bus_message_get_cookie(m, &cookie);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_new_method_call(a,
|
||||
&msg,
|
||||
name,
|
||||
"/",
|
||||
"org.freedesktop.DBus.Peer",
|
||||
"Ping");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = bus_message_seal(msg, cookie, BUS_DEFAULT_TIMEOUT);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
activation = new0(ProxyActivation, 1);
|
||||
if (!activation)
|
||||
return synthetic_reply_method_errno(m, -ENOMEM, NULL);
|
||||
|
||||
r = sd_bus_call_async(a,
|
||||
&activation->slot,
|
||||
msg,
|
||||
driver_activation,
|
||||
activation,
|
||||
0);
|
||||
if (r < 0) {
|
||||
free(activation);
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
activation->proxy = p;
|
||||
activation->request = sd_bus_message_ref(m);
|
||||
LIST_PREPEND(activations_by_proxy, p->activations, activation);
|
||||
++p->n_activations;
|
||||
return 1;
|
||||
|
||||
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL;
|
||||
_cleanup_strv_free_ char **args = NULL;
|
||||
|
||||
if (!sd_bus_message_has_signature(m, "a{ss}"))
|
||||
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
|
||||
|
||||
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
r = sd_bus_message_read(m, "ss", &key, &value);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
s = strjoin(key, "=", value, NULL);
|
||||
if (!s)
|
||||
return synthetic_reply_method_errno(m, -ENOMEM, NULL);
|
||||
|
||||
if (!env_assignment_is_valid(s)) {
|
||||
log_warning("UpdateActivationEnvironment() called with invalid assignment, discarding: %s", s);
|
||||
} else {
|
||||
r = strv_extend(&args, s);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
if (strv_isempty(args)) /* nothing to do? */
|
||||
return synthetic_reply_method_return(m, NULL);
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
a,
|
||||
&msg,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"SetEnvironment");
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_message_append_strv(msg, args);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
r = sd_bus_call(a, msg, 0, NULL, NULL);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(m, r, NULL);
|
||||
|
||||
return synthetic_reply_method_return(m, NULL);
|
||||
|
||||
} else {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
|
||||
|
||||
return synthetic_reply_method_errno(m, r, &error);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-xml-policy.h"
|
||||
#include "proxy.h"
|
||||
|
||||
int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
|
@ -1,953 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2013 Daniel Mack
|
||||
Copyright 2014 Kay Sievers
|
||||
Copyright 2014 David Herrmann
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-control.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-util.h"
|
||||
#include "bus-xml-policy.h"
|
||||
#include "driver.h"
|
||||
#include "fd-util.h"
|
||||
#include "formats-util.h"
|
||||
#include "log.h"
|
||||
#include "proxy.h"
|
||||
#include "set.h"
|
||||
#include "strv.h"
|
||||
#include "synthesize.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *b = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_bus_new(&b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate bus: %m");
|
||||
|
||||
r = sd_bus_set_description(b, "sd-proxy");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set bus name: %m");
|
||||
|
||||
r = sd_bus_set_address(b, destination);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set address to connect to: %m");
|
||||
|
||||
r = sd_bus_negotiate_fds(b, negotiate_fds);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set FD negotiation: %m");
|
||||
|
||||
r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set credential negotiation: %m");
|
||||
|
||||
if (p->local_creds.pid > 0) {
|
||||
b->fake_pids.pid = p->local_creds.pid;
|
||||
b->fake_pids_valid = true;
|
||||
|
||||
b->fake_creds.uid = UID_INVALID;
|
||||
b->fake_creds.euid = p->local_creds.uid;
|
||||
b->fake_creds.suid = UID_INVALID;
|
||||
b->fake_creds.fsuid = UID_INVALID;
|
||||
b->fake_creds.gid = GID_INVALID;
|
||||
b->fake_creds.egid = p->local_creds.gid;
|
||||
b->fake_creds.sgid = GID_INVALID;
|
||||
b->fake_creds.fsgid = GID_INVALID;
|
||||
b->fake_creds_valid = true;
|
||||
}
|
||||
|
||||
if (local_sec) {
|
||||
b->fake_label = strdup(local_sec);
|
||||
if (!b->fake_label)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
b->manual_peer_interface = true;
|
||||
|
||||
r = sd_bus_start(b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start bus client: %m");
|
||||
|
||||
p->destination_bus = b;
|
||||
b = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proxy_create_local(Proxy *p, bool negotiate_fds) {
|
||||
sd_id128_t server_id;
|
||||
sd_bus *b;
|
||||
int r;
|
||||
|
||||
r = sd_bus_new(&b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate bus: %m");
|
||||
|
||||
r = sd_bus_set_fd(b, p->local_in, p->local_out);
|
||||
if (r < 0) {
|
||||
sd_bus_unref(b);
|
||||
return log_error_errno(r, "Failed to set fds: %m");
|
||||
}
|
||||
|
||||
/* The fds are now owned by the bus, and we indicate that by
|
||||
* storing the bus object in the proxy object. */
|
||||
p->local_bus = b;
|
||||
|
||||
r = sd_bus_get_bus_id(p->destination_bus, &server_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get server ID: %m");
|
||||
|
||||
r = sd_bus_set_server(b, 1, server_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set server mode: %m");
|
||||
|
||||
r = sd_bus_negotiate_fds(b, negotiate_fds);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set FD negotiation: %m");
|
||||
|
||||
r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set credential negotiation: %m");
|
||||
|
||||
r = sd_bus_set_anonymous(b, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set anonymous authentication: %m");
|
||||
|
||||
b->manual_peer_interface = true;
|
||||
|
||||
r = sd_bus_start(b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start bus client: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
Proxy *p = userdata;
|
||||
|
||||
p->synthetic_matched = true;
|
||||
return 0; /* make sure to continue processing it in further handlers */
|
||||
}
|
||||
|
||||
/*
|
||||
* We always need NameOwnerChanged so we can synthesize NameLost and
|
||||
* NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so
|
||||
* subscribe unconditionally.
|
||||
*/
|
||||
static int proxy_prepare_matches(Proxy *p) {
|
||||
_cleanup_free_ char *match = NULL;
|
||||
const char *unique;
|
||||
int r;
|
||||
|
||||
if (!p->destination_bus->is_kernel)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_get_unique_name(p->destination_bus, &unique);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get unique name: %m");
|
||||
|
||||
match = strjoin("type='signal',"
|
||||
"sender='org.freedesktop.DBus',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged',"
|
||||
"arg1='",
|
||||
unique,
|
||||
"'",
|
||||
NULL);
|
||||
if (!match)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add match for NameLost: %m");
|
||||
|
||||
free(match);
|
||||
match = strjoin("type='signal',"
|
||||
"sender='org.freedesktop.DBus',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged',"
|
||||
"arg2='",
|
||||
unique,
|
||||
"'",
|
||||
NULL);
|
||||
if (!match)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add match for NameAcquired: %m");
|
||||
|
||||
free(match);
|
||||
match = strjoin("type='signal',"
|
||||
"destination='",
|
||||
unique,
|
||||
"'",
|
||||
NULL);
|
||||
if (!match)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to add match for directed signals: %m");
|
||||
/* FIXME: temporarily ignore error to support older kdbus versions */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
|
||||
_cleanup_(proxy_freep) Proxy *p = NULL;
|
||||
_cleanup_free_ char *local_sec = NULL;
|
||||
bool is_unix;
|
||||
int r;
|
||||
|
||||
/* This takes possession/destroys the file descriptors passed
|
||||
* in even on failure. The caller should hence forget about
|
||||
* the fds in all cases after calling this function and not
|
||||
* close them. */
|
||||
|
||||
p = new0(Proxy, 1);
|
||||
if (!p) {
|
||||
safe_close(in_fd);
|
||||
safe_close(out_fd);
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
p->local_in = in_fd;
|
||||
p->local_out = out_fd;
|
||||
|
||||
p->owned_names = set_new(&string_hash_ops);
|
||||
if (!p->owned_names)
|
||||
return log_oom();
|
||||
|
||||
is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
|
||||
sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
|
||||
|
||||
if (is_unix) {
|
||||
(void) getpeercred(in_fd, &p->local_creds);
|
||||
(void) getpeersec(in_fd, &local_sec);
|
||||
}
|
||||
|
||||
r = proxy_create_destination(p, destination, local_sec, is_unix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = proxy_create_local(p, is_unix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = proxy_prepare_matches(p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*out = p;
|
||||
p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Proxy *proxy_free(Proxy *p) {
|
||||
ProxyActivation *activation;
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
while ((activation = p->activations)) {
|
||||
LIST_REMOVE(activations_by_proxy, p->activations, activation);
|
||||
sd_bus_message_unref(activation->request);
|
||||
sd_bus_slot_unref(activation->slot);
|
||||
free(activation);
|
||||
}
|
||||
|
||||
if (p->local_bus)
|
||||
sd_bus_flush_close_unref(p->local_bus);
|
||||
else {
|
||||
safe_close(p->local_in);
|
||||
if (p->local_out != p->local_in)
|
||||
safe_close(p->local_out);
|
||||
}
|
||||
|
||||
sd_bus_flush_close_unref(p->destination_bus);
|
||||
set_free_free(p->owned_names);
|
||||
free(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
|
||||
_cleanup_strv_free_ char **strv = NULL;
|
||||
Policy *policy;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(sp);
|
||||
|
||||
/* no need to load legacy policy if destination is not kdbus */
|
||||
if (!p->destination_bus->is_kernel)
|
||||
return 0;
|
||||
|
||||
p->policy = sp;
|
||||
|
||||
policy = shared_policy_acquire(sp);
|
||||
if (policy) {
|
||||
/* policy already pre-loaded */
|
||||
shared_policy_release(sp, policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!configuration) {
|
||||
const char *scope;
|
||||
|
||||
r = sd_bus_get_scope(p->destination_bus, &scope);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Couldn't determine bus scope: %m");
|
||||
|
||||
if (streq(scope, "system"))
|
||||
strv = strv_new("/usr/share/dbus-1/system.conf",
|
||||
"/etc/dbus-1/system.conf",
|
||||
"/usr/share/dbus-1/system.d/",
|
||||
"/etc/dbus-1/system.d/",
|
||||
"/etc/dbus-1/system-local.conf",
|
||||
NULL);
|
||||
else if (streq(scope, "user"))
|
||||
strv = strv_new("/usr/share/dbus-1/session.conf",
|
||||
"/etc/dbus-1/session.conf",
|
||||
"/usr/share/dbus-1/session.d/",
|
||||
"/etc/dbus-1/session.d/",
|
||||
"/etc/dbus-1/session-local.conf",
|
||||
NULL);
|
||||
else
|
||||
return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
|
||||
|
||||
if (!strv)
|
||||
return log_oom();
|
||||
|
||||
configuration = strv;
|
||||
}
|
||||
|
||||
return shared_policy_preload(sp, configuration);
|
||||
}
|
||||
|
||||
int proxy_hello_policy(Proxy *p, uid_t original_uid) {
|
||||
Policy *policy;
|
||||
int r = 0;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (!p->policy)
|
||||
return 0;
|
||||
|
||||
policy = shared_policy_acquire(p->policy);
|
||||
|
||||
if (p->local_creds.uid == original_uid)
|
||||
log_debug("Permitting access, since bus owner matches bus client.");
|
||||
else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
|
||||
log_debug("Permitting access due to XML policy.");
|
||||
else
|
||||
r = log_error_errno(EPERM, "Policy denied connection.");
|
||||
|
||||
shared_policy_release(p->policy, policy);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int proxy_wait(Proxy *p) {
|
||||
uint64_t timeout_destination, timeout_local, t;
|
||||
int events_destination, events_local, fd;
|
||||
struct timespec _ts, *ts;
|
||||
struct pollfd *pollfd;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
fd = sd_bus_get_fd(p->destination_bus);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to get fd: %m");
|
||||
|
||||
events_destination = sd_bus_get_events(p->destination_bus);
|
||||
if (events_destination < 0)
|
||||
return log_error_errno(events_destination, "Failed to get events mask: %m");
|
||||
|
||||
r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get timeout: %m");
|
||||
|
||||
events_local = sd_bus_get_events(p->local_bus);
|
||||
if (events_local < 0)
|
||||
return log_error_errno(events_local, "Failed to get events mask: %m");
|
||||
|
||||
r = sd_bus_get_timeout(p->local_bus, &timeout_local);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get timeout: %m");
|
||||
|
||||
t = timeout_destination;
|
||||
if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
|
||||
t = timeout_local;
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
ts = NULL;
|
||||
else {
|
||||
usec_t nw;
|
||||
|
||||
nw = now(CLOCK_MONOTONIC);
|
||||
if (t > nw)
|
||||
t -= nw;
|
||||
else
|
||||
t = 0;
|
||||
|
||||
ts = timespec_store(&_ts, t);
|
||||
}
|
||||
|
||||
pollfd = (struct pollfd[3]) {
|
||||
{ .fd = fd, .events = events_destination, },
|
||||
{ .fd = p->local_in, .events = events_local & POLLIN, },
|
||||
{ .fd = p->local_out, .events = events_local & POLLOUT, },
|
||||
};
|
||||
|
||||
r = ppoll(pollfd, 3, ts, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "ppoll() failed: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_policy_error(sd_bus_message *m, int r) {
|
||||
if (r == -ESRCH || r == -ENXIO)
|
||||
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
assert(to);
|
||||
assert(m);
|
||||
|
||||
if (!policy)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* dbus-1 distinguishes expected and non-expected replies by tracking
|
||||
* method-calls and timeouts. By default, DENY rules are *NEVER* applied
|
||||
* on expected replies, unless explicitly specified. But we dont track
|
||||
* method-calls, thus, we cannot know whether a reply is expected.
|
||||
* Fortunately, the kdbus forbids non-expected replies, so we can safely
|
||||
* ignore any policy on those and let the kernel deal with it.
|
||||
*
|
||||
* TODO: To be correct, we should only ignore policy-tags that are
|
||||
* applied on non-expected replies. However, so far we don't parse those
|
||||
* tags so we let everything pass. I haven't seen a DENY policy tag on
|
||||
* expected-replies, ever, so don't bother..
|
||||
*/
|
||||
if (m->reply_cookie > 0)
|
||||
return 0;
|
||||
|
||||
if (from->is_kernel) {
|
||||
uid_t sender_uid = UID_INVALID;
|
||||
gid_t sender_gid = GID_INVALID;
|
||||
char **sender_names = NULL;
|
||||
|
||||
/* Driver messages are always OK */
|
||||
if (streq_ptr(m->sender, "org.freedesktop.DBus"))
|
||||
return 0;
|
||||
|
||||
/* The message came from the kernel, and is sent to our legacy client. */
|
||||
(void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
|
||||
|
||||
(void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
|
||||
(void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
|
||||
|
||||
if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *sender_creds = NULL;
|
||||
|
||||
/* If the message came from another legacy
|
||||
* client, then the message creds will be
|
||||
* missing, simply because on legacy clients
|
||||
* per-message creds were unknown. In this
|
||||
* case, query the creds of the peer
|
||||
* instead. */
|
||||
|
||||
r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
|
||||
if (r < 0)
|
||||
return handle_policy_error(m, r);
|
||||
|
||||
(void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
|
||||
(void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
|
||||
}
|
||||
|
||||
/* First check whether the sender can send the message to our name */
|
||||
if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
|
||||
policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
|
||||
return 0;
|
||||
|
||||
/* Return an error back to the caller */
|
||||
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
|
||||
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
|
||||
|
||||
/* Return 1, indicating that the message shall not be processed any further */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (to->is_kernel) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *destination_creds = NULL;
|
||||
uid_t destination_uid = UID_INVALID;
|
||||
gid_t destination_gid = GID_INVALID;
|
||||
const char *destination_unique = NULL;
|
||||
char **destination_names = NULL;
|
||||
char *n;
|
||||
|
||||
/* Driver messages are always OK */
|
||||
if (streq_ptr(m->destination, "org.freedesktop.DBus"))
|
||||
return 0;
|
||||
|
||||
/* The message came from the legacy client, and is sent to kdbus. */
|
||||
if (m->destination) {
|
||||
r = bus_get_name_creds_kdbus(to, m->destination,
|
||||
SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
|
||||
SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
|
||||
true, &destination_creds);
|
||||
if (r < 0)
|
||||
return handle_policy_error(m, r);
|
||||
|
||||
r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
|
||||
if (r < 0)
|
||||
return handle_policy_error(m, r);
|
||||
|
||||
(void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
|
||||
|
||||
(void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
|
||||
(void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
|
||||
}
|
||||
|
||||
/* First check if we (the sender) can send to this name */
|
||||
if (sd_bus_message_is_signal(m, NULL, NULL)) {
|
||||
/* If we forward a signal from dbus-1 to kdbus, we have
|
||||
* no idea who the recipient is. Therefore, we cannot
|
||||
* apply any dbus-1 policies that match on receiver
|
||||
* credentials. We know sd-bus always sets
|
||||
* KDBUS_MSG_SIGNAL, so the kernel applies policies to
|
||||
* the message. Therefore, skip policy checks in this
|
||||
* case. */
|
||||
return 0;
|
||||
} else if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) {
|
||||
if (n) {
|
||||
/* If we made a receiver decision, then remember which
|
||||
* name's policy we used, and to which unique ID it
|
||||
* mapped when we made the decision. Then, let's pass
|
||||
* this to the kernel when sending the message, so that
|
||||
* it refuses the operation should the name and unique
|
||||
* ID not map to each other anymore. */
|
||||
|
||||
r = free_and_strdup(&m->destination_ptr, n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return an error back to the caller */
|
||||
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
|
||||
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
|
||||
|
||||
/* Return 1, indicating that the message shall not be processed any further */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
|
||||
Policy *policy;
|
||||
int r;
|
||||
|
||||
assert(sp);
|
||||
|
||||
policy = shared_policy_acquire(sp);
|
||||
r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
|
||||
shared_policy_release(sp, policy);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int process_hello(Proxy *p, sd_bus_message *m) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
|
||||
bool is_hello;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(m);
|
||||
|
||||
/* As reaction to hello we need to respond with two messages:
|
||||
* the callback reply and the NameAcquired for the unique
|
||||
* name, since hello is otherwise obsolete on kdbus. */
|
||||
|
||||
is_hello =
|
||||
sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
|
||||
streq_ptr(m->destination, "org.freedesktop.DBus");
|
||||
|
||||
if (!is_hello) {
|
||||
if (p->got_hello)
|
||||
return 0;
|
||||
|
||||
return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
|
||||
}
|
||||
|
||||
if (p->got_hello)
|
||||
return log_error_errno(EIO, "Got duplicate hello, aborting.");
|
||||
|
||||
p->got_hello = true;
|
||||
|
||||
if (!p->destination_bus->is_kernel)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_method_return(m, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate HELLO reply: %m");
|
||||
|
||||
r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
|
||||
|
||||
r = bus_message_append_sender(n, "org.freedesktop.DBus");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
|
||||
|
||||
r = bus_seal_synthetic_message(p->local_bus, n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to seal HELLO reply: %m");
|
||||
|
||||
r = sd_bus_send(p->local_bus, n, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to send HELLO reply: %m");
|
||||
|
||||
n = sd_bus_message_unref(n);
|
||||
r = sd_bus_message_new_signal(
|
||||
p->local_bus,
|
||||
&n,
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"NameAcquired");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
|
||||
|
||||
r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
|
||||
|
||||
r = bus_message_append_sender(n, "org.freedesktop.DBus");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
|
||||
|
||||
r = sd_bus_message_set_destination(n, p->destination_bus->unique_name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set destination for NameAcquired message: %m");
|
||||
|
||||
r = bus_seal_synthetic_message(p->local_bus, n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to seal NameAcquired message: %m");
|
||||
|
||||
r = sd_bus_send(p->local_bus, n, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to send NameAcquired message: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int patch_sender(sd_bus *a, sd_bus_message *m) {
|
||||
char **well_known = NULL;
|
||||
sd_bus_creds *c;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(m);
|
||||
|
||||
if (!a->is_kernel)
|
||||
return 0;
|
||||
|
||||
/* We will change the sender of messages from the bus driver
|
||||
* so that they originate from the bus driver. This is a
|
||||
* speciality originating from dbus1, where the bus driver did
|
||||
* not have a unique id, but only the well-known name. */
|
||||
|
||||
c = sd_bus_message_get_creds(m);
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_creds_get_well_known_names(c, &well_known);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_contains(well_known, "org.freedesktop.DBus"))
|
||||
m->sender = "org.freedesktop.DBus";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proxy_process_destination_to_local(Proxy *p) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
bool matched, matched_synthetic;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
/*
|
||||
* Usually, we would just take any message that the bus passes to us
|
||||
* and forward it to the local connection. However, there are actually
|
||||
* applications that fail if they receive broadcasts that they didn't
|
||||
* subscribe to. Therefore, we actually emulate a real broadcast
|
||||
* matching here, and discard any broadcasts that weren't matched. Our
|
||||
* match-handlers remembers whether a message was matched by any rule,
|
||||
* by marking it in @p->message_matched.
|
||||
*/
|
||||
|
||||
r = sd_bus_process(p->destination_bus, &m);
|
||||
|
||||
matched = p->message_matched;
|
||||
matched_synthetic = p->synthetic_matched;
|
||||
p->message_matched = false;
|
||||
p->synthetic_matched = false;
|
||||
|
||||
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
|
||||
return r;
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to process destination bus: %m");
|
||||
return r;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (!m)
|
||||
return 1;
|
||||
|
||||
/* We officially got EOF, let's quit */
|
||||
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
|
||||
return -ECONNRESET;
|
||||
|
||||
r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to synthesize message: %m");
|
||||
|
||||
/* discard broadcasts that were not matched by any MATCH rule */
|
||||
if (!matched && !sd_bus_message_get_destination(m)) {
|
||||
if (!matched_synthetic)
|
||||
log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s",
|
||||
p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
|
||||
strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
|
||||
return 1;
|
||||
}
|
||||
|
||||
patch_sender(p->destination_bus, m);
|
||||
|
||||
if (p->policy) {
|
||||
r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to process policy: %m");
|
||||
if (r > 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = sd_bus_send(p->local_bus, m, NULL);
|
||||
if (r < 0) {
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
|
||||
/* If the peer tries to send a reply and it is
|
||||
* rejected with EBADSLT by the kernel, we ignore the
|
||||
* error. This catches cases where the original
|
||||
* method-call didn't had EXPECT_REPLY set, but the
|
||||
* proxy-peer still sends a reply. This is allowed in
|
||||
* dbus1, but not in kdbus. We don't want to track
|
||||
* reply-windows in the proxy, so we simply ignore
|
||||
* EBADSLT for all replies. The only downside is, that
|
||||
* callers are no longer notified if their replies are
|
||||
* dropped. However, this is equivalent to the
|
||||
* caller's timeout to expire, so this should be
|
||||
* acceptable. Nobody sane sends replies without a
|
||||
* matching method-call, so nobody should care. */
|
||||
|
||||
/* FIXME: remove -EPERM when kdbus is updated */
|
||||
if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
|
||||
return 1;
|
||||
|
||||
/* Return the error to the client, if we can */
|
||||
synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
|
||||
if (r == -ENOBUFS) {
|
||||
/* if local dbus1 peer does not dispatch its queue, warn only once */
|
||||
if (!p->queue_overflow)
|
||||
log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
|
||||
p->queue_overflow = true;
|
||||
} else
|
||||
log_error_errno(r,
|
||||
"Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
|
||||
p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
|
||||
strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
p->queue_overflow = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int proxy_process_local_to_destination(Proxy *p) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
r = sd_bus_process(p->local_bus, &m);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
|
||||
return r;
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to process local bus: %m");
|
||||
return r;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (!m)
|
||||
return 1;
|
||||
|
||||
/* We officially got EOF, let's quit */
|
||||
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
|
||||
return -ECONNRESET;
|
||||
|
||||
r = process_hello(p, m);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to process HELLO: %m");
|
||||
if (r > 0)
|
||||
return 1;
|
||||
|
||||
r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to process driver calls: %m");
|
||||
if (r > 0)
|
||||
return 1;
|
||||
|
||||
for (;;) {
|
||||
if (p->policy) {
|
||||
r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to process policy: %m");
|
||||
if (r > 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = sd_bus_send(p->destination_bus, m, NULL);
|
||||
if (r < 0) {
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return r;
|
||||
|
||||
/* The name database changed since the policy check, hence let's check again */
|
||||
if (r == -EREMCHG)
|
||||
continue;
|
||||
|
||||
/* see above why EBADSLT is ignored for replies */
|
||||
if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
|
||||
return 1;
|
||||
|
||||
synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
|
||||
log_error_errno(r,
|
||||
"Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
|
||||
p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
|
||||
strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
Proxy *p = userdata;
|
||||
|
||||
p->message_matched = true;
|
||||
return 0; /* make sure to continue processing it in further handlers */
|
||||
}
|
||||
|
||||
int proxy_run(Proxy *p) {
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
for (;;) {
|
||||
bool busy = false;
|
||||
|
||||
if (p->got_hello) {
|
||||
/* Read messages from bus, to pass them on to our client */
|
||||
r = proxy_process_destination_to_local(p);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
busy = true;
|
||||
}
|
||||
|
||||
/* Read messages from our client, to pass them on to the bus */
|
||||
r = proxy_process_local_to_destination(p);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
busy = true;
|
||||
|
||||
if (!busy) {
|
||||
r = proxy_wait(p);
|
||||
if (r == -ECONNRESET || r == -ENOTCONN)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 David Herrmann
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-xml-policy.h"
|
||||
|
||||
typedef struct Proxy Proxy;
|
||||
typedef struct ProxyActivation ProxyActivation;
|
||||
|
||||
#define PROXY_ACTIVATIONS_MAX (16) /* max parallel activation requests */
|
||||
|
||||
struct Proxy {
|
||||
sd_bus *local_bus;
|
||||
struct ucred local_creds;
|
||||
int local_in;
|
||||
int local_out;
|
||||
|
||||
sd_bus *destination_bus;
|
||||
|
||||
Set *owned_names;
|
||||
SharedPolicy *policy;
|
||||
|
||||
LIST_HEAD(ProxyActivation, activations);
|
||||
size_t n_activations;
|
||||
|
||||
bool got_hello : 1;
|
||||
bool queue_overflow : 1;
|
||||
bool message_matched : 1;
|
||||
bool synthetic_matched : 1;
|
||||
};
|
||||
|
||||
struct ProxyActivation {
|
||||
LIST_FIELDS(ProxyActivation, activations_by_proxy);
|
||||
Proxy *proxy;
|
||||
sd_bus_message *request;
|
||||
sd_bus_slot *slot;
|
||||
};
|
||||
|
||||
int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
|
||||
Proxy *proxy_free(Proxy *p);
|
||||
|
||||
int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration);
|
||||
int proxy_hello_policy(Proxy *p, uid_t original_uid);
|
||||
int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error);
|
||||
int proxy_run(Proxy *p);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
|
@ -1,244 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2013 Daniel Mack
|
||||
Copyright 2014 Kay Sievers
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-util.h"
|
||||
#include "def.h"
|
||||
#include "formats-util.h"
|
||||
#include "log.h"
|
||||
#include "proxy.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static char *arg_address = NULL;
|
||||
static char *arg_command_line_buffer = NULL;
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"Connect STDIO to a given bus address.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --machine=MACHINE Connect to specified machine\n"
|
||||
" --address=ADDRESS Connect to the bus specified by ADDRESS\n"
|
||||
" (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_ADDRESS,
|
||||
ARG_MACHINE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "address", required_argument, NULL, ARG_ADDRESS },
|
||||
{ "machine", required_argument, NULL, ARG_MACHINE },
|
||||
{},
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_ADDRESS: {
|
||||
char *a;
|
||||
|
||||
a = strdup(optarg);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
free(arg_address);
|
||||
arg_address = a;
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_MACHINE: {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
char *a;
|
||||
|
||||
e = bus_address_escape(optarg);
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
free(arg_address);
|
||||
arg_address = a;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unhandled option");
|
||||
}
|
||||
|
||||
/* If the first command line argument is only "x" characters
|
||||
* we'll write who we are talking to into it, so that "ps" is
|
||||
* explanatory */
|
||||
arg_command_line_buffer = argv[optind];
|
||||
if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
|
||||
log_error("Too many arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!arg_address) {
|
||||
arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
|
||||
if (!arg_address)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rename_service(sd_bus *a, sd_bus *b) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_free_ char *p = NULL, *name = NULL;
|
||||
const char *comm;
|
||||
char **cmdline;
|
||||
uid_t uid;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_euid(creds, &uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_cmdline(creds, &cmdline);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_comm(creds, &comm);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
name = uid_to_name(uid);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
p = strv_join(cmdline, " ");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The status string gets the full command line ... */
|
||||
sd_notifyf(false,
|
||||
"STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
|
||||
pid, p,
|
||||
uid, name);
|
||||
|
||||
/* ... and the argv line only the short comm */
|
||||
if (arg_command_line_buffer) {
|
||||
size_t m, w;
|
||||
|
||||
m = strlen(arg_command_line_buffer);
|
||||
w = snprintf(arg_command_line_buffer, m,
|
||||
"[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
|
||||
pid, comm,
|
||||
uid, name);
|
||||
|
||||
if (m > w)
|
||||
memzero(arg_command_line_buffer + w, m - w);
|
||||
}
|
||||
|
||||
log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
|
||||
pid, p,
|
||||
uid, name,
|
||||
a->unique_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(proxy_freep) Proxy *p = NULL;
|
||||
int r;
|
||||
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
|
||||
r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = rename_service(p->destination_bus, p->local_bus);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to rename process: %m");
|
||||
|
||||
r = proxy_run(p);
|
||||
|
||||
finish:
|
||||
sd_notify(false,
|
||||
"STOPPING=1\n"
|
||||
"STATUS=Shutting down.");
|
||||
|
||||
free(arg_address);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2013 Daniel Mack
|
||||
Copyright 2014 Kay Sievers
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-internal.h"
|
||||
#include "bus-match.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-util.h"
|
||||
#include "synthesize.h"
|
||||
#include "util.h"
|
||||
|
||||
int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(b);
|
||||
assert(m);
|
||||
|
||||
r = bus_message_append_sender(m, "org.freedesktop.DBus");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_seal_synthetic_message(b, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(b, m, NULL);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(call);
|
||||
|
||||
if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_method_error(call, &m, e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return synthetic_driver_send(call->bus, m);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
bus_error_setfv(&error, name, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return synthetic_reply_method_error(call, &error);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
|
||||
|
||||
assert(call);
|
||||
|
||||
if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
return 0;
|
||||
|
||||
if (sd_bus_error_is_set(p))
|
||||
return synthetic_reply_method_error(call, p);
|
||||
|
||||
sd_bus_error_set_errno(&berror, error);
|
||||
|
||||
return synthetic_reply_method_error(call, &berror);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
|
||||
va_list ap;
|
||||
|
||||
assert(call);
|
||||
|
||||
if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
return 0;
|
||||
|
||||
va_start(ap, format);
|
||||
sd_bus_error_set_errnofv(&berror, error, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return synthetic_reply_method_error(call, &berror);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(call);
|
||||
|
||||
if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_method_return(call, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(types)) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, types);
|
||||
r = bus_message_append_ap(m, types, ap);
|
||||
va_end(ap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return synthetic_driver_send(call->bus, m);
|
||||
}
|
||||
|
||||
int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(call);
|
||||
|
||||
if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_new_method_return(call, &m);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(call, r, NULL);
|
||||
|
||||
r = sd_bus_message_append_strv(m, l);
|
||||
if (r < 0)
|
||||
return synthetic_reply_method_errno(call, r, NULL);
|
||||
|
||||
return synthetic_driver_send(call->bus, m);
|
||||
}
|
||||
|
||||
int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
|
||||
const char *name, *old_owner, *new_owner;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(m);
|
||||
|
||||
/* If we get NameOwnerChanged for our own name, we need to
|
||||
* synthesize NameLost/NameAcquired, since socket clients need
|
||||
* that, even though it is obsoleted on kdbus */
|
||||
|
||||
if (!a->is_kernel)
|
||||
return 0;
|
||||
|
||||
if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
|
||||
!streq_ptr(m->path, "/org/freedesktop/DBus") ||
|
||||
!streq_ptr(m->sender, "org.freedesktop.DBus"))
|
||||
return 0;
|
||||
|
||||
r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_rewind(m, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq(old_owner, a->unique_name)) {
|
||||
|
||||
r = sd_bus_message_new_signal(
|
||||
b,
|
||||
&n,
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"NameLost");
|
||||
|
||||
} else if (streq(new_owner, a->unique_name)) {
|
||||
|
||||
r = sd_bus_message_new_signal(
|
||||
b,
|
||||
&n,
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"NameAcquired");
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(n, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_message_append_sender(n, "org.freedesktop.DBus");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_set_destination(n, a->unique_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_seal_synthetic_message(b, n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(b, n, NULL);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "proxy.h"
|
||||
|
||||
int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
|
||||
|
||||
int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...);
|
||||
int synthetic_reply_method_return_strv(sd_bus_message *call, char **l);
|
||||
|
||||
int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e);
|
||||
int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4);
|
||||
int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p);
|
||||
int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4);
|
||||
|
||||
int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m);
|
@ -1,170 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Daniel Mack
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-xml-policy.h"
|
||||
#include "log.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
static int test_policy_load(Policy *p, const char *name) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r = 0;
|
||||
|
||||
path = strjoin(TEST_DIR, "/bus-policy/", name, NULL);
|
||||
assert_se(path);
|
||||
|
||||
if (access(path, R_OK) == 0)
|
||||
r = policy_load(p, STRV_MAKE(path));
|
||||
else
|
||||
r = -ENOENT;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int show_policy(const char *fn) {
|
||||
Policy p = {};
|
||||
int r;
|
||||
|
||||
r = policy_load(&p, STRV_MAKE(fn));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to load policy %s: %m", fn);
|
||||
return r;
|
||||
}
|
||||
|
||||
policy_dump(&p);
|
||||
policy_free(&p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
Policy p = {};
|
||||
|
||||
printf("Showing session policy BEGIN\n");
|
||||
show_policy("/etc/dbus-1/session.conf");
|
||||
printf("Showing session policy END\n");
|
||||
|
||||
printf("Showing system policy BEGIN\n");
|
||||
show_policy("/etc/dbus-1/system.conf");
|
||||
printf("Showing system policy END\n");
|
||||
|
||||
/* Ownership tests */
|
||||
assert_se(test_policy_load(&p, "ownerships.conf") == 0);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true);
|
||||
assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true);
|
||||
assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false);
|
||||
assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false);
|
||||
assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
/* Signaltest */
|
||||
assert_se(test_policy_load(&p, "signals.conf") == 0);
|
||||
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true);
|
||||
assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
/* Method calls */
|
||||
assert_se(test_policy_load(&p, "methods.conf") == 0);
|
||||
policy_dump(&p);
|
||||
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true);
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true);
|
||||
|
||||
assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
/* User and groups */
|
||||
assert_se(test_policy_load(&p, "hello.conf") == 0);
|
||||
policy_dump(&p);
|
||||
|
||||
assert_se(policy_check_hello(&p, 0, 0) == true);
|
||||
assert_se(policy_check_hello(&p, 1, 0) == false);
|
||||
assert_se(policy_check_hello(&p, 0, 1) == false);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
/* dbus1 test file: ownership */
|
||||
|
||||
assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0);
|
||||
policy_dump(&p);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
/* dbus1 test file: many rules */
|
||||
|
||||
assert_se(test_policy_load(&p, "many-rules.conf") >= 0);
|
||||
policy_dump(&p);
|
||||
policy_free(&p);
|
||||
|
||||
/* dbus1 test file: generic test */
|
||||
|
||||
assert_se(test_policy_load(&p, "test.conf") >= 0);
|
||||
policy_dump(&p);
|
||||
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true);
|
||||
assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false);
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
|
||||
assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
|
||||
assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
|
||||
assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
|
||||
assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
|
||||
|
||||
assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false);
|
||||
assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false);
|
||||
assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
|
||||
assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
|
||||
assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
|
||||
assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
|
||||
assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
|
||||
|
||||
policy_free(&p);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-dump.h"
|
||||
#include "bus-kernel.h"
|
||||
#include "bus-util.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct {
|
||||
const char *sender;
|
||||
int matched_acquired;
|
||||
} TestProxyMatch;
|
||||
|
||||
static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
TestProxyMatch *match = userdata;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
assert_se(r >= 0);
|
||||
|
||||
if (!streq_ptr(match->sender, name))
|
||||
return 0;
|
||||
|
||||
++match->matched_acquired;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_proxy_matched(void) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL;
|
||||
_cleanup_free_ char *matchstr = NULL;
|
||||
TestProxyMatch match = {};
|
||||
const char *me;
|
||||
int r;
|
||||
|
||||
/* open bus 'a' */
|
||||
|
||||
r = sd_bus_new(&a);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_set_bus_client(a, true);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_start(a);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(a, &me);
|
||||
assert_se(r >= 0);
|
||||
|
||||
matchstr = strjoin("type='signal',"
|
||||
"member='NameAcquired',"
|
||||
"destination='",
|
||||
me,
|
||||
"'",
|
||||
NULL);
|
||||
assert_se(matchstr);
|
||||
r = sd_bus_add_match(a, NULL, matchstr, test_proxy_acquired, &match);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(a, &match.sender);
|
||||
assert_se(r >= 0);
|
||||
|
||||
/* barrier to guarantee proxy/dbus-daemon handled the previous data */
|
||||
r = sd_bus_call_method(a,
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"GetId",
|
||||
NULL, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
/* now we can be sure the Name* signals were sent */
|
||||
do {
|
||||
r = sd_bus_process(a, NULL);
|
||||
} while (r > 0);
|
||||
assert_se(r == 0);
|
||||
|
||||
assert_se(match.matched_acquired == 1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (access("/var/run/dbus/system_bus_socket", F_OK) < 0)
|
||||
return EXIT_TEST_SKIP;
|
||||
|
||||
log_parse_environment();
|
||||
|
||||
test_proxy_matched();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
301
src/stdio-bridge/stdio-bridge.c
Normal file
301
src/stdio-bridge/stdio-bridge.c
Normal file
@ -0,0 +1,301 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "bus-internal.h"
|
||||
#include "bus-util.h"
|
||||
#include "build.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
|
||||
|
||||
const char *arg_bus_path = DEFAULT_BUS_PATH;
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --bus-path=PATH Path to the kernel bus (default: %s)\n",
|
||||
program_invocation_short_name, DEFAULT_BUS_PATH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "bus-path", required_argument, NULL, 'p' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
case 'p':
|
||||
arg_bus_path = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown option code %c", c);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
|
||||
sd_id128_t server_id;
|
||||
bool is_unix;
|
||||
int r, in_fd, out_fd;
|
||||
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_listen_fds(0);
|
||||
if (r == 0) {
|
||||
in_fd = STDIN_FILENO;
|
||||
out_fd = STDOUT_FILENO;
|
||||
} else if (r == 1) {
|
||||
in_fd = SD_LISTEN_FDS_START;
|
||||
out_fd = SD_LISTEN_FDS_START;
|
||||
} else {
|
||||
log_error("Illegal number of file descriptors passed\n");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
is_unix =
|
||||
sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
|
||||
sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
|
||||
|
||||
r = sd_bus_new(&a);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to allocate bus: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_set_address(a, arg_bus_path);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set address to connect to: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_negotiate_fds(a, is_unix);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set FD negotiation: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_start(a);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to start bus client: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_get_bus_id(a, &server_id);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get server ID: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_new(&b);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to allocate bus: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_set_fd(b, in_fd, out_fd);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set fds: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_set_server(b, 1, server_id);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set server mode: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_negotiate_fds(b, is_unix);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set FD negotiation: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_set_anonymous(b, true);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set anonymous authentication: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_start(b);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to start bus client: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL;
|
||||
int events_a, events_b, fd;
|
||||
uint64_t timeout_a, timeout_b, t;
|
||||
struct timespec _ts, *ts;
|
||||
|
||||
r = sd_bus_process(a, &m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to process bus a: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (m) {
|
||||
r = sd_bus_send(b, m, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send message: %m");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
r = sd_bus_process(b, &m);
|
||||
if (r < 0) {
|
||||
/* treat 'connection reset by peer' as clean exit condition */
|
||||
if (r == -ECONNRESET)
|
||||
r = 0;
|
||||
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (m) {
|
||||
r = sd_bus_send(a, m, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send message: %m");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
fd = sd_bus_get_fd(a);
|
||||
if (fd < 0) {
|
||||
log_error_errno(r, "Failed to get fd: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
events_a = sd_bus_get_events(a);
|
||||
if (events_a < 0) {
|
||||
log_error_errno(r, "Failed to get events mask: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_get_timeout(a, &timeout_a);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get timeout: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
events_b = sd_bus_get_events(b);
|
||||
if (events_b < 0) {
|
||||
log_error_errno(r, "Failed to get events mask: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_get_timeout(b, &timeout_b);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get timeout: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
t = timeout_a;
|
||||
if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
|
||||
t = timeout_b;
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
ts = NULL;
|
||||
else {
|
||||
usec_t nw;
|
||||
|
||||
nw = now(CLOCK_MONOTONIC);
|
||||
if (t > nw)
|
||||
t -= nw;
|
||||
else
|
||||
t = 0;
|
||||
|
||||
ts = timespec_store(&_ts, t);
|
||||
}
|
||||
|
||||
{
|
||||
struct pollfd p[3] = {
|
||||
{.fd = fd, .events = events_a, },
|
||||
{.fd = STDIN_FILENO, .events = events_b & POLLIN, },
|
||||
{.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
|
||||
|
||||
r = ppoll(p, ELEMENTSOF(p), ts, NULL);
|
||||
}
|
||||
if (r < 0) {
|
||||
log_error("ppoll() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "architecture.h"
|
||||
#include "automount.h"
|
||||
#include "bus-xml-policy.h"
|
||||
#include "busname.h"
|
||||
#include "cgroup.h"
|
||||
#include "compress.h"
|
||||
@ -83,8 +82,6 @@ int main(int argc, char **argv) {
|
||||
test_table(path_result, PATH_RESULT);
|
||||
test_table(path_state, PATH_STATE);
|
||||
test_table(path_type, PATH_TYPE);
|
||||
test_table(policy_item_class, POLICY_ITEM_CLASS);
|
||||
test_table(policy_item_type, POLICY_ITEM_TYPE);
|
||||
test_table(protect_home, PROTECT_HOME);
|
||||
test_table(protect_system, PROTECT_SYSTEM);
|
||||
test_table(rlimit, RLIMIT);
|
||||
|
@ -6,7 +6,6 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
g systemd-journal - -
|
||||
u systemd-bus-proxy - "systemd Bus Proxy"
|
||||
m4_ifdef(`ENABLE_NETWORKD',
|
||||
u systemd-network - "systemd Network Management"
|
||||
)m4_dnl
|
||||
|
2
units/.gitignore
vendored
2
units/.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
/systemd-bus-proxyd.service.m4
|
||||
/user@.service.m4
|
||||
/console-getty.service
|
||||
/console-getty.service.m4
|
||||
@ -24,7 +23,6 @@
|
||||
/systemd-backlight@.service
|
||||
/systemd-binfmt.service
|
||||
/systemd-bootchart.service
|
||||
/systemd-bus-proxyd.service
|
||||
/systemd-coredump@.service
|
||||
/systemd-firstboot.service
|
||||
/systemd-fsck-root.service
|
||||
|
@ -1,25 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Legacy D-Bus Protocol Compatibility Daemon
|
||||
|
||||
[Service]
|
||||
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus
|
||||
ExecReload=@bindir@/busctl --address=unix:path=/run/dbus/system_bus_socket call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfig
|
||||
NotifyAccess=main
|
||||
CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN )
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
PrivateNetwork=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=yes
|
||||
|
||||
# The proxy manages connections of all users, so it needs an elevated file
|
||||
# limit. It does proper per-user accounting (indirectly via kdbus), therefore,
|
||||
# the effective per-user limits stay the same.
|
||||
LimitNOFILE=16384
|
@ -1,12 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Legacy D-Bus Protocol Compatibility Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=/var/run/dbus/system_bus_socket
|
1
units/user/.gitignore
vendored
1
units/user/.gitignore
vendored
@ -1,2 +1 @@
|
||||
/systemd-exit.service
|
||||
/systemd-bus-proxyd.service
|
||||
|
@ -1,14 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Legacy D-Bus Protocol Compatibility Daemon
|
||||
|
||||
[Service]
|
||||
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus
|
||||
ExecReload=@bindir@/busctl --address=unix:path=/run/user/%U/bus call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfig
|
||||
NotifyAccess=main
|
@ -1,12 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Legacy D-Bus Protocol Compatibility Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/bus
|
Loading…
Reference in New Issue
Block a user