notify systemd on listen and reload

Standalone implementation that does not depend on libsystemd.
With assistance from Luca Boccassi, and feedback/testing from Colin
Watson. bz2641
This commit is contained in:
Damien Miller 2024-04-03 14:40:32 +11:00
parent 43e7c1c07c
commit 08f579231c
No known key found for this signature in database
6 changed files with 115 additions and 2 deletions

View 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.*)

View File

@ -21,16 +21,23 @@
#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 */

View 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 */

View 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

View 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);

2
sshd.c
View File

@ -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