mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
bus-proxy: turn into multi-threaded daemon
Instead of using Accept=true and running one proxy for each connection, we now run one proxy-daemon with a thread per connection. This will enable us to share resources like policies in the future.
This commit is contained in:
parent
f4a53250ac
commit
a8a1a43f48
14
Makefile.am
14
Makefile.am
@ -2699,6 +2699,10 @@ libsystemd_proxy_la_LIBADD = \
|
||||
systemd_bus_proxyd_SOURCES = \
|
||||
src/bus-proxyd/bus-proxyd.c
|
||||
|
||||
systemd_bus_proxyd_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
-pthread
|
||||
|
||||
systemd_bus_proxyd_LDADD = \
|
||||
libsystemd-proxy.la \
|
||||
libsystemd-internal.la \
|
||||
@ -2714,24 +2718,24 @@ systemd_stdio_bridge_LDADD = \
|
||||
|
||||
if ENABLE_KDBUS
|
||||
nodist_systemunit_DATA += \
|
||||
units/systemd-bus-proxyd@.service
|
||||
units/systemd-bus-proxyd.service
|
||||
|
||||
dist_systemunit_DATA += \
|
||||
units/systemd-bus-proxyd.socket
|
||||
|
||||
nodist_userunit_DATA += \
|
||||
units/user/systemd-bus-proxyd@.service
|
||||
units/user/systemd-bus-proxyd.service
|
||||
|
||||
dist_userunit_DATA += \
|
||||
units/user/systemd-bus-proxyd.socket
|
||||
endif
|
||||
|
||||
EXTRA_DIST += \
|
||||
units/systemd-bus-proxyd@.service.m4.in \
|
||||
units/user/systemd-bus-proxyd@.service.in
|
||||
units/systemd-bus-proxyd.service.m4.in \
|
||||
units/user/systemd-bus-proxyd.service.in
|
||||
|
||||
CLEANFILES += \
|
||||
units/systemd-bus-proxyd@.service.m4
|
||||
units/systemd-bus-proxyd.service.m4
|
||||
|
||||
if HAVE_SMACK
|
||||
bus-proxyd-set-cap-hook:
|
||||
|
@ -6,6 +6,7 @@
|
||||
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
|
||||
@ -31,9 +32,11 @@
|
||||
#include <sys/poll.h>
|
||||
#include <stddef.h>
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "hashmap.h"
|
||||
#include "socket-util.h"
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-bus.h"
|
||||
@ -53,17 +56,118 @@
|
||||
#include "synthesize.h"
|
||||
|
||||
static char *arg_address = NULL;
|
||||
static char *arg_command_line_buffer = NULL;
|
||||
static bool arg_drop_privileges = false;
|
||||
static char **arg_configuration = NULL;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
} ClientContext;
|
||||
|
||||
static ClientContext *client_context_free(ClientContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
close(c->fd);
|
||||
free(c);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
|
||||
|
||||
static int client_context_new(ClientContext **out, int fd) {
|
||||
_cleanup_(client_context_freep) ClientContext *c = NULL;
|
||||
|
||||
c = new0(ClientContext, 1);
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
c->fd = fd;
|
||||
|
||||
*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;
|
||||
int r;
|
||||
|
||||
r = proxy_new(&p, c->fd, c->fd, arg_address);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = proxy_load_policy(p, arg_configuration);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = proxy_hello_policy(p, getuid());
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = proxy_run(p);
|
||||
|
||||
exit:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int loop_clients(int accept_fd) {
|
||||
pthread_attr_t attr;
|
||||
int r;
|
||||
|
||||
r = pthread_attr_init(&attr);
|
||||
if (r < 0) {
|
||||
r = log_error_errno(errno, "Cannot initialize pthread attributes: %m");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (r < 0) {
|
||||
r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
|
||||
goto exit_attr;
|
||||
}
|
||||
|
||||
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");
|
||||
break;
|
||||
}
|
||||
|
||||
r = client_context_new(&c, fd);
|
||||
if (r < 0) {
|
||||
log_oom();
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = pthread_create(&tid, &attr, run_client, c);
|
||||
if (r < 0) {
|
||||
log_error("Cannot spawn thread: %m");
|
||||
client_context_free(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
exit_attr:
|
||||
pthread_attr_destroy(&attr);
|
||||
exit:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"Connect STDIO or a socket to a given bus address.\n\n"
|
||||
"DBus proxy server.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --drop-privileges Drop privileges\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"
|
||||
@ -78,7 +182,6 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_ADDRESS,
|
||||
ARG_DROP_PRIVILEGES,
|
||||
ARG_CONFIGURATION,
|
||||
ARG_MACHINE,
|
||||
};
|
||||
@ -87,7 +190,6 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "address", required_argument, NULL, ARG_ADDRESS },
|
||||
{ "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
|
||||
{ "configuration", required_argument, NULL, ARG_CONFIGURATION },
|
||||
{ "machine", required_argument, NULL, ARG_MACHINE },
|
||||
{},
|
||||
@ -123,10 +225,6 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_DROP_PRIVILEGES:
|
||||
arg_drop_privileges = true;
|
||||
break;
|
||||
|
||||
case ARG_CONFIGURATION:
|
||||
r = strv_extend(&arg_configuration, optarg);
|
||||
if (r < 0)
|
||||
@ -162,11 +260,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
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"))) {
|
||||
if (argc > optind) {
|
||||
log_error("Too many arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -180,78 +274,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rename_service(sd_bus *a, sd_bus *b) {
|
||||
_cleanup_bus_creds_unref_ 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_UID|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_uid(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, in_fd, out_fd;
|
||||
uid_t original_uid;
|
||||
int r, accept_fd;
|
||||
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
|
||||
log_parse_environment();
|
||||
@ -262,52 +286,19 @@ int main(int argc, char *argv[]) {
|
||||
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 {
|
||||
if (r != 1) {
|
||||
log_error("Illegal number of file descriptors passed");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
original_uid = getuid();
|
||||
|
||||
if (arg_drop_privileges) {
|
||||
const char *user = "systemd-bus-proxy";
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
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)
|
||||
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 = proxy_new(&p, in_fd, out_fd, arg_address);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = proxy_load_policy(p, arg_configuration);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = proxy_hello_policy(p, original_uid);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = rename_service(p->dest_bus, p->local_bus);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to rename process: %m");
|
||||
|
||||
r = proxy_run(p);
|
||||
r = loop_clients(accept_fd);
|
||||
|
||||
finish:
|
||||
sd_notify(false,
|
||||
|
4
units/.gitignore
vendored
4
units/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
/systemd-bus-proxyd@.service.m4
|
||||
/systemd-bus-proxyd.service.m4
|
||||
/user@.service.m4
|
||||
/console-getty.service
|
||||
/console-getty.service.m4
|
||||
@ -24,7 +24,7 @@
|
||||
/systemd-backlight@.service
|
||||
/systemd-binfmt.service
|
||||
/systemd-bootchart.service
|
||||
/systemd-bus-proxyd@.service
|
||||
/systemd-bus-proxyd.service
|
||||
/systemd-firstboot.service
|
||||
/systemd-fsck-root.service
|
||||
/systemd-fsck@.service
|
||||
|
@ -9,8 +9,11 @@
|
||||
Description=Legacy D-Bus Protocol Compatibility Daemon
|
||||
|
||||
[Service]
|
||||
# The first argument will be replaced by the service by information on
|
||||
# the process requesting the proxy, we need a placeholder to keep the
|
||||
# space available for this.
|
||||
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus
|
||||
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
|
@ -10,4 +10,3 @@ Description=Legacy D-Bus Protocol Compatibility Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=/var/run/dbus/system_bus_socket
|
||||
Accept=yes
|
||||
|
@ -1,22 +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]
|
||||
# The first argument will be replaced by the service by information on
|
||||
# the process requesting the proxy, we need a placeholder to keep the
|
||||
# space available for this.
|
||||
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --drop-privileges --address=kernel:path=/sys/fs/kdbus/0-system/bus xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
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
|
2
units/user/.gitignore
vendored
2
units/user/.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
/systemd-exit.service
|
||||
/systemd-bus-proxyd@.service
|
||||
/systemd-bus-proxyd.service
|
||||
/systemd-consoled.service
|
||||
|
13
units/user/systemd-bus-proxyd.service.in
Normal file
13
units/user/systemd-bus-proxyd.service.in
Normal file
@ -0,0 +1,13 @@
|
||||
# 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
|
||||
NotifyAccess=main
|
@ -10,4 +10,3 @@ Description=Legacy D-Bus Protocol Compatibility Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/bus
|
||||
Accept=yes
|
||||
|
Loading…
Reference in New Issue
Block a user