]> andersk Git - openssh.git/blobdiff - ssh-keyscan.c
- djm@cvs.openbsd.org 2010/01/30 02:54:53
[openssh.git] / ssh-keyscan.c
index 80eab26927f734240bbfe6d8034a271ac46242d5..7afe446ae2889baa2bebff60acca23830a74074d 100644 (file)
@@ -1,3 +1,4 @@
+/* $OpenBSD: ssh-keyscan.c,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */
 /*
  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
  *
@@ -7,40 +8,47 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh-keyscan.c,v 1.33 2001/12/10 20:34:31 markus Exp $");
-
-#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H)
-#include <sys/queue.h>
-#else
-#include "openbsd-compat/fake-queue.h"
+#include "openbsd-compat/sys-queue.h"
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
 #endif
-#include <errno.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <openssl/bn.h>
 
+#include <netdb.h>
+#include <errno.h>
 #include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
+#include "buffer.h"
 #include "key.h"
+#include "cipher.h"
 #include "kex.h"
 #include "compat.h"
 #include "myproposal.h"
 #include "packet.h"
 #include "dispatch.h"
-#include "buffer.h"
-#include "bufaux.h"
 #include "log.h"
 #include "atomicio.h"
 #include "misc.h"
+#include "hostfile.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. */
-#ifdef IPV4_DEFAULT
-int IPv4or6 = AF_INET;
-#else
 int IPv4or6 = AF_UNSPEC;
-#endif
 
 int ssh_port = SSH_DEFAULT_PORT;
 
@@ -48,7 +56,9 @@ int ssh_port = SSH_DEFAULT_PORT;
 #define KT_DSA 2
 #define KT_RSA 4
 
-int get_keytypes = KT_RSA1;    /* Get only RSA1 keys by default */
+int get_keytypes = KT_RSA;     /* Get only RSA keys by default */
+
+int hash_hosts = 0;            /* Hash hostname on output */
 
 #define MAXMAXFD 256
 
@@ -58,13 +68,9 @@ int timeout = 5;
 int maxfd;
 #define MAXCON (maxfd - 10)
 
-#ifdef HAVE___PROGNAME
 extern char *__progname;
-#else
-char *__progname;
-#endif
 fd_set *read_wait;
-size_t read_wait_size;
+size_t read_wait_nfdset;
 int ncon;
 int nonfatal_fatal = 0;
 jmp_buf kexjmp;
@@ -121,7 +127,8 @@ Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
 
        if (!(lb = malloc(sizeof(*lb)))) {
                if (errfun)
-                       (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+                       (*errfun) ("linebuf (%s): malloc failed\n",
+                           filename ? filename : "(stdin)");
                return (NULL);
        }
        if (filename) {
@@ -137,7 +144,7 @@ Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
                lb->stream = stdin;
        }
 
-       if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
+       if (!(lb->buf = malloc((lb->size = LINEBUF_SIZE)))) {
                if (errfun)
                        (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
                xfree(lb);
@@ -175,14 +182,15 @@ Linebuf_lineno(Linebuf * lb)
 static char *
 Linebuf_getline(Linebuf * lb)
 {
-       int n = 0;
+       size_t n = 0;
+       void *p;
 
        lb->lineno++;
        for (;;) {
                /* Read a line */
                if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
                        if (ferror(lb->stream) && lb->errfun)
-                               (*lb->errfun) ("%s: %s\n", lb->filename,
+                               (*lb->errfun)("%s: %s\n", lb->filename,
                                    strerror(errno));
                        return (NULL);
                }
@@ -195,17 +203,20 @@ Linebuf_getline(Linebuf * lb)
                }
                if (n != lb->size - 1) {
                        if (lb->errfun)
-                               (*lb->errfun) ("%s: skipping incomplete last line\n",
+                               (*lb->errfun)("%s: skipping incomplete last line\n",
                                    lb->filename);
                        return (NULL);
                }
                /* Double the buffer if we need more space */
-               if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) {
+               lb->size *= 2;
+               if ((p = realloc(lb->buf, lb->size)) == NULL) {
+                       lb->size /= 2;
                        if (lb->errfun)
-                               (*lb->errfun) ("linebuf (%s): realloc failed\n",
+                               (*lb->errfun)("linebuf (%s): realloc failed\n",
                                    lb->filename);
                        return (NULL);
                }
+               lb->buf = p;
        }
 }
 
@@ -218,13 +229,11 @@ fdlim_get(int hard)
        if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
                return (-1);
        if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
-               return 10000;
+               return SSH_SYSFDMAX;
        else
                return hard ? rlfd.rlim_max : rlfd.rlim_cur;
-#elif defined (HAVE_SYSCONF)
-       return sysconf (_SC_OPEN_MAX);
 #else
-       return 10000;
+       return SSH_SYSFDMAX;
 #endif
 }
 
@@ -234,6 +243,7 @@ fdlim_set(int lim)
 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
        struct rlimit rlfd;
 #endif
+
        if (lim <= 0)
                return (-1);
 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
@@ -353,6 +363,10 @@ keygrab_ssh2(con *c)
        myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
            "ssh-dss": "ssh-rsa";
        c->c_kex = kex_setup(myproposal);
+       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->verify_host_key = hostjump;
 
        if (!(j = setjmp(kexjmp))) {
@@ -372,10 +386,14 @@ keygrab_ssh2(con *c)
 static void
 keyprint(con *c, Key *key)
 {
+       char *host = c->c_output_name ? c->c_output_name : c->c_name;
+
        if (!key)
                return;
+       if (hash_hosts && (host = host_hash(host, NULL, 0)) == NULL)
+               fatal("host_hash failed");
 
-       fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
+       fprintf(stdout, "%s ", host);
        key_write(key, stdout);
        fputs("\n", stdout);
 }
@@ -392,15 +410,15 @@ tcpconnect(char *host)
        hints.ai_family = IPv4or6;
        hints.ai_socktype = SOCK_STREAM;
        if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
-               fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
+               fatal("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
        for (ai = aitop; ai; ai = ai->ai_next) {
-               s = socket(ai->ai_family, SOCK_STREAM, 0);
+               s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
                if (s < 0) {
                        error("socket: %s", strerror(errno));
                        continue;
                }
-               if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
-                       fatal("F_SETFL: %s", strerror(errno));
+               if (set_nonblock(s) == -1)
+                       fatal("%s: set_nonblock(%d)", __func__, s);
                if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
                    errno != EINPROGRESS)
                        error("connect (`%s'): %s", host, strerror(errno));
@@ -416,8 +434,8 @@ tcpconnect(char *host)
 static int
 conalloc(char *iname, char *oname, int keytype)
 {
-       int s;
        char *namebase, *name, *namelist;
+       int s;
 
        namebase = namelist = xstrdup(iname);
 
@@ -481,8 +499,8 @@ contouch(int s)
 static int
 conrecycle(int s)
 {
-       int ret;
        con *c = &fdcon[s];
+       int ret;
 
        ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
        confree(s);
@@ -492,22 +510,36 @@ conrecycle(int s)
 static void
 congreet(int s)
 {
+       int n = 0, remote_major = 0, remote_minor = 0;
        char buf[256], *cp;
        char remote_version[sizeof buf];
        size_t bufsiz;
-       int remote_major, remote_minor, n = 0;
        con *c = &fdcon[s];
 
-       bufsiz = sizeof(buf);
-       cp = buf;
-       while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n') {
-               if (*cp == '\r')
-                       *cp = '\n';
-               cp++;
+       for (;;) {
+               memset(buf, '\0', sizeof(buf));
+               bufsiz = sizeof(buf);
+               cp = buf;
+               while (bufsiz-- &&
+                   (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
+                       if (*cp == '\r')
+                               *cp = '\n';
+                       cp++;
+               }
+               if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
+                       break;
        }
-       if (n < 0) {
-               if (errno != ECONNREFUSED)
+       if (n == 0) {
+               switch (errno) {
+               case EPIPE:
+                       error("%s: Connection closed by remote host", c->c_name);
+                       break;
+               case ECONNREFUSED:
+                       break;
+               default:
                        error("read (%s): %s", c->c_name, strerror(errno));
+                       break;
+               }
                conrecycle(s);
                return;
        }
@@ -537,7 +569,12 @@ congreet(int s)
        n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
            c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
            c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
-       if (atomicio(write, s, buf, n) != n) {
+       if (n < 0 || (size_t)n >= sizeof(buf)) {
+               error("snprintf: buffer too small");
+               confree(s);
+               return;
+       }
+       if (atomicio(vwrite, s, buf, n) != (size_t)n) {
                error("write (%s): %s", c->c_name, strerror(errno));
                confree(s);
                return;
@@ -554,15 +591,15 @@ congreet(int s)
 static void
 conread(int s)
 {
-       int n;
        con *c = &fdcon[s];
+       size_t n;
 
        if (c->c_status == CS_CON) {
                congreet(s);
                return;
        }
-       n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
-       if (n < 0) {
+       n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
+       if (n == 0) {
                error("read (%s): %s", c->c_name, strerror(errno));
                confree(s);
                return;
@@ -582,7 +619,6 @@ conread(int s)
                        keyprint(c, keygrab_ssh1(c));
                        confree(s);
                        return;
-                       break;
                default:
                        fatal("conread: invalid status %d", c->c_status);
                        break;
@@ -594,13 +630,13 @@ conread(int s)
 static void
 conloop(void)
 {
-       fd_set *r, *e;
        struct timeval seltime, now;
-       int i;
+       fd_set *r, *e;
        con *c;
+       int i;
 
        gettimeofday(&now, NULL);
-       c = tq.tqh_first;
+       c = TAILQ_FIRST(&tq);
 
        if (c && (c->c_tv.tv_sec > now.tv_sec ||
            (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
@@ -614,13 +650,13 @@ conloop(void)
        } else
                seltime.tv_sec = seltime.tv_usec = 0;
 
-       r = xmalloc(read_wait_size);
-       memcpy(r, read_wait, read_wait_size);
-       e = xmalloc(read_wait_size);
-       memcpy(e, read_wait, read_wait_size);
+       r = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+       e = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+       memcpy(r, read_wait, read_wait_nfdset * sizeof(fd_mask));
+       memcpy(e, read_wait, read_wait_nfdset * sizeof(fd_mask));
 
        while (select(maxfd, r, NULL, e, &seltime) == -1 &&
-           (errno == EAGAIN || errno == EINTR))
+           (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
                ;
 
        for (i = 0; i < maxfd; i++) {
@@ -633,12 +669,12 @@ conloop(void)
        xfree(r);
        xfree(e);
 
-       c = tq.tqh_first;
+       c = TAILQ_FIRST(&tq);
        while (c && (c->c_tv.tv_sec < now.tv_sec ||
            (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
                int s = c->c_fd;
 
-               c = c->c_link.tqe_next;
+               c = TAILQ_NEXT(c, c_link);
                conrecycle(s);
        }
 }
@@ -660,26 +696,27 @@ do_host(char *host)
        }
 }
 
-static void
-fatal_callback(void *arg)
+void
+fatal(const char *fmt,...)
 {
+       va_list args;
+
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+       va_end(args);
        if (nonfatal_fatal)
                longjmp(kexjmp, -1);
+       else
+               exit(255);
 }
 
 static void
 usage(void)
 {
-       fprintf(stderr, "Usage: %s [options] host ...\n",
+       fprintf(stderr,
+           "usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n"
+           "\t\t   [host | addrlist namelist] ...\n",
            __progname);
-       fprintf(stderr, "Options:\n");
-       fprintf(stderr, "  -f file     Read hosts or addresses from file.\n");
-       fprintf(stderr, "  -p port     Connect to the specified port.\n");
-       fprintf(stderr, "  -t keytype  Specify the host key type.\n");
-       fprintf(stderr, "  -T timeout  Set connection timeout.\n");
-        fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
-        fprintf(stderr, "  -4          Use IPv4 only.\n");
-        fprintf(stderr, "  -6          Use IPv6 only.\n");
        exit(1);
 }
 
@@ -693,27 +730,35 @@ main(int argc, char **argv)
        extern int optind;
        extern char *optarg;
 
-       __progname = get_progname(argv[0]);
+       __progname = ssh_get_progname(argv[0]);
        init_rng();
        seed_rng();
        TAILQ_INIT(&tq);
 
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
        if (argc <= 1)
                usage();
 
-       while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
+       while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) {
                switch (opt) {
+               case 'H':
+                       hash_hosts = 1;
+                       break;
                case 'p':
                        ssh_port = a2port(optarg);
-                       if (ssh_port == 0) {
+                       if (ssh_port <= 0) {
                                fprintf(stderr, "Bad port '%s'\n", optarg);
                                exit(1);
                        }
                        break;
                case 'T':
-                       timeout = atoi(optarg);
-                       if (timeout <= 0)
+                       timeout = convtime(optarg);
+                       if (timeout == -1 || timeout == 0) {
+                               fprintf(stderr, "Bad timeout '%s'\n", optarg);
                                usage();
+                       }
                        break;
                case 'v':
                        if (!debug_flag) {
@@ -766,7 +811,6 @@ main(int argc, char **argv)
                usage();
 
        log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
-       fatal_add_cleanup(fatal_callback, NULL);
 
        maxfd = fdlim_get(1);
        if (maxfd < 0)
@@ -777,12 +821,10 @@ main(int argc, char **argv)
                fatal("%s: not enough file descriptors", __progname);
        if (maxfd > fdlim_get(0))
                fdlim_set(maxfd);
-       fdcon = xmalloc(maxfd * sizeof(con));
-       memset(fdcon, 0, maxfd * sizeof(con));
+       fdcon = xcalloc(maxfd, sizeof(con));
 
-       read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
-       read_wait = xmalloc(read_wait_size);
-       memset(read_wait, 0, read_wait_size);
+       read_wait_nfdset = howmany(maxfd, NFDBITS);
+       read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask));
 
        if (fopt_count) {
                Linebuf *lb;
This page took 0.064518 seconds and 4 git commands to generate.