]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
notify systemd on listen and reload
authorDamien Miller <djm@mindrot.org>
Wed, 3 Apr 2024 03:40:32 +0000 (14:40 +1100)
committerDamien Miller <djm@mindrot.org>
Wed, 3 Apr 2024 03:40:32 +0000 (14:40 +1100)
Standalone implementation that does not depend on libsystemd.
With assistance from Luca Boccassi, and feedback/testing from Colin
Watson. bz2641

configure.ac
openbsd-compat/port-linux.c
openbsd-compat/port-linux.h
platform.c
platform.h
sshd.c

index c04349f35f609fd89b261423f9b0acd85ccb1b1e..2cf16b46abb7e899e724f352d6153f3923b8d005 100644 (file)
@@ -915,6 +915,7 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
        AC_DEFINE([_PATH_BTMP], ["/var/log/btmp"], [log for bad login attempts])
        AC_DEFINE([USE_BTMP])
        AC_DEFINE([LINUX_OOM_ADJUST], [1], [Adjust Linux out-of-memory killer])
+       AC_DEFINE([SYSTEMD_NOTIFY], [1], [Have sshd notify systemd on start/reload])
        inet6_default_4in6=yes
        case `uname -r` in
        1.*|2.0.*)
index 0457e28d0660b0580624b2a08f386ee813141ce8..df7290246df63a65cfef80d2d7d0db4ce3803128 100644 (file)
 
 #include "includes.h"
 
-#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
+#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST) || \
+    defined(SYSTEMD_NOTIFY)
+#include <sys/socket.h>
+#include <sys/un.h>
+
 #include <errno.h>
+#include <inttypes.h>
 #include <stdarg.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 
 #include "log.h"
 #include "xmalloc.h"
 #include "port-linux.h"
+#include "misc.h"
 
 #ifdef WITH_SELINUX
 #include <selinux/selinux.h>
@@ -310,4 +317,90 @@ oom_adjust_restore(void)
        return;
 }
 #endif /* LINUX_OOM_ADJUST */
-#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */
+
+#ifdef SYSTEMD_NOTIFY
+
+static void ssh_systemd_notify(const char *, ...)
+    __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1)));
+
+static void
+ssh_systemd_notify(const char *fmt, ...)
+{
+       char *s = NULL;
+       const char *path;
+       struct stat sb;
+       struct sockaddr_un addr;
+       int fd = -1;
+       va_list ap;
+
+       if ((path = getenv("NOTIFY_SOCKET")) == NULL || strlen(path) == 0)
+               return;
+
+       va_start(ap, fmt);
+       xvasprintf(&s, fmt, ap);
+       va_end(ap);
+
+       /* Only AF_UNIX is supported, with path or abstract sockets */
+       if (path[0] != '/' && path[0] != '@') {
+               error_f("socket \"%s\" is not compatible with AF_UNIX", path);
+               goto out;
+       }
+
+       if (path[0] == '/' && stat(path, &sb) != 0) {
+               error_f("socket \"%s\" stat: %s", path, strerror(errno));
+               goto out;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       if (strlcpy(addr.sun_path, path,
+           sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
+               error_f("socket path \"%s\" too long", path);
+               goto out;
+       }
+       /* Support for abstract socket */
+       if (addr.sun_path[0] == '@')
+               addr.sun_path[0] = 0;
+       if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1) {
+               error_f("socket \"%s\": %s", path, strerror(errno));
+               goto out;
+       }
+       if (connect(fd, &addr, sizeof(addr)) != 0) {
+               error_f("socket \"%s\" connect: %s", path, strerror(errno));
+               goto out;
+       }
+       if (write(fd, s, strlen(s)) != (ssize_t)strlen(s)) {
+               error_f("socket \"%s\" write: %s", path, strerror(errno));
+               goto out;
+       }
+       debug_f("socket \"%s\" notified %s", path, s);
+ out:
+       if (fd != -1)
+               close(fd);
+       free(s);
+}
+
+void
+ssh_systemd_notify_ready(void)
+{
+       ssh_systemd_notify("READY=1");
+}
+
+void
+ssh_systemd_notify_reload(void)
+{
+       struct timespec now;
+
+       monotime_ts(&now);
+       if (now.tv_sec < 0 || now.tv_nsec < 0) {
+               error_f("monotime returned negative value");
+               ssh_systemd_notify("RELOADING=1");
+       } else {
+               ssh_systemd_notify("RELOADING=1\nMONOTONIC_USEC=%llu",
+                   ((uint64_t)now.tv_sec * 1000000ULL) +
+                   ((uint64_t)now.tv_nsec / 1000ULL));
+       }
+}
+#endif /* SYSTEMD_NOTIFY */
+
+#endif /* WITH_SELINUX || LINUX_OOM_ADJUST || SYSTEMD_NOTIFY */
index 3c22a854dbce4770d3f465cb9498164275a6cfc2..14064f87db8ef80edc5f054671c509b9e19131f6 100644 (file)
@@ -30,4 +30,9 @@ void oom_adjust_restore(void);
 void oom_adjust_setup(void);
 #endif
 
+#ifdef SYSTEMD_NOTIFY
+void ssh_systemd_notify_ready(void);
+void ssh_systemd_notify_reload(void);
+#endif
+
 #endif /* ! _PORT_LINUX_H */
index 4fe8744ee887c4297c9e7721fb83ecf47e14c54d..9cf81815324cfda9ebb900fe0d76c12f5a7358c7 100644 (file)
@@ -44,6 +44,14 @@ platform_pre_listen(void)
 #endif
 }
 
+void
+platform_post_listen(void)
+{
+#ifdef SYSTEMD_NOTIFY
+       ssh_systemd_notify_ready();
+#endif
+}
+
 void
 platform_pre_fork(void)
 {
@@ -55,6 +63,9 @@ platform_pre_fork(void)
 void
 platform_pre_restart(void)
 {
+#ifdef SYSTEMD_NOTIFY
+       ssh_systemd_notify_reload();
+#endif
 #ifdef LINUX_OOM_ADJUST
        oom_adjust_restore();
 #endif
index 7fef8c983e5ed22d59d391bc7a9fe9e2ad96d75e..5dec23276a61fe2f0c69556818ebfecedcbc5f50 100644 (file)
@@ -21,6 +21,7 @@
 void platform_pre_listen(void);
 void platform_pre_fork(void);
 void platform_pre_restart(void);
+void platform_post_listen(void);
 void platform_post_fork_parent(pid_t child_pid);
 void platform_post_fork_child(void);
 int  platform_privileged_uidswap(void);
diff --git a/sshd.c b/sshd.c
index b4f2b9742f39ec95be59f19c83541daa4beea553..865331b461eac2fedd328019240bfe4dd6a93adb 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -2077,6 +2077,8 @@ main(int ac, char **av)
                ssh_signal(SIGTERM, sigterm_handler);
                ssh_signal(SIGQUIT, sigterm_handler);
 
+               platform_post_listen();
+
                /*
                 * Write out the pid file after the sigterm handler
                 * is setup and the listen sockets are bound