[openssh-commits] [openssh] branch master updated: Support systemd-style socket activation in agent

git+noreply at mindrot.org git+noreply at mindrot.org
Thu Dec 5 00:03:31 AEDT 2024


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

The following commit(s) were added to refs/heads/master by this push:
     new 66e98688 Support systemd-style socket activation in agent
66e98688 is described below

commit 66e986880b2472fefaad781f10113b138b65ff27
Author: Damien Miller <djm at mindrot.org>
AuthorDate: Thu Dec 5 00:01:33 2024 +1100

    Support systemd-style socket activation in agent
    
    Adds support for systemd LISTEN_PID/LISTEN_FDS socket activation to
    ssh-agent. Activated when these environment variables are set and
    the agent is started with the -d or -D option and no socket path
    is set.
    
    Based on GHPR502 by Daniel Kahn Gillmor, ok dtucker
---
 ssh-agent.1 | 26 ++++++++++++++++++--
 ssh-agent.c | 82 +++++++++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/ssh-agent.1 b/ssh-agent.1
index 2f5b091e..062e87bb 100644
--- a/ssh-agent.1
+++ b/ssh-agent.1
@@ -190,7 +190,7 @@ The agent exits automatically when the command given on the command
 line terminates.
 .El
 .Pp
-There are two main ways to get an agent set up.
+There are three main ways to get an agent set up.
 The first is at the start of an X session,
 where all other windows or programs are started as children of the
 .Nm
@@ -208,11 +208,33 @@ it prints the shell commands required to set its environment variables,
 which in turn can be evaluated in the calling shell, for example
 .Cm eval `ssh-agent -s` .
 .Pp
-In both cases,
+In both of these cases,
 .Xr ssh 1
 looks at these environment variables
 and uses them to establish a connection to the agent.
 .Pp
+The third way to run
+.Nm
+is via socket activation from a supervising process, such as systemd.
+In this mode, the supervising process creates the listening socket and
+is responsible for starting
+.Nm
+as needed, and also for communicating the location of the socket listener
+to other programs in the user's session.
+Socket activation is used when
+.Nm
+is started with either of the
+.Fl d
+or
+.Fl D
+flags, so socket listening address specified by the
+.Fl a
+flag, and both the
+.Ev LISTEN_FDS
+and
+.Ev LISTEN_PID
+environment variables correctly supplied by the supervising process.
+.Pp
 The agent initially does not have any private keys.
 Keys are added using
 .Xr ssh-add 1
diff --git a/ssh-agent.c b/ssh-agent.c
index 96c25b9d..48973b2c 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -2215,8 +2215,9 @@ 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;
-	char *shell, *format, *pidstr, *agentsocket = NULL;
+	int sock = -1, ch, result, saved_errno;
+	char *shell, *format, *fdstr, *pidstr, *agentsocket = NULL;
+	const char *errstr = NULL;
 	const char *ccp;
 #ifdef HAVE_SETRLIMIT
 	struct rlimit rlim;
@@ -2329,8 +2330,6 @@ main(int ac, char **av)
 			c_flag = 1;
 	}
 	if (k_flag) {
-		const char *errstr = NULL;
-
 		pidstr = getenv(SSH_AGENTPID_ENV_NAME);
 		if (pidstr == NULL) {
 			fprintf(stderr, "%s not set, cannot kill agent\n",
@@ -2368,33 +2367,59 @@ main(int ac, char **av)
 
 	parent_pid = getpid();
 
-	if (agentsocket == NULL) {
-		/* Create private directory for agent socket */
-		mktemp_proto(socket_dir, sizeof(socket_dir));
-		if (mkdtemp(socket_dir) == NULL) {
-			perror("mkdtemp: private socket dir");
-			exit(1);
+	/* Has the socket been provided via socket activation? */
+	if (agentsocket == NULL && ac == 0 && (d_flag || D_flag) &&
+	    (pidstr = getenv("LISTEN_PID")) != NULL &&
+	    (fdstr = getenv("LISTEN_FDS")) != NULL) {
+		if (strcmp(fdstr, "1") != 0) {
+			fatal("unexpected LISTEN_FDS contents "
+			    "(want: \"1\" got\"%s\"", fdstr);
 		}
-		snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
+		if (fcntl(3, F_GETFL) == -1)
+			fatal("LISTEN_FDS set but fd 3 unavailable");
+		pid = (int)strtonum(pidstr, 1, INT_MAX, &errstr);
+		if (errstr != NULL)
+			fatal("invalid LISTEN_PID: %s", errstr);
+		if (pid != getpid())
+			fatal("bad LISTEN_PID: %d vs pid %d", pid, getpid());
+		debug("using socket activation on fd=3");
+		sock = 3;
+	}
+
+	/* Otherwise, create private directory for agent socket */
+	if (sock == -1) {
+		if (agentsocket == NULL) {
+			mktemp_proto(socket_dir, sizeof(socket_dir));
+			if (mkdtemp(socket_dir) == NULL) {
+				perror("mkdtemp: private socket dir");
+				exit(1);
+			}
+			snprintf(socket_name, sizeof socket_name,
+			   "%s/agent.%ld", socket_dir,
 		    (long)parent_pid);
-	} else {
-		/* Try to use specified agent socket */
-		socket_dir[0] = '\0';
-		strlcpy(socket_name, agentsocket, sizeof socket_name);
+		} else {
+			/* Try to use specified agent socket */
+			socket_dir[0] = '\0';
+			strlcpy(socket_name, agentsocket, sizeof socket_name);
+		}
 	}
 
+	closefrom(sock == -1 ? STDERR_FILENO + 1 : sock + 1);
+
 	/*
 	 * 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 == -1) {
+		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 existing file */
+			cleanup_exit(1);
+		}
+		umask(prev_mask);
 	}
-	umask(prev_mask);
 
 	/*
 	 * Fork, and have the parent execute the command, if any, or present
@@ -2404,11 +2429,14 @@ main(int ac, char **av)
 		log_init(__progname,
 		    d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
 		    SYSLOG_FACILITY_AUTH, 1);
-		format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
-		printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
-		    SSH_AUTHSOCKET_ENV_NAME);
-		printf("echo Agent pid %ld;\n", (long)parent_pid);
-		fflush(stdout);
+		if (socket_name[0] != '\0') {
+			format = c_flag ?
+			    "setenv %s %s;\n" : "%s=%s; export %s;\n";
+			printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+			    SSH_AUTHSOCKET_ENV_NAME);
+			printf("echo Agent pid %ld;\n", (long)parent_pid);
+			fflush(stdout);
+		}
 		goto skip;
 	}
 	pid = fork();

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list