[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