ability to select which identity to forward when using "ForwardAgent" ?
Damien Miller
djm at mindrot.org
Sun Oct 4 23:35:06 AEDT 2020
On Sun, 4 Oct 2020, Pablo Escobar wrote:
> Hi,
>
> I usually have around 10 identities loaded in my local ssh-agent and when I
> use the "ForwardAgent" option all them are forwarded to the remote server,
> which is not ideal. I usually only need to forward one (or two) of the
> identities and I would like to be able to choose which one(s) to forward.
>
> Looking for solutions it seems that the only option is to create a new
> ssh-agent, add the required identities and then do the forwarding as
> described in https://serverfault.com/a/1012678 but this is not very
> convenient for daily usage mainly when I need to connect to many different
> servers and all my private keys are password protected.
>
> I have also found an external tool to do it (
> https://github.com/tiwe-de/ssh-agent-filter ) but this tool doesn't seem to
> be actively maintained and a native openssh functionality would be
> preferred.
>
> Ideally it would be great to be able to add something like this to my
> ~/.ssh/config ( option "IdentitiesToForward" in this example doesn't exist
> and it's what I am missing)
>
> Host myserver
> Hostname myserver.com
> IdentityFile ~/.ssh/id_ed25519
> ForwardAgent yes
> IdentitiesToForward ~/.ssh/id_ed25519,~/.ssh/id_rsa
>
> Do you think this feature or any alternative providing similar
> functionality could be added to openssh?
Yes, I have been working on better control over what gets forwarded but
not quite what you have here. Generally, I don't want to implement in
ssh fine-grained control over which keys are offered for agent forwarding
because that would force ssh into a much more trusted role in agent key
handling than it currently occupies.
Instead, I have some work-in-progress patches that let ssh-add mark a key
as "local only". These keys may be used for authentication by ssh but are
never forwarded. This lets users separate the two commingled roles of the
agent: 1) a handy place way to use private keys without having to type the
passphrase over and over and 2) a repository of keys that you want to
forward to remote hosts.
Patches are attached but be warned that are likely incomplete :)
-d
-------------- next part --------------
From b6cb3abb87b7a6acdd626abd13c90e3b3cea5de2 Mon Sep 17 00:00:00 2001
From: Damien Miller <djm at mindrot.org>
Date: Thu, 10 Sep 2020 11:57:11 +1000
Subject: [PATCH 1/4] ssh-agent forwarded socket restrictions
This makes ssh-agent listen on a new $SSH_AUTH_SOCK_LOCAL socket in
addition to the usual $SSH_AUTH_SOCK. The original socket loses the
ability to add smartcard or FIDO keys.
Makes ssh-add prefer $SSH_AUTH_SOCK_LOCAL if present.
This makes forwarded agents by default lose the ability to add new
smartcard or FIDO keys to a remote agent. "ssh-agent -L" will get
back the old behaviour.
---
ssh-add.1 | 8 ++--
ssh-add.c | 10 ++++-
ssh-agent.1 | 29 ++++++++++++-
ssh-agent.c | 123 ++++++++++++++++++++++++++++++++++++++++------------
ssh.h | 6 +++
5 files changed, 144 insertions(+), 32 deletions(-)
diff --git a/ssh-add.1 b/ssh-add.1
index 2786df5..2f1793a 100644
--- a/ssh-add.1
+++ b/ssh-add.1
@@ -215,10 +215,12 @@ then the askpass program will be used for all passphrase input regardless
of whether
.Ev DISPLAY
is set.
-.It Ev SSH_AUTH_SOCK
-Identifies the path of a
+.It Ev SSH_AUTH_SOCK | Ev SSH_AUTH_SOCK_LOCAL
+Identifies paths to
.Ux Ns -domain
-socket used to communicate with the agent.
+sockets used to communicate with the agent.
+.Ev SSH_AUTH_SOCK_LOCAL
+is preferred if available.
.It Ev SSH_SK_PROVIDER
Specifies a path to a library that will be used when loading any
FIDO authenticator-hosted keys, overriding the default of using
diff --git a/ssh-add.c b/ssh-add.c
index 0ce989f..6ce1142 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -658,6 +658,7 @@ main(int argc, char **argv)
extern char *optarg;
extern int optind;
int agent_fd;
+ const char *sock_path;
char *pkcs11provider = NULL, *skprovider = NULL;
int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
@@ -674,8 +675,15 @@ main(int argc, char **argv)
setvbuf(stdout, NULL, _IOLBF, 0);
+ if ((sock_path = getenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME)) == NULL &&
+ (sock_path = getenv(SSH_AUTHSOCKET_ENV_NAME)) == NULL) {
+ fprintf(stderr, "No $%s or $%s socket found\n",
+ SSH_AUTHSOCKET_ENV_NAME, SSH_AUTHSOCKET_LOCAL_ENV_NAME);
+ exit(2);
+ }
+
/* First, get a connection to the authentication agent. */
- switch (r = ssh_get_authentication_socket(&agent_fd)) {
+ switch (r = ssh_get_authentication_socket_path(sock_path, &agent_fd)) {
case 0:
break;
case SSH_ERR_AGENT_NOT_PRESENT:
diff --git a/ssh-agent.1 b/ssh-agent.1
index 2cf4616..c7e37fa 100644
--- a/ssh-agent.1
+++ b/ssh-agent.1
@@ -43,7 +43,7 @@
.Sh SYNOPSIS
.Nm ssh-agent
.Op Fl c | s
-.Op Fl \&Dd
+.Op Fl \&DdL
.Op Fl a Ar bind_address
.Op Fl E Ar fingerprint_hash
.Op Fl P Ar allowed_providers
@@ -102,6 +102,16 @@ The default is
Kill the current agent (given by the
.Ev SSH_AGENT_PID
environment variable).
+.It Fl L
+Makes
+.Nm
+listen on only the primary
+.Ev SSH_AUTH_SOCK
+instead of both that and
+.Ev SSH_AUTH_SOCK_LOCAL .
+This flag will also remove the default restrictions on adding smartcard or
+FIDO key by the main
+.Ev SSH_AUTH_SOCK .
.It Fl P Ar allowed_providers
Specify a pattern-list of acceptable paths for PKCS#11 provider and FIDO
authenticator middleware shared libraries that may be used with the
@@ -203,8 +213,25 @@ When
starts, it creates a
.Ux Ns -domain
socket and stores its pathname in this variable.
+This socket is used for communication with
+.Nm
+by
+.Xr ssh-add 1 ,
+.Xr ssh 1
+and other tools.
It is accessible only to the current user,
but is easily abused by root or another instance of the same user.
+.It Ev SSH_AUTH_SOCK_LOCAL
+Is another
+.Ux Ns -domain
+socket
+started by
+.Nm .
+It is intended to be used only locally and never forwarded by
+.Xr ssh 1 .
+This socket is permitted to perform additional operations, such as adding
+FIDO or smartcard keys that is by default restricted on the primary
+.Ev SSH_AUTH_SOCK .
.El
.Sh FILES
.Bl -tag -width Ds
diff --git a/ssh-agent.c b/ssh-agent.c
index 86d771e..152b8d9 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -91,7 +91,9 @@
typedef enum {
AUTH_UNUSED,
AUTH_SOCKET,
- AUTH_CONNECTION
+ AUTH_SOCKET_LOCAL,
+ AUTH_CONNECTION,
+ AUTH_CONNECTION_LOCAL,
} sock_type;
typedef struct {
@@ -132,9 +134,10 @@ time_t parent_alive_interval = 0;
/* pid of process for which cleanup_socket is applicable */
pid_t cleanup_pid = 0;
-/* pathname and directory for AUTH_SOCKET */
-char socket_name[PATH_MAX];
-char socket_dir[PATH_MAX];
+/* pathname and directory for AUTH_SOCKET and AUTH_SOCKET_LOCAL */
+static char socket_name[PATH_MAX];
+static char localsocket_name[PATH_MAX];
+static char socket_dir[PATH_MAX];
/* Pattern-list of allowed PKCS#11/Security key paths */
static char *allowed_providers;
@@ -495,7 +498,7 @@ reaper(void)
}
static void
-process_add_identity(SocketEntry *e)
+process_add_identity(SocketEntry *e, int islocal)
{
Identity *id;
int success = 0, confirm = 0;
@@ -586,6 +589,11 @@ process_add_identity(SocketEntry *e)
free(sk_provider);
goto send;
}
+ if (!islocal) {
+ error("Refusing add FIDO key from forwarded agent");
+ free(sk_provider);
+ goto send;
+ }
if (strcasecmp(sk_provider, "internal") == 0) {
debug("%s: internal provider", __func__);
} else {
@@ -712,7 +720,7 @@ no_identities(SocketEntry *e)
#ifdef ENABLE_PKCS11
static void
-process_add_smartcard_key(SocketEntry *e)
+process_add_smartcard_key(SocketEntry *e, int islocal)
{
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
char **comments = NULL;
@@ -751,6 +759,10 @@ process_add_smartcard_key(SocketEntry *e)
goto send;
}
}
+ if (!islocal) {
+ error("Refusing add of smartcard key from forwarded agent");
+ goto send;
+ }
if (realpath(provider, canonical_provider) == NULL) {
verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
provider, strerror(errno));
@@ -843,7 +855,7 @@ send:
* returns 1 on success, 0 for incomplete messages or -1 on error.
*/
static int
-process_message(u_int socknum)
+process_message(u_int socknum, int islocal)
{
u_int msg_len;
u_char type;
@@ -915,7 +927,7 @@ process_message(u_int socknum)
break;
case SSH2_AGENTC_ADD_IDENTITY:
case SSH2_AGENTC_ADD_ID_CONSTRAINED:
- process_add_identity(e);
+ process_add_identity(e, islocal);
break;
case SSH2_AGENTC_REMOVE_IDENTITY:
process_remove_identity(e);
@@ -926,7 +938,7 @@ process_message(u_int socknum)
#ifdef ENABLE_PKCS11
case SSH_AGENTC_ADD_SMARTCARD_KEY:
case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
- process_add_smartcard_key(e);
+ process_add_smartcard_key(e, islocal);
break;
case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
process_remove_smartcard_key(e);
@@ -981,7 +993,7 @@ new_socket(sock_type type, int fd)
}
static int
-handle_socket_read(u_int socknum)
+handle_socket_read(u_int socknum, int islocal)
{
struct sockaddr_un sunaddr;
socklen_t slen;
@@ -992,7 +1004,8 @@ handle_socket_read(u_int socknum)
slen = sizeof(sunaddr);
fd = accept(sockets[socknum].fd, (struct sockaddr *)&sunaddr, &slen);
if (fd == -1) {
- error("accept from AUTH_SOCKET: %s", strerror(errno));
+ error("accept from %s auth socket: %s",
+ islocal ? "local" : "remote", strerror(errno));
return -1;
}
if (getpeereid(fd, &euid, &egid) == -1) {
@@ -1006,12 +1019,12 @@ handle_socket_read(u_int socknum)
close(fd);
return -1;
}
- new_socket(AUTH_CONNECTION, fd);
+ new_socket(islocal ? AUTH_CONNECTION_LOCAL : AUTH_CONNECTION, fd);
return 0;
}
static int
-handle_conn_read(u_int socknum)
+handle_conn_read(u_int socknum, int islocal)
{
char buf[AGENT_RBUF_LEN];
ssize_t len;
@@ -1031,7 +1044,7 @@ handle_conn_read(u_int socknum)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
explicit_bzero(buf, sizeof(buf));
for (;;) {
- if ((r = process_message(socknum)) == -1)
+ if ((r = process_message(socknum, islocal)) == -1)
return -1;
else if (r == 0)
break;
@@ -1069,15 +1082,22 @@ after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
{
size_t i;
u_int socknum, activefds = npfd;
+ SocketEntry *s;
for (i = 0; i < npfd; i++) {
if (pfd[i].revents == 0)
continue;
/* Find sockets entry */
for (socknum = 0; socknum < sockets_alloc; socknum++) {
- if (sockets[socknum].type != AUTH_SOCKET &&
- sockets[socknum].type != AUTH_CONNECTION)
+ switch (sockets[socknum].type) {
+ case AUTH_SOCKET:
+ case AUTH_SOCKET_LOCAL:
+ case AUTH_CONNECTION:
+ case AUTH_CONNECTION_LOCAL:
+ break;
+ default:
continue;
+ }
if (pfd[i].fd == sockets[socknum].fd)
break;
}
@@ -1086,8 +1106,10 @@ after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
continue;
}
/* Process events */
- switch (sockets[socknum].type) {
+ s = sockets + socknum;
+ switch (s->type) {
case AUTH_SOCKET:
+ case AUTH_SOCKET_LOCAL:
if ((pfd[i].revents & (POLLIN|POLLERR)) == 0)
break;
if (npfd > maxfds) {
@@ -1095,12 +1117,15 @@ after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
"skipping accept", activefds, maxfds);
break;
}
- if (handle_socket_read(socknum) == 0)
+ if (handle_socket_read(socknum,
+ s->type == AUTH_SOCKET_LOCAL) == 0)
activefds++;
break;
case AUTH_CONNECTION:
+ case AUTH_CONNECTION_LOCAL:
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
- handle_conn_read(socknum) != 0) {
+ handle_conn_read(socknum,
+ s->type == AUTH_CONNECTION_LOCAL) != 0) {
goto close_sock;
}
if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
@@ -1131,7 +1156,9 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
for (i = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
+ case AUTH_SOCKET_LOCAL:
case AUTH_CONNECTION:
+ case AUTH_CONNECTION_LOCAL:
npfd++;
break;
case AUTH_UNUSED:
@@ -1150,6 +1177,7 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
for (i = j = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
+ case AUTH_SOCKET_LOCAL:
if (npfd > maxfds) {
debug3("out of fds (active %zu >= limit %u); "
"skipping arming listener", npfd, maxfds);
@@ -1161,6 +1189,7 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
j++;
break;
case AUTH_CONNECTION:
+ case AUTH_CONNECTION_LOCAL:
pfd[j].fd = sockets[i].fd;
pfd[j].revents = 0;
/*
@@ -1207,6 +1236,8 @@ cleanup_socket(void)
debug("%s: cleanup", __func__);
if (socket_name[0])
unlink(socket_name);
+ if (localsocket_name[0])
+ unlink(localsocket_name);
if (socket_dir[0])
rmdir(socket_dir);
}
@@ -1247,9 +1278,9 @@ static void
usage(void)
{
fprintf(stderr,
- "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
+ "usage: ssh-agent [-c | -s] [-DdL] [-a bind_address] [-E fingerprint_hash]\n"
" [-P allowed_providers] [-t life]\n"
- " ssh-agent [-a bind_address] [-E fingerprint_hash] [-P allowed_providers]\n"
+ " ssh-agent [-DdL] [-a bind_address] [-E fingerprint_hash] [-P allowed_providers]\n"
" [-t life] command [arg ...]\n"
" ssh-agent [-c | -s] -k\n");
exit(1);
@@ -1259,7 +1290,8 @@ 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 L_flag = 0;
+ int sock, localsock = -1, ch, result, saved_errno;
char *shell, *format, *pidstr, *agentsocket = NULL;
struct rlimit rlim;
extern int optind;
@@ -1287,7 +1319,7 @@ main(int ac, char **av)
OpenSSL_add_all_algorithms();
#endif
- while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) {
+ while ((ch = getopt(ac, av, "cDdkLsE:a:O:P:t:")) != -1) {
switch (ch) {
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -1302,6 +1334,9 @@ main(int ac, char **av)
case 'k':
k_flag++;
break;
+ case 'L':
+ L_flag = 1;
+ break;
case 'O':
if (strcmp(optarg, "no-restrict-websafe") == 0)
restrict_websafe = 0;
@@ -1403,12 +1438,20 @@ main(int ac, char **av)
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);
+ if (!L_flag) {
+ snprintf(localsocket_name, sizeof localsocket_name,
+ "%s/agent.local.%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 (!L_flag) {
+ snprintf(localsocket_name, sizeof localsocket_name,
+ "%s.local", agentsocket);
+ }
}
/*
@@ -1422,6 +1465,14 @@ main(int ac, char **av)
*socket_name = '\0'; /* Don't unlink any existing file */
cleanup_exit(1);
}
+ if (*localsocket_name != '\0') {
+ localsock = unix_listener(localsocket_name,
+ SSH_LISTEN_BACKLOG, 0);
+ if (localsock < 0) {
+ *localsocket_name = '\0';
+ cleanup_exit(1);
+ }
+ }
umask(prev_mask);
/*
@@ -1435,6 +1486,10 @@ main(int ac, char **av)
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
+ if (*localsocket_name != '\0') {
+ printf(format, SSH_AUTHSOCKET_LOCAL_ENV_NAME,
+ localsocket_name, SSH_AUTHSOCKET_LOCAL_ENV_NAME);
+ }
printf("echo Agent pid %ld;\n", (long)parent_pid);
fflush(stdout);
goto skip;
@@ -1451,13 +1506,21 @@ main(int ac, char **av)
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
+ if (*localsocket_name != '\0') {
+ printf(format, SSH_AUTHSOCKET_LOCAL_ENV_NAME,
+ localsocket_name,
+ SSH_AUTHSOCKET_LOCAL_ENV_NAME);
+ }
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
SSH_AGENTPID_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)pid);
exit(0);
}
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
- setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
+ setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1 ||
+ (*localsocket_name != '\0' &&
+ setenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME,
+ localsocket_name, 1) == -1)) {
perror("setenv");
exit(1);
}
@@ -1491,7 +1554,13 @@ skip:
#ifdef ENABLE_PKCS11
pkcs11_init(0);
#endif
- new_socket(AUTH_SOCKET, sock);
+ if (localsock != -1) {
+ new_socket(AUTH_SOCKET_LOCAL, localsock);
+ new_socket(AUTH_SOCKET, sock);
+ } else {
+ new_socket(AUTH_SOCKET_LOCAL, sock);
+ }
+
if (ac > 0)
parent_alive_interval = 10;
idtab_init();
diff --git a/ssh.h b/ssh.h
index e40f04a..146cecc 100644
--- a/ssh.h
+++ b/ssh.h
@@ -62,6 +62,12 @@
*/
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
+/*
+ * Name of the environment variable containing the pathname of the
+ * local authentication socket.
+ */
+#define SSH_AUTHSOCKET_LOCAL_ENV_NAME "SSH_AUTH_SOCK_LOCAL"
+
/*
* Environment variable for overwriting the default location of askpass
*/
--
2.28.0
-------------- next part --------------
From 378a659110b144dde0fd35d8dc0186f533f5947a Mon Sep 17 00:00:00 2001
From: Damien Miller <djm at mindrot.org>
Date: Thu, 10 Sep 2020 12:05:17 +1000
Subject: [PATCH 2/4] add ssh_get_authentication_socket_local()
This prefers the SSH_AUTH_SOCK_LOCAL socket, but will fall back
---
authfd.c | 13 +++++++++++++
authfd.h | 1 +
ssh-add.c | 10 +---------
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/authfd.c b/authfd.c
index ab5b2b7..861b9f5 100644
--- a/authfd.c
+++ b/authfd.c
@@ -132,6 +132,19 @@ ssh_get_authentication_socket(int *fdp)
return ssh_get_authentication_socket_path(authsocket, fdp);
}
+/* Opens the authentication socket, preferring the privileged local socket */
+int
+ssh_get_authentication_socket_local(int *fdp)
+{
+ const char *authsocket;
+
+ if (fdp != NULL)
+ *fdp = -1;
+ if ((authsocket = getenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME)) != NULL)
+ return ssh_get_authentication_socket_path(authsocket, fdp);
+ return ssh_get_authentication_socket(fdp);
+}
+
/* Communicate with agent: send request and read reply */
static int
ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
diff --git a/authfd.h b/authfd.h
index 4fbf82f..fc81ecc 100644
--- a/authfd.h
+++ b/authfd.h
@@ -24,6 +24,7 @@ struct ssh_identitylist {
};
int ssh_get_authentication_socket(int *fdp);
+int ssh_get_authentication_socket_local(int *fdp);
int ssh_get_authentication_socket_path(const char *authsocket, int *fdp);
void ssh_close_authentication_socket(int sock);
diff --git a/ssh-add.c b/ssh-add.c
index 6ce1142..4e112dc 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -658,7 +658,6 @@ main(int argc, char **argv)
extern char *optarg;
extern int optind;
int agent_fd;
- const char *sock_path;
char *pkcs11provider = NULL, *skprovider = NULL;
int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
@@ -675,15 +674,8 @@ main(int argc, char **argv)
setvbuf(stdout, NULL, _IOLBF, 0);
- if ((sock_path = getenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME)) == NULL &&
- (sock_path = getenv(SSH_AUTHSOCKET_ENV_NAME)) == NULL) {
- fprintf(stderr, "No $%s or $%s socket found\n",
- SSH_AUTHSOCKET_ENV_NAME, SSH_AUTHSOCKET_LOCAL_ENV_NAME);
- exit(2);
- }
-
/* First, get a connection to the authentication agent. */
- switch (r = ssh_get_authentication_socket_path(sock_path, &agent_fd)) {
+ switch (r = ssh_get_authentication_socket_local(&agent_fd)) {
case 0:
break;
case SSH_ERR_AGENT_NOT_PRESENT:
--
2.28.0
-------------- next part --------------
From 16fbc4aeff8f896995c16134d892326e7872fd83 Mon Sep 17 00:00:00 2001
From: Damien Miller <djm at mindrot.org>
Date: Thu, 10 Sep 2020 12:08:43 +1000
Subject: [PATCH 3/4] prefer local agent socket for non-forwarding cases
---
ssh-keygen.c | 4 ++--
sshconnect.c | 2 +-
sshconnect2.c | 4 ++--
sshd.c | 6 +++---
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 703a5fb..fcc0b3e 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1749,7 +1749,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
fatal("Cannot load CA public key %s: %s",
tmp, ssh_err(r));
- if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
+ if ((r = ssh_get_authentication_socket_local(&agent_fd)) != 0)
fatal("Cannot use public key for CA signature: %s",
ssh_err(r));
if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0)
@@ -2623,7 +2623,7 @@ sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
goto done;
}
- if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
+ if ((r = ssh_get_authentication_socket_local(&agent_fd)) != 0)
debug("Couldn't get agent socket: %s", ssh_err(r));
else {
if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0)
diff --git a/sshconnect.c b/sshconnect.c
index f9323eb..00c4267 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1400,7 +1400,7 @@ maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
if (options.add_keys_to_agent == 0)
return;
- if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
+ if ((r = ssh_get_authentication_socket_local(&auth_sock)) != 0) {
debug3("no authentication agent, not adding key");
return;
}
diff --git a/sshconnect2.c b/sshconnect2.c
index 2aca328..d7697c8 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1674,9 +1674,9 @@ pubkey_prepare(Authctxt *authctxt)
TAILQ_INSERT_TAIL(preferred, id, next);
}
/* list of keys supported by the agent */
- if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
+ if ((r = ssh_get_authentication_socket_local(&agent_fd)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
- debug("%s: ssh_get_authentication_socket: %s",
+ debug("%s: ssh_get_authentication_socket_local: %s",
__func__, ssh_err(r));
} else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
diff --git a/sshd.c b/sshd.c
index f944c7e..5088dee 100644
--- a/sshd.c
+++ b/sshd.c
@@ -465,7 +465,7 @@ privsep_preauth(struct ssh *ssh)
pmonitor->m_pid = pid;
if (have_agent) {
- r = ssh_get_authentication_socket(&auth_sock);
+ r = ssh_get_authentication_socket_local(&auth_sock);
if (r != 0) {
error("Could not get agent socket: %s",
ssh_err(r));
@@ -1685,7 +1685,7 @@ main(int ac, char **av)
if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
setenv(SSH_AUTHSOCKET_ENV_NAME,
options.host_key_agent, 1);
- if ((r = ssh_get_authentication_socket(NULL)) == 0)
+ if ((r = ssh_get_authentication_socket_local(NULL)) == 0)
have_agent = 1;
else
error("Could not connect to agent \"%s\": %s",
@@ -2066,7 +2066,7 @@ main(int ac, char **av)
if (privsep_preauth(ssh) == 1)
goto authenticated;
} else if (have_agent) {
- if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
+ if ((r = ssh_get_authentication_socket_local(&auth_sock)) != 0) {
error("Unable to get agent socket: %s", ssh_err(r));
have_agent = 0;
}
--
2.28.0
-------------- next part --------------
From 0552c5c3c552bc18240eca9c77ae2e272df053d4 Mon Sep 17 00:00:00 2001
From: Damien Miller <djm at mindrot.org>
Date: Thu, 10 Sep 2020 13:10:53 +1000
Subject: [PATCH 4/4] implement unforwardable agent keys
This adds a new a do-not-forward at openssh.com key constraint that tells
the agent to only offer the key over the SSH_AUTH_SOCK_LOCAL socket
and never by the default SSH_AUTH_SOCK. This restriction may be set
when adding keys using "ssh-add -r key [...]"
ssh will only ever forward SSH_AUTH_SOCK unless explicitly instructed
so, unless the user overrides something, restricted keys will not be
usable off the host running ssh-agent.
---
authfd.c | 19 ++++++++----
authfd.h | 4 +--
ssh-add.c | 38 ++++++++++++++----------
ssh-agent.c | 83 ++++++++++++++++++++++++++++++++++++++--------------
ssh.1 | 8 +++--
sshconnect.c | 3 +-
6 files changed, 107 insertions(+), 48 deletions(-)
diff --git a/authfd.c b/authfd.c
index 861b9f5..f1177d0 100644
--- a/authfd.c
+++ b/authfd.c
@@ -450,7 +450,7 @@ ssh_agent_sign(int sock, const struct sshkey *key,
static int
encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
- const char *provider)
+ const char *provider, u_int local)
{
int r;
@@ -476,6 +476,13 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
(r = sshbuf_put_cstring(m, provider)) != 0)
goto out;
}
+ if (local != 0) {
+ if ((r = sshbuf_put_u8(m,
+ SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
+ (r = sshbuf_put_cstring(m,
+ "do-not-forward at openssh.com")) != 0)
+ goto out;
+ }
r = 0;
out:
return r;
@@ -488,10 +495,10 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
int
ssh_add_identity_constrained(int sock, struct sshkey *key,
const char *comment, u_int life, u_int confirm, u_int maxsign,
- const char *provider)
+ const char *provider, u_int local)
{
struct sshbuf *msg;
- int r, constrained = (life || confirm || maxsign || provider);
+ int r, constrained = (life || confirm || maxsign || provider || local);
u_char type;
if ((msg = sshbuf_new()) == NULL)
@@ -529,7 +536,7 @@ ssh_add_identity_constrained(int sock, struct sshkey *key,
}
if (constrained &&
(r = encode_constraints(msg, life, confirm, maxsign,
- provider)) != 0)
+ provider, local)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
@@ -585,7 +592,7 @@ ssh_remove_identity(int sock, const struct sshkey *key)
*/
int
ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
- u_int life, u_int confirm)
+ u_int life, u_int confirm, u_int local)
{
struct sshbuf *msg;
int r, constrained = (life || confirm);
@@ -605,7 +612,7 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
(r = sshbuf_put_cstring(msg, pin)) != 0)
goto out;
if (constrained &&
- (r = encode_constraints(msg, life, confirm, 0, NULL)) != 0)
+ (r = encode_constraints(msg, life, confirm, 0, NULL, local)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
diff --git a/authfd.h b/authfd.h
index fc81ecc..6888350 100644
--- a/authfd.h
+++ b/authfd.h
@@ -33,11 +33,11 @@ int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
void ssh_free_identitylist(struct ssh_identitylist *idl);
int ssh_add_identity_constrained(int sock, struct sshkey *key,
const char *comment, u_int life, u_int confirm, u_int maxsign,
- const char *provider);
+ const char *provider, u_int local);
int ssh_agent_has_key(int sock, const struct sshkey *key);
int ssh_remove_identity(int sock, const struct sshkey *key);
int ssh_update_card(int sock, int add, const char *reader_id,
- const char *pin, u_int life, u_int confirm);
+ const char *pin, u_int life, u_int confirm, u_int local);
int ssh_remove_all_identities(int sock, int version);
int ssh_agent_sign(int sock, const struct sshkey *key,
diff --git a/ssh-add.c b/ssh-add.c
index 4e112dc..aae0ad7 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -225,7 +225,7 @@ delete_all(int agent_fd, int qflag)
static int
add_file(int agent_fd, const char *filename, int key_only, int qflag,
- const char *skprovider)
+ int localonly, const char *skprovider)
{
struct sshkey *private, *cert;
char *comment = NULL;
@@ -359,7 +359,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
}
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
- lifetime, confirm, maxsign, skprovider)) == 0) {
+ lifetime, confirm, maxsign, skprovider, localonly)) == 0) {
ret = 0;
if (!qflag) {
fprintf(stderr, "Identity added: %s (%s)\n",
@@ -412,7 +412,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
sshkey_free(cert);
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
- lifetime, confirm, maxsign, skprovider)) != 0) {
+ lifetime, confirm, maxsign, skprovider, localonly)) != 0) {
error("Certificate %s (%s) add failed: %s", certpath,
private->cert->key_id, ssh_err(r));
goto out;
@@ -440,7 +440,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
}
static int
-update_card(int agent_fd, int add, const char *id, int qflag)
+update_card(int agent_fd, int add, const char *id, int qflag, int rflag)
{
char *pin = NULL;
int r, ret = -1;
@@ -452,7 +452,7 @@ update_card(int agent_fd, int add, const char *id, int qflag)
}
if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin,
- lifetime, confirm)) == 0) {
+ lifetime, confirm, rflag)) == 0) {
ret = 0;
if (!qflag) {
fprintf(stderr, "Card %s: %s\n",
@@ -575,7 +575,7 @@ lock_agent(int agent_fd, int lock)
}
static int
-load_resident_keys(int agent_fd, const char *skprovider, int qflag)
+load_resident_keys(int agent_fd, const char *skprovider, int qflag, int rflag)
{
struct sshkey **keys;
size_t nkeys, i;
@@ -593,7 +593,7 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag)
fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint failed", __func__);
if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "",
- lifetime, confirm, maxsign, skprovider)) != 0) {
+ lifetime, confirm, maxsign, skprovider, rflag)) != 0) {
error("Unable to add key %s %s",
sshkey_type(keys[i]), fp);
free(fp);
@@ -625,13 +625,14 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag)
static int
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
- const char *skprovider)
+ int rflag, const char *skprovider)
{
if (deleting) {
if (delete_file(agent_fd, file, key_only, qflag) == -1)
return -1;
} else {
- if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1)
+ if (add_file(agent_fd, file, key_only, qflag, rflag,
+ skprovider) == -1)
return -1;
}
return 0;
@@ -660,7 +661,7 @@ main(int argc, char **argv)
int agent_fd;
char *pkcs11provider = NULL, *skprovider = NULL;
int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
- int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
+ int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, rflag = 0, Tflag = 0;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
LogLevel log_level = SYSLOG_LEVEL_INFO;
@@ -689,7 +690,7 @@ main(int argc, char **argv)
skprovider = getenv("SSH_SK_PROVIDER");
- while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) {
+ while ((ch = getopt(argc, argv, "cDdKkLlrTvXxE:e:M:m:qS:s:t:")) != -1) {
switch (ch) {
case 'v':
if (log_level == SYSLOG_LEVEL_INFO)
@@ -755,6 +756,9 @@ main(int argc, char **argv)
deleting = 1;
pkcs11provider = optarg;
break;
+ case 'r':
+ rflag = 1;
+ break;
case 't':
if ((lifetime = convtime(optarg)) == -1 ||
lifetime < 0 || (u_long)lifetime > UINT32_MAX) {
@@ -792,6 +796,10 @@ main(int argc, char **argv)
ret = 1;
goto done;
}
+ if (rflag && getenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME) == NULL) {
+ fatal("Local-only restriction requested by no $%s agent "
+ "socket present", SSH_AUTHSOCKET_LOCAL_ENV_NAME);
+ }
if (skprovider == NULL)
skprovider = "internal";
@@ -808,14 +816,14 @@ main(int argc, char **argv)
}
if (pkcs11provider != NULL) {
if (update_card(agent_fd, !deleting, pkcs11provider,
- qflag) == -1)
+ qflag, rflag) == -1)
ret = 1;
goto done;
}
if (do_download) {
if (skprovider == NULL)
fatal("Cannot download keys without provider");
- if (load_resident_keys(agent_fd, skprovider, qflag) != 0)
+ if (load_resident_keys(agent_fd, skprovider, qflag, rflag) != 0)
ret = 1;
goto done;
}
@@ -838,7 +846,7 @@ main(int argc, char **argv)
if (stat(buf, &st) == -1)
continue;
if (do_file(agent_fd, deleting, key_only, buf,
- qflag, skprovider) == -1)
+ qflag, rflag, skprovider) == -1)
ret = 1;
else
count++;
@@ -848,7 +856,7 @@ main(int argc, char **argv)
} else {
for (i = 0; i < argc; i++) {
if (do_file(agent_fd, deleting, key_only,
- argv[i], qflag, skprovider) == -1)
+ argv[i], qflag, rflag, skprovider) == -1)
ret = 1;
}
}
diff --git a/ssh-agent.c b/ssh-agent.c
index 152b8d9..f69c67b 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -114,6 +114,7 @@ typedef struct identity {
char *provider;
time_t death;
u_int confirm;
+ int localonly;
char *sk_provider;
} Identity;
@@ -232,18 +233,35 @@ send_status(SocketEntry *e, int success)
/* send list of supported public keys to 'client' */
static void
-process_request_identities(SocketEntry *e)
+process_request_identities(SocketEntry *e, int islocal)
{
Identity *id;
struct sshbuf *msg;
int r;
+ u_int ntotal = 0, nentries = 0;
if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
+
+ /* count visible keys */
+ TAILQ_FOREACH(id, &idtab->idlist, next) {
+ ntotal++;
+ if (id->localonly && !islocal)
+ continue;
+ nentries++;
+ }
+ debug2("%s: start local=%d, returning %u/%u", __func__, islocal,
+ nentries, ntotal);
+
+ /* reply header */
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
- (r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
+ (r = sshbuf_put_u32(msg, nentries)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
+
+ /* append visible keys */
TAILQ_FOREACH(id, &idtab->idlist, next) {
+ if (id->localonly && !islocal)
+ continue;
if ((r = sshkey_puts_opts(id->key, msg, SSHKEY_SERIALIZE_INFO))
!= 0 ||
(r = sshbuf_put_cstring(msg, id->comment)) != 0) {
@@ -351,7 +369,7 @@ check_websafe_message_contents(struct sshkey *key,
/* ssh2 only */
static void
-process_sign_request2(SocketEntry *e)
+process_sign_request2(SocketEntry *e, int islocal)
{
const u_char *data;
u_char *signature = NULL;
@@ -372,11 +390,15 @@ process_sign_request2(SocketEntry *e)
error("%s: couldn't parse request: %s", __func__, ssh_err(r));
goto send;
}
-
if ((id = lookup_identity(key)) == NULL) {
verbose("%s: %s key not found", __func__, sshkey_type(key));
goto send;
}
+ if (id->localonly && !islocal) {
+ verbose("%s: attempt to use local %s key via remote agent",
+ __func__, sshkey_type(key));
+ goto send;
+ }
if (id->confirm && confirm_key(id) != 0) {
verbose("%s: user refused key", __func__);
goto send;
@@ -425,7 +447,7 @@ process_sign_request2(SocketEntry *e)
/* shared */
static void
-process_remove_identity(SocketEntry *e)
+process_remove_identity(SocketEntry *e, int islocal)
{
int r, success = 0;
struct sshkey *key = NULL;
@@ -439,6 +461,11 @@ process_remove_identity(SocketEntry *e)
debug("%s: key not found", __func__);
goto done;
}
+ if (id->localonly && !islocal) {
+ verbose("%s: attempt to remove local %s key via remote agent",
+ __func__, sshkey_type(key));
+ goto done;
+ }
/* We have this key, free it. */
if (idtab->nentries < 1)
fatal("%s: internal error: nentries %d",
@@ -501,9 +528,9 @@ static void
process_add_identity(SocketEntry *e, int islocal)
{
Identity *id;
- int success = 0, confirm = 0;
+ int success = 0, confirm = 0, localonly = 0;
u_int seconds = 0, maxsign;
- char *fp, *comment = NULL, *ext_name = NULL, *sk_provider = NULL;
+ char *fp = NULL, *comment = NULL, *ext_name = NULL, *sk_provider = NULL;
char canonical_provider[PATH_MAX];
time_t death = 0;
struct sshkey *k = NULL;
@@ -564,6 +591,13 @@ process_add_identity(SocketEntry *e, int islocal)
__func__, ext_name, ssh_err(r));
goto err;
}
+ } else if (strcmp(ext_name, "do-not-forward at openssh.com") == 0) {
+ if (!islocal) {
+ error("Refusing add local-only key on "
+ "forwarded connection");
+ goto send;
+ }
+ localonly = 1;
} else {
error("%s: unsupported constraint \"%s\"",
__func__, ext_name);
@@ -574,11 +608,8 @@ process_add_identity(SocketEntry *e, int islocal)
default:
error("%s: Unknown constraint %d", __func__, ctype);
err:
- free(sk_provider);
free(ext_name);
sshbuf_reset(e->request);
- free(comment);
- sshkey_free(k);
goto send;
}
}
@@ -586,12 +617,10 @@ process_add_identity(SocketEntry *e, int islocal)
if (!sshkey_is_sk(k)) {
error("Cannot add provider: %s is not an "
"authenticator-hosted key", sshkey_type(k));
- free(sk_provider);
goto send;
}
if (!islocal) {
error("Refusing add FIDO key from forwarded agent");
- free(sk_provider);
goto send;
}
if (strcasecmp(sk_provider, "internal") == 0) {
@@ -601,7 +630,6 @@ process_add_identity(SocketEntry *e, int islocal)
verbose("failed provider \"%.100s\": "
"realpath: %s", sk_provider,
strerror(errno));
- free(sk_provider);
goto send;
}
free(sk_provider);
@@ -610,7 +638,6 @@ process_add_identity(SocketEntry *e, int islocal)
allowed_providers, 0) != 1) {
error("Refusing add key: "
"provider %s not allowed", sk_provider);
- free(sk_provider);
goto send;
}
}
@@ -638,16 +665,26 @@ process_add_identity(SocketEntry *e, int islocal)
id->comment = comment;
id->death = death;
id->confirm = confirm;
+ id->localonly = localonly;
id->sk_provider = sk_provider;
if ((fp = sshkey_fingerprint(k, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint failed", __func__);
debug("%s: add %s %s \"%.100s\" (life: %u) (confirm: %u) "
- "(provider: %s)", __func__, sshkey_ssh_name(k), fp, comment,
- seconds, confirm, sk_provider == NULL ? "none" : sk_provider);
- free(fp);
+ "(local: %s) (provider: %s)", __func__, sshkey_ssh_name(k), fp,
+ comment, seconds, confirm, localonly ? "YES" : "NO",
+ sk_provider == NULL ? "none" : sk_provider);
+
+ /* transferred */
+ k = NULL;
+ comment = NULL;
+ sk_provider = NULL;
send:
+ free(fp);
+ sshkey_free(k);
+ free(comment);
+ free(sk_provider);
send_status(e, success);
}
@@ -809,7 +846,7 @@ send:
}
static void
-process_remove_smartcard_key(SocketEntry *e)
+process_remove_smartcard_key(SocketEntry *e, int islocal)
{
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
int r, success = 0;
@@ -831,6 +868,8 @@ process_remove_smartcard_key(SocketEntry *e)
debug("%s: remove %.100s", __func__, canonical_provider);
for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
nxt = TAILQ_NEXT(id, next);
+ if (id->localonly && !islocal)
+ continue;
/* Skip file--based keys */
if (id->provider == NULL)
continue;
@@ -920,17 +959,17 @@ process_message(u_int socknum, int islocal)
break;
/* ssh2 */
case SSH2_AGENTC_SIGN_REQUEST:
- process_sign_request2(e);
+ process_sign_request2(e, islocal);
break;
case SSH2_AGENTC_REQUEST_IDENTITIES:
- process_request_identities(e);
+ process_request_identities(e, islocal);
break;
case SSH2_AGENTC_ADD_IDENTITY:
case SSH2_AGENTC_ADD_ID_CONSTRAINED:
process_add_identity(e, islocal);
break;
case SSH2_AGENTC_REMOVE_IDENTITY:
- process_remove_identity(e);
+ process_remove_identity(e, islocal);
break;
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e);
@@ -941,7 +980,7 @@ process_message(u_int socknum, int islocal)
process_add_smartcard_key(e, islocal);
break;
case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
- process_remove_smartcard_key(e);
+ process_remove_smartcard_key(e, islocal);
break;
#endif /* ENABLE_PKCS11 */
default:
diff --git a/ssh.1 b/ssh.1
index 5553178..9cb3ec8 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1428,10 +1428,14 @@ then the askpass program will be used for all passphrase input regardless
of whether
.Ev DISPLAY
is set.
-.It Ev SSH_AUTH_SOCK
-Identifies the path of a
+.It Ev SSH_AUTH_SOCK | Ev SSH_AUTH_SOCK_LOCAL
+Identifies paths of a
.Ux Ns -domain
socket used to communicate with the agent.
+.Ev SSH_AUTH_SOCK_LOCAL
+is preferred for user authentication.
+.Ev SSH_AUTH_SOCK
+is used for forwarding.
.It Ev SSH_CONNECTION
Identifies the client and server ends of the connection.
The variable contains
diff --git a/sshconnect.c b/sshconnect.c
index 00c4267..b9274d6 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1416,7 +1416,8 @@ maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
if ((r = ssh_add_identity_constrained(auth_sock, private,
comment == NULL ? authfile : comment,
options.add_keys_to_agent_lifespan,
- (options.add_keys_to_agent == 3), 0, skprovider)) == 0)
+ (options.add_keys_to_agent == 3), 0, skprovider,
+ getenv(SSH_AUTHSOCKET_LOCAL_ENV_NAME) == NULL)) == 0)
debug("identity added to agent: %s", authfile);
else
debug("could not add identity to agent: %s (%d)", authfile, r);
--
2.28.0
More information about the openssh-unix-dev
mailing list