From: djm Date: Fri, 24 Jan 2003 00:36:23 +0000 (+0000) Subject: - markus@cvs.openbsd.org 2003/01/23 13:50:27 X-Git-Tag: V_3_6_P1~63 X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/commitdiff_plain/c4087616f1a10711c137daf020267a2557417138 - markus@cvs.openbsd.org 2003/01/23 13:50:27 [authfd.c authfd.h readpass.c ssh-add.1 ssh-add.c ssh-agent.c] ssh-add -c, prompt user for confirmation (using ssh-askpass) when private agent key is used; with djm@; test by dugsong@, djm@; ok deraadt@ --- diff --git a/ChangeLog b/ChangeLog index 20e8be23..43c50412 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,11 @@ - jmc@cvs.openbsd.org 2003/01/23 08:58:47 [sshd_config.5] typos; ok millert@ + - markus@cvs.openbsd.org 2003/01/23 13:50:27 + [authfd.c authfd.h readpass.c ssh-add.1 ssh-add.c ssh-agent.c] + ssh-add -c, prompt user for confirmation (using ssh-askpass) when + private agent key is used; with djm@; test by dugsong@, djm@; + ok deraadt@ 20030123 - (djm) OpenBSD CVS Sync diff --git a/authfd.c b/authfd.c index f04e0858..a186e011 100644 --- a/authfd.c +++ b/authfd.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.57 2002/09/11 18:27:26 stevesk Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.58 2003/01/23 13:50:27 markus Exp $"); #include @@ -499,10 +499,10 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) int ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, - const char *comment, u_int life) + const char *comment, u_int life, u_int confirm) { Buffer msg; - int type, constrained = (life != 0); + int type, constrained = (life || confirm); buffer_init(&msg); @@ -532,6 +532,8 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); buffer_put_int(&msg, life); } + if (confirm != 0) + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); } if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); @@ -545,7 +547,7 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, int ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) { - return ssh_add_identity_constrained(auth, key, comment, 0); + return ssh_add_identity_constrained(auth, key, comment, 0, 0); } /* diff --git a/authfd.h b/authfd.h index 38ee49e8..2a8751ec 100644 --- a/authfd.h +++ b/authfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.h,v 1.31 2002/09/11 18:27:25 stevesk Exp $ */ +/* $OpenBSD: authfd.h,v 1.32 2003/01/23 13:50:27 markus Exp $ */ /* * Author: Tatu Ylonen @@ -51,6 +51,7 @@ #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 #define SSH_AGENT_CONSTRAIN_LIFETIME 1 +#define SSH_AGENT_CONSTRAIN_CONFIRM 2 /* extended failure messages */ #define SSH2_AGENT_FAILURE 30 @@ -76,7 +77,8 @@ int ssh_get_num_identities(AuthenticationConnection *, int); Key *ssh_get_first_identity(AuthenticationConnection *, char **, int); Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); int ssh_add_identity(AuthenticationConnection *, Key *, const char *); -int ssh_add_identity_constrained(AuthenticationConnection *, Key *, const char *, u_int); +int ssh_add_identity_constrained(AuthenticationConnection *, Key *, + const char *, u_int, u_int); int ssh_remove_identity(AuthenticationConnection *, Key *); int ssh_remove_all_identities(AuthenticationConnection *, int); int ssh_lock_agent(AuthenticationConnection *, int, const char *); diff --git a/readpass.c b/readpass.c index 96b7e84b..95ec5d87 100644 --- a/readpass.c +++ b/readpass.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readpass.c,v 1.27 2002/03/26 15:58:46 markus Exp $"); +RCSID("$OpenBSD: readpass.c,v 1.28 2003/01/23 13:50:27 markus Exp $"); #include "xmalloc.h" #include "readpass.h" @@ -46,11 +46,11 @@ ssh_askpass(char *askpass, const char *msg) fatal("internal error: askpass undefined"); if (pipe(p) < 0) { error("ssh_askpass: pipe: %s", strerror(errno)); - return xstrdup(""); + return NULL; } if ((pid = fork()) < 0) { error("ssh_askpass: fork: %s", strerror(errno)); - return xstrdup(""); + return NULL; } if (pid == 0) { seteuid(getuid()); @@ -79,6 +79,11 @@ ssh_askpass(char *askpass, const char *msg) if (errno != EINTR) break; + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + memset(buf, 0, sizeof(buf)); + return NULL; + } + buf[strcspn(buf, "\r\n")] = '\0'; pass = xstrdup(buf); memset(buf, 0, sizeof(buf)); @@ -115,7 +120,10 @@ read_passphrase(const char *prompt, int flags) askpass = getenv(SSH_ASKPASS_ENV); else askpass = _PATH_SSH_ASKPASS_DEFAULT; - return ssh_askpass(askpass, prompt); + if ((ret = ssh_askpass(askpass, prompt)) == NULL) + if (!(flags & RP_ALLOW_EOF)) + return xstrdup(""); + return ret; } if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { diff --git a/ssh-add.1 b/ssh-add.1 index 2a34a513..66a8f971 100644 --- a/ssh-add.1 +++ b/ssh-add.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-add.1,v 1.35 2002/06/19 00:27:55 deraadt Exp $ +.\" $OpenBSD: ssh-add.1,v 1.36 2003/01/23 13:50:27 markus Exp $ .\" .\" -*- nroff -*- .\" @@ -45,7 +45,7 @@ .Nd adds RSA or DSA identities to the authentication agent .Sh SYNOPSIS .Nm ssh-add -.Op Fl lLdDxX +.Op Fl lLdDxXc .Op Fl t Ar life .Op Ar .Nm ssh-add @@ -93,6 +93,14 @@ Set a maximum lifetime when adding identities to an agent. The lifetime may be specified in seconds or in a time format specified in .Xr sshd 8 . +.It Fl c +Indicates that added identities should be subject to confirmation before +being used for authentication. Confirmation is performed by the +.Ev SSH_ASKPASS +program mentioned below. Successful confirmation is signaled by a zero +exit status from the +.Ev SSH_ASKPASS +program, rather than text entered into the requester. .It Fl s Ar reader Add key in smartcard .Ar reader . diff --git a/ssh-add.c b/ssh-add.c index 4f4ab3a0..0c2ce163 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-add.c,v 1.64 2002/11/21 23:03:51 deraadt Exp $"); +RCSID("$OpenBSD: ssh-add.c,v 1.65 2003/01/23 13:50:27 markus Exp $"); #include @@ -70,6 +70,9 @@ static char *default_files[] = { /* Default lifetime (0 == forever) */ static int lifetime = 0; +/* User has to confirm key use */ +static int confirm = 0; + /* we keep a cache of one passphrases */ static char *pass = NULL; static void @@ -165,12 +168,16 @@ add_file(AuthenticationConnection *ac, const char *filename) } } - if (ssh_add_identity_constrained(ac, private, comment, lifetime)) { + if (ssh_add_identity_constrained(ac, private, comment, lifetime, + confirm)) { fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); ret = 0; if (lifetime != 0) fprintf(stderr, "Lifetime set to %d seconds\n", lifetime); + if (confirm != 0) + fprintf(stderr, + "The user has to confirm each use of the key\n"); } else if (ssh_add_identity(ac, private, comment)) { fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); ret = 0; @@ -292,6 +299,7 @@ usage(void) fprintf(stderr, " -x Lock agent.\n"); fprintf(stderr, " -X Unlock agent.\n"); fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); + fprintf(stderr, " -c Require confirmation to sign using identities\n"); #ifdef SMARTCARD fprintf(stderr, " -s reader Add key in smartcard reader.\n"); fprintf(stderr, " -e reader Remove key in smartcard reader.\n"); @@ -319,7 +327,7 @@ main(int argc, char **argv) fprintf(stderr, "Could not open a connection to your authentication agent.\n"); exit(2); } - while ((ch = getopt(argc, argv, "lLdDxXe:s:t:")) != -1) { + while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) { switch (ch) { case 'l': case 'L': @@ -333,6 +341,9 @@ main(int argc, char **argv) ret = 1; goto done; break; + case 'c': + confirm = 1; + break; case 'd': deleting = 1; break; diff --git a/ssh-agent.c b/ssh-agent.c index 554f8942..b18dd980 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -35,7 +35,7 @@ #include "includes.h" #include "openbsd-compat/sys-queue.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.106 2003/01/21 18:14:36 marc Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.107 2003/01/23 13:50:27 markus Exp $"); #include #include @@ -50,6 +50,8 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.106 2003/01/21 18:14:36 marc Exp $"); #include "authfd.h" #include "compat.h" #include "log.h" +#include "readpass.h" +#include "misc.h" #ifdef SMARTCARD #include "scard.h" @@ -77,6 +79,7 @@ typedef struct identity { Key *key; char *comment; u_int death; + u_int confirm; } Identity; typedef struct { @@ -162,6 +165,30 @@ lookup_identity(Key *key, int version) return (NULL); } +/* Check confirmation of keysign request */ +static int +confirm_key(Identity *id) +{ + char *p, prompt[1024]; + int ret = -1; + + p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); + snprintf(prompt, sizeof(prompt), "Allow use of key %s?\n" + "Key fingerprint %s.", id->comment, p); + xfree(p); + p = read_passphrase(prompt, RP_ALLOW_EOF); + if (p != NULL) { + /* + * Accept empty responses and responses consisting + * of the word "yes" as affirmative. + */ + if (*p == '\0' || *p == '\n' || strcasecmp(p, "yes") == 0) + ret = 0; + xfree(p); + } + return (ret); +} + /* send list of supported public keys to 'client' */ static void process_request_identities(SocketEntry *e, int version) @@ -225,7 +252,7 @@ process_authentication_challenge1(SocketEntry *e) goto failure; id = lookup_identity(key, 1); - if (id != NULL) { + if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { Key *private = id->key; /* Decrypt the challenge using the private key. */ if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) @@ -285,7 +312,7 @@ process_sign_request2(SocketEntry *e) key = key_from_blob(blob, blen); if (key != NULL) { Identity *id = lookup_identity(key, 2); - if (id != NULL) + if (id != NULL && (!id->confirm || confirm_key(id) == 0)) ok = key_sign(id->key, &signature, &slen, data, dlen); } key_free(key); @@ -405,7 +432,7 @@ static void process_add_identity(SocketEntry *e, int version) { Idtab *tab = idtab_lookup(version); - int type, success = 0, death = 0; + int type, success = 0, death = 0, confirm = 0; char *type_name, *comment; Key *k = NULL; @@ -467,6 +494,9 @@ process_add_identity(SocketEntry *e, int version) case SSH_AGENT_CONSTRAIN_LIFETIME: death = time(NULL) + buffer_get_int(&e->request); break; + case SSH_AGENT_CONSTRAIN_CONFIRM: + confirm = 1; + break; default: break; } @@ -478,6 +508,7 @@ process_add_identity(SocketEntry *e, int version) id->key = k; id->comment = comment; id->death = death; + id->confirm = confirm; TAILQ_INSERT_TAIL(&tab->idlist, id, next); /* Increment the number of identities. */ tab->nentries++; @@ -562,6 +593,7 @@ process_add_smartcard_key (SocketEntry *e) id->key = k; id->comment = xstrdup("smartcard key"); id->death = 0; + id->confirm = 0; TAILQ_INSERT_TAIL(&tab->idlist, id, next); tab->nentries++; success = 1; @@ -942,7 +974,8 @@ usage(void) int main(int ac, char **av) { - int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc; + int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; + int sock, fd, ch, nalloc; char *shell, *format, *pidstr, *agentsocket = NULL; fd_set *readsetp = NULL, *writesetp = NULL; struct sockaddr_un sunaddr; @@ -1128,9 +1161,14 @@ main(int ac, char **av) } (void)chdir("/"); - close(0); - close(1); - close(2); + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + /* XXX might close listen socket */ + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } #ifdef HAVE_SETRLIMIT /* deny core dumps, since memory contains unencrypted private keys */