mirror of
https://github.com/systemd/systemd.git
synced 2025-01-03 05:18:09 +03:00
ssh-generator: add simple new generator
This commit is contained in:
parent
045f7b8fe4
commit
0e3220684c
@ -138,6 +138,18 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>systemd.ssh_auto=</varname></term>
|
||||||
|
<term><varname>systemd.ssh_listen=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>These parameters are interpreted by
|
||||||
|
<citerefentry><refentrytitle>systemd-ssh-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
|
and may be used to control SSH sockets the system shall be reachable on.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>systemd.volatile=</varname></term>
|
<term><varname>systemd.volatile=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -1054,6 +1054,7 @@ manpages = [
|
|||||||
['systemd-socket-activate', '1', [], ''],
|
['systemd-socket-activate', '1', [], ''],
|
||||||
['systemd-socket-proxyd', '8', [], ''],
|
['systemd-socket-proxyd', '8', [], ''],
|
||||||
['systemd-soft-reboot.service', '8', [], ''],
|
['systemd-soft-reboot.service', '8', [], ''],
|
||||||
|
['systemd-ssh-generator', '8', [], ''],
|
||||||
['systemd-stdio-bridge', '1', [], ''],
|
['systemd-stdio-bridge', '1', [], ''],
|
||||||
['systemd-storagetm.service', '8', ['systemd-storagetm'], 'ENABLE_STORAGETM'],
|
['systemd-storagetm.service', '8', ['systemd-storagetm'], 'ENABLE_STORAGETM'],
|
||||||
['systemd-stub',
|
['systemd-stub',
|
||||||
|
141
man/systemd-ssh-generator.xml
Normal file
141
man/systemd-ssh-generator.xml
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--*-nxml-*-->
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||||
|
<!ENTITY % entities SYSTEM "custom-entities.ent" >
|
||||||
|
%entities;
|
||||||
|
]>
|
||||||
|
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||||
|
<refentry id="systemd-ssh-generator"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<refentryinfo>
|
||||||
|
<title>systemd-ssh-generator</title>
|
||||||
|
<productname>systemd</productname>
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>systemd-ssh-generator</refentrytitle>
|
||||||
|
<manvolnum>8</manvolnum>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>systemd-ssh-generator</refname>
|
||||||
|
<refpurpose>Generator for binding a socket-activated SSH server to local <constant>AV_VSOCK</constant>
|
||||||
|
and <constant>AF_UNIX</constant> sockets</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<para><filename>/usr/lib/systemd/system-generators/systemd-ssh-generator</filename></para>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
|
||||||
|
<para><command>systemd-ssh-generator</command> binds a socket-activated SSH server to local
|
||||||
|
<constant>AV_VSOCK</constant> and <constant>AF_UNIX</constant> sockets under certain conditions. It only
|
||||||
|
has an effect if the <citerefentry
|
||||||
|
project="man-pages"><refentrytitle>sshd</refentrytitle><manvolnum>8</manvolnum></citerefentry> binary is
|
||||||
|
installed. Specifically, it does the following:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>If invoked in a VM with <constant>AF_VSOCK</constant> support, a socket-activated SSH
|
||||||
|
per-connection service is bound to <constant>AF_VSOCK</constant> port 22.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>If invoked in a container environment with a writable directory
|
||||||
|
<filename>/run/host/unix-export/</filename> pre-mounted it binds SSH to an <constant>AF_UNIX</constant>
|
||||||
|
socket <filename>/run/host/unix-export/ssh</filename>. The assumption is that this directory is bind
|
||||||
|
mounted to the host side as well, and can be used to connect to the container from there. See <ulink
|
||||||
|
url="https://systemd.io/CONTAINER_INTERFACE">Container Interface</ulink> for more information about
|
||||||
|
this interface.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>A local <constant>AF_UNIX</constant> socket
|
||||||
|
<filename>/run/ssh-unix-local/socket</filename> is also bound, unconditionally. This may be used for
|
||||||
|
SSH communication from the host to itself, without involving networking, for example to traverse
|
||||||
|
security boundaries safely and with secure authentication.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>Additional <constant>AF_UNIX</constant> and <constant>AF_VSOCK</constant> sockets are
|
||||||
|
optionally bound, based on the <varname>systemd.ssh_listen=</varname> kernel command line option or the
|
||||||
|
<filename>ssh.listen</filename> system credential (see below).</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>See
|
||||||
|
<citerefentry><refentrytitle>systemd-ssh-proxy</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||||
|
details on how to connect to these sockets via the <command>ssh</command> client.</para>
|
||||||
|
|
||||||
|
<para>The generator will use a packaged <filename>sshd@.service</filename> service template file if one
|
||||||
|
exists, and otherwise generate a suitable service template file.</para>
|
||||||
|
|
||||||
|
<para><filename>systemd-ssh-generator</filename> implements
|
||||||
|
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Kernel Command Line</title>
|
||||||
|
|
||||||
|
<para><filename>systemd-ssh-generator</filename> understands the following
|
||||||
|
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
|
parameters:</para>
|
||||||
|
|
||||||
|
<variablelist class='kernel-commandline-options'>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>systemd.ssh_auto=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>This option takes an optional boolean argument, and defaults to yes. If enabled, the
|
||||||
|
automatic binding to the <constant>AF_VSOCK</constant> and <constant>AF_UNIX</constant> sockets
|
||||||
|
listed above is done. If disable, this is not done, except for those explicitly requested via
|
||||||
|
<varname>systemd.ssh_listen=</varname> on the kernel command line or via the
|
||||||
|
<varname>ssh.listen</varname> system credential.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>systemd.ssh_listen=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>This option configures an additional socket to bind SSH to. It may be used multiple
|
||||||
|
times to bind multiple sockets. The syntax should follow the one of <varname>ListenStream=</varname>,
|
||||||
|
see
|
||||||
|
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for details. This functionality supports all socket families systemd supports, including
|
||||||
|
<constant>AF_INET</constant> and <constant>AF_INET6</constant>.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Credentials</title>
|
||||||
|
|
||||||
|
<para><command>systemd-ssh-generator</command> supports the system credentials logic. The following
|
||||||
|
credentials are used when passed in:</para>
|
||||||
|
|
||||||
|
<variablelist class='system-credentials'>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>ssh.listen</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>This credential should be a text file, with each line referencing one additional
|
||||||
|
socket to bind SSH to. The syntax should follow the one of <varname>ListenStream=</varname>, see
|
||||||
|
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for details. This functionality supports all socket families systemd supports, including
|
||||||
|
<constant>AF_INET</constant> and <constant>AF_INET6</constant>.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>See Also</title>
|
||||||
|
<para><simplelist type="inline">
|
||||||
|
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project="man-pages"><refentrytitle>vsock</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project="man-pages"><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project="man-pages"><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry project="man-pages"><refentrytitle>sshd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
|
</simplelist></para>
|
||||||
|
</refsect1>
|
||||||
|
</refentry>
|
@ -217,6 +217,17 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>ssh.listen</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>May be used to configure SSH sockets the system shall be reachable on. See
|
||||||
|
<citerefentry><refentrytitle>systemd-ssh-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
|
for details.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>sysusers.extra</varname></term>
|
<term><varname>sysusers.extra</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -2206,6 +2206,7 @@ subdir('src/shutdown')
|
|||||||
subdir('src/sleep')
|
subdir('src/sleep')
|
||||||
subdir('src/socket-activate')
|
subdir('src/socket-activate')
|
||||||
subdir('src/socket-proxy')
|
subdir('src/socket-proxy')
|
||||||
|
subdir('src/ssh-generator')
|
||||||
subdir('src/stdio-bridge')
|
subdir('src/stdio-bridge')
|
||||||
subdir('src/sulogin-shell')
|
subdir('src/sulogin-shell')
|
||||||
subdir('src/sysctl')
|
subdir('src/sysctl')
|
||||||
|
8
src/ssh-generator/meson.build
Normal file
8
src/ssh-generator/meson.build
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
executables += [
|
||||||
|
generator_template + {
|
||||||
|
'name' : 'systemd-ssh-generator',
|
||||||
|
'sources' : files('ssh-generator.c'),
|
||||||
|
},
|
||||||
|
]
|
476
src/ssh-generator/ssh-generator.c
Normal file
476
src/ssh-generator/ssh-generator.c
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "creds-util.h"
|
||||||
|
#include "fd-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
|
#include "generator.h"
|
||||||
|
#include "install.h"
|
||||||
|
#include "missing_socket.h"
|
||||||
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
#include "proc-cmdline.h"
|
||||||
|
#include "socket-netlink.h"
|
||||||
|
#include "socket-util.h"
|
||||||
|
#include "special.h"
|
||||||
|
#include "virt.h"
|
||||||
|
|
||||||
|
/* A small generator binding potentially five or more SSH sockets:
|
||||||
|
*
|
||||||
|
* 1. Listen on AF_VSOCK port 22 if we run in a VM with AF_VSOCK enabled
|
||||||
|
* 2. Listen on AF_UNIX socket /run/host/unix-export/ssh if we run in a container with /run/host/ support
|
||||||
|
* 3. Listen on AF_UNIX socket /run/ssh-unix-local/socket (always)
|
||||||
|
* 4. Listen on any socket specified via kernel command line option systemd.ssh_listen=
|
||||||
|
* 5. Similar, but from system credential ssh.listen
|
||||||
|
*
|
||||||
|
* The first two provide a nice way for hosts to connect to containers and VMs they invoke via the usual SSH
|
||||||
|
* logic, but without waiting for networking or suchlike. The third allows the same for local clients. */
|
||||||
|
|
||||||
|
static const char *arg_dest = NULL;
|
||||||
|
static bool arg_auto = true;
|
||||||
|
static char **arg_listen_extra = NULL;
|
||||||
|
|
||||||
|
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(key);
|
||||||
|
|
||||||
|
if (proc_cmdline_key_streq(key, "systemd.ssh_auto")) {
|
||||||
|
r = value ? parse_boolean(value) : 1;
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to parse systemd.ssh_auto switch \"%s\", ignoring: %m", value);
|
||||||
|
else
|
||||||
|
arg_auto = r;
|
||||||
|
|
||||||
|
} else if (proc_cmdline_key_streq(key, "systemd.ssh_listen")) {
|
||||||
|
|
||||||
|
if (proc_cmdline_value_missing(key, value))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SocketAddress sa;
|
||||||
|
r = socket_address_parse(&sa, value);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to parse systemd.ssh_listen= expression, ignoring: %s", value);
|
||||||
|
else {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
r = socket_address_print(&sa, &s);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to format socket address: %m");
|
||||||
|
|
||||||
|
if (strv_consume(&arg_listen_extra, TAKE_PTR(s)) < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_sshd_template_unit(
|
||||||
|
const char *dest,
|
||||||
|
const char *template,
|
||||||
|
const char *sshd_binary,
|
||||||
|
const char *found_sshd_template_service,
|
||||||
|
char **generated_sshd_template_unit) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(template);
|
||||||
|
assert(sshd_binary);
|
||||||
|
assert(generated_sshd_template_unit);
|
||||||
|
|
||||||
|
/* If the system has a suitable template already, symlink it to the name we want to reuse it */
|
||||||
|
if (found_sshd_template_service)
|
||||||
|
return generator_add_symlink(
|
||||||
|
dest,
|
||||||
|
template,
|
||||||
|
/* dep_type= */ NULL,
|
||||||
|
found_sshd_template_service);
|
||||||
|
|
||||||
|
if (!*generated_sshd_template_unit) {
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
|
||||||
|
r = generator_open_unit_file_full(
|
||||||
|
dest,
|
||||||
|
/* source= */ NULL,
|
||||||
|
"sshd-generated@.service", /* Give this generated unit a generic name, since we want to use it for both AF_UNIX and AF_VSOCK */
|
||||||
|
&f,
|
||||||
|
generated_sshd_template_unit,
|
||||||
|
/* ret_temp_path= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
fprintf(f,
|
||||||
|
"[Unit]\n"
|
||||||
|
"Description=OpenSSH Per-Connection Server Daemon\n"
|
||||||
|
"Documentation=man:systemd-ssh-generator(8) man:sshd(8)\n"
|
||||||
|
"[Service]\n"
|
||||||
|
"ExecStart=-%s -i\n"
|
||||||
|
"StandardInput=socket",
|
||||||
|
sshd_binary);
|
||||||
|
|
||||||
|
r = fflush_and_check(f);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to write sshd template: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
return generator_add_symlink(
|
||||||
|
dest,
|
||||||
|
template,
|
||||||
|
/* dep_type= */ NULL,
|
||||||
|
*generated_sshd_template_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_socket_unit(
|
||||||
|
const char *dest,
|
||||||
|
const char *unit,
|
||||||
|
const char *listen_stream,
|
||||||
|
const char *comment) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(unit);
|
||||||
|
assert(listen_stream);
|
||||||
|
assert(comment);
|
||||||
|
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
r = generator_open_unit_file(
|
||||||
|
dest,
|
||||||
|
/* source= */ NULL,
|
||||||
|
unit,
|
||||||
|
&f);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
fprintf(f,
|
||||||
|
"[Unit]\n"
|
||||||
|
"Description=OpenSSH Server Socket (systemd-ssh-generator, %s)\n"
|
||||||
|
"Documentation=man:systemd-ssh-generator(8)\n"
|
||||||
|
"\n[Socket]\n"
|
||||||
|
"ListenStream=%s\n"
|
||||||
|
"Accept=yes\n"
|
||||||
|
"PollLimitIntervalSec=30s\n"
|
||||||
|
"PollLimitBurst=50\n",
|
||||||
|
comment,
|
||||||
|
listen_stream);
|
||||||
|
|
||||||
|
r = fflush_and_check(f);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to write %s SSH socket unit: %m", comment);
|
||||||
|
|
||||||
|
r = generator_add_symlink(
|
||||||
|
dest,
|
||||||
|
SPECIAL_SOCKETS_TARGET,
|
||||||
|
"wants",
|
||||||
|
unit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_vsock_socket(
|
||||||
|
const char *dest,
|
||||||
|
const char *sshd_binary,
|
||||||
|
const char *found_sshd_template_unit,
|
||||||
|
char **generated_sshd_template_unit) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(generated_sshd_template_unit);
|
||||||
|
|
||||||
|
Virtualization v = detect_vm();
|
||||||
|
if (v < 0)
|
||||||
|
return log_error_errno(v, "Failed to detect if we run in a VM: %m");
|
||||||
|
if (v == VIRTUALIZATION_NONE) {
|
||||||
|
log_debug("Not running in a VM, not listening on AF_VSOCK.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_close_ int vsock_fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||||
|
if (vsock_fd < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||||
|
log_debug("Not creating AF_VSOCK ssh listener, since AF_VSOCK is not available.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_error_errno(errno, "Unable to test if AF_VSOCK is available: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
vsock_fd = safe_close(vsock_fd);
|
||||||
|
|
||||||
|
/* Determine the local CID so that we can log it to help users to connect to this VM */
|
||||||
|
unsigned local_cid;
|
||||||
|
r = vsock_get_local_cid(&local_cid);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m");
|
||||||
|
|
||||||
|
r = make_sshd_template_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-vsock@.service",
|
||||||
|
sshd_binary,
|
||||||
|
found_sshd_template_unit,
|
||||||
|
generated_sshd_template_unit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = write_socket_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-vsock.socket",
|
||||||
|
"vsock::22",
|
||||||
|
"AF_VSOCK");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
log_info("Binding SSH to AF_VSOCK vsock::22.\n"
|
||||||
|
"→ connect via 'ssh vsock/%u' from host", local_cid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_local_unix_socket(
|
||||||
|
const char *dest,
|
||||||
|
const char *sshd_binary,
|
||||||
|
const char *found_sshd_template_unit,
|
||||||
|
char **generated_sshd_template_unit) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(sshd_binary);
|
||||||
|
assert(generated_sshd_template_unit);
|
||||||
|
|
||||||
|
r = make_sshd_template_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-unix-local@.service",
|
||||||
|
sshd_binary,
|
||||||
|
found_sshd_template_unit,
|
||||||
|
generated_sshd_template_unit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = write_socket_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-unix-local.socket",
|
||||||
|
"/run/ssh-unix-local/socket",
|
||||||
|
"AF_UNIX Local");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
|
||||||
|
log_info("Binding SSH to AF_UNIX socket /run/ssh-unix-local/socket.\n"
|
||||||
|
"→ connect via 'ssh .host' locally");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_export_unix_socket(
|
||||||
|
const char *dest,
|
||||||
|
const char *sshd_binary,
|
||||||
|
const char *found_sshd_template_unit,
|
||||||
|
char **generated_sshd_template_unit) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(sshd_binary);
|
||||||
|
assert(generated_sshd_template_unit);
|
||||||
|
|
||||||
|
Virtualization v = detect_container();
|
||||||
|
if (v < 0)
|
||||||
|
return log_error_errno(v, "Failed to detect if we run in a container: %m");
|
||||||
|
if (v == VIRTUALIZATION_NONE) {
|
||||||
|
log_debug("Not running in container, not listening on /run/host/unix-export/ssh");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access("/run/host/unix-export/", W_OK) < 0) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
log_debug("Container manager does not provide /run/host/unix-export/ mount, not binding AF_UNIX socket there.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (errno == EROFS || ERRNO_IS_PRIVILEGE(errno)) {
|
||||||
|
log_debug("Container manager does not provide write access to /run/host/unix-export/, not binding AF_UNIX socket there.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_debug_errno(errno, "Unable to check if /run/host/unix-export exists: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
r = make_sshd_template_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-unix-export@.service",
|
||||||
|
sshd_binary,
|
||||||
|
found_sshd_template_unit,
|
||||||
|
generated_sshd_template_unit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = write_socket_unit(
|
||||||
|
dest,
|
||||||
|
"sshd-unix-export.socket",
|
||||||
|
"/run/host/unix-export/ssh",
|
||||||
|
"AF_UNIX Export");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
log_info("Binding SSH to AF_UNIX socket /run/host/unix-export/ssh\n"
|
||||||
|
"→ connect via 'ssh unix/run/systemd/nspawn/unix-export/\?\?\?/ssh' from host");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_extra_sockets(
|
||||||
|
const char *dest,
|
||||||
|
const char *sshd_binary,
|
||||||
|
const char *found_sshd_template_unit,
|
||||||
|
char **generated_sshd_template_unit) {
|
||||||
|
|
||||||
|
unsigned n = 1;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
assert(sshd_binary);
|
||||||
|
assert(generated_sshd_template_unit);
|
||||||
|
|
||||||
|
if (strv_isempty(arg_listen_extra))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
STRV_FOREACH(i, arg_listen_extra) {
|
||||||
|
_cleanup_free_ char *service = NULL, *socket = NULL;
|
||||||
|
|
||||||
|
if (n > 1) {
|
||||||
|
if (asprintf(&service, "sshd-extra-%u@.service", n) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (asprintf(&socket, "sshd-extra-%u.socket", n) < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = make_sshd_template_unit(
|
||||||
|
dest,
|
||||||
|
service ?: "sshd-extra@.service",
|
||||||
|
sshd_binary,
|
||||||
|
found_sshd_template_unit,
|
||||||
|
generated_sshd_template_unit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = write_socket_unit(
|
||||||
|
dest,
|
||||||
|
socket ?: "sshd-extra.socket",
|
||||||
|
*i,
|
||||||
|
*i);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
log_info("Binding SSH to socket %s.", *i);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_credentials(void) {
|
||||||
|
_cleanup_free_ char *b = NULL;
|
||||||
|
size_t sz = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = read_credential_with_decryption("ssh.listen", (void*) &b, &sz);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
f = fmemopen_unlocked(b, sz, "r");
|
||||||
|
if (!f)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *item = NULL;
|
||||||
|
|
||||||
|
r = read_stripped_line(f, LINE_MAX, &item);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r < 0) {
|
||||||
|
log_error_errno(r, "Failed to parse credential 'ssh.listen': %m");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startswith(item, "#"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SocketAddress sa;
|
||||||
|
r = socket_address_parse(&sa, item);
|
||||||
|
if (r < 0) {
|
||||||
|
log_warning_errno(r, "Failed to parse systemd.ssh_listen= expression, ignoring: %s", item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
r = socket_address_print(&sa, &s);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to format socket address: %m");
|
||||||
|
|
||||||
|
if (strv_consume(&arg_listen_extra, TAKE_PTR(s)) < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert_se(arg_dest = dest);
|
||||||
|
|
||||||
|
r = proc_cmdline_parse(parse_proc_cmdline_item, /* userdata= */ NULL, /* flags= */ 0);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||||
|
|
||||||
|
(void) parse_credentials();
|
||||||
|
|
||||||
|
strv_sort(arg_listen_extra);
|
||||||
|
strv_uniq(arg_listen_extra);
|
||||||
|
|
||||||
|
if (!arg_auto && strv_isempty(arg_listen_extra)) {
|
||||||
|
log_debug("Disabling SSH generator logic, because as it has been turned off explicitly.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *sshd_binary = NULL;
|
||||||
|
r = find_executable("sshd", &sshd_binary);
|
||||||
|
if (r == -ENOENT) {
|
||||||
|
log_info("Disabling SSH generator logic, since sshd is not installed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine if sshd is installed: %m");
|
||||||
|
|
||||||
|
_cleanup_(lookup_paths_free) LookupPaths lp = {};
|
||||||
|
r = lookup_paths_init_or_warn(&lp, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, /* root_dir= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
_cleanup_free_ char *found_sshd_template_unit = NULL;
|
||||||
|
r = unit_file_exists_full(RUNTIME_SCOPE_SYSTEM, &lp, "sshd@.service", &found_sshd_template_unit);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to detect if sshd@.service exists: %m");
|
||||||
|
|
||||||
|
_cleanup_free_ char *generated_sshd_template_unit = NULL;
|
||||||
|
RET_GATHER(r, add_extra_sockets(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
|
||||||
|
|
||||||
|
if (arg_auto) {
|
||||||
|
RET_GATHER(r, add_vsock_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
|
||||||
|
RET_GATHER(r, add_local_unix_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
|
||||||
|
RET_GATHER(r, add_export_unix_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
Loading…
Reference in New Issue
Block a user