Skip to content

Commit

Permalink
upstream commit
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jcs authored and djmdjm committed Nov 16, 2015
1 parent d87063d commit f361df4
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 30 deletions.
22 changes: 20 additions & 2 deletions readconf.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
* Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -204,6 +204,7 @@ static struct {
{ "identityfile2", oIdentityFile }, /* obsolete */
{ "identitiesonly", oIdentitiesOnly },
{ "certificatefile", oCertificateFile },
{ "addkeystoagent", oAddKeysToAgent },
{ "hostname", oHostName },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand },
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -1533,6 +1543,11 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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, "~/",
Expand Down
4 changes: 3 additions & 1 deletion readconf.h
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 9 additions & 2 deletions ssh-agent.1
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
.\" Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions ssh.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
37 changes: 35 additions & 2 deletions ssh_config.5
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
30 changes: 29 additions & 1 deletion sshconnect.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
* Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
4 changes: 3 additions & 1 deletion sshconnect.h
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
*/
Expand Down
15 changes: 11 additions & 4 deletions sshconnect1.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
* Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);

Expand Down
35 changes: 20 additions & 15 deletions sshconnect2.c
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 = "";
Expand All @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit f361df4

Please sign in to comment.