upstream commit
Add an AddKeysToAgent client option which can be set to 'yes', 'no', 'ask', or 'confirm', and defaults to 'no'. When enabled, a private key that is used during authentication will be added to ssh-agent if it is running (with confirmation enabled if set to 'confirm'). Initial version from Joachim Schipper many years ago. ok markus@ Upstream-ID: a680db2248e8064ec55f8be72d539458c987d5f4
This commit is contained in:
parent
d87063d9ba
commit
f361df474c
22
readconf.c
22
readconf.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: readconf.c,v 1.245 2015/10/27 08:54:52 djm Exp $ */
|
||||
/* $OpenBSD: readconf.c,v 1.246 2015/11/15 22:26:49 jcs Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -135,7 +135,7 @@ typedef enum {
|
|||
oPasswordAuthentication, oRSAAuthentication,
|
||||
oChallengeResponseAuthentication, oXAuthLocation,
|
||||
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
|
||||
oCertificateFile,
|
||||
oCertificateFile, oAddKeysToAgent,
|
||||
oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
|
||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
|
@ -204,6 +204,7 @@ static struct {
|
|||
{ "identityfile2", oIdentityFile }, /* obsolete */
|
||||
{ "identitiesonly", oIdentitiesOnly },
|
||||
{ "certificatefile", oCertificateFile },
|
||||
{ "addkeystoagent", oAddKeysToAgent },
|
||||
{ "hostname", oHostName },
|
||||
{ "hostkeyalias", oHostKeyAlias },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
|
@ -712,6 +713,15 @@ static const struct multistate multistate_yesnoask[] = {
|
|||
{ "ask", 2 },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
static const struct multistate multistate_yesnoaskconfirm[] = {
|
||||
{ "true", 1 },
|
||||
{ "false", 0 },
|
||||
{ "yes", 1 },
|
||||
{ "no", 0 },
|
||||
{ "ask", 2 },
|
||||
{ "confirm", 3 },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
static const struct multistate multistate_addressfamily[] = {
|
||||
{ "inet", AF_INET },
|
||||
{ "inet6", AF_INET6 },
|
||||
|
@ -1533,6 +1543,11 @@ parse_keytypes:
|
|||
charptr = &options->pubkey_key_types;
|
||||
goto parse_keytypes;
|
||||
|
||||
case oAddKeysToAgent:
|
||||
intptr = &options->add_keys_to_agent;
|
||||
multistate_ptr = multistate_yesnoaskconfirm;
|
||||
goto parse_multistate;
|
||||
|
||||
case oDeprecated:
|
||||
debug("%s line %d: Deprecated option \"%s\"",
|
||||
filename, linenum, keyword);
|
||||
|
@ -1699,6 +1714,7 @@ initialize_options(Options * options)
|
|||
options->local_command = NULL;
|
||||
options->permit_local_command = -1;
|
||||
options->use_roaming = -1;
|
||||
options->add_keys_to_agent = -1;
|
||||
options->visual_host_key = -1;
|
||||
options->ip_qos_interactive = -1;
|
||||
options->ip_qos_bulk = -1;
|
||||
|
@ -1803,6 +1819,8 @@ fill_default_options(Options * options)
|
|||
/* options->hostkeyalgorithms, default set in myproposals.h */
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_2;
|
||||
if (options->add_keys_to_agent == -1)
|
||||
options->add_keys_to_agent = 0;
|
||||
if (options->num_identity_files == 0) {
|
||||
if (options->protocol & SSH_PROTO_1) {
|
||||
add_identity_file(options, "~/",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: readconf.h,v 1.111 2015/09/24 06:15:11 djm Exp $ */
|
||||
/* $OpenBSD: readconf.h,v 1.112 2015/11/15 22:26:49 jcs Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -100,6 +100,8 @@ typedef struct {
|
|||
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
|
||||
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
|
||||
|
||||
int add_keys_to_agent;
|
||||
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
struct Forward *local_forwards;
|
||||
|
|
11
ssh-agent.1
11
ssh-agent.1
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: ssh-agent.1,v 1.60 2015/11/05 09:48:05 jmc Exp $
|
||||
.\" $OpenBSD: ssh-agent.1,v 1.61 2015/11/15 22:26:49 jcs Exp $
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@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: November 5 2015 $
|
||||
.Dd $Mdocdate: November 15 2015 $
|
||||
.Dt SSH-AGENT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -66,6 +66,13 @@ machines using
|
|||
.Pp
|
||||
The agent initially does not have any private keys.
|
||||
Keys are added using
|
||||
.Xr ssh 1
|
||||
(see
|
||||
.Cm AddKeysToAgent
|
||||
in
|
||||
.Xr ssh_config 5
|
||||
for details)
|
||||
or
|
||||
.Xr ssh-add 1 .
|
||||
Multiple identities may be stored in
|
||||
.Nm
|
||||
|
|
9
ssh.1
9
ssh.1
|
@ -33,8 +33,8 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh.1,v 1.365 2015/11/06 00:31:41 mmcc Exp $
|
||||
.Dd $Mdocdate: November 6 2015 $
|
||||
.\" $OpenBSD: ssh.1,v 1.366 2015/11/15 22:26:49 jcs Exp $
|
||||
.Dd $Mdocdate: November 15 2015 $
|
||||
.Dt SSH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -462,6 +462,7 @@ For full details of the options listed below, and their possible values, see
|
|||
.Xr ssh_config 5 .
|
||||
.Pp
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It AddKeysToAgent
|
||||
.It AddressFamily
|
||||
.It BatchMode
|
||||
.It BindAddress
|
||||
|
@ -926,6 +927,10 @@ The most convenient way to use public key or certificate authentication
|
|||
may be with an authentication agent.
|
||||
See
|
||||
.Xr ssh-agent 1
|
||||
and (optionally) the
|
||||
.Cm AddKeysToAgent
|
||||
directive in
|
||||
.Xr ssh_config 5
|
||||
for more information.
|
||||
.Pp
|
||||
Challenge-response authentication works as follows:
|
||||
|
|
37
ssh_config.5
37
ssh_config.5
|
@ -33,8 +33,8 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh_config.5,v 1.221 2015/09/24 06:15:11 djm Exp $
|
||||
.Dd $Mdocdate: September 24 2015 $
|
||||
.\" $OpenBSD: ssh_config.5,v 1.222 2015/11/15 22:26:49 jcs Exp $
|
||||
.Dd $Mdocdate: November 15 2015 $
|
||||
.Dt SSH_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -221,6 +221,39 @@ keyword matches against the name of the local user running
|
|||
(this keyword may be useful in system-wide
|
||||
.Nm
|
||||
files).
|
||||
.It Cm AddKeysToAgent
|
||||
Specifies whether keys should be automatically added to a running
|
||||
.Xr ssh-agent 5 .
|
||||
If this option is set to
|
||||
.Dq yes
|
||||
and a key is loaded from a file, the key and its passphrase are added to
|
||||
the agent with the default lifetime, as if by
|
||||
.Xr ssh-add 1 .
|
||||
If this option is set to
|
||||
.Dq ask ,
|
||||
.Nm ssh
|
||||
will require confirmation using the
|
||||
.Ev SSH_ASKPASS
|
||||
program before adding a key (see
|
||||
.Xr ssh-add 1
|
||||
for details).
|
||||
If this option is set to
|
||||
.Dq confirm ,
|
||||
each use of the key must be confirmed, as if the
|
||||
.Fl c
|
||||
option was specified to
|
||||
.Xr ssh-add 1 .
|
||||
If this option is set to
|
||||
.Dq no ,
|
||||
no keys are added to the agent.
|
||||
The argument must be
|
||||
.Dq yes ,
|
||||
.Dq confirm ,
|
||||
.Dq ask ,
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm AddressFamily
|
||||
Specifies which address family to use when connecting.
|
||||
Valid arguments are
|
||||
|
|
30
sshconnect.c
30
sshconnect.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect.c,v 1.265 2015/09/04 04:55:24 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect.c,v 1.266 2015/11/15 22:26:49 jcs Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -65,6 +65,7 @@
|
|||
#include "version.h"
|
||||
#include "authfile.h"
|
||||
#include "ssherr.h"
|
||||
#include "authfd.h"
|
||||
|
||||
char *client_version_string = NULL;
|
||||
char *server_version_string = NULL;
|
||||
|
@ -1487,3 +1488,30 @@ ssh_local_cmd(const char *args)
|
|||
|
||||
return (WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
void
|
||||
maybe_add_key_to_agent(char *authfile, Key *private, char *comment,
|
||||
char *passphrase)
|
||||
{
|
||||
int auth_sock = -1, r;
|
||||
|
||||
if (options.add_keys_to_agent == 0)
|
||||
return;
|
||||
|
||||
if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
|
||||
debug3("no authentication agent, not adding key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.add_keys_to_agent == 2 &&
|
||||
!ask_permission("Add key %s (%s) to agent?", authfile, comment)) {
|
||||
debug3("user denied adding this key");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((r = ssh_add_identity_constrained(auth_sock, private, comment, 0,
|
||||
(options.add_keys_to_agent == 3))) == 0)
|
||||
debug("identity added to agent: %s", authfile);
|
||||
else
|
||||
debug("could not add identity to agent: %s (%d)", authfile, r);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect.h,v 1.28 2013/10/16 02:31:47 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect.h,v 1.29 2015/11/15 22:26:49 jcs Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
|
@ -55,6 +55,8 @@ void ssh_userauth2(const char *, const char *, char *, Sensitive *);
|
|||
void ssh_put_password(char *);
|
||||
int ssh_local_cmd(const char *);
|
||||
|
||||
void maybe_add_key_to_agent(char *, Key *, char *, char *);
|
||||
|
||||
/*
|
||||
* Macros to raise/lower permissions.
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect1.c,v 1.77 2015/01/14 20:05:27 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect1.c,v 1.78 2015/11/15 22:26:49 jcs Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -221,7 +221,7 @@ try_rsa_authentication(int idx)
|
|||
{
|
||||
BIGNUM *challenge;
|
||||
Key *public, *private;
|
||||
char buf[300], *passphrase, *comment, *authfile;
|
||||
char buf[300], *passphrase = NULL, *comment, *authfile;
|
||||
int i, perm_ok = 1, type, quit;
|
||||
|
||||
public = options.identity_keys[idx];
|
||||
|
@ -283,13 +283,20 @@ try_rsa_authentication(int idx)
|
|||
debug2("no passphrase given, try next key");
|
||||
quit = 1;
|
||||
}
|
||||
explicit_bzero(passphrase, strlen(passphrase));
|
||||
free(passphrase);
|
||||
if (private != NULL || quit)
|
||||
break;
|
||||
debug2("bad passphrase given, try again...");
|
||||
}
|
||||
}
|
||||
|
||||
if (private != NULL)
|
||||
maybe_add_key_to_agent(authfile, private, comment, passphrase);
|
||||
|
||||
if (passphrase != NULL) {
|
||||
explicit_bzero(passphrase, strlen(passphrase));
|
||||
free(passphrase);
|
||||
}
|
||||
|
||||
/* We no longer need the comment. */
|
||||
free(comment);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect2.c,v 1.228 2015/10/13 16:15:21 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect2.c,v 1.229 2015/11/15 22:26:49 jcs Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||
|
@ -313,7 +313,7 @@ void userauth(Authctxt *, char *);
|
|||
static int sign_and_send_pubkey(Authctxt *, Identity *);
|
||||
static void pubkey_prepare(Authctxt *);
|
||||
static void pubkey_cleanup(Authctxt *);
|
||||
static Key *load_identity_file(char *, int);
|
||||
static Key *load_identity_file(Identity *);
|
||||
|
||||
static Authmethod *authmethod_get(char *authlist);
|
||||
static Authmethod *authmethod_lookup(const char *name);
|
||||
|
@ -990,7 +990,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
|||
return (sshkey_sign(id->key, sigp, lenp, data, datalen,
|
||||
compat));
|
||||
/* load the private key from the file */
|
||||
if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL)
|
||||
if ((prv = load_identity_file(id)) == NULL)
|
||||
return (-1); /* XXX return decent error code */
|
||||
ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat);
|
||||
sshkey_free(prv);
|
||||
|
@ -1147,20 +1147,20 @@ send_pubkey_test(Authctxt *authctxt, Identity *id)
|
|||
}
|
||||
|
||||
static Key *
|
||||
load_identity_file(char *filename, int userprovided)
|
||||
load_identity_file(Identity *id)
|
||||
{
|
||||
Key *private;
|
||||
char prompt[300], *passphrase;
|
||||
char prompt[300], *passphrase, *comment;
|
||||
int r, perm_ok = 0, quit = 0, i;
|
||||
struct stat st;
|
||||
|
||||
if (stat(filename, &st) < 0) {
|
||||
(userprovided ? logit : debug3)("no such identity: %s: %s",
|
||||
filename, strerror(errno));
|
||||
if (stat(id->filename, &st) < 0) {
|
||||
(id->userprovided ? logit : debug3)("no such identity: %s: %s",
|
||||
id->filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
snprintf(prompt, sizeof prompt,
|
||||
"Enter passphrase for key '%.100s': ", filename);
|
||||
"Enter passphrase for key '%.100s': ", id->filename);
|
||||
for (i = 0; i <= options.number_of_password_prompts; i++) {
|
||||
if (i == 0)
|
||||
passphrase = "";
|
||||
|
@ -1172,8 +1172,8 @@ load_identity_file(char *filename, int userprovided)
|
|||
break;
|
||||
}
|
||||
}
|
||||
switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename,
|
||||
passphrase, &private, NULL, &perm_ok))) {
|
||||
switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename,
|
||||
passphrase, &private, &comment, &perm_ok))) {
|
||||
case 0:
|
||||
break;
|
||||
case SSH_ERR_KEY_WRONG_PASSPHRASE:
|
||||
|
@ -1187,20 +1187,26 @@ load_identity_file(char *filename, int userprovided)
|
|||
case SSH_ERR_SYSTEM_ERROR:
|
||||
if (errno == ENOENT) {
|
||||
debug2("Load key \"%s\": %s",
|
||||
filename, ssh_err(r));
|
||||
id->filename, ssh_err(r));
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
error("Load key \"%s\": %s", filename, ssh_err(r));
|
||||
error("Load key \"%s\": %s", id->filename, ssh_err(r));
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
if (!quit && private != NULL && !id->agent_fd &&
|
||||
!(id->key && id->isprivate))
|
||||
maybe_add_key_to_agent(id->filename, private, comment,
|
||||
passphrase);
|
||||
if (i > 0) {
|
||||
explicit_bzero(passphrase, strlen(passphrase));
|
||||
free(passphrase);
|
||||
}
|
||||
if (comment)
|
||||
free(comment);
|
||||
if (private != NULL || quit)
|
||||
break;
|
||||
}
|
||||
|
@ -1403,8 +1409,7 @@ userauth_pubkey(Authctxt *authctxt)
|
|||
}
|
||||
} else {
|
||||
debug("Trying private key: %s", id->filename);
|
||||
id->key = load_identity_file(id->filename,
|
||||
id->userprovided);
|
||||
id->key = load_identity_file(id);
|
||||
if (id->key != NULL) {
|
||||
if (try_identity(id)) {
|
||||
id->isprivate = 1;
|
||||
|
|
Loading…
Reference in New Issue