summarylogtreecommitdiffstats
path: root/0001-ssh-agent-add-systemd-socket-based-activation.patch
blob: 2013f6f20774035f707258ca4fc783e5760a3d63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
From 60132e12267ecb4e53d8f7311eb34d3aae46b55b Mon Sep 17 00:00:00 2001
From: Ronan Pigott <ronan@rjp.ie>
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 <stdlib.h>
 #include <time.h>
 #include <string.h>
+#ifdef WITH_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
 #include <unistd.h>
 #ifdef HAVE_UTIL_H
 # include <util.h>
@@ -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