X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/7efa84825b00b20d70e16b43176f1d1ef8a7ac11..23aa123701299d88160cdd67e871a2244082afa6:/ssh-agent.c diff --git a/ssh-agent.c b/ssh-agent.c index 46a1199b..33596c47 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,5 +1,3 @@ -/* $OpenBSD: ssh-agent.c,v 1.68 2001/07/20 14:46:11 markus Exp $ */ - /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -36,7 +34,8 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.68 2001/07/20 14:46:11 markus Exp $"); +#include "openbsd-compat/fake-queue.h" +RCSID("$OpenBSD: ssh-agent.c,v 1.85 2002/04/02 11:49:39 markus Exp $"); #include #include @@ -46,26 +45,25 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.68 2001/07/20 14:46:11 markus Exp $"); #include "buffer.h" #include "bufaux.h" #include "xmalloc.h" -#include "packet.h" #include "getput.h" -#include "mpaux.h" #include "key.h" #include "authfd.h" -#include "cipher.h" -#include "kex.h" #include "compat.h" #include "log.h" #ifdef SMARTCARD -#include #include "scard.h" #endif +typedef enum { + AUTH_UNUSED, + AUTH_SOCKET, + AUTH_CONNECTION +} sock_type; + typedef struct { int fd; - enum { - AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION - } type; + sock_type type; Buffer input; Buffer output; } SocketEntry; @@ -73,14 +71,15 @@ typedef struct { u_int sockets_alloc = 0; SocketEntry *sockets = NULL; -typedef struct { +typedef struct identity { + TAILQ_ENTRY(identity) next; Key *key; char *comment; } Identity; typedef struct { int nentries; - Identity *identities; + TAILQ_HEAD(idqueue, identity) idlist; } Idtab; /* private key table, one per protocol version */ @@ -105,8 +104,8 @@ static void idtab_init(void) { int i; - for (i = 0; i <=2; i++){ - idtable[i].identities = NULL; + for (i = 0; i <=2; i++) { + TAILQ_INIT(&idtable[i].idlist); idtable[i].nentries = 0; } } @@ -121,19 +120,25 @@ idtab_lookup(int version) } /* return matching private key for given public key */ -static Key * -lookup_private_key(Key *key, int *idx, int version) +static Identity * +lookup_identity(Key *key, int version) { - int i; + Identity *id; + Idtab *tab = idtab_lookup(version); - for (i = 0; i < tab->nentries; i++) { - if (key_equal(key, tab->identities[i].key)) { - if (idx != NULL) - *idx = i; - return tab->identities[i].key; - } + TAILQ_FOREACH(id, &tab->idlist, next) { + if (key_equal(key, id->key)) + return (id); } - return NULL; + return (NULL); +} + +static void +free_identity(Identity *id) +{ + key_free(id->key); + xfree(id->comment); + xfree(id); } /* send list of supported public keys to 'client' */ @@ -142,14 +147,13 @@ process_request_identities(SocketEntry *e, int version) { Idtab *tab = idtab_lookup(version); Buffer msg; - int i; + Identity *id; buffer_init(&msg); buffer_put_char(&msg, (version == 1) ? SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); buffer_put_int(&msg, tab->nentries); - for (i = 0; i < tab->nentries; i++) { - Identity *id = &tab->identities[i]; + TAILQ_FOREACH(id, &tab->idlist, next) { if (id->key->type == KEY_RSA1) { buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); buffer_put_bignum(&msg, id->key->rsa->e); @@ -172,7 +176,8 @@ process_request_identities(SocketEntry *e, int version) static void process_authentication_challenge1(SocketEntry *e) { - Key *key, *private; + Identity *id; + Key *key; BIGNUM *challenge; int i, len; Buffer msg; @@ -182,7 +187,8 @@ process_authentication_challenge1(SocketEntry *e) buffer_init(&msg); key = key_new(KEY_RSA1); - challenge = BN_new(); + if ((challenge = BN_new()) == NULL) + fatal("process_authentication_challenge1: BN_new failed"); buffer_get_int(&e->input); /* ignored */ buffer_get_bignum(&e->input, key->rsa->e); @@ -192,13 +198,14 @@ process_authentication_challenge1(SocketEntry *e) /* Only protocol 1.1 is supported */ if (buffer_len(&e->input) == 0) goto failure; - buffer_get(&e->input, (char *) session_id, 16); + buffer_get(&e->input, session_id, 16); response_type = buffer_get_int(&e->input); if (response_type != 1) goto failure; - private = lookup_private_key(key, NULL, 1); - if (private != NULL) { + id = lookup_identity(key, 1); + if (id != NULL) { + Key *private = id->key; /* Decrypt the challenge using the private key. */ if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) goto failure; @@ -239,7 +246,7 @@ static void process_sign_request2(SocketEntry *e) { extern int datafellows; - Key *key, *private; + Key *key; u_char *blob, *data, *signature = NULL; u_int blen, dlen, slen = 0; int flags; @@ -257,9 +264,9 @@ process_sign_request2(SocketEntry *e) key = key_from_blob(blob, blen); if (key != NULL) { - private = lookup_private_key(key, NULL, 2); - if (private != NULL) - ok = key_sign(private, &signature, &slen, data, dlen); + Identity *id = lookup_identity(key, 2); + if (id != NULL) + ok = key_sign(id->key, &signature, &slen, data, dlen); } key_free(key); buffer_init(&msg); @@ -283,13 +290,13 @@ process_sign_request2(SocketEntry *e) static void process_remove_identity(SocketEntry *e, int version) { - Key *key = NULL, *private; + Key *key = NULL; u_char *blob; u_int blen; u_int bits; int success = 0; - switch(version){ + switch (version) { case 1: key = key_new(KEY_RSA1); bits = buffer_get_int(&e->input); @@ -307,9 +314,8 @@ process_remove_identity(SocketEntry *e, int version) break; } if (key != NULL) { - int idx; - private = lookup_private_key(key, &idx, version); - if (private != NULL) { + Identity *id = lookup_identity(key, version); + if (id != NULL) { /* * We have this key. Free the old key. Since we * don\'t want to leave empty slots in the middle of @@ -318,19 +324,12 @@ process_remove_identity(SocketEntry *e, int version) * of the array. */ Idtab *tab = idtab_lookup(version); - key_free(tab->identities[idx].key); - xfree(tab->identities[idx].comment); if (tab->nentries < 1) fatal("process_remove_identity: " "internal error: tab->nentries %d", tab->nentries); - if (idx != tab->nentries - 1) { - int i; - for (i = idx; i < tab->nentries - 1; i++) - tab->identities[i] = tab->identities[i+1]; - } - tab->identities[tab->nentries - 1].key = NULL; - tab->identities[tab->nentries - 1].comment = NULL; + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); tab->nentries--; success = 1; } @@ -344,13 +343,14 @@ process_remove_identity(SocketEntry *e, int version) static void process_remove_all_identities(SocketEntry *e, int version) { - u_int i; Idtab *tab = idtab_lookup(version); + Identity *id; /* Loop over all identities and clear the keys. */ - for (i = 0; i < tab->nentries; i++) { - key_free(tab->identities[i].key); - xfree(tab->identities[i].comment); + for (id = TAILQ_FIRST(&tab->idlist); id; + id = TAILQ_FIRST(&tab->idlist)) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); } /* Mark that there are no identities. */ @@ -391,7 +391,7 @@ process_add_identity(SocketEntry *e, int version) type_name = buffer_get_string(&e->input, NULL); type = key_type_from_name(type_name); xfree(type_name); - switch(type) { + switch (type) { case KEY_DSA: k = key_new_private(type); buffer_get_bignum2(&e->input, k->dsa->p); @@ -424,14 +424,11 @@ process_add_identity(SocketEntry *e, int version) goto send; } success = 1; - if (lookup_private_key(k, NULL, version) == NULL) { - if (tab->nentries == 0) - tab->identities = xmalloc(sizeof(Identity)); - else - tab->identities = xrealloc(tab->identities, - (tab->nentries + 1) * sizeof(Identity)); - tab->identities[tab->nentries].key = k; - tab->identities[tab->nentries].comment = comment; + if (lookup_identity(k, version) == NULL) { + Identity *id = xmalloc(sizeof(Identity)); + id->key = k; + id->comment = comment; + TAILQ_INSERT_TAIL(&tab->idlist, id, next); /* Increment the number of identities. */ tab->nentries++; } else { @@ -449,55 +446,39 @@ send: static void process_add_smartcard_key (SocketEntry *e) { + Identity *id; Idtab *tab; - Key *n = NULL, *k = NULL; - int success = 0; - int sc_reader_num = 0; - - sc_reader_num = buffer_get_int(&e->input); - - k = sc_get_key(sc_reader_num); - if (k == NULL) { - error("sc_get_pubkey failed"); + Key **keys, *k; + char *sc_reader_id = NULL, *pin; + int i, version, success = 0; + + sc_reader_id = buffer_get_string(&e->input, NULL); + pin = buffer_get_string(&e->input, NULL); + keys = sc_get_keys(sc_reader_id, pin); + xfree(sc_reader_id); + xfree(pin); + + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); goto send; } - success = 1; - - tab = idtab_lookup(1); - k->type = KEY_RSA1; - if (lookup_private_key(k, NULL, 1) == NULL) { - if (tab->nentries == 0) - tab->identities = xmalloc(sizeof(Identity)); - else - tab->identities = xrealloc(tab->identities, - (tab->nentries + 1) * sizeof(Identity)); - n = key_new(KEY_RSA1); - BN_copy(n->rsa->n, k->rsa->n); - BN_copy(n->rsa->e, k->rsa->e); - RSA_set_method(n->rsa, sc_get_engine()); - tab->identities[tab->nentries].key = n; - tab->identities[tab->nentries].comment = - xstrdup("rsa1 smartcard"); - tab->nentries++; - } - k->type = KEY_RSA; - tab = idtab_lookup(2); - if (lookup_private_key(k, NULL, 2) == NULL) { - if (tab->nentries == 0) - tab->identities = xmalloc(sizeof(Identity)); - else - tab->identities = xrealloc(tab->identities, - (tab->nentries + 1) * sizeof(Identity)); - n = key_new(KEY_RSA); - BN_copy(n->rsa->n, k->rsa->n); - BN_copy(n->rsa->e, k->rsa->e); - RSA_set_method(n->rsa, sc_get_engine()); - tab->identities[tab->nentries].key = n; - tab->identities[tab->nentries].comment = - xstrdup("rsa smartcard"); - tab->nentries++; + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + tab = idtab_lookup(version); + if (lookup_identity(k, version) == NULL) { + id = xmalloc(sizeof(Identity)); + id->key = k; + id->comment = xstrdup("smartcard key"); + TAILQ_INSERT_TAIL(&tab->idlist, id, next); + tab->nentries++; + success = 1; + } else { + key_free(k); + } + keys[i] = NULL; } - key_free(k); + xfree(keys); send: buffer_put_int(&e->output, 1); buffer_put_char(&e->output, @@ -507,46 +488,42 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { - Key *k = NULL, *private; - int idx; - int success = 0; - int sc_reader_num = 0; - - sc_reader_num = buffer_get_int(&e->input); - - if ((k = sc_get_key(sc_reader_num)) == NULL) { - error("sc_get_pubkey failed"); - } else { - k->type = KEY_RSA1; - private = lookup_private_key(k, &idx, 1); - if (private != NULL) { - Idtab *tab = idtab_lookup(1); - key_free(tab->identities[idx].key); - xfree(tab->identities[idx].comment); - if (idx != tab->nentries) - tab->identities[idx] = tab->identities[tab->nentries]; - tab->nentries--; - success = 1; - } - k->type = KEY_RSA; - private = lookup_private_key(k, &idx, 2); - if (private != NULL) { - Idtab *tab = idtab_lookup(2); - key_free(tab->identities[idx].key); - xfree(tab->identities[idx].comment); - if (idx != tab->nentries) - tab->identities[idx] = tab->identities[tab->nentries]; + Identity *id; + Idtab *tab; + Key **keys, *k = NULL; + char *sc_reader_id = NULL, *pin; + int i, version, success = 0; + + sc_reader_id = buffer_get_string(&e->input, NULL); + pin = buffer_get_string(&e->input, NULL); + keys = sc_get_keys(sc_reader_id, pin); + xfree(sc_reader_id); + xfree(pin); + + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); + goto send; + } + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + if ((id = lookup_identity(k, version)) != NULL) { + tab = idtab_lookup(version); + TAILQ_REMOVE(&tab->idlist, id, next); tab->nentries--; + free_identity(id); success = 1; } key_free(k); + keys[i] = NULL; } - + xfree(keys); +send: buffer_put_int(&e->output, 1); buffer_put_char(&e->output, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } -#endif +#endif /* SMARTCARD */ /* dispatch incoming messages */ @@ -558,7 +535,7 @@ process_message(SocketEntry *e) u_char *cp; if (buffer_len(&e->input) < 5) return; /* Incomplete message. */ - cp = (u_char *) buffer_ptr(&e->input); + cp = buffer_ptr(&e->input); msg_len = GET_32BIT(cp); if (msg_len > 256 * 1024) { shutdown(e->fd, SHUT_RDWR); @@ -608,11 +585,11 @@ process_message(SocketEntry *e) #ifdef SMARTCARD case SSH_AGENTC_ADD_SMARTCARD_KEY: process_add_smartcard_key(e); - break; + break; case SSH_AGENTC_REMOVE_SMARTCARD_KEY: process_remove_smartcard_key(e); - break; -#endif + break; +#endif /* SMARTCARD */ default: /* Unknown message. Respond with failure. */ error("Unknown message %d", type); @@ -624,7 +601,7 @@ process_message(SocketEntry *e) } static void -new_socket(int type, int fd) +new_socket(sock_type type, int fd) { u_int i, old_alloc; if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) @@ -725,7 +702,8 @@ after_select(fd_set *readset, fd_set *writeset) sock = accept(sockets[i].fd, (struct sockaddr *) &sunaddr, &slen); if (sock < 0) { - perror("accept from AUTH_SOCKET"); + error("accept from AUTH_SOCKET: %s", + strerror(errno)); break; } new_socket(AUTH_CONNECTION, sock); @@ -779,7 +757,7 @@ after_select(fd_set *readset, fd_set *writeset) } static void -cleanup_socket(void) +cleanup_socket(void *p) { if (socket_name[0]) unlink(socket_name); @@ -790,14 +768,14 @@ cleanup_socket(void) static void cleanup_exit(int i) { - cleanup_socket(); + cleanup_socket(NULL); exit(i); } static void cleanup_handler(int sig) { - cleanup_socket(); + cleanup_socket(NULL); _exit(2); } @@ -818,9 +796,13 @@ check_parent_exists(int sig) static void usage(void) { - fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); - fprintf(stderr, "Usage: %s [-c | -s] [-k] [-d] [command [args...]]\n", + fprintf(stderr, "Usage: %s [options] [command [args ...]]\n", __progname); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -c Generate C-shell commands on stdout.\n"); + fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n"); + fprintf(stderr, " -k Kill the current agent.\n"); + fprintf(stderr, " -d Debug mode.\n"); exit(1); } @@ -880,7 +862,7 @@ main(int ac, char **av) if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) usage(); - if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) { + if (ac == 0 && !c_flag && !s_flag) { shell = getenv("SHELL"); if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) c_flag = 1; @@ -964,7 +946,7 @@ main(int ac, char **av) pid = fork(); if (pid == -1) { perror("fork"); - exit(1); + cleanup_exit(1); } if (pid != 0) { /* Parent - execute the given command. */ close(sock); @@ -987,9 +969,11 @@ main(int ac, char **av) perror(av[0]); exit(1); } + /* child */ + log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0); if (setsid() == -1) { - perror("setsid"); + error("setsid: %s", strerror(errno)); cleanup_exit(1); } @@ -1002,16 +986,13 @@ main(int ac, char **av) /* deny core dumps, since memory contains unencrypted private keys */ rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) { - perror("setrlimit rlimit_core failed"); + error("setrlimit RLIMIT_CORE: %s", strerror(errno)); cleanup_exit(1); } #endif skip: - if (atexit(cleanup_socket) < 0) { - perror("atexit"); - cleanup_exit(1); - } + fatal_add_cleanup(cleanup_socket, NULL); new_socket(AUTH_SOCKET, sock); if (ac > 0) { signal(SIGALRM, check_parent_exists); @@ -1030,7 +1011,7 @@ skip: if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) { if (errno == EINTR) continue; - exit(1); + fatal("select: %s", strerror(errno)); } after_select(readsetp, writesetp); }