=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-agent.c,v retrieving revision 1.54 retrieving revision 1.54.2.1 diff -u -r1.54 -r1.54.2.1 --- src/usr.bin/ssh/ssh-agent.c 2001/04/03 13:56:11 1.54 +++ src/usr.bin/ssh/ssh-agent.c 2001/09/27 19:03:55 1.54.2.1 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.54.2.1 2001/09/27 19:03:55 jason Exp $ */ /* * Author: Tatu Ylonen @@ -12,8 +12,7 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * - * SSH2 implementation, - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.54.2.1 2001/09/27 19:03:55 jason Exp $"); #include #include @@ -57,6 +56,11 @@ #include "compat.h" #include "log.h" +#ifdef SMARTCARD +#include +#include "scard.h" +#endif + typedef struct { int fd; enum { @@ -93,9 +97,7 @@ extern char *__progname; -int prepare_select(fd_set **, fd_set **, int *); - -void +static void idtab_init(void) { int i; @@ -106,7 +108,7 @@ } /* return private key table for requested protocol version */ -Idtab * +static Idtab * idtab_lookup(int version) { if (version < 1 || version > 2) @@ -115,7 +117,7 @@ } /* return matching private key for given public key */ -Key * +static Key * lookup_private_key(Key *key, int *idx, int version) { int i; @@ -131,7 +133,7 @@ } /* send list of supported public keys to 'client' */ -void +static void process_request_identities(SocketEntry *e, int version) { Idtab *tab = idtab_lookup(version); @@ -163,7 +165,7 @@ } /* ssh1 only */ -void +static void process_authentication_challenge1(SocketEntry *e) { Key *key, *private; @@ -229,7 +231,7 @@ } /* ssh2 only */ -void +static void process_sign_request2(SocketEntry *e) { extern int datafellows; @@ -274,7 +276,7 @@ } /* shared */ -void +static void process_remove_identity(SocketEntry *e, int version) { Key *key = NULL, *private; @@ -335,7 +337,7 @@ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } -void +static void process_remove_all_identities(SocketEntry *e, int version) { u_int i; @@ -356,7 +358,7 @@ return; } -void +static void process_add_identity(SocketEntry *e, int version) { Key *k = NULL; @@ -379,7 +381,7 @@ buffer_get_bignum(&e->input, k->rsa->p); /* q */ /* Generate additional parameters */ - generate_additional_parameters(k->rsa); + rsa_generate_additional_parameters(k->rsa); break; case 2: type_name = buffer_get_string(&e->input, NULL); @@ -404,7 +406,7 @@ buffer_get_bignum2(&e->input, k->rsa->q); /* Generate additional parameters */ - generate_additional_parameters(k->rsa); + rsa_generate_additional_parameters(k->rsa); break; default: buffer_clear(&e->input); @@ -438,9 +440,116 @@ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } + +#ifdef SMARTCARD +static void +process_add_smartcard_key (SocketEntry *e) +{ + Idtab *tab; + Key *n = NULL, *k = NULL; + char *sc_reader_id = NULL; + int success = 0; + + sc_reader_id = buffer_get_string(&e->input, NULL); + k = sc_get_key(sc_reader_id); + xfree(sc_reader_id); + + if (k == NULL) { + error("sc_get_pubkey 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++; + } + key_free(k); +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) +{ + Key *k = NULL, *private; + int idx; + int success = 0; + char *sc_reader_id = NULL; + + sc_reader_id = buffer_get_string(&e->input, NULL); + k = sc_get_key(sc_reader_id); + xfree(sc_reader_id); + + if (k == 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]; + tab->nentries--; + success = 1; + } + key_free(k); + } + + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} +#endif /* SMARTCARD */ + /* dispatch incoming messages */ -void +static void process_message(SocketEntry *e) { u_int msg_len; @@ -461,6 +570,7 @@ buffer_consume(&e->input, 4); type = buffer_get_char(&e->input); + debug("type %d", type); switch (type) { /* ssh1 */ case SSH_AGENTC_RSA_CHALLENGE: @@ -494,6 +604,14 @@ 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); @@ -504,7 +622,7 @@ } } -void +static void new_socket(int type, int fd) { u_int i, old_alloc; @@ -536,8 +654,8 @@ buffer_init(&sockets[old_alloc].output); } -int -prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl) +static int +prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp) { u_int i, sz; int n = 0; @@ -557,15 +675,18 @@ } sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); - if (*fdrp == NULL || n > *fdl) { + if (*fdrp == NULL || sz > *nallocp) { if (*fdrp) xfree(*fdrp); if (*fdwp) xfree(*fdwp); *fdrp = xmalloc(sz); *fdwp = xmalloc(sz); - *fdl = n; + *nallocp = sz; } + if (n < *fdl) + debug("XXX shrink: %d < %d", n, *fdl); + *fdl = n; memset(*fdrp, 0, sz); memset(*fdwp, 0, sz); @@ -584,7 +705,7 @@ return (1); } -void +static void after_select(fd_set *readset, fd_set *writeset) { u_int i; @@ -656,21 +777,7 @@ } } -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"); */ - exit(1); - } - signal(SIGALRM, check_parent_exists); - alarm(10); - errno = save_errno; -} - -void +static void cleanup_socket(void) { if (socket_name[0]) @@ -679,33 +786,51 @@ rmdir(socket_dir); } -void +static void cleanup_exit(int i) { cleanup_socket(); exit(i); } -void +static void cleanup_handler(int sig) { cleanup_socket(); _exit(2); } -void +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, "ssh-agent version %s\n", SSH_VERSION); - fprintf(stderr, "Usage: %s [-c | -s] [-k] [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); } int main(int ac, char **av) { - int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; + int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc; struct sockaddr_un sunaddr; struct rlimit rlim; pid_t pid; @@ -715,7 +840,7 @@ SSLeay_add_all_algorithms(); - while ((ch = getopt(ac, av, "cks")) != -1) { + while ((ch = getopt(ac, av, "cdks")) != -1) { switch (ch) { case 'c': if (s_flag) @@ -730,6 +855,11 @@ usage(); s_flag++; break; + case 'd': + if (d_flag) + usage(); + d_flag++; + break; default: usage(); } @@ -737,10 +867,10 @@ ac -= optind; av += optind; - if (ac > 0 && (c_flag || k_flag || s_flag)) + if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) usage(); - if (ac == 0 && !c_flag && !k_flag && !s_flag) { + if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) { shell = getenv("SHELL"); if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) c_flag = 1; @@ -804,6 +934,14 @@ * 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"); @@ -830,6 +968,13 @@ perror(av[0]); exit(1); } + + if (setsid() == -1) { + perror("setsid"); + cleanup_exit(1); + } + + (void)chdir("/"); close(0); close(1); close(2); @@ -840,10 +985,8 @@ perror("setrlimit rlimit_core failed"); cleanup_exit(1); } - if (setsid() == -1) { - perror("setsid"); - cleanup_exit(1); - } + +skip: if (atexit(cleanup_socket) < 0) { perror("atexit"); cleanup_exit(1); @@ -854,12 +997,15 @@ alarm(10); } idtab_init(); - signal(SIGINT, SIG_IGN); + if (!d_flag) + 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); + prepare_select(&readsetp, &writesetp, &max_fd, &nalloc); if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) { if (errno == EINTR) continue;