[openssh-commits] [openssh] 02/04: upstream: Move agent listener sockets from /tmp to under
git+noreply at mindrot.org
git+noreply at mindrot.org
Mon May 5 14:59:35 AEST 2025
This is an automated email from the git hooks/post-receive script.
djm pushed a commit to branch master
in repository openssh.
commit 80162f9d7e7eadca4ffd0bd1c015d38cb1821ab6
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Mon May 5 02:48:06 2025 +0000
upstream: Move agent listener sockets from /tmp to under
~/.ssh/agent for both ssh-agent(1) and forwarded sockets in sshd(8).
This ensures processes (such as Firefox) that have restricted
filesystem access that includes /tmp (via unveil(3)) do not have the
ability to use keys in an agent.
Moving the default directory has the consequence that the OS will no
longer clean up stale agent sockets, so ssh-agent now gains this
ability.
To support $HOME on NFS, the socket path includes a truncated hash of
the hostname. ssh-agent will by default only clean up sockets from
the same hostname.
ssh-agent gains some new flags: -U suppresses the automatic cleanup
of stale sockets when it starts. -u forces a cleanup without
keeping a running agent, -uu forces a cleanup that ignores the
hostname. -T makes ssh-agent put the socket back in /tmp.
feedback deraadt@ naddy@, doitdoitdoit deraadt@
OpenBSD-Commit-ID: 8383dabd98092fe5498d5f7f15c7d314b03a93e1
---
Makefile.in | 6 ++---
hostfile.c | 2 +-
misc.c | 17 ++++++++++++-
misc.h | 8 +++++-
pathnames.h | 9 ++++++-
session.c | 34 +++----------------------
ssh-agent.1 | 32 +++++++++++++++++++----
ssh-agent.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
8 files changed, 136 insertions(+), 57 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index f15ac558a..4550e1795 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -140,7 +140,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o \
sftp-server.o sftp-common.o \
- uidswap.o platform-listen.o $(SKOBJS)
+ uidswap.o platform-listen.o misc-agent.o $(SKOBJS)
SSHD_AUTH_OBJS=sshd-auth.o \
auth2-methods.o \
@@ -155,7 +155,7 @@ SSHD_AUTH_OBJS=sshd-auth.o \
sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o \
sftp-server.o sftp-common.o \
- uidswap.o $(SKOBJS)
+ uidswap.o misc-agent.o $(SKOBJS)
SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
@@ -163,7 +163,7 @@ SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS)
SSHADD_OBJS= ssh-add.o $(SKOBJS)
-SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS)
+SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o misc-agent.o $(SKOBJS)
SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(SKOBJS)
diff --git a/hostfile.c b/hostfile.c
index e941fc450..4b4a0e31e 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hostfile.c,v 1.97 2025/04/30 05:26:15 djm Exp $ */
+/* $OpenBSD: hostfile.c,v 1.98 2025/05/05 02:48:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
diff --git a/misc.c b/misc.c
index dd0bd032a..25465dcd2 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.198 2024/10/24 03:14:37 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.199 2025/05/05 02:48:06 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@@ -3138,3 +3138,18 @@ signal_is_crash(int sig)
}
return 0;
}
+
+char *
+get_homedir(void)
+{
+ char *cp;
+ struct passwd *pw;
+
+ if ((cp = getenv("HOME")) != NULL && *cp != '\0')
+ return xstrdup(cp);
+
+ if ((pw = getpwuid(getuid())) != NULL && *pw->pw_dir != '\0')
+ return xstrdup(pw->pw_dir);
+
+ return NULL;
+}
diff --git a/misc.h b/misc.h
index efecdf1ad..a7afa23e8 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.110 2024/09/25 01:24:04 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.111 2025/05/05 02:48:06 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -108,6 +108,7 @@ int parse_pattern_interval(const char *, char **, int *);
int path_absolute(const char *);
int stdfd_devnull(int, int, int);
int lib_contains_symbol(const char *, const char *);
+char *get_homedir(void);
void sock_set_v6only(int);
@@ -231,6 +232,11 @@ int ptimeout_get_ms(struct timespec *pt);
struct timespec *ptimeout_get_tsp(struct timespec *pt);
int ptimeout_isset(struct timespec *pt);
+/* misc-agent.c */
+char *agent_hostname_hash(void);
+int agent_listener(const char *, const char *, int *, char **);
+void agent_cleanup_stale(const char *, int);
+
/* readpass.c */
#define RP_ECHO 0x0001
diff --git a/pathnames.h b/pathnames.h
index 1158bec96..e07395cb6 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pathnames.h,v 1.32 2024/05/17 00:30:24 djm Exp $ */
+/* $OpenBSD: pathnames.h,v 1.34 2025/05/05 02:48:06 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -67,6 +67,13 @@
*/
#define _PATH_SSH_USER_DIR ".ssh"
+
+/*
+ * The directory in which ssh-agent sockets and agent sockets forwarded by
+ * sshd reside. This directory should not be world-readable.
+ */
+#define _PATH_SSH_AGENT_SOCKET_DIR _PATH_SSH_USER_DIR "/agent"
+
/*
* Per-user file containing host keys of known hosts. This file need not be
* readable by anyone except the user him/herself, though this does not
diff --git a/session.c b/session.c
index 6444c77f3..630e0e6a3 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.341 2025/04/09 07:00:03 djm Exp $ */
+/* $OpenBSD: session.c,v 1.342 2025/05/05 02:48:06 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -175,7 +175,6 @@ static char *auth_info_file = NULL;
/* Name and directory of socket for authentication agent forwarding. */
static char *auth_sock_name = NULL;
-static char *auth_sock_dir = NULL;
/* removes the agent forwarding socket */
@@ -185,7 +184,6 @@ auth_sock_cleanup_proc(struct passwd *pw)
if (auth_sock_name != NULL) {
temporarily_use_uid(pw);
unlink(auth_sock_name);
- rmdir(auth_sock_dir);
auth_sock_name = NULL;
restore_uid();
}
@@ -205,32 +203,15 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
/* Temporarily drop privileged uid for mkdir/bind. */
temporarily_use_uid(pw);
- /* Allocate a buffer for the socket name, and format the name. */
- auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
-
- /* Create private directory for socket */
- if (mkdtemp(auth_sock_dir) == NULL) {
+ if (agent_listener(pw->pw_dir, "sshd", &sock, &auth_sock_name) != 0) {
+ /* a more detailed error is already logged */
ssh_packet_send_debug(ssh, "Agent forwarding disabled: "
- "mkdtemp() failed: %.100s", strerror(errno));
+ "couldn't create listener socket");
restore_uid();
- free(auth_sock_dir);
- auth_sock_dir = NULL;
goto authsock_err;
}
-
- xasprintf(&auth_sock_name, "%s/agent.%ld",
- auth_sock_dir, (long) getpid());
-
- /* Start a Unix listener on auth_sock_name. */
- sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
-
- /* Restore the privileged uid. */
restore_uid();
- /* Check for socket/bind/listen failure. */
- if (sock < 0)
- goto authsock_err;
-
/* Allocate a channel for the authentication agent socket. */
nc = channel_new(ssh, "auth-listener",
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
@@ -241,16 +222,9 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
authsock_err:
free(auth_sock_name);
- if (auth_sock_dir != NULL) {
- temporarily_use_uid(pw);
- rmdir(auth_sock_dir);
- restore_uid();
- free(auth_sock_dir);
- }
if (sock != -1)
close(sock);
auth_sock_name = NULL;
- auth_sock_dir = NULL;
return 0;
}
diff --git a/ssh-agent.1 b/ssh-agent.1
index 533ad6d3a..3b515ac42 100644
--- a/ssh-agent.1
+++ b/ssh-agent.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-agent.1,v 1.82 2025/02/09 18:24:08 schwarze Exp $
+.\" $OpenBSD: ssh-agent.1,v 1.83 2025/05/05 02:48:06 djm Exp $
.\"
.\" Author: Tatu Ylonen <ylo at cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: February 9 2025 $
+.Dd $Mdocdate: May 5 2025 $
.Dt SSH-AGENT 1
.Os
.Sh NAME
@@ -43,13 +43,14 @@
.Sh SYNOPSIS
.Nm ssh-agent
.Op Fl c | s
-.Op Fl \&Dd
+.Op Fl \&DdTU
.Op Fl a Ar bind_address
.Op Fl E Ar fingerprint_hash
.Op Fl O Ar option
.Op Fl P Ar allowed_providers
.Op Fl t Ar life
.Nm ssh-agent
+.Op Fl TU
.Op Fl a Ar bind_address
.Op Fl E Ar fingerprint_hash
.Op Fl O Ar option
@@ -59,6 +60,8 @@
.Nm ssh-agent
.Op Fl c | s
.Fl k
+.Nm ssh-agent
+.Fl u
.Sh DESCRIPTION
.Nm
is a program to hold private keys used for public key authentication.
@@ -74,8 +77,8 @@ Bind the agent to the
.Ux Ns -domain
socket
.Ar bind_address .
-The default is
-.Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt .
+The default is to create a socket at a random path matching
+.Pa $HOME/.ssh/agent/s.*
.It Fl c
Generate C-shell commands on standard output.
This is the default if
@@ -173,6 +176,11 @@ Generate Bourne shell commands on standard output.
This is the default if
.Ev SHELL
does not look like it's a csh style of shell.
+.It Fl T
+Bind the agent socket in a randomised subdirectory of the form
+.Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt ,
+instead of the default behaviour of using a randomised name matching
+.Pa $HOME/.ssh/agent/s.* .
.It Fl t Ar life
Set a default value for the maximum lifetime of identities added to the agent.
The lifetime may be specified in seconds or in a time format specified in
@@ -186,6 +194,20 @@ If a command (and optional arguments) is given,
this is executed as a subprocess of the agent.
The agent exits automatically when the command given on the command
line terminates.
+.It Fl U
+Instructs
+.Nm
+not to clean up stale agent sockets under
+.Pa $HOME/.ssh/agent/ .
+.It Fl u
+Instructs
+.Nm
+to only clean up stale agent sockets under
+.Pa $HOME/.ssh/agent/
+and then exit immediately.
+If this option is given twice,
+.Nm
+will delete stale agent sockets regardless of the host name that created them.
.El
.Pp
There are three main ways to get an agent set up.
diff --git a/ssh-agent.c b/ssh-agent.c
index 55b9f44f4..8a88ef3fd 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.311 2025/04/15 09:22:25 dtucker Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.312 2025/05/05 02:48:06 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -2208,20 +2208,23 @@ static void
usage(void)
{
fprintf(stderr,
- "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
+ "usage: ssh-agent [-c | -s] [-DdTU] [-a bind_address] [-E fingerprint_hash]\n"
" [-O option] [-P allowed_providers] [-t life]\n"
- " ssh-agent [-a bind_address] [-E fingerprint_hash] [-O option]\n"
+ " ssh-agent [-TU] [-a bind_address] [-E fingerprint_hash] [-O option]\n"
" [-P allowed_providers] [-t life] command [arg ...]\n"
- " ssh-agent [-c | -s] -k\n");
+ " ssh-agent [-c | -s] -k\n"
+ " ssh-agent -u\n");
exit(1);
}
int
main(int ac, char **av)
{
- int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
+ int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0;
+ int s_flag = 0, T_flag = 0, u_flag = 0, U_flag = 0;
int sock = -1, ch, result, saved_errno;
- char *shell, *format, *fdstr, *pidstr, *agentsocket = NULL;
+ char *homedir = NULL, *shell, *format, *pidstr, *agentsocket = NULL;
+ char *fdstr;
const char *errstr = NULL;
const char *ccp;
#ifdef HAVE_SETRLIMIT
@@ -2256,7 +2259,7 @@ main(int ac, char **av)
__progname = ssh_get_progname(av[0]);
seed_rng();
- while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) {
+ while ((ch = getopt(ac, av, "cDdksTuUE:a:O:P:t:")) != -1) {
switch (ch) {
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -2313,6 +2316,15 @@ main(int ac, char **av)
usage();
}
break;
+ case 'T':
+ T_flag++;
+ break;
+ case 'u':
+ u_flag++;
+ break;
+ case 'U':
+ U_flag++;
+ break;
default:
usage();
}
@@ -2320,9 +2332,14 @@ main(int ac, char **av)
ac -= optind;
av += optind;
- if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
+ if (ac > 0 &&
+ (c_flag || k_flag || s_flag || d_flag || D_flag || u_flag))
usage();
+ log_init(__progname,
+ d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
+ SYSLOG_FACILITY_AUTH, 1);
+
if (allowed_providers == NULL)
allowed_providers = xstrdup(DEFAULT_ALLOWED_PROVIDERS);
if (websafe_allowlist == NULL)
@@ -2358,6 +2375,14 @@ main(int ac, char **av)
printf("echo Agent pid %ld killed;\n", (long)pid);
exit(0);
}
+ if (u_flag) {
+ if ((homedir = get_homedir()) == NULL)
+ fatal("Couldn't determine home directory");
+ agent_cleanup_stale(homedir, u_flag > 1);
+ printf("Deleted stale agent sockets in ~/%s\n",
+ _PATH_SSH_AGENT_SOCKET_DIR);
+ exit(0);
+ }
/*
* Minimum file descriptors:
@@ -2391,22 +2416,52 @@ main(int ac, char **av)
sock = 3;
}
- /* Otherwise, create private directory for agent socket */
- if (sock == -1) {
- if (agentsocket == NULL) {
+ if (sock == -1 && agentsocket == NULL && !T_flag) {
+ /* Default case: ~/.ssh/agent/[socket] */
+ if ((homedir = get_homedir()) == NULL)
+ fatal("Couldn't determine home directory");
+ if (!U_flag)
+ agent_cleanup_stale(homedir, 0);
+ if (agent_listener(homedir, "agent", &sock, &agentsocket) != 0)
+ fatal_f("Couldn't prepare agent socket");
+ if (strlcpy(socket_name, agentsocket,
+ sizeof(socket_name)) >= sizeof(socket_name)) {
+ fatal_f("Socket path \"%s\" too long",
+ agentsocket);
+ }
+ free(homedir);
+ free(agentsocket);
+ agentsocket = NULL;
+ } else if (sock == -1) {
+ if (T_flag) {
+ /*
+ * Create private directory for agent socket
+ * in $TMPDIR.
+ */
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);
+ 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);
+ if (strlcpy(socket_name, agentsocket,
+ sizeof(socket_name)) >= sizeof(socket_name)) {
+ fatal_f("Socket path \"%s\" too long",
+ agentsocket);
+ }
}
+ /* Listen on socket */
+ prev_mask = umask(0177);
+ if ((sock = unix_listener(socket_name,
+ SSH_LISTEN_BACKLOG, 0)) < 0) {
+ *socket_name = '\0'; /* Don't unlink existing file */
+ cleanup_exit(1);
+ }
+ umask(prev_mask);
}
closefrom(sock == -1 ? STDERR_FILENO + 1 : sock + 1);
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list