diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index 988b7175ba8..5980a8f9304 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -83,6 +83,7 @@
sockets.target,
soft-reboot.target,
sound.target,
+ ssh-access.target,
storage-target-mode.target,
suspend.target,
swap.target,
@@ -1172,6 +1173,19 @@
the $portmap facility.
+
+ ssh-access.target
+
+ Service and socket units that provide remote SSH secure shell access to the local system
+ should pull in this unit and order themselves before this unit. It's supposed to act as a
+ milestone indicating if and when SSH access into the system is available. It should only become
+ active when an SSH port is bound for remote clients (i.e. if SSH is used as a local privilege
+ escalation mechanism, it should not involve this target unit), regardless of
+ the protocol choices, i.e. regardless if IPv4, IPv6 or AF_VSOCK is
+ used.
+
+
+
time-set.target
diff --git a/src/ssh-generator/ssh-generator.c b/src/ssh-generator/ssh-generator.c
index 08532690a9c..613e88dd194 100644
--- a/src/ssh-generator/ssh-generator.c
+++ b/src/ssh-generator/ssh-generator.c
@@ -128,7 +128,8 @@ static int write_socket_unit(
const char *dest,
const char *unit,
const char *listen_stream,
- const char *comment) {
+ const char *comment,
+ bool with_ssh_access_target_dependency) {
int r;
@@ -149,13 +150,21 @@ static int write_socket_unit(
fprintf(f,
"[Unit]\n"
"Description=OpenSSH Server Socket (systemd-ssh-generator, %s)\n"
- "Documentation=man:systemd-ssh-generator(8)\n"
+ "Documentation=man:systemd-ssh-generator(8)\n",
+ comment);
+
+ /* When this is a remotely accessible socket let's mark this with a milestone: ssh-access.target */
+ if (with_ssh_access_target_dependency)
+ fputs("Wants=ssh-access.target\n"
+ "Before=ssh-access.target\n",
+ f);
+
+ fprintf(f,
"\n[Socket]\n"
"ListenStream=%s\n"
"Accept=yes\n"
"PollLimitIntervalSec=30s\n"
"PollLimitBurst=50\n",
- comment,
listen_stream);
r = fflush_and_check(f);
@@ -230,7 +239,8 @@ static int add_vsock_socket(
dest,
"sshd-vsock.socket",
"vsock::22",
- "AF_VSOCK");
+ "AF_VSOCK",
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
@@ -264,7 +274,8 @@ static int add_local_unix_socket(
dest,
"sshd-unix-local.socket",
"/run/ssh-unix-local/socket",
- "AF_UNIX Local");
+ "AF_UNIX Local",
+ /* with_ssh_access_target_dependency= */ false);
if (r < 0)
return r;
@@ -320,7 +331,8 @@ static int add_export_unix_socket(
dest,
"sshd-unix-export.socket",
"/run/host/unix-export/ssh",
- "AF_UNIX Export");
+ "AF_UNIX Export",
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
@@ -370,7 +382,8 @@ static int add_extra_sockets(
dest,
socket ?: "sshd-extra.socket",
*i,
- *i);
+ *i,
+ /* with_ssh_access_target_dependency= */ true);
if (r < 0)
return r;
diff --git a/units/meson.build b/units/meson.build
index 1458cc59867..151d3bc6098 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -203,6 +203,7 @@ units = [
{ 'file' : 'sockets.target' },
{ 'file' : 'soft-reboot.target' },
{ 'file' : 'sound.target' },
+ { 'file' : 'ssh-access.target' },
{
'file' : 'suspend-then-hibernate.target',
'conditions' : ['ENABLE_HIBERNATE'],
diff --git a/units/ssh-access.target b/units/ssh-access.target
new file mode 100644
index 00000000000..f9b6a4c1490
--- /dev/null
+++ b/units/ssh-access.target
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# 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=SSH Access Available
+Documentation=man:systemd.special(7)