From 60132e12267ecb4e53d8f7311eb34d3aae46b55b Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Thu, 15 Jun 2023 13:03:38 -0700 Subject: [PATCH] ssh-agent: add systemd socket-based activation --- Makefile.in | 3 ++- configure.ac | 25 ++++++++++++++++++++++++ ssh-agent.c | 54 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/Makefile.in b/Makefile.in index 70287f51fb81..9bace646fecf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,6 +53,7 @@ CHANNELLIBS=@CHANNELLIBS@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHDLIBS=@SSHDLIBS@ +AGENTLIBS=@AGENTLIBS@ LIBEDIT=@LIBEDIT@ LIBFIDO2=@LIBFIDO2@ AR=@AR@ @@ -216,7 +217,7 @@ ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHADD_OBJS) $(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS) ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHAGENT_OBJS) - $(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS) + $(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(AGENTLIBS) $(LIBS) $(CHANNELLIBS) ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYGEN_OBJS) $(LD) -o $@ $(SSHKEYGEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS) diff --git a/configure.ac b/configure.ac index 07893e870659..d12b6e9c0588 100644 --- a/configure.ac +++ b/configure.ac @@ -147,6 +147,16 @@ else AC_MSG_RESULT([no]) fi +systemd=no +AC_ARG_WITH([systemd], + [ --with-systemd Enable use of systemd socket-based activation ], + [ if test "x$withval" = "xyes" ; then + systemd=yes + AC_DEFINE([WITH_SYSTEMD], [1], [enable systemd socket-based activation]) + fi + ] +) + use_stack_protector=1 use_toolchain_hardening=1 AC_ARG_WITH([stackprotect], @@ -3376,6 +3386,18 @@ AC_CHECK_LIB([crypt], [crypt], [ AC_CHECK_FUNCS([crypt]) LIBS="$saved_LIBS" +if test "x$systemd" == "xyes" ; then + # Check for sd_listen_fds in libsystemd for socket activation + saved_LIBS="$LIBS" + AC_CHECK_LIB([systemd], [sd_listen_fds], [ + LIBS="-lsystemd $LIBS" + AGENTLIBS="-lsystemd $AGENTLIBS" + ]) + AC_CHECK_FUNCS([sd_listen_fds]) + LIBS="$saved_LIBS" + AC_SUBST([AGENTLIBS]) +fi + # Check for PAM libs PAM_MSG="no" AC_ARG_WITH([pam], @@ -5632,6 +5654,9 @@ fi if test ! -z "${SSHDLIBS}"; then echo " +for sshd: ${SSHDLIBS}" fi +if test ! -z "${AGENTLIBS}"; then +echo " +for ssh-agent: ${AGENTLIBS}" +fi echo "" diff --git a/ssh-agent.c b/ssh-agent.c index c72518ba3537..eb3a8b022590 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -69,6 +69,9 @@ #include #include #include +#ifdef WITH_SYSTEMD +# include +#endif #include #ifdef HAVE_UTIL_H # include @@ -166,6 +169,11 @@ pid_t cleanup_pid = 0; char socket_name[PATH_MAX]; char socket_dir[PATH_MAX]; +#ifdef WITH_SYSTEMD +/* tracks whether the active AUTH_SOCKET was passed to us by a third party */ +int external_socket = 0; +#endif + /* Pattern-list of allowed PKCS#11/Security key paths */ static char *allowed_providers; @@ -1946,6 +1954,10 @@ cleanup_socket(void) { if (cleanup_pid != 0 && getpid() != cleanup_pid) return; +#ifdef WITH_SYSTEMD + if (external_socket) + return; +#endif debug_f("cleanup"); if (socket_name[0]) unlink(socket_name); @@ -2000,7 +2012,7 @@ int main(int ac, char **av) { int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0; - int sock, ch, result, saved_errno; + int sock = 0, ch, result, saved_errno; char *shell, *format, *pidstr, *agentsocket = NULL; #ifdef HAVE_SETRLIMIT struct rlimit rlim; @@ -2015,6 +2027,9 @@ main(int ac, char **av) struct pollfd *pfd = NULL; size_t npfd = 0; u_int maxfds; +#ifdef WITH_SYSTEMD + int nfds = 0; +#endif /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -2142,6 +2157,25 @@ main(int ac, char **av) parent_pid = getpid(); +#ifdef WITH_SYSTEMD + nfds = sd_listen_fds(1); + if (nfds > 0) { + sock = SD_LISTEN_FDS_START; + if (agentsocket == NULL) { + fprintf(stderr, "%s not set, cannot use socket-activation", + SSH_AUTHSOCKET_ENV_NAME); + exit(1); + } else if (sd_is_socket_unix(sock, SOCK_STREAM, 1, agentsocket, 0) <= 0) { + fprintf(stderr, "Unexpected auth sock received from systemd. Expected %s\n", agentsocket); + exit(1); + } else if (nfds > 1) { + fprintf(stderr, "too many fds received from systemd (%d)\n", nfds); + exit(1); + } + strlcpy(socket_name, agentsocket, sizeof socket_name); + external_socket = 1; + } +#endif if (agentsocket == NULL) { /* Create private directory for agent socket */ mktemp_proto(socket_dir, sizeof(socket_dir)); @@ -2150,7 +2184,7 @@ main(int ac, char **av) exit(1); } snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, - (long)parent_pid); + (long)parent_pid); } else { /* Try to use specified agent socket */ socket_dir[0] = '\0'; @@ -2161,14 +2195,16 @@ main(int ac, char **av) * Create socket early so it will exist before command gets run from * the parent. */ - prev_mask = umask(0177); - sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0); - if (sock < 0) { - /* XXX - unix_listener() calls error() not perror() */ - *socket_name = '\0'; /* Don't unlink any existing file */ - cleanup_exit(1); + if (sock == 0) { + prev_mask = umask(0177); + sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0); + if (sock < 0) { + /* XXX - unix_listener() calls error() not perror() */ + *socket_name = '\0'; /* Don't unlink any existing file */ + cleanup_exit(1); + } + umask(prev_mask); } - umask(prev_mask); /* * Fork, and have the parent execute the command, if any, or present -- 2.41.0