diff options
37 files changed, 418 insertions, 4793 deletions
diff --git a/.gitignore b/.gitignore index cc24233ab8..2324e6e478 100644 --- a/.gitignore +++ b/.gitignore @@ -49,14 +49,12 @@ /systemctl /systemd /systemd-ac-power -/systemd-activate /systemd-analyze /systemd-ask-password /systemd-backlight /systemd-binfmt /systemd-bootchart /systemd-bootx64.efi -/systemd-bus-proxyd /systemd-cat /systemd-cgls /systemd-cgroups-agent @@ -109,6 +107,7 @@ /systemd-run /systemd-shutdown /systemd-sleep +/systemd-socket-activate /systemd-socket-proxyd /systemd-stdio-bridge /systemd-sysctl @@ -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 diff --git a/Makefile-man.am b/Makefile-man.am index 28b5fb6adb..8b68bf37cc 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -94,12 +94,9 @@ MANPAGES += \ man/shutdown.8 \ man/sysctl.d.5 \ man/systemctl.1 \ - man/systemd-activate.8 \ 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 \ @@ -126,6 +123,7 @@ MANPAGES += \ man/systemd-resolve.1 \ man/systemd-run.1 \ man/systemd-sleep.conf.5 \ + man/systemd-socket-activate.1 \ man/systemd-socket-proxyd.8 \ man/systemd-suspend.service.8 \ man/systemd-sysctl.service.8 \ @@ -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) @@ -2574,15 +2567,12 @@ EXTRA_DIST += \ man/standard-options.xml \ man/sysctl.d.xml \ man/systemctl.xml \ - man/systemd-activate.xml \ man/systemd-analyze.xml \ man/systemd-ask-password-console.service.xml \ man/systemd-ask-password.xml \ 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 \ @@ -2628,6 +2618,7 @@ EXTRA_DIST += \ man/systemd-rfkill.service.xml \ man/systemd-run.xml \ man/systemd-sleep.conf.xml \ + man/systemd-socket-activate.xml \ man/systemd-socket-proxyd.xml \ man/systemd-suspend.service.xml \ man/systemd-sysctl.service.xml \ diff --git a/Makefile.am b/Makefile.am index 676d97c7d4..9bc0bf2c05 100644 --- a/Makefile.am +++ b/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 @@ -3875,13 +3809,13 @@ tests += \ # ------------------------------------------------------------------------------ -rootlibexec_PROGRAMS += \ - systemd-activate +bin_PROGRAMS += \ + systemd-socket-activate -systemd_activate_SOURCES = \ +systemd_socket_activate_SOURCES = \ src/activate/activate.c -systemd_activate_LDADD = \ +systemd_socket_activate_LDADD = \ libshared.la # ------------------------------------------------------------------------------ @@ -1,5 +1,11 @@ systemd System and Service Manager +CHANGES WITH 230 in spe: + + * Testing tool /usr/lib/systemd/systemd-activate is renamed to + systemd-socket-activate and installed into /usr/bin. It is now fully + supported. + CHANGES WITH 229: * The systemd-resolved DNS resolver service has gained a substantial @@ -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. @@ -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. diff --git a/man/busctl.xml b/man/busctl.xml index 26d778d4dd..b71a174634 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -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> diff --git a/man/systemd-bus-proxyd.service.xml b/man/systemd-bus-proxyd.service.xml deleted file mode 100644 index 02189eea7c..0000000000 --- a/man/systemd-bus-proxyd.service.xml +++ /dev/null @@ -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> diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml deleted file mode 100644 index 0923396151..0000000000 --- a/man/systemd-bus-proxyd.xml +++ /dev/null @@ -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> diff --git a/man/systemd-activate.xml b/man/systemd-socket-activate.xml index 995e6eecce..5d7f157c72 100644 --- a/man/systemd-activate.xml +++ b/man/systemd-socket-activate.xml @@ -21,11 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="systemd-activate" +<refentry id="systemd-socket-activate" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> - <title>systemd-activate</title> + <title>systemd-socket-activate</title> <productname>systemd</productname> <authorgroup> @@ -39,18 +39,18 @@ </refentryinfo> <refmeta> - <refentrytitle>systemd-activate</refentrytitle> - <manvolnum>8</manvolnum> + <refentrytitle>systemd-socket-activate</refentrytitle> + <manvolnum>1</manvolnum> </refmeta> <refnamediv> - <refname>systemd-activate</refname> + <refname>systemd-socket-activate</refname> <refpurpose>Test socket activation of daemons</refpurpose> </refnamediv> <refsynopsisdiv> <cmdsynopsis> - <command>/usr/lib/systemd/systemd-activate</command> + <command>systemd-socket-activate</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain"><replaceable>daemon</replaceable></arg> <arg choice="opt" rep="repeat">OPTIONS</arg> @@ -60,20 +60,20 @@ <refsect1> <title>Description</title> - <para><command>systemd-activate</command> may be used to launch a socket-activated service binary from the command + <para><command>systemd-socket-activate</command> may be used to launch a socket-activated service binary from the command line for testing purposes. It may also be used to launch individual instances of the service binary per connection. </para> <para>The daemon to launch and its options should be specified - after options intended for <command>systemd-activate</command>. + after options intended for <command>systemd-socket-activate</command>. </para> <para>If the <option>--inetd</option> option is given, the socket file descriptor will be used as the standard input and output of the launched process. Otherwise, standard input and output will be inherited, and sockets will be passed through file descriptors 3 and higher. Sockets passed through <varname>$LISTEN_FDS</varname> to - <command>systemd-activate</command> will be passed through to the daemon, in the original positions. Other sockets + <command>systemd-socket-activate</command> will be passed through to the daemon, in the original positions. Other sockets specified with <option>--listen=</option> will use consecutive descriptors. By default, - <command>systemd-activate</command> listens on a stream socket, use <option>--datagram</option> and + <command>systemd-socket-activate</command> listens on a stream socket, use <option>--datagram</option> and <option>--seqpacket</option> to listen on datagram or sequential packet sockets instead (see below). </para> </refsect1> @@ -131,18 +131,20 @@ launched process. If <replaceable>VAR</replaceable> is followed by <literal>=</literal>, assume that it is a variable–value pair. Otherwise, obtain the value from the - environment of <command>systemd-activate</command> itself. + environment of <command>systemd-socket-activate</command> itself. </para></listitem> </varlistentry> <varlistentry> - <term><option>--fdname=</option><replaceable>NAME</replaceable></term> - - <listitem><para>Specify a name for the activation file - descriptors. This is equivalent to setting - <varname>FileDescriptorName=</varname> in socket unit files, and - enables use of - <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + <term><option>--fdname=</option><replaceable>NAME</replaceable><optional>:<replaceable>NAME</replaceable>...</optional></term> + + <listitem><para>Specify names for the file descriptors passed. This is equivalent to setting + <varname>FileDescriptorName=</varname> in socket unit files, and enables use of + <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + Multiple entries may be specifies using separate options or by separating names with colons + (<literal>:</literal>) in one option. In case more names are given than descriptors, superflous ones willl be + ignored. In case less names are given than descriptors, the remaining file descriptors will be unnamed. + </para></listitem> </varlistentry> <xi:include href="standard-options.xml" xpointer="help" /> @@ -180,13 +182,13 @@ <example> <title>Run an echo server on port 2000</title> - <programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 --inetd -a cat</programlisting> + <programlisting>$ systemd-socket-activate -l 2000 --inetd -a cat</programlisting> </example> <example> <title>Run a socket-activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title> - <programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting> + <programlisting>$ systemd-socket-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting> </example> </refsect1> diff --git a/src/activate/activate.c b/src/activate/activate.c index 0db4967edb..23244fdc62 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -27,6 +27,7 @@ #include "sd-daemon.h" #include "alloc-util.h" +#include "escape.h" #include "fd-util.h" #include "log.h" #include "macro.h" @@ -40,7 +41,7 @@ static bool arg_accept = false; static int arg_socket_type = SOCK_STREAM; static char** arg_args = NULL; static char** arg_setenv = NULL; -static const char *arg_fdname = NULL; +static char **arg_fdnames = NULL; static bool arg_inetd = false; static int add_epoll(int epoll_fd, int fd) { @@ -134,7 +135,6 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, _cleanup_free_ char *joined = NULL; unsigned n_env = 0, length; const char *tocopy; - unsigned i; char **s; int r; @@ -224,25 +224,30 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0) return log_oom(); - if (arg_fdname) { + if (arg_fdnames) { + _cleanup_free_ char *names = NULL; + size_t len; char *e; + int i; + + len = strv_length(arg_fdnames); + if (len == 1) + for (i = 1; i < n_fds; i++) { + r = strv_extend(&arg_fdnames, arg_fdnames[0]); + if (r < 0) + return log_error_errno(r, "Failed to extend strv: %m"); + } + else if (len != (unsigned) n_fds) + log_warning("The number of fd names is different than number of fds: %zu vs %d", + len, n_fds); - e = strappend("LISTEN_FDNAMES=", arg_fdname); - if (!e) + names = strv_join(arg_fdnames, ":"); + if (!names) return log_oom(); - for (i = 1; i < (unsigned) n_fds; i++) { - char *c; - - c = strjoin(e, ":", arg_fdname, NULL); - if (!c) { - free(e); - return log_oom(); - } - - free(e); - e = c; - } + e = strappend("LISTEN_FDNAMES=", names); + if (!e) + return log_oom(); envp[n_env++] = e; } @@ -339,14 +344,15 @@ static void help(void) { printf("%s [OPTIONS...]\n\n" "Listen on sockets and launch child on connection.\n\n" "Options:\n" - " -h --help Show this help and exit\n" - " --version Print version string and exit\n" - " -l --listen=ADDR Listen for raw connections at ADDR\n" - " -d --datagram Listen on datagram instead of stream socket\n" - " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" - " -a --accept Spawn separate child for each connection\n" - " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" - " --inetd Enable inetd file descriptor passing protocol\n" + " -h --help Show this help and exit\n" + " --version Print version string and exit\n" + " -l --listen=ADDR Listen for raw connections at ADDR\n" + " -d --datagram Listen on datagram instead of stream socket\n" + " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" + " -a --accept Spawn separate child for each connection\n" + " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" + " --fdname=NAME[:NAME...] Specify names for file descriptors\n" + " --inetd Enable inetd file descriptor passing protocol\n" "\n" "Note: file descriptors from sd_listen_fds() will be passed through.\n" , program_invocation_short_name); @@ -424,14 +430,30 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_FDNAME: - if (!fdname_is_valid(optarg)) { - log_error("File descriptor name %s is not valid, refusing.", optarg); - return -EINVAL; - } + case ARG_FDNAME: { + _cleanup_strv_free_ char **names; + char **s; + + names = strv_split(optarg, ":"); + if (!names) + return log_oom(); + + STRV_FOREACH(s, names) + if (!fdname_is_valid(*s)) { + _cleanup_free_ char *esc; - arg_fdname = optarg; + esc = cescape(*s); + log_warning("File descriptor name \"%s\" is not valid.", esc); + } + + /* Empty optargs means one empty name */ + r = strv_extend_strv(&arg_fdnames, + strv_isempty(names) ? STRV_MAKE("") : names, + false); + if (r < 0) + return log_error_errno(r, "strv_extend_strv: %m"); break; + } case ARG_INETD: arg_inetd = true; diff --git a/src/basic/missing.h b/src/basic/missing.h index 36b060496a..4d3764c022 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -714,6 +714,7 @@ static inline int setns(int fd, int nstype) { #endif #if !HAVE_DECL_IFLA_PHYS_PORT_ID +#define IFLA_EXT_MASK 29 #undef IFLA_PROMISCUITY #define IFLA_PROMISCUITY 30 #define IFLA_NUM_TX_QUEUES 31 diff --git a/src/basic/strv.c b/src/basic/strv.c index b5d4d8191b..8282298dca 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -371,7 +371,7 @@ char *strv_join(char **l, const char *separator) { n = 0; STRV_FOREACH(s, l) { - if (n != 0) + if (s != l) n += k; n += strlen(*s); } @@ -382,7 +382,7 @@ char *strv_join(char **l, const char *separator) { e = r; STRV_FOREACH(s, l) { - if (e != r) + if (s != l) e = stpcpy(e, separator); e = stpcpy(e, *s); diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/bus-proxyd/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c deleted file mode 100644 index b6bd6eb390..0000000000 --- a/src/bus-proxyd/bus-proxyd.c +++ /dev/null @@ -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; -} diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c deleted file mode 100644 index 8943e0dc12..0000000000 --- a/src/bus-proxyd/bus-xml-policy.c +++ /dev/null @@ -1,1327 +0,0 @@ -/*** - 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 "sd-login.h" - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-xml-policy.h" -#include "conf-files.h" -#include "fileio.h" -#include "formats-util.h" -#include "locale-util.h" -#include "set.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "user-util.h" -#include "xml.h" - -static void policy_item_free(PolicyItem *i) { - assert(i); - - free(i->interface); - free(i->member); - free(i->error); - free(i->name); - free(i->path); - free(i); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free); - -static void item_append(PolicyItem *i, PolicyItem **list) { - - PolicyItem *tail; - - LIST_FIND_TAIL(items, *list, tail); - LIST_INSERT_AFTER(items, *list, tail, i); -} - -static int file_load(Policy *p, const char *path) { - - _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL; - _cleanup_(policy_item_freep) PolicyItem *i = NULL; - void *xml_state = NULL; - unsigned n_other = 0; - const char *q; - int r; - - enum { - STATE_OUTSIDE, - STATE_BUSCONFIG, - STATE_POLICY, - STATE_POLICY_CONTEXT, - STATE_POLICY_CONSOLE, - STATE_POLICY_USER, - STATE_POLICY_GROUP, - STATE_POLICY_OTHER_ATTRIBUTE, - STATE_ALLOW_DENY, - STATE_ALLOW_DENY_INTERFACE, - STATE_ALLOW_DENY_MEMBER, - STATE_ALLOW_DENY_ERROR, - STATE_ALLOW_DENY_PATH, - STATE_ALLOW_DENY_MESSAGE_TYPE, - STATE_ALLOW_DENY_NAME, - STATE_ALLOW_DENY_OTHER_ATTRIBUTE, - STATE_OTHER, - } state = STATE_OUTSIDE; - - enum { - POLICY_CATEGORY_NONE, - POLICY_CATEGORY_DEFAULT, - POLICY_CATEGORY_MANDATORY, - POLICY_CATEGORY_ON_CONSOLE, - POLICY_CATEGORY_NO_CONSOLE, - POLICY_CATEGORY_USER, - POLICY_CATEGORY_GROUP - } policy_category = POLICY_CATEGORY_NONE; - - unsigned line = 0; - - assert(p); - - r = read_full_file(path, &c, NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - if (r == -EISDIR) - return r; - - return log_error_errno(r, "Failed to load %s: %m", path); - } - - q = c; - for (;;) { - _cleanup_free_ char *name = NULL; - int t; - - t = xml_tokenize(&q, &name, &xml_state, &line); - if (t < 0) - return log_error_errno(t, "XML parse failure in %s: %m", path); - - switch (state) { - - case STATE_OUTSIDE: - - if (t == XML_TAG_OPEN) { - if (streq(name, "busconfig")) - state = STATE_BUSCONFIG; - else { - log_error("Unexpected tag %s at %s:%u.", name, path, line); - return -EINVAL; - } - - } else if (t == XML_END) - return 0; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_BUSCONFIG: - - if (t == XML_TAG_OPEN) { - if (streq(name, "policy")) { - state = STATE_POLICY; - policy_category = POLICY_CATEGORY_NONE; - free(policy_user); - free(policy_group); - policy_user = policy_group = NULL; - } else { - state = STATE_OTHER; - n_other = 0; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "busconfig"))) - state = STATE_OUTSIDE; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (2) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY: - - if (t == XML_ATTRIBUTE_NAME) { - if (streq(name, "context")) - state = STATE_POLICY_CONTEXT; - else if (streq(name, "at_console")) - state = STATE_POLICY_CONSOLE; - else if (streq(name, "user")) - state = STATE_POLICY_USER; - else if (streq(name, "group")) - state = STATE_POLICY_GROUP; - else { - log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line); - state = STATE_POLICY_OTHER_ATTRIBUTE; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "policy"))) - state = STATE_BUSCONFIG; - else if (t == XML_TAG_OPEN) { - PolicyItemType it; - - if (streq(name, "allow")) - it = POLICY_ITEM_ALLOW; - else if (streq(name, "deny")) - it = POLICY_ITEM_DENY; - else { - log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line); - return -EINVAL; - } - - assert(!i); - i = new0(PolicyItem, 1); - if (!i) - return log_oom(); - - i->type = it; - state = STATE_ALLOW_DENY; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (3) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONTEXT: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "default")) { - policy_category = POLICY_CATEGORY_DEFAULT; - state = STATE_POLICY; - } else if (streq(name, "mandatory")) { - policy_category = POLICY_CATEGORY_MANDATORY; - state = STATE_POLICY; - } else { - log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONSOLE: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "true")) { - policy_category = POLICY_CATEGORY_ON_CONSOLE; - state = STATE_POLICY; - } else if (streq(name, "false")) { - policy_category = POLICY_CATEGORY_NO_CONSOLE; - state = STATE_POLICY; - } else { - log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4.1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_USER: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_user); - policy_user = name; - name = NULL; - policy_category = POLICY_CATEGORY_USER; - state = STATE_POLICY; - } else { - log_error("Unexpected token (5) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_GROUP: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_group); - policy_group = name; - name = NULL; - policy_category = POLICY_CATEGORY_GROUP; - state = STATE_POLICY; - } else { - log_error("Unexpected token (6) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_POLICY; - else { - log_error("Unexpected token (7) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY: - - assert(i); - - if (t == XML_ATTRIBUTE_NAME) { - PolicyItemClass ic; - - if (startswith(name, "send_")) - ic = POLICY_ITEM_SEND; - else if (startswith(name, "receive_")) - ic = POLICY_ITEM_RECV; - else if (streq(name, "own")) - ic = POLICY_ITEM_OWN; - else if (streq(name, "own_prefix")) - ic = POLICY_ITEM_OWN_PREFIX; - else if (streq(name, "user")) - ic = POLICY_ITEM_USER; - else if (streq(name, "group")) - ic = POLICY_ITEM_GROUP; - else if (STR_IN_SET(name, "eavesdrop", "log")) { - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } else { - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - - if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) { - log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line); - return -EINVAL; - } - - i->class = ic; - - if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) { - const char *u; - - u = strchr(name, '_'); - assert(u); - - u++; - - if (streq(u, "interface")) - state = STATE_ALLOW_DENY_INTERFACE; - else if (streq(u, "member")) - state = STATE_ALLOW_DENY_MEMBER; - else if (streq(u, "error")) - state = STATE_ALLOW_DENY_ERROR; - else if (streq(u, "path")) - state = STATE_ALLOW_DENY_PATH; - else if (streq(u, "type")) - state = STATE_ALLOW_DENY_MESSAGE_TYPE; - else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) || - (streq(u, "sender") && ic == POLICY_ITEM_RECV)) - state = STATE_ALLOW_DENY_NAME; - else { - if (streq(u, "requested_reply")) - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - else - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - } else - state = STATE_ALLOW_DENY_NAME; - - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) { - - /* If the tag is fully empty so far, we consider it a recv */ - if (i->class == _POLICY_ITEM_CLASS_UNSET) - i->class = POLICY_ITEM_RECV; - - if (policy_category == POLICY_CATEGORY_DEFAULT) - item_append(i, &p->default_items); - else if (policy_category == POLICY_CATEGORY_MANDATORY) - item_append(i, &p->mandatory_items); - else if (policy_category == POLICY_CATEGORY_ON_CONSOLE) - item_append(i, &p->on_console_items); - else if (policy_category == POLICY_CATEGORY_NO_CONSOLE) - item_append(i, &p->no_console_items); - else if (policy_category == POLICY_CATEGORY_USER) { - const char *u = policy_user; - - assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->user_items, NULL); - if (r < 0) - return log_oom(); - - if (!u) { - log_error("User policy without name"); - return -EINVAL; - } - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->user_items, UID_TO_PTR(i->uid)); - item_append(i, &first); - i->uid_valid = true; - - r = hashmap_replace(p->user_items, UID_TO_PTR(i->uid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - - } else if (policy_category == POLICY_CATEGORY_GROUP) { - const char *g = policy_group; - - assert_cc(sizeof(gid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->group_items, NULL); - if (r < 0) - return log_oom(); - - if (!g) { - log_error("Group policy without name"); - return -EINVAL; - } - - r = get_group_creds(&g, &i->gid); - if (r < 0) { - log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->group_items, GID_TO_PTR(i->gid)); - item_append(i, &first); - i->gid_valid = true; - - r = hashmap_replace(p->group_items, GID_TO_PTR(i->gid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - } - - state = STATE_POLICY; - i = NULL; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (8) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_INTERFACE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->interface) { - log_error("Duplicate interface at %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->interface = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (9) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MEMBER: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->member) { - log_error("Duplicate member in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->member = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (10) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_ERROR: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->error) { - log_error("Duplicate error in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->error = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (11) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_PATH: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->path) { - log_error("Duplicate path in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->path = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (12) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MESSAGE_TYPE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - - if (i->message_type != 0) { - log_error("Duplicate message type in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - r = bus_message_type_from_string(name, &i->message_type); - if (r < 0) { - log_error("Invalid message type in %s:%u.", path, line); - return -EINVAL; - } - } - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (13) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_NAME: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->name) { - log_error("Duplicate name in %s:%u.", path, line); - return -EINVAL; - } - - switch (i->class) { - case POLICY_ITEM_USER: - if (!streq(name, "*")) { - const char *u = name; - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) - log_error_errno(r, "Failed to resolve user %s: %m", name); - else - i->uid_valid = true; - } - break; - case POLICY_ITEM_GROUP: - if (!streq(name, "*")) { - const char *g = name; - - r = get_group_creds(&g, &i->gid); - if (r < 0) - log_error_errno(r, "Failed to resolve group %s: %m", name); - else - i->gid_valid = true; - } - break; - - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (streq(name, "*")) - name = mfree(name); - break; - - - default: - break; - } - - i->name = name; - name = NULL; - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (14) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_ALLOW_DENY; - else { - log_error("Unexpected token (15) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_OTHER: - - if (t == XML_TAG_OPEN) - n_other++; - else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) { - - if (n_other == 0) - state = STATE_BUSCONFIG; - else - n_other--; - } - - break; - } - } -} - -enum { - DENY, - ALLOW, - DUNNO, -}; - -static const char *verdict_to_string(int v) { - switch (v) { - - case DENY: - return "DENY"; - case ALLOW: - return "ALLOW"; - case DUNNO: - return "DUNNO"; - } - - return NULL; -} - -struct policy_check_filter { - PolicyItemClass class; - uid_t uid; - gid_t gid; - int message_type; - const char *name; - const char *interface; - const char *path; - const char *member; -}; - -static int is_permissive(PolicyItem *i) { - - assert(i); - - return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; -} - -static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) { - - assert(i); - assert(filter); - - switch (i->class) { - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (i->name && !streq_ptr(i->name, filter->name)) - break; - - if ((i->message_type != 0) && (i->message_type != filter->message_type)) - break; - - if (i->path && !streq_ptr(i->path, filter->path)) - break; - - if (i->member && !streq_ptr(i->member, filter->member)) - break; - - if (i->interface && !streq_ptr(i->interface, filter->interface)) - break; - - return is_permissive(i); - - case POLICY_ITEM_OWN: - assert(filter->name); - - if (streq(i->name, "*") || streq(i->name, filter->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_OWN_PREFIX: - assert(filter->name); - - if (streq(i->name, "*") || service_name_startswith(filter->name, i->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_USER: - if (filter->uid != UID_INVALID) - if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid))) - return is_permissive(i); - break; - - case POLICY_ITEM_GROUP: - if (filter->gid != GID_INVALID) - if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid))) - return is_permissive(i); - break; - - case POLICY_ITEM_IGNORE: - default: - break; - } - - return DUNNO; -} - -static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) { - - PolicyItem *i; - int verdict = DUNNO; - - assert(filter); - - /* Check all policies in a set - a broader one might be followed by a more specific one, - * and the order of rules in policy definitions matters */ - LIST_FOREACH(items, i, items) { - int v; - - if (i->class != filter->class && - !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN)) - continue; - - v = check_policy_item(i, filter); - if (v != DUNNO) - verdict = v; - } - - return verdict; -} - -static int policy_check(Policy *p, const struct policy_check_filter *filter) { - - PolicyItem *items; - int verdict, v; - - assert(p); - assert(filter); - - assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP)); - - /* - * The policy check is implemented by the following logic: - * - * 1. Check default items - * 2. Check group items - * 3. Check user items - * 4. Check on/no_console items - * 5. Check mandatory items - * - * Later rules override earlier rules. - */ - - verdict = check_policy_items(p->default_items, filter); - - if (filter->gid != GID_INVALID) { - items = hashmap_get(p->group_items, GID_TO_PTR(filter->gid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID) { - items = hashmap_get(p->user_items, UID_TO_PTR(filter->uid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0) - v = check_policy_items(p->on_console_items, filter); - else - v = check_policy_items(p->no_console_items, filter); - if (v != DUNNO) - verdict = v; - - v = check_policy_items(p->mandatory_items, filter); - if (v != DUNNO) - verdict = v; - - return verdict; -} - -bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_OWN, - .uid = uid, - .gid = gid, - .name = name, - }; - - int verdict; - - assert(p); - assert(name); - - verdict = policy_check(p, &filter); - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s", - uid, gid, strna(name), strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) { - - struct policy_check_filter filter = { - .uid = uid, - .gid = gid, - }; - int verdict; - - assert(p); - - filter.class = POLICY_ITEM_USER; - verdict = policy_check(p, &filter); - - if (verdict != DENY) { - int v; - - filter.class = POLICY_ITEM_GROUP; - v = policy_check(p, &filter); - if (v != DUNNO) - verdict = v; - } - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s", - uid, gid, strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -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) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_RECV, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -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) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -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) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_SEND, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -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) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - if (out_used_name) - *out_used_name = last; - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -int policy_load(Policy *p, char **files) { - char **i; - int r; - - assert(p); - - STRV_FOREACH(i, files) { - - r = file_load(p, *i); - if (r == -EISDIR) { - _cleanup_strv_free_ char **l = NULL; - char **j; - - r = conf_files_list(&l, ".conf", NULL, *i, NULL); - if (r < 0) - return log_error_errno(r, "Failed to get configuration file list: %m"); - - STRV_FOREACH(j, l) - file_load(p, *j); - } - - /* We ignore all errors but EISDIR, and just proceed. */ - } - - return 0; -} - -void policy_free(Policy *p) { - PolicyItem *i, *first; - - if (!p) - return; - - while ((i = p->default_items)) { - LIST_REMOVE(items, p->default_items, i); - policy_item_free(i); - } - - while ((i = p->mandatory_items)) { - LIST_REMOVE(items, p->mandatory_items, i); - policy_item_free(i); - } - - while ((i = p->on_console_items)) { - LIST_REMOVE(items, p->on_console_items, i); - policy_item_free(i); - } - - while ((i = p->no_console_items)) { - LIST_REMOVE(items, p->no_console_items, i); - policy_item_free(i); - } - - while ((first = hashmap_steal_first(p->user_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - while ((first = hashmap_steal_first(p->group_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - hashmap_free(p->user_items); - hashmap_free(p->group_items); - - p->user_items = p->group_items = NULL; -} - -static void dump_items(PolicyItem *items, const char *prefix) { - - PolicyItem *i; - - if (!items) - return; - - if (!prefix) - prefix = ""; - - LIST_FOREACH(items, i, items) { - - printf("%sType: %s\n" - "%sClass: %s\n", - prefix, policy_item_type_to_string(i->type), - prefix, policy_item_class_to_string(i->class)); - - if (i->interface) - printf("%sInterface: %s\n", - prefix, i->interface); - - if (i->member) - printf("%sMember: %s\n", - prefix, i->member); - - if (i->error) - printf("%sError: %s\n", - prefix, i->error); - - if (i->path) - printf("%sPath: %s\n", - prefix, i->path); - - if (i->name) - printf("%sName: %s\n", - prefix, i->name); - - if (i->message_type != 0) - printf("%sMessage Type: %s\n", - prefix, bus_message_type_to_string(i->message_type)); - - if (i->uid_valid) { - _cleanup_free_ char *user; - - user = uid_to_name(i->uid); - - printf("%sUser: %s ("UID_FMT")\n", - prefix, strna(user), i->uid); - } - - if (i->gid_valid) { - _cleanup_free_ char *group; - - group = gid_to_name(i->gid); - - printf("%sGroup: %s ("GID_FMT")\n", - prefix, strna(group), i->gid); - } - printf("%s-\n", prefix); - } -} - -static void dump_hashmap_items(Hashmap *h) { - PolicyItem *i; - Iterator j; - void *k; - - HASHMAP_FOREACH_KEY(i, k, h, j) { - printf("\t%s Item for " UID_FMT ":\n", draw_special_char(DRAW_ARROW), PTR_TO_UID(k)); - dump_items(i, "\t\t"); - } -} - -void policy_dump(Policy *p) { - - printf("%s Default Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->default_items, "\t"); - - printf("%s Group Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->group_items); - - printf("%s User Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->user_items); - - printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->on_console_items, "\t"); - - printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->no_console_items, "\t"); - - printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->mandatory_items, "\t"); - - fflush(stdout); -} - -int shared_policy_new(SharedPolicy **out) { - SharedPolicy *sp; - int r; - - sp = new0(SharedPolicy, 1); - if (!sp) - return log_oom(); - - r = pthread_mutex_init(&sp->lock, NULL); - if (r != 0) { - r = log_error_errno(r, "Cannot initialize shared policy mutex: %m"); - goto exit_free; - } - - r = pthread_rwlock_init(&sp->rwlock, NULL); - if (r != 0) { - r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); - goto exit_mutex; - } - - *out = sp; - sp = NULL; - return 0; - - /* pthread lock destruction is not fail-safe... meh! */ -exit_mutex: - pthread_mutex_destroy(&sp->lock); -exit_free: - free(sp); - return r; -} - -SharedPolicy *shared_policy_free(SharedPolicy *sp) { - if (!sp) - return NULL; - - policy_free(sp->policy); - pthread_rwlock_destroy(&sp->rwlock); - pthread_mutex_destroy(&sp->lock); - strv_free(sp->configuration); - free(sp); - - return NULL; -} - -static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) { - Policy old, buffer = {}; - bool free_old; - int r; - - assert(sp); - - r = policy_load(&buffer, configuration); - if (r < 0) - return log_error_errno(r, "Failed to load policy: %m"); - - log_debug("Reloading configuration"); - /* policy_dump(&buffer); */ - - pthread_rwlock_wrlock(&sp->rwlock); - memcpy(&old, &sp->buffer, sizeof(old)); - memcpy(&sp->buffer, &buffer, sizeof(buffer)); - free_old = !!sp->policy; - sp->policy = &sp->buffer; - pthread_rwlock_unlock(&sp->rwlock); - - if (free_old) - policy_free(&old); - - return 0; -} - -int shared_policy_reload(SharedPolicy *sp) { - int r; - - assert(sp); - - pthread_mutex_lock(&sp->lock); - r = shared_policy_reload_unlocked(sp, sp->configuration); - pthread_mutex_unlock(&sp->lock); - - return r; -} - -int shared_policy_preload(SharedPolicy *sp, char **configuration) { - _cleanup_strv_free_ char **conf = NULL; - int r = 0; - - assert(sp); - - conf = strv_copy(configuration); - if (!conf) - return log_oom(); - - pthread_mutex_lock(&sp->lock); - if (!sp->policy) { - r = shared_policy_reload_unlocked(sp, conf); - if (r >= 0) { - sp->configuration = conf; - conf = NULL; - } - } - pthread_mutex_unlock(&sp->lock); - - return r; -} - -Policy *shared_policy_acquire(SharedPolicy *sp) { - assert(sp); - - pthread_rwlock_rdlock(&sp->rwlock); - if (sp->policy) - return sp->policy; - pthread_rwlock_unlock(&sp->rwlock); - - return NULL; -} - -void shared_policy_release(SharedPolicy *sp, Policy *p) { - assert(sp); - assert(!p || sp->policy == p); - - if (p) - pthread_rwlock_unlock(&sp->rwlock); -} - -static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = { - [_POLICY_ITEM_TYPE_UNSET] = "unset", - [POLICY_ITEM_ALLOW] = "allow", - [POLICY_ITEM_DENY] = "deny", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType); - -static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = { - [_POLICY_ITEM_CLASS_UNSET] = "unset", - [POLICY_ITEM_SEND] = "send", - [POLICY_ITEM_RECV] = "recv", - [POLICY_ITEM_OWN] = "own", - [POLICY_ITEM_OWN_PREFIX] = "own-prefix", - [POLICY_ITEM_USER] = "user", - [POLICY_ITEM_GROUP] = "group", - [POLICY_ITEM_IGNORE] = "ignore", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass); diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h deleted file mode 100644 index 3dcddaa048..0000000000 --- a/src/bus-proxyd/bus-xml-policy.h +++ /dev/null @@ -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); diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c deleted file mode 100644 index 1af5c310ea..0000000000 --- a/src/bus-proxyd/driver.c +++ /dev/null @@ -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); - } -} diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h deleted file mode 100644 index 1630cdc7b9..0000000000 --- a/src/bus-proxyd/driver.h +++ /dev/null @@ -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); diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c deleted file mode 100644 index 907d93d4c7..0000000000 --- a/src/bus-proxyd/proxy.c +++ /dev/null @@ -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; -} diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h deleted file mode 100644 index d9e75cf73b..0000000000 --- a/src/bus-proxyd/proxy.h +++ /dev/null @@ -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); diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c deleted file mode 100644 index 291c1b09e3..0000000000 --- a/src/bus-proxyd/stdio-bridge.c +++ /dev/null @@ -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; -} diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c deleted file mode 100644 index 8eea7dc5b9..0000000000 --- a/src/bus-proxyd/synthesize.c +++ /dev/null @@ -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); -} diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h deleted file mode 100644 index 1b7197f8ec..0000000000 --- a/src/bus-proxyd/synthesize.h +++ /dev/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); diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c deleted file mode 100644 index af7c9128a2..0000000000 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ /dev/null @@ -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; -} diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index cad1a52c09..5fd59f7dd3 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -958,7 +958,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) { client->timeout_resend = sd_event_source_unref(client->timeout_resend); if (client->start_delay) { - sd_event_now(client->event, clock_boottime_or_monotonic(), &usec); + assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0); usec += client->start_delay; } diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c deleted file mode 100644 index 45d0a5ffce..0000000000 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ /dev/null @@ -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; -} diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c new file mode 100644 index 0000000000..91eace90e2 --- /dev/null +++ b/src/stdio-bridge/stdio-bridge.c @@ -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; +} diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 2b2f76cc7f..ef451c6abf 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -70,6 +70,18 @@ static const char* const input_table_none[] = { NULL, }; +static const char* const input_table_two_empties[] = { + "", + "", + NULL, +}; + +static const char* const input_table_one_empty[] = { + "", + NULL, +}; + + static const char* const input_table_quotes[] = { "\"", "'", @@ -130,7 +142,7 @@ static void test_strv_find_startswith(void) { } static void test_strv_join(void) { - _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL; + _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; p = strv_join((char **)input_table_multiple, ", "); assert_se(p); @@ -151,6 +163,14 @@ static void test_strv_join(void) { t = strv_join((char **)input_table_none, ", "); assert_se(t); assert_se(streq(t, "")); + + v = strv_join((char **)input_table_two_empties, ", "); + assert_se(v); + assert_se(streq(v, ", ")); + + w = strv_join((char **)input_table_one_empty, ", "); + assert_se(w); + assert_se(streq(w, "")); } static void test_strv_quote_unquote(const char* const *split, const char *quoted) { @@ -653,6 +673,8 @@ int main(int argc, char *argv[]) { test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\""); test_strv_quote_unquote(input_table_one, "\"one\""); test_strv_quote_unquote(input_table_none, ""); + test_strv_quote_unquote(input_table_one_empty, "\"\""); + test_strv_quote_unquote(input_table_two_empties, "\"\" \"\""); test_strv_quote_unquote(input_table_quotes, QUOTES_STRING); test_strv_quote_unquote(input_table_spaces, SPACES_STRING); diff --git a/src/test/test-tables.c b/src/test/test-tables.c index aef992ee3c..0be74921fc 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -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); diff --git a/sysusers.d/systemd.conf.m4 b/sysusers.d/systemd.conf.m4 index 317240a9fd..af97509c05 100644 --- a/sysusers.d/systemd.conf.m4 +++ b/sysusers.d/systemd.conf.m4 @@ -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 diff --git a/units/.gitignore b/units/.gitignore index 2fff20a052..e62fd01466 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -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 diff --git a/units/systemd-bus-proxyd.service.m4.in b/units/systemd-bus-proxyd.service.m4.in deleted file mode 100644 index e75cdb1a59..0000000000 --- a/units/systemd-bus-proxyd.service.m4.in +++ /dev/null @@ -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 diff --git a/units/systemd-bus-proxyd.socket b/units/systemd-bus-proxyd.socket deleted file mode 100644 index 3f80a1d547..0000000000 --- a/units/systemd-bus-proxyd.socket +++ /dev/null @@ -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 diff --git a/units/user/.gitignore b/units/user/.gitignore index ce9df9e7e1..41a74f5461 100644 --- a/units/user/.gitignore +++ b/units/user/.gitignore @@ -1,2 +1 @@ /systemd-exit.service -/systemd-bus-proxyd.service diff --git a/units/user/systemd-bus-proxyd.service.in b/units/user/systemd-bus-proxyd.service.in deleted file mode 100644 index 6f79707b46..0000000000 --- a/units/user/systemd-bus-proxyd.service.in +++ /dev/null @@ -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 diff --git a/units/user/systemd-bus-proxyd.socket b/units/user/systemd-bus-proxyd.socket deleted file mode 100644 index b9efc0e7ce..0000000000 --- a/units/user/systemd-bus-proxyd.socket +++ /dev/null @@ -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 |