=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-agent.c,v retrieving revision 1.54.2.3 retrieving revision 1.55 diff -u -r1.54.2.3 -r1.55 --- src/usr.bin/ssh/ssh-agent.c 2002/06/02 22:56:11 1.54.2.3 +++ src/usr.bin/ssh/ssh-agent.c 2001/06/23 15:12:20 1.55 @@ -1,3 +1,5 @@ +/* $OpenBSD: ssh-agent.c,v 1.55 2001/06/23 15:12:20 itojun Exp $ */ + /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -10,7 +12,8 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * - * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * SSH2 implementation, + * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,8 +37,7 @@ */ #include "includes.h" -#include -RCSID("$OpenBSD: ssh-agent.c,v 1.54.2.3 2002/06/02 22:56:11 miod Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.55 2001/06/23 15:12:20 itojun Exp $"); #include #include @@ -45,25 +47,21 @@ #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 "scard.h" -#endif - -typedef enum { - AUTH_UNUSED, - AUTH_SOCKET, - AUTH_CONNECTION -} sock_type; - typedef struct { int fd; - sock_type type; + enum { + AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION + } type; Buffer input; Buffer output; } SocketEntry; @@ -71,15 +69,14 @@ u_int sockets_alloc = 0; SocketEntry *sockets = NULL; -typedef struct identity { - TAILQ_ENTRY(identity) next; +typedef struct { Key *key; char *comment; } Identity; typedef struct { int nentries; - TAILQ_HEAD(idqueue, identity) idlist; + Identity *identities; } Idtab; /* private key table, one per protocol version */ @@ -100,8 +97,8 @@ idtab_init(void) { int i; - for (i = 0; i <=2; i++) { - TAILQ_INIT(&idtable[i].idlist); + for (i = 0; i <=2; i++){ + idtable[i].identities = NULL; idtable[i].nentries = 0; } } @@ -116,40 +113,35 @@ } /* return matching private key for given public key */ -static Identity * -lookup_identity(Key *key, int version) +static Key * +lookup_private_key(Key *key, int *idx, int version) { - Identity *id; - + int i; Idtab *tab = idtab_lookup(version); - TAILQ_FOREACH(id, &tab->idlist, next) { - if (key_equal(key, id->key)) - return (id); + 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; + } } - 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' */ static void process_request_identities(SocketEntry *e, int version) { Idtab *tab = idtab_lookup(version); Buffer msg; - Identity *id; + int i; buffer_init(&msg); buffer_put_char(&msg, (version == 1) ? SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); buffer_put_int(&msg, tab->nentries); - TAILQ_FOREACH(id, &tab->idlist, next) { + for (i = 0; i < tab->nentries; i++) { + Identity *id = &tab->identities[i]; 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,8 +164,7 @@ static void process_authentication_challenge1(SocketEntry *e) { - Identity *id; - Key *key; + Key *key, *private; BIGNUM *challenge; int i, len; Buffer msg; @@ -183,8 +174,7 @@ buffer_init(&msg); key = key_new(KEY_RSA1); - if ((challenge = BN_new()) == NULL) - fatal("process_authentication_challenge1: BN_new failed"); + challenge = BN_new(); buffer_get_int(&e->input); /* ignored */ buffer_get_bignum(&e->input, key->rsa->e); @@ -194,14 +184,13 @@ /* Only protocol 1.1 is supported */ if (buffer_len(&e->input) == 0) goto failure; - buffer_get(&e->input, session_id, 16); + buffer_get(&e->input, (char *) session_id, 16); response_type = buffer_get_int(&e->input); if (response_type != 1) goto failure; - id = lookup_identity(key, 1); - if (id != NULL) { - Key *private = id->key; + private = lookup_private_key(key, NULL, 1); + if (private != NULL) { /* Decrypt the challenge using the private key. */ if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) goto failure; @@ -242,7 +231,7 @@ process_sign_request2(SocketEntry *e) { extern int datafellows; - Key *key; + Key *key, *private; u_char *blob, *data, *signature = NULL; u_int blen, dlen, slen = 0; int flags; @@ -260,9 +249,9 @@ key = key_from_blob(blob, blen); if (key != NULL) { - Identity *id = lookup_identity(key, 2); - if (id != NULL) - ok = key_sign(id->key, &signature, &slen, data, dlen); + private = lookup_private_key(key, NULL, 2); + if (private != NULL) + ok = key_sign(private, &signature, &slen, data, dlen); } key_free(key); buffer_init(&msg); @@ -286,13 +275,13 @@ static void process_remove_identity(SocketEntry *e, int version) { - Key *key = NULL; + Key *key = NULL, *private; 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); @@ -310,8 +299,9 @@ break; } if (key != NULL) { - Identity *id = lookup_identity(key, version); - if (id != NULL) { + int idx; + private = lookup_private_key(key, &idx, version); + if (private != NULL) { /* * We have this key. Free the old key. Since we * don\'t want to leave empty slots in the middle of @@ -320,12 +310,19 @@ * 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); - TAILQ_REMOVE(&tab->idlist, id, next); - free_identity(id); + 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; tab->nentries--; success = 1; } @@ -339,14 +336,13 @@ 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 (id = TAILQ_FIRST(&tab->idlist); id; - id = TAILQ_FIRST(&tab->idlist)) { - TAILQ_REMOVE(&tab->idlist, id, next); - free_identity(id); + for (i = 0; i < tab->nentries; i++) { + key_free(tab->identities[i].key); + xfree(tab->identities[i].comment); } /* Mark that there are no identities. */ @@ -381,13 +377,13 @@ buffer_get_bignum(&e->input, k->rsa->p); /* q */ /* Generate additional parameters */ - rsa_generate_additional_parameters(k->rsa); + generate_additional_parameters(k->rsa); break; case 2: 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); @@ -406,7 +402,7 @@ buffer_get_bignum2(&e->input, k->rsa->q); /* Generate additional parameters */ - rsa_generate_additional_parameters(k->rsa); + generate_additional_parameters(k->rsa); break; default: buffer_clear(&e->input); @@ -420,11 +416,14 @@ goto send; } success = 1; - if (lookup_identity(k, version) == NULL) { - Identity *id = xmalloc(sizeof(Identity)); - id->key = k; - id->comment = comment; - TAILQ_INSERT_TAIL(&tab->idlist, id, next); + 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; /* Increment the number of identities. */ tab->nentries++; } else { @@ -437,90 +436,6 @@ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } - -#ifdef SMARTCARD -static void -process_add_smartcard_key (SocketEntry *e) -{ - Identity *id; - Idtab *tab; - 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; - } - 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; - } - xfree(keys); -send: - buffer_put_int(&e->output, 1); - buffer_put_char(&e->output, - success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); -} - -static void -process_remove_smartcard_key(SocketEntry *e) -{ - 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 /* SMARTCARD */ - /* dispatch incoming messages */ static void @@ -531,7 +446,7 @@ u_char *cp; if (buffer_len(&e->input) < 5) return; /* Incomplete message. */ - cp = buffer_ptr(&e->input); + cp = (u_char *) buffer_ptr(&e->input); msg_len = GET_32BIT(cp); if (msg_len > 256 * 1024) { shutdown(e->fd, SHUT_RDWR); @@ -544,7 +459,6 @@ buffer_consume(&e->input, 4); type = buffer_get_char(&e->input); - debug("type %d", type); switch (type) { /* ssh1 */ case SSH_AGENTC_RSA_CHALLENGE: @@ -578,14 +492,6 @@ case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: process_remove_all_identities(e, 2); break; -#ifdef SMARTCARD - case SSH_AGENTC_ADD_SMARTCARD_KEY: - process_add_smartcard_key(e); - break; - case SSH_AGENTC_REMOVE_SMARTCARD_KEY: - process_remove_smartcard_key(e); - break; -#endif /* SMARTCARD */ default: /* Unknown message. Respond with failure. */ error("Unknown message %d", type); @@ -597,7 +503,7 @@ } static void -new_socket(sock_type type, int fd) +new_socket(int type, int fd) { u_int i, old_alloc; if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) @@ -629,7 +535,7 @@ } static int -prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp) +prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl) { u_int i, sz; int n = 0; @@ -649,18 +555,15 @@ } sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); - if (*fdrp == NULL || sz > *nallocp) { + if (*fdrp == NULL || n > *fdl) { if (*fdrp) xfree(*fdrp); if (*fdwp) xfree(*fdwp); *fdrp = xmalloc(sz); *fdwp = xmalloc(sz); - *nallocp = sz; + *fdl = n; } - if (n < *fdl) - debug("XXX shrink: %d < %d", n, *fdl); - *fdl = n; memset(*fdrp, 0, sz); memset(*fdwp, 0, sz); @@ -698,8 +601,7 @@ sock = accept(sockets[i].fd, (struct sockaddr *) &sunaddr, &slen); if (sock < 0) { - error("accept from AUTH_SOCKET: %s", - strerror(errno)); + perror("accept from AUTH_SOCKET"); break; } new_socket(AUTH_CONNECTION, sock); @@ -753,8 +655,22 @@ } static void -cleanup_socket(void *p) +check_parent_exists(int sig) { + int save_errno = errno; + + if (parent_pid != -1 && kill(parent_pid, 0) < 0) { + /* printf("Parent has died - Authentication agent exiting.\n"); */ + exit(1); + } + signal(SIGALRM, check_parent_exists); + alarm(10); + errno = save_errno; +} + +static void +cleanup_socket(void) +{ if (socket_name[0]) unlink(socket_name); if (socket_dir[0]) @@ -764,48 +680,30 @@ static void cleanup_exit(int i) { - cleanup_socket(NULL); + cleanup_socket(); exit(i); } static void cleanup_handler(int sig) { - cleanup_socket(NULL); + cleanup_socket(); _exit(2); } static void -check_parent_exists(int sig) -{ - int save_errno = errno; - - if (parent_pid != -1 && kill(parent_pid, 0) < 0) { - /* printf("Parent has died - Authentication agent exiting.\n"); */ - cleanup_handler(sig); /* safe */ - } - signal(SIGALRM, check_parent_exists); - alarm(10); - errno = save_errno; -} - -static void usage(void) { - fprintf(stderr, "Usage: %s [options] [command [args ...]]\n", + fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); + fprintf(stderr, "Usage: %s [-c | -s] [-k] [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); } int main(int ac, char **av) { - int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc; + int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; struct sockaddr_un sunaddr; struct rlimit rlim; pid_t pid; @@ -815,7 +713,7 @@ SSLeay_add_all_algorithms(); - while ((ch = getopt(ac, av, "cdks")) != -1) { + while ((ch = getopt(ac, av, "cks")) != -1) { switch (ch) { case 'c': if (s_flag) @@ -830,11 +728,6 @@ usage(); s_flag++; break; - case 'd': - if (d_flag) - usage(); - d_flag++; - break; default: usage(); } @@ -842,10 +735,10 @@ ac -= optind; av += optind; - if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) + if (ac > 0 && (c_flag || k_flag || s_flag)) usage(); - if (ac == 0 && !c_flag && !s_flag) { + if (ac == 0 && !c_flag && !k_flag && !s_flag) { shell = getenv("SHELL"); if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) c_flag = 1; @@ -909,18 +802,10 @@ * Fork, and have the parent execute the command, if any, or present * the socket data. The child continues as the authentication agent. */ - if (d_flag) { - log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1); - format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; - printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, - SSH_AUTHSOCKET_ENV_NAME); - printf("echo Agent pid %d;\n", parent_pid); - goto skip; - } pid = fork(); if (pid == -1) { perror("fork"); - cleanup_exit(1); + exit(1); } if (pid != 0) { /* Parent - execute the given command. */ close(sock); @@ -943,15 +828,6 @@ perror(av[0]); exit(1); } - /* child */ - log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0); - - if (setsid() == -1) { - error("setsid: %s", strerror(errno)); - cleanup_exit(1); - } - - (void)chdir("/"); close(0); close(1); close(2); @@ -959,31 +835,33 @@ /* deny core dumps, since memory contains unencrypted private keys */ rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) { - error("setrlimit RLIMIT_CORE: %s", strerror(errno)); + perror("setrlimit rlimit_core failed"); cleanup_exit(1); } - -skip: - fatal_add_cleanup(cleanup_socket, NULL); + if (setsid() == -1) { + perror("setsid"); + cleanup_exit(1); + } + if (atexit(cleanup_socket) < 0) { + perror("atexit"); + cleanup_exit(1); + } new_socket(AUTH_SOCKET, sock); if (ac > 0) { signal(SIGALRM, check_parent_exists); alarm(10); } idtab_init(); - if (!d_flag) - signal(SIGINT, SIG_IGN); + signal(SIGINT, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, cleanup_handler); signal(SIGTERM, cleanup_handler); - nalloc = 0; - while (1) { - prepare_select(&readsetp, &writesetp, &max_fd, &nalloc); + prepare_select(&readsetp, &writesetp, &max_fd); if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) { if (errno == EINTR) continue; - fatal("select: %s", strerror(errno)); + exit(1); } after_select(readsetp, writesetp); }