summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@ubuntu.com>2022-09-01 16:03:37 +0100
committerColin Watson <cjwatson@debian.org>2024-03-31 00:35:21 +0000
commitd4af38f9aa8f2daa0ae01b994666116f1420d305 (patch)
treecd029cf3c4e9c4272c4d1abeb709aed5af96d520
parent25f238231292eefa02a723b84de6428baca3b7ab (diff)
Support systemd socket activation
Unlike inetd socket activation, with systemd socket activation the supervisor passes the listened-on socket to the child process and lets the child process handle the accept(). This lets us do delayed start of the sshd daemon without becoming incompatible with config options like ClientAliveCountMax. Last-Update: 2022-09-01 Patch-Name: systemd-socket-activation.patch
-rw-r--r--sshd.c89
1 files changed, 75 insertions, 14 deletions
diff --git a/sshd.c b/sshd.c
index b981e7758..565e17b16 100644
--- a/sshd.c
+++ b/sshd.c
@@ -140,10 +140,16 @@ int deny_severity;
#endif /* LIBWRAP */
/* Re-exec fds */
-#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
-#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
-#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3)
-#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4)
+#ifdef HAVE_SYSTEMD
+#define SYSTEMD_OFFSET sd_listen_fds(0)
+#else
+#define SYSTEMD_OFFSET 0
+#endif
+
+#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1 + SYSTEMD_OFFSET)
+#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2 + SYSTEMD_OFFSET)
+#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3 + SYSTEMD_OFFSET)
+#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4 + SYSTEMD_OFFSET)
extern char *__progname;
@@ -1020,6 +1026,48 @@ server_accept_inetd(int *sock_in, int *sock_out)
debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out);
}
+#ifdef HAVE_SYSTEMD
+/*
+ * Configure our socket fds that were passed from systemd
+ */
+static void
+setup_systemd_socket(int listen_sock)
+{
+ int ret;
+ struct sockaddr_storage addr;
+ socklen_t len = sizeof(addr);
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+
+ if (getsockname(listen_sock, (struct sockaddr *)&addr, &len) != 0)
+ return;
+
+ if (((struct sockaddr *)&addr)->sa_family != AF_INET
+ && ((struct sockaddr *)&addr)->sa_family != AF_INET6)
+ return;
+ if (num_listen_socks >= MAX_LISTEN_SOCKS)
+ fatal("Too many listen sockets. "
+ "Enlarge MAX_LISTEN_SOCKS");
+ if ((ret = getnameinfo((struct sockaddr *)&addr, len, ntop,
+ sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+ error("getnameinfo failed: %.100s",
+ ssh_gai_strerror(ret));
+ return;
+ }
+ if (set_nonblock(listen_sock) == -1) {
+ close(listen_sock);
+ return;
+ }
+ /* Socket options */
+ set_reuseaddr(listen_sock);
+
+ listen_socks[num_listen_socks] = listen_sock;
+ num_listen_socks++;
+
+ logit("Server listening on %s port %s.", ntop, strport);
+}
+#endif
+
/*
* Listen for TCP connections
*/
@@ -1099,22 +1147,35 @@ static void
server_listen(void)
{
u_int i;
+#ifdef HAVE_SYSTEMD
+ int systemd_socket_count;
+#endif
/* Initialise per-source limit tracking. */
srclimit_init(options.max_startups, options.per_source_max_startups,
options.per_source_masklen_ipv4, options.per_source_masklen_ipv6);
- for (i = 0; i < options.num_listen_addrs; i++) {
- listen_on_addrs(&options.listen_addrs[i]);
- freeaddrinfo(options.listen_addrs[i].addrs);
- free(options.listen_addrs[i].rdomain);
- memset(&options.listen_addrs[i], 0,
- sizeof(options.listen_addrs[i]));
+#ifdef HAVE_SYSTEMD
+ systemd_socket_count = sd_listen_fds(0);
+ if (systemd_socket_count > 0)
+ {
+ int i;
+ for (i = 0; i < systemd_socket_count; i++)
+ setup_systemd_socket(SD_LISTEN_FDS_START + i);
+ } else
+#endif
+ {
+ for (i = 0; i < options.num_listen_addrs; i++) {
+ listen_on_addrs(&options.listen_addrs[i]);
+ freeaddrinfo(options.listen_addrs[i].addrs);
+ free(options.listen_addrs[i].rdomain);
+ memset(&options.listen_addrs[i], 0,
+ sizeof(options.listen_addrs[i]));
+ }
+ free(options.listen_addrs);
+ options.listen_addrs = NULL;
+ options.num_listen_addrs = 0;
}
- free(options.listen_addrs);
- options.listen_addrs = NULL;
- options.num_listen_addrs = 0;
-
if (!num_listen_socks)
fatal("Cannot bind any address.");
}