From: markus Date: Mon, 19 Jan 2015 20:32:39 +0000 (+0000) Subject: switch ssh-keyscan from setjmp to multiple ssh transport layer instances X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=0016f7990ad9411eb32cb33405dd5385baa06ba6;p=openbsd switch ssh-keyscan from setjmp to multiple ssh transport layer instances ok djm@ --- diff --git a/usr.bin/ssh/ssh-keyscan.c b/usr.bin/ssh/ssh-keyscan.c index 24d42b46ecb..367f731c06f 100644 --- a/usr.bin/ssh/ssh-keyscan.c +++ b/usr.bin/ssh/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.94 2015/01/19 20:16:15 markus Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.95 2015/01/19 20:32:39 markus Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -29,8 +28,8 @@ #include "xmalloc.h" #include "ssh.h" #include "ssh1.h" -#include "buffer.h" -#include "key.h" +#include "sshbuf.h" +#include "sshkey.h" #include "cipher.h" #include "kex.h" #include "compat.h" @@ -41,6 +40,8 @@ #include "atomicio.h" #include "misc.h" #include "hostfile.h" +#include "ssherr.h" +#include "ssh_api.h" /* Flag indicating whether IPv4 or IPv6. This can be set on the command line. Default value is AF_UNSPEC means both IPv4 and IPv6. */ @@ -70,9 +71,6 @@ extern char *__progname; fd_set *read_wait; size_t read_wait_nfdset; int ncon; -int nonfatal_fatal = 0; -jmp_buf kexjmp; -Key *kexjmp_key; /* * Keep a connection structure for each file descriptor. The state @@ -89,12 +87,13 @@ typedef struct Connection { int c_len; /* Total bytes which must be read. */ int c_off; /* Length of data read so far. */ int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ + int c_done; /* SSH2 done */ char *c_namebase; /* Address to free for c_name and c_namelist */ char *c_name; /* Hostname of connection for errors */ char *c_namelist; /* Pointer to other possible addresses */ char *c_output_name; /* Hostname of connection for output */ char *c_data; /* Data read from this fd */ - struct kex *c_kex; /* The key-exchange struct for ssh2 */ + struct ssh *c_ssh; /* SSH-connection */ struct timeval c_tv; /* Time at which connection gets aborted */ TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ } con; @@ -102,6 +101,8 @@ typedef struct Connection { TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ con *fdcon; +static void keyprint(con *c, struct sshkey *key); + static int fdlim_get(int hard) { @@ -169,46 +170,61 @@ strnnsep(char **stringp, char *delim) } #ifdef WITH_SSH1 -static Key * +static struct sshkey * keygrab_ssh1(con *c) { - static Key *rsa; - static Buffer msg; + static struct sshkey *rsa; + static struct sshbuf *msg; + int r; + u_char type; if (rsa == NULL) { - buffer_init(&msg); - rsa = key_new(KEY_RSA1); + if ((rsa = sshkey_new(KEY_RSA1)) == NULL) { + error("%s: sshkey_new failed", __func__); + return NULL; + } + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); } - buffer_append(&msg, c->c_data, c->c_plen); - buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */ - if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { + if ((r = sshbuf_put(msg, c->c_data, c->c_plen)) != 0 || + (r = sshbuf_consume(msg, 8 - (c->c_plen & 7))) != 0 || /* padding */ + (r = sshbuf_get_u8(msg, &type)) != 0) + goto buf_err; + if (type != (int) SSH_SMSG_PUBLIC_KEY) { error("%s: invalid packet type", c->c_name); - buffer_clear(&msg); + sshbuf_reset(msg); + return NULL; + } + if ((r = sshbuf_consume(msg, 8)) != 0 || /* cookie */ + /* server key */ + (r = sshbuf_get_u32(msg, NULL)) != 0 || + (r = sshbuf_get_bignum1(msg, NULL)) != 0 || + (r = sshbuf_get_bignum1(msg, NULL)) != 0 || + /* host key */ + (r = sshbuf_get_u32(msg, NULL)) != 0 || + (r = sshbuf_get_bignum1(msg, rsa->rsa->e)) != 0 || + (r = sshbuf_get_bignum1(msg, rsa->rsa->n)) != 0) { + buf_err: + error("%s: buffer error: %s", __func__, ssh_err(r)); + sshbuf_reset(msg); return NULL; } - buffer_consume(&msg, 8); /* cookie */ - - /* server key */ - (void) buffer_get_int(&msg); - buffer_get_bignum(&msg, rsa->rsa->e); - buffer_get_bignum(&msg, rsa->rsa->n); - - /* host key */ - (void) buffer_get_int(&msg); - buffer_get_bignum(&msg, rsa->rsa->e); - buffer_get_bignum(&msg, rsa->rsa->n); - buffer_clear(&msg); + sshbuf_reset(msg); return (rsa); } #endif static int -hostjump(Key *hostkey, struct ssh *ssh) +key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh) { - kexjmp_key = hostkey; - longjmp(kexjmp, 1); + con *c; + + if ((c = ssh_get_app_data(ssh)) != NULL) + keyprint(c, hostkey); + /* always abort key exchange */ + return -1; } static int @@ -227,48 +243,41 @@ ssh2_capable(int remote_major, int remote_minor) return 0; } -static Key * +static void keygrab_ssh2(con *c) { char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; - int r, j; + int r; - packet_set_connection(c->c_fd, c->c_fd); enable_compat20(); myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA ? "ssh-dss" : (c->c_keytype == KT_RSA ? "ssh-rsa" : (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); - if ((r = kex_setup(active_state, myproposal)) < 0) - fatal("%s: kex_setup: %s", __func__, ssh_err(r)); - c->c_kex = active_state->kex; -#ifdef WITH_OPENSSL - c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; - c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; - c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; - c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; - c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client; -#endif - c->c_kex->kex[KEX_C25519_SHA256] = kexc25519_client; - c->c_kex->verify_host_key = hostjump; - - if (!(j = setjmp(kexjmp))) { - nonfatal_fatal = 1; - dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, active_state); - fprintf(stderr, "Impossible! dispatch_run() returned!\n"); + if ((r = kex_setup(c->c_ssh, myproposal)) != 0) { + free(c->c_ssh); + fprintf(stderr, "kex_setup: %s\n", ssh_err(r)); exit(1); } - nonfatal_fatal = 0; - free(c->c_kex); - c->c_kex = NULL; - packet_close(); - - return j < 0? NULL : kexjmp_key; +#ifdef WITH_OPENSSL + c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; + c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_client; +#endif + c->c_ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_client; + ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper); + /* + * do the key-exchange until an error occurs or until + * the key_print_wrapper() callback sets c_done. + */ + ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done, c->c_ssh); } static void -keyprint(con *c, Key *key) +keyprint(con *c, struct sshkey *key) { char *host = c->c_output_name ? c->c_output_name : c->c_name; @@ -278,7 +287,7 @@ keyprint(con *c, Key *key) fatal("host_hash failed"); fprintf(stdout, "%s ", host); - key_write(key, stdout); + sshkey_write(key, stdout); fputs("\n", stdout); } @@ -366,6 +375,11 @@ confree(int s) free(fdcon[s].c_data); fdcon[s].c_status = CS_UNUSED; fdcon[s].c_keytype = 0; + if (fdcon[s].c_ssh) { + ssh_packet_close(fdcon[s].c_ssh); + free(fdcon[s].c_ssh); + fdcon[s].c_ssh = NULL; + } TAILQ_REMOVE(&tq, &fdcon[s], c_link); FD_CLR(s, read_wait); ncon--; @@ -433,11 +447,13 @@ congreet(int s) return; } *cp = '\0'; + c->c_ssh = ssh_packet_set_connection(NULL, s, s); + ssh_set_app_data(c->c_ssh, c); /* back link */ if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) == 3) - compat_datafellows(remote_version); + c->c_ssh->compat = compat_datafellows(remote_version); else - datafellows = 0; + c->c_ssh->compat = 0; if (c->c_keytype != KT_RSA1) { if (!ssh2_capable(remote_major, remote_minor)) { debug("%s doesn't support ssh2", c->c_name); @@ -464,7 +480,7 @@ congreet(int s) return; } if (c->c_keytype != KT_RSA1) { - keyprint(c, keygrab_ssh2(c)); + keygrab_ssh2(c); confree(s); return; } @@ -590,10 +606,7 @@ fatal(const char *fmt,...) va_start(args, fmt); do_log(SYSLOG_LEVEL_FATAL, fmt, args); va_end(args); - if (nonfatal_fatal) - longjmp(kexjmp, -1); - else - exit(255); + exit(255); } static void @@ -664,7 +677,7 @@ main(int argc, char **argv) get_keytypes = 0; tname = strtok(optarg, ","); while (tname) { - int type = key_type_from_name(tname); + int type = sshkey_type_from_name(tname); switch (type) { case KEY_RSA1: get_keytypes |= KT_RSA1;