From a2431e7ad6a99821a09e9e3037faf89e15d3b2a3 Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Wed, 18 Mar 2015 11:46:16 +0100 Subject: [PATCH] Add an identity to the agent automatically when loading the identity Updated patch from https://bugzilla.mindrot.org/show_bug.cgi?id=2191 Originally by Tomohiro Matsuyama. --- readconf.c | 39 +++++++++++++++++++++++++++++++++++++++ readconf.h | 4 ++++ sshconnect2.c | 31 ++++++++++++++++++++++++------- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git readconf.c readconf.c index 42a2961..4eb0bae 100644 --- readconf.c +++ readconf.c @@ -148,6 +148,7 @@ typedef enum { oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oIdentityPersist, oIdentityPersistConfirm, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, @@ -249,6 +250,8 @@ static struct { { "addressfamily", oAddressFamily }, { "serveraliveinterval", oServerAliveInterval }, { "serveralivecountmax", oServerAliveCountMax }, + { "identitypersist", oIdentityPersist }, + { "identitypersistconfirm", oIdentityPersistConfirm }, { "sendenv", oSendEnv }, { "controlpath", oControlPath }, { "controlmaster", oControlMaster }, @@ -1274,6 +1277,33 @@ parse_int: intptr = &options->server_alive_count_max; goto parse_int; + case oIdentityPersist: + /* no/false/yes/true, or a time spec */ + intptr = &options->identity_persist; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing IdentityPersist" + " argument.", filename, linenum); + value = 0; + value2 = 0; /* lifetime */ + if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) + value = 0; + else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) + value = 1; + else if ((value2 = convtime(arg)) >= 0) + value = 1; + else + fatal("%.200s line %d: Bad IdentityPersist argument.", + filename, linenum); + if (*activep && *intptr == -1) { + *intptr = value; + options->identity_persist_lifetime = value2; + } + break; + case oIdentityPersistConfirm: + intptr = &options->identity_persist_confirm; + goto parse_flag; + case oSendEnv: while ((arg = strdelim(&s)) != NULL && *arg != '\0') { if (strchr(arg, '=') != NULL) @@ -1649,6 +1679,9 @@ initialize_options(Options * options) options->verify_host_key_dns = -1; options->server_alive_interval = -1; options->server_alive_count_max = -1; + options->identity_persist = -1; + options->identity_persist_lifetime = -1; + options->identity_persist_confirm = -1; options->num_send_env = 0; options->control_path = NULL; options->control_master = -1; @@ -1819,6 +1852,12 @@ fill_default_options(Options * options) options->server_alive_interval = 0; if (options->server_alive_count_max == -1) options->server_alive_count_max = 3; + if (options->identity_persist == -1) + options->identity_persist = 0; + if (options->identity_persist_lifetime == -1) + options->identity_persist_lifetime = 0; + if (options->identity_persist_confirm == -1) + options->identity_persist_confirm = 0; if (options->control_master == -1) options->control_master = 0; if (options->control_persist == -1) { diff --git readconf.h readconf.h index 576b9e3..bc0b2ce 100644 --- readconf.h +++ readconf.h @@ -112,6 +112,10 @@ typedef struct { int server_alive_interval; int server_alive_count_max; + int identity_persist; + int identity_persist_lifetime; + int identity_persist_confirm; + int num_send_env; char *send_env[MAX_SEND_ENV]; diff --git sshconnect2.c sshconnect2.c index ba56f64..5058e7c 100644 --- sshconnect2.c +++ sshconnect2.c @@ -320,7 +320,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(Authctxt *, char *, int); static Authmethod *authmethod_get(char *authlist); static Authmethod *authmethod_lookup(const char *name); @@ -978,7 +978,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) } static int -identity_sign(struct identity *id, u_char **sigp, size_t *lenp, +identity_sign(Authctxt *authctxt, struct identity *id, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { Key *prv; @@ -997,7 +997,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(authctxt, id->filename, id->userprovided)) == NULL) return (-1); /* XXX return decent error code */ ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); sshkey_free(prv); @@ -1052,7 +1052,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) buffer_put_string(&b, blob, bloblen); /* generate signature */ - ret = identity_sign(id, &signature, &slen, + ret = identity_sign(authctxt, id, &signature, &slen, buffer_ptr(&b), buffer_len(&b), datafellows); if (ret != 0) { free(blob); @@ -1125,11 +1125,13 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) } static Key * -load_identity_file(char *filename, int userprovided) +load_identity_file(Authctxt *authctxt, char *filename, int userprovided) { Key *private; char prompt[300], *passphrase; + char *comment = NULL; int r, perm_ok = 0, quit = 0, i; + int agent_fd = -1; struct stat st; if (stat(filename, &st) < 0) { @@ -1151,8 +1153,23 @@ load_identity_file(char *filename, int userprovided) } } switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, - passphrase, &private, NULL, &perm_ok))) { + passphrase, &private, &comment, &perm_ok))) { case 0: + ssh_get_authentication_socket(&agent_fd); + if (authctxt && agent_fd && + private && options.identity_persist) { + if (comment == NULL) + comment = xstrdup(filename); + if (ssh_add_identity_constrained(agent_fd, + private, comment, + options.identity_persist_lifetime, + options.identity_persist_confirm) == 0) { + fprintf(stderr, + "Identity added: %s (%s) %d\n", + filename, comment, agent_fd); + } + free(comment); + } break; case SSH_ERR_KEY_WRONG_PASSPHRASE: if (options.batch_mode) { @@ -1344,7 +1361,7 @@ userauth_pubkey(Authctxt *authctxt) } } else { debug("Trying private key: %s", id->filename); - id->key = load_identity_file(id->filename, + id->key = load_identity_file(authctxt, id->filename, id->userprovided); if (id->key != NULL) { id->isprivate = 1; -- 2.3.3