X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/9fd2a2156b8bd6b8cf563a70e3ac6a83cb729201..ca71903419fcc62ab0bec1f92f50788030a8d231:/ssh-agent.c diff --git a/ssh-agent.c b/ssh-agent.c index d4c008bb..61ea3458 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.103 2002/09/10 20:24:47 markus Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.110 2003/06/11 11:18:38 djm Exp $"); #include #include @@ -50,6 +50,8 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.103 2002/09/10 20:24:47 markus 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 { @@ -106,6 +109,9 @@ extern char *__progname; char *__progname; #endif +/* Default lifetime (0 == forever) */ +static int lifetime = 0; + static void close_socket(SocketEntry *e) { @@ -159,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) @@ -222,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) @@ -231,7 +261,7 @@ process_authentication_challenge1(SocketEntry *e) /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); if (len <= 0 || len > 32) { - log("process_authentication_challenge: bad challenge length %d", len); + logit("process_authentication_challenge: bad challenge length %d", len); goto failure; } memset(buf, 0, 32); @@ -282,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); @@ -320,7 +350,7 @@ process_remove_identity(SocketEntry *e, int version) buffer_get_bignum(&e->request, key->rsa->n); if (bits != key_size(key)) - log("Warning: identity keysize mismatch: actual %u, announced %u", + logit("Warning: identity keysize mismatch: actual %u, announced %u", key_size(key), bits); break; case 2: @@ -402,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; @@ -453,6 +483,17 @@ process_add_identity(SocketEntry *e, int version) } break; } + /* enable blinding */ + switch (k->type) { + case KEY_RSA: + case KEY_RSA1: + if (RSA_blinding_on(k->rsa, NULL) != 1) { + error("process_add_identity: RSA_blinding_on failed"); + key_free(k); + goto send; + } + break; + } comment = buffer_get_string(&e->request, NULL); if (k == NULL) { xfree(comment); @@ -464,15 +505,21 @@ 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; } } + if (lifetime && !death) + death = time(NULL) + lifetime; if (lookup_identity(k, version) == NULL) { Identity *id = xmalloc(sizeof(Identity)); 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++; @@ -533,13 +580,29 @@ static void process_add_smartcard_key (SocketEntry *e) { char *sc_reader_id = NULL, *pin; - int i, version, success = 0; + int i, version, success = 0, death = 0, confirm = 0; Key **keys, *k; Identity *id; Idtab *tab; sc_reader_id = buffer_get_string(&e->request, NULL); pin = buffer_get_string(&e->request, NULL); + + while (buffer_len(&e->request)) { + switch (buffer_get_char(&e->request)) { + case SSH_AGENT_CONSTRAIN_LIFETIME: + death = time(NULL) + buffer_get_int(&e->request); + break; + case SSH_AGENT_CONSTRAIN_CONFIRM: + confirm = 1; + break; + default: + break; + } + } + if (lifetime && !death) + death = time(NULL) + lifetime; + keys = sc_get_keys(sc_reader_id, pin); xfree(sc_reader_id); xfree(pin); @@ -556,7 +619,8 @@ process_add_smartcard_key (SocketEntry *e) id = xmalloc(sizeof(Identity)); id->key = k; id->comment = xstrdup("smartcard key"); - id->death = 0; + id->death = death; + id->confirm = confirm; TAILQ_INSERT_TAIL(&tab->idlist, id, next); tab->nentries++; success = 1; @@ -700,6 +764,7 @@ process_message(SocketEntry *e) break; #ifdef SMARTCARD case SSH_AGENTC_ADD_SMARTCARD_KEY: + case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: process_add_smartcard_key(e); break; case SSH_AGENTC_REMOVE_SMARTCARD_KEY: @@ -833,10 +898,10 @@ after_select(fd_set *readset, fd_set *writeset) close(sock); break; } - if (getuid() != euid) { + if ((euid != 0) && (getuid() != euid)) { error("uid mismatch: " - "peer euid %d != uid %d", - (int) euid, (int) getuid()); + "peer euid %u != uid %u", + (u_int) euid, (u_int) getuid()); close(sock); break; } @@ -914,7 +979,7 @@ check_parent_exists(int sig) /* printf("Parent has died - Authentication agent exiting.\n"); */ cleanup_handler(sig); /* safe */ } - signal(SIGALRM, check_parent_exists); + mysignal(SIGALRM, check_parent_exists); alarm(10); errno = save_errno; } @@ -930,13 +995,15 @@ usage(void) fprintf(stderr, " -k Kill the current agent.\n"); fprintf(stderr, " -d Debug mode.\n"); fprintf(stderr, " -a socket Bind agent socket to given name.\n"); + fprintf(stderr, " -t life Default identity lifetime (seconds).\n"); exit(1); } 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; @@ -961,7 +1028,7 @@ main(int ac, char **av) init_rng(); seed_rng(); - while ((ch = getopt(ac, av, "cdksa:")) != -1) { + while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { switch (ch) { case 'c': if (s_flag) @@ -984,6 +1051,12 @@ main(int ac, char **av) case 'a': agentsocket = optarg; break; + case 't': + if ((lifetime = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid lifetime\n"); + usage(); + } + break; default: usage(); } @@ -1116,9 +1189,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 */ @@ -1133,7 +1211,7 @@ skip: fatal_add_cleanup(cleanup_socket, NULL); new_socket(AUTH_SOCKET, sock); if (ac > 0) { - signal(SIGALRM, check_parent_exists); + mysignal(SIGALRM, check_parent_exists); alarm(10); } idtab_init();