]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream commit
authorjcs@openbsd.org <jcs@openbsd.org>
Sun, 15 Nov 2015 22:26:49 +0000 (22:26 +0000)
committerDamien Miller <djm@mindrot.org>
Mon, 16 Nov 2015 00:31:39 +0000 (11:31 +1100)
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

readconf.c
readconf.h
ssh-agent.1
ssh.1
ssh_config.5
sshconnect.c
sshconnect.h
sshconnect1.c
sshconnect2.c

index c062433cec45fb91847b77d903aa5b319d8d17ab..0a380913f79f7fd3dfe86b2488697e66f34e3e4a 100644 (file)
@@ -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, "~/",
index 6d6927f0667fd85553ee0bd4d9ac57c40e824342..2034bfd9d465ae0d9b79aabac3c214b4e752bdc8 100644 (file)
@@ -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;
index 5a521cb562e46727e80163fbd171c28f42fb13c9..dabc5c46bf8673022f3ab7eaa73a82432bb2e1d8 100644 (file)
@@ -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
diff --git a/ssh.1 b/ssh.1
index c4b7250a5e463ab8c830dc74945d32567c91155c..5b35b6cc0c45289019aec85c77b76aeaf563985c 100644 (file)
--- a/ssh.1
+++ b/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:
index 39cf932d3e0f6e6308b500ff3d3445412b470741..e6673b1037bfbbf0543b9290b661f355e60fa657 100644 (file)
@@ -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
index c9f88e03554ea3f1aa8cefec08fbb8c7e8d210c7..19d393f7b0e4471c3891cfa4994ef6ace852d8e2 100644 (file)
@@ -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);
+}
index 0ea6e99f6171704a2436797e66dd9b8bc3fa6ed3..cf1851a959b75216d6da78c09369e325b5d6a57a 100644 (file)
@@ -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.
  */
index 016abbce5fbd20768fd68cb9df6412551457c73e..bfc523bde3176fc47615314bdda66a8948f6e257 100644 (file)
@@ -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);
 
index 3ab686e86c74c28bd1bf49386c8b312ac5e1c3b0..69d0bee4e09a4f2443c27c9509efb00b6e11c278 100644 (file)
@@ -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;