1 /*
   2  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
   3  *
   4  * Modification and redistribution in source and binary forms is
   5  * permitted provided that due credit is given to the author and the
   6  * OpenBSD project by leaving this copyright notice intact.
   7  */
   8 
   9 /*
  10  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  11  * Use is subject to license terms.
  12  */
  13 
  14 #include "includes.h"
  15 RCSID("$OpenBSD: ssh-keyscan.c,v 1.40 2002/07/06 17:47:58 stevesk Exp $");
  16 
  17 #include "sys-queue.h"
  18 
  19 #include <openssl/bn.h>
  20 
  21 #include <setjmp.h>
  22 #include "xmalloc.h"
  23 #include "ssh.h"
  24 #include "ssh1.h"
  25 #include "key.h"
  26 #include "kex.h"
  27 #include "compat.h"
  28 #include "myproposal.h"
  29 #include "packet.h"
  30 #include "dispatch.h"
  31 #include "buffer.h"
  32 #include "bufaux.h"
  33 #include "log.h"
  34 #include "atomicio.h"
  35 #include "misc.h"
  36 
  37 /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
  38    Default value is AF_UNSPEC means both IPv4 and IPv6. */
  39 #ifdef IPV4_DEFAULT
  40 int IPv4or6 = AF_INET;
  41 #else
  42 int IPv4or6 = AF_UNSPEC;
  43 #endif
  44 
  45 int ssh_port = SSH_DEFAULT_PORT;
  46 
  47 #define KT_RSA1 1
  48 #define KT_DSA  2
  49 #define KT_RSA  4
  50 
  51 int get_keytypes = KT_RSA1;     /* Get only RSA1 keys by default */
  52 
  53 #define MAXMAXFD 256
  54 
  55 /* The number of seconds after which to give up on a TCP connection */
  56 int timeout = 5;
  57 
  58 int maxfd;
  59 #define MAXCON (maxfd - 10)
  60 
  61 #ifdef HAVE___PROGNAME
  62 extern char *__progname;
  63 #else
  64 char *__progname;
  65 #endif
  66 fd_set *read_wait;
  67 size_t read_wait_size;
  68 int ncon;
  69 int nonfatal_fatal = 0;
  70 jmp_buf kexjmp;
  71 Key *kexjmp_key;
  72 
  73 /*
  74  * Keep a connection structure for each file descriptor.  The state
  75  * associated with file descriptor n is held in fdcon[n].
  76  */
  77 typedef struct Connection {
  78         u_char c_status;        /* State of connection on this file desc. */
  79 #define CS_UNUSED 0             /* File descriptor unused */
  80 #define CS_CON 1                /* Waiting to connect/read greeting */
  81 #define CS_SIZE 2               /* Waiting to read initial packet size */
  82 #define CS_KEYS 3               /* Waiting to read public key packet */
  83         int c_fd;               /* Quick lookup: c->c_fd == c - fdcon */
  84         int c_plen;             /* Packet length field for ssh packet */
  85         int c_len;              /* Total bytes which must be read. */
  86         int c_off;              /* Length of data read so far. */
  87         int c_keytype;          /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
  88         char *c_namebase;       /* Address to free for c_name and c_namelist */
  89         char *c_name;           /* Hostname of connection for errors */
  90         char *c_namelist;       /* Pointer to other possible addresses */
  91         char *c_output_name;    /* Hostname of connection for output */
  92         char *c_data;           /* Data read from this fd */
  93         Kex *c_kex;             /* The key-exchange struct for ssh2 */
  94         struct timeval c_tv;    /* Time at which connection gets aborted */
  95         TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
  96 } con;
  97 
  98 TAILQ_HEAD(conlist, Connection) tq;     /* Timeout Queue */
  99 con *fdcon;
 100 
 101 /*
 102  *  This is just a wrapper around fgets() to make it usable.
 103  */
 104 
 105 /* Stress-test.  Increase this later. */
 106 #define LINEBUF_SIZE 16
 107 
 108 typedef struct {
 109         char *buf;
 110         u_int size;
 111         int lineno;
 112         const char *filename;
 113         FILE *stream;
 114         void (*errfun) (const char *,...);
 115 } Linebuf;
 116 
 117 static Linebuf *
 118 Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
 119 {
 120         Linebuf *lb;
 121 
 122         if (!(lb = malloc(sizeof(*lb)))) {
 123                 if (errfun)
 124                         (*errfun) ("linebuf (%s): malloc failed\n",
 125                             filename ? filename : "(stdin)");
 126                 return (NULL);
 127         }
 128         if (filename) {
 129                 lb->filename = filename;
 130                 if (!(lb->stream = fopen(filename, "r"))) {
 131                         xfree(lb);
 132                         if (errfun)
 133                                 (*errfun) ("%s: %s\n", filename, strerror(errno));
 134                         return (NULL);
 135                 }
 136         } else {
 137                 lb->filename = "(stdin)";
 138                 lb->stream = stdin;
 139         }
 140 
 141         if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
 142                 if (errfun)
 143                         (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
 144                 xfree(lb);
 145                 return (NULL);
 146         }
 147         lb->errfun = errfun;
 148         lb->lineno = 0;
 149         return (lb);
 150 }
 151 
 152 static void
 153 Linebuf_free(Linebuf * lb)
 154 {
 155         fclose(lb->stream);
 156         xfree(lb->buf);
 157         xfree(lb);
 158 }
 159 
 160 #if 0
 161 static void
 162 Linebuf_restart(Linebuf * lb)
 163 {
 164         clearerr(lb->stream);
 165         rewind(lb->stream);
 166         lb->lineno = 0;
 167 }
 168 
 169 static int
 170 Linebuf_lineno(Linebuf * lb)
 171 {
 172         return (lb->lineno);
 173 }
 174 #endif
 175 
 176 static char *
 177 Linebuf_getline(Linebuf * lb)
 178 {
 179         int n = 0;
 180         void *p;
 181 
 182         lb->lineno++;
 183         for (;;) {
 184                 /* Read a line */
 185                 if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
 186                         if (ferror(lb->stream) && lb->errfun)
 187                                 (*lb->errfun)("%s: %s\n", lb->filename,
 188                                     strerror(errno));
 189                         return (NULL);
 190                 }
 191                 n = strlen(lb->buf);
 192 
 193                 /* Return it or an error if it fits */
 194                 if (n > 0 && lb->buf[n - 1] == '\n') {
 195                         lb->buf[n - 1] = '\0';
 196                         return (lb->buf);
 197                 }
 198                 if (n != lb->size - 1) {
 199                         if (lb->errfun)
 200                                 (*lb->errfun)("%s: skipping incomplete last line\n",
 201                                     lb->filename);
 202                         return (NULL);
 203                 }
 204                 /* Double the buffer if we need more space */
 205                 lb->size *= 2;
 206                 if ((p = realloc(lb->buf, lb->size)) == NULL) {
 207                         lb->size /= 2;
 208                         if (lb->errfun)
 209                                 (*lb->errfun)("linebuf (%s): realloc failed\n",
 210                                     lb->filename);
 211                         return (NULL);
 212                 }
 213                 lb->buf = p;
 214         }
 215 }
 216 
 217 static int
 218 fdlim_get(int hard)
 219 {
 220 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
 221         struct rlimit rlfd;
 222 
 223         if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
 224                 return (-1);
 225         if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
 226                 return 10000;
 227         else
 228                 return hard ? rlfd.rlim_max : rlfd.rlim_cur;
 229 #elif defined (HAVE_SYSCONF)
 230         return sysconf (_SC_OPEN_MAX);
 231 #else
 232         return 10000;
 233 #endif
 234 }
 235 
 236 static int
 237 fdlim_set(int lim)
 238 {
 239 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
 240         struct rlimit rlfd;
 241 #endif
 242 
 243         if (lim <= 0)
 244                 return (-1);
 245 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
 246         if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
 247                 return (-1);
 248         rlfd.rlim_cur = lim;
 249         if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
 250                 return (-1);
 251 #elif defined (HAVE_SETDTABLESIZE)
 252         setdtablesize(lim);
 253 #endif
 254         return (0);
 255 }
 256 
 257 /*
 258  * This is an strsep function that returns a null field for adjacent
 259  * separators.  This is the same as the 4.4BSD strsep, but different from the
 260  * one in the GNU libc.
 261  */
 262 static char *
 263 xstrsep(char **str, const char *delim)
 264 {
 265         char *s, *e;
 266 
 267         if (!**str)
 268                 return (NULL);
 269 
 270         s = *str;
 271         e = s + strcspn(s, delim);
 272 
 273         if (*e != '\0')
 274                 *e++ = '\0';
 275         *str = e;
 276 
 277         return (s);
 278 }
 279 
 280 /*
 281  * Get the next non-null token (like GNU strsep).  Strsep() will return a
 282  * null token for two adjacent separators, so we may have to loop.
 283  */
 284 static char *
 285 strnnsep(char **stringp, char *delim)
 286 {
 287         char *tok;
 288 
 289         do {
 290                 tok = xstrsep(stringp, delim);
 291         } while (tok && *tok == '\0');
 292         return (tok);
 293 }
 294 
 295 static Key *
 296 keygrab_ssh1(con *c)
 297 {
 298         static Key *rsa;
 299         static Buffer msg;
 300 
 301         if (rsa == NULL) {
 302                 buffer_init(&msg);
 303                 rsa = key_new(KEY_RSA1);
 304         }
 305         buffer_append(&msg, c->c_data, c->c_plen);
 306         buffer_consume(&msg, 8 - (c->c_plen & 7));   /* padding */
 307         if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
 308                 error("%s: invalid packet type", c->c_name);
 309                 buffer_clear(&msg);
 310                 return NULL;
 311         }
 312         buffer_consume(&msg, 8);            /* cookie */
 313 
 314         /* server key */
 315         (void) buffer_get_int(&msg);
 316         buffer_get_bignum(&msg, rsa->rsa->e);
 317         buffer_get_bignum(&msg, rsa->rsa->n);
 318 
 319         /* host key */
 320         (void) buffer_get_int(&msg);
 321         buffer_get_bignum(&msg, rsa->rsa->e);
 322         buffer_get_bignum(&msg, rsa->rsa->n);
 323 
 324         buffer_clear(&msg);
 325 
 326         return (rsa);
 327 }
 328 
 329 static int
 330 hostjump(Key *hostkey)
 331 {
 332         kexjmp_key = hostkey;
 333         longjmp(kexjmp, 1);
 334         /* NOTREACHED */
 335         return (0);
 336 }
 337 
 338 static int
 339 ssh2_capable(int remote_major, int remote_minor)
 340 {
 341         switch (remote_major) {
 342         case 1:
 343                 if (remote_minor == 99)
 344                         return 1;
 345                 break;
 346         case 2:
 347                 return 1;
 348         default:
 349                 break;
 350         }
 351         return 0;
 352 }
 353 
 354 static Key *
 355 keygrab_ssh2(con *c)
 356 {
 357         int j;
 358 
 359         packet_set_connection(c->c_fd, c->c_fd);
 360         enable_compat20();
 361         my_clnt_proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
 362             c->c_keytype == KT_DSA? "ssh-dss": "ssh-rsa";
 363         c->c_kex = kex_setup(c->c_name, my_clnt_proposal, NULL);
 364         kex_start(c->c_kex);
 365         c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
 366         c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
 367         c->c_kex->verify_host_key = hostjump;
 368 
 369         if (!(j = setjmp(kexjmp))) {
 370                 nonfatal_fatal = 1;
 371                 dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
 372                 fprintf(stderr, "Impossible! dispatch_run() returned!\n");
 373                 exit(1);
 374         }
 375         nonfatal_fatal = 0;
 376         xfree(c->c_kex);
 377         c->c_kex = NULL;
 378         packet_close();
 379 
 380         return j < 0? NULL : kexjmp_key;
 381 }
 382 
 383 static void
 384 keyprint(con *c, Key *key)
 385 {
 386         if (!key)
 387                 return;
 388 
 389         fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
 390         key_write(key, stdout);
 391         fputs("\n", stdout);
 392 }
 393 
 394 static int
 395 tcpconnect(char *host)
 396 {
 397         struct addrinfo hints, *ai, *aitop;
 398         char strport[NI_MAXSERV];
 399         int gaierr, s = -1;
 400 
 401         snprintf(strport, sizeof strport, "%d", ssh_port);
 402         memset(&hints, 0, sizeof(hints));
 403         hints.ai_family = IPv4or6;
 404         hints.ai_socktype = SOCK_STREAM;
 405         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
 406                 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
 407         for (ai = aitop; ai; ai = ai->ai_next) {
 408                 s = socket(ai->ai_family, SOCK_STREAM, 0);
 409                 if (s < 0) {
 410                         error("socket: %s", strerror(errno));
 411                         continue;
 412                 }
 413                 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
 414                         fatal("F_SETFL: %s", strerror(errno));
 415                 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
 416                     errno != EINPROGRESS)
 417                         error("connect (`%s'): %s", host, strerror(errno));
 418                 else
 419                         break;
 420                 close(s);
 421                 s = -1;
 422         }
 423         freeaddrinfo(aitop);
 424         return s;
 425 }
 426 
 427 static int
 428 conalloc(char *iname, char *oname, int keytype)
 429 {
 430         char *namebase, *name, *namelist;
 431         int s;
 432 
 433         namebase = namelist = xstrdup(iname);
 434 
 435         do {
 436                 name = xstrsep(&namelist, ",");
 437                 if (!name) {
 438                         xfree(namebase);
 439                         return (-1);
 440                 }
 441         } while ((s = tcpconnect(name)) < 0);
 442 
 443         if (s >= maxfd)
 444                 fatal("conalloc: fdno %d too high", s);
 445         if (fdcon[s].c_status)
 446                 fatal("conalloc: attempt to reuse fdno %d", s);
 447 
 448         fdcon[s].c_fd = s;
 449         fdcon[s].c_status = CS_CON;
 450         fdcon[s].c_namebase = namebase;
 451         fdcon[s].c_name = name;
 452         fdcon[s].c_namelist = namelist;
 453         fdcon[s].c_output_name = xstrdup(oname);
 454         fdcon[s].c_data = (char *) &fdcon[s].c_plen;
 455         fdcon[s].c_len = 4;
 456         fdcon[s].c_off = 0;
 457         fdcon[s].c_keytype = keytype;
 458         gettimeofday(&fdcon[s].c_tv, NULL);
 459         fdcon[s].c_tv.tv_sec += timeout;
 460         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
 461         FD_SET(s, read_wait);
 462         ncon++;
 463         return (s);
 464 }
 465 
 466 static void
 467 confree(int s)
 468 {
 469         if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
 470                 fatal("confree: attempt to free bad fdno %d", s);
 471         close(s);
 472         xfree(fdcon[s].c_namebase);
 473         xfree(fdcon[s].c_output_name);
 474         if (fdcon[s].c_status == CS_KEYS)
 475                 xfree(fdcon[s].c_data);
 476         fdcon[s].c_status = CS_UNUSED;
 477         fdcon[s].c_keytype = 0;
 478         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
 479         FD_CLR(s, read_wait);
 480         ncon--;
 481 }
 482 
 483 static void
 484 contouch(int s)
 485 {
 486         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
 487         gettimeofday(&fdcon[s].c_tv, NULL);
 488         fdcon[s].c_tv.tv_sec += timeout;
 489         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
 490 }
 491 
 492 static int
 493 conrecycle(int s)
 494 {
 495         con *c = &fdcon[s];
 496         int ret;
 497 
 498         ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
 499         confree(s);
 500         return (ret);
 501 }
 502 
 503 static void
 504 congreet(int s)
 505 {
 506         int remote_major, remote_minor, n = 0;
 507         char buf[256], *cp;
 508         char remote_version[sizeof buf];
 509         size_t bufsiz;
 510         con *c = &fdcon[s];
 511 
 512         bufsiz = sizeof(buf);
 513         cp = buf;
 514         while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n') {
 515                 if (*cp == '\r')
 516                         *cp = '\n';
 517                 cp++;
 518         }
 519         if (n < 0) {
 520                 if (errno != ECONNREFUSED)
 521                         error("read (%s): %s", c->c_name, strerror(errno));
 522                 conrecycle(s);
 523                 return;
 524         }
 525         if (n == 0) {
 526                 error("%s: Connection closed by remote host", c->c_name);
 527                 conrecycle(s);
 528                 return;
 529         }
 530         if (*cp != '\n' && *cp != '\r') {
 531                 error("%s: bad greeting", c->c_name);
 532                 confree(s);
 533                 return;
 534         }
 535         *cp = '\0';
 536         if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
 537             &remote_major, &remote_minor, remote_version) == 3)
 538                 compat_datafellows(remote_version);
 539         else
 540                 datafellows = 0;
 541         if (c->c_keytype != KT_RSA1) {
 542                 if (!ssh2_capable(remote_major, remote_minor)) {
 543                         debug("%s doesn't support ssh2", c->c_name);
 544                         confree(s);
 545                         return;
 546                 }
 547         } else if (remote_major != 1) {
 548                 debug("%s doesn't support ssh1", c->c_name);
 549                 confree(s);
 550                 return;
 551         }
 552         fprintf(stderr, "# %s %s\n", c->c_name, chop(buf));
 553         n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
 554             c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
 555             c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
 556         if (atomicio(write, s, buf, n) != n) {
 557                 error("write (%s): %s", c->c_name, strerror(errno));
 558                 confree(s);
 559                 return;
 560         }
 561         if (c->c_keytype != KT_RSA1) {
 562                 keyprint(c, keygrab_ssh2(c));
 563                 confree(s);
 564                 return;
 565         }
 566         c->c_status = CS_SIZE;
 567         contouch(s);
 568 }
 569 
 570 static void
 571 conread(int s)
 572 {
 573         con *c = &fdcon[s];
 574         int n;
 575 
 576         if (c->c_status == CS_CON) {
 577                 congreet(s);
 578                 return;
 579         }
 580         n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
 581         if (n < 0) {
 582                 error("read (%s): %s", c->c_name, strerror(errno));
 583                 confree(s);
 584                 return;
 585         }
 586         c->c_off += n;
 587 
 588         if (c->c_off == c->c_len)
 589                 switch (c->c_status) {
 590                 case CS_SIZE:
 591                         c->c_plen = htonl(c->c_plen);
 592                         c->c_len = c->c_plen + 8 - (c->c_plen & 7);
 593                         c->c_off = 0;
 594                         c->c_data = xmalloc(c->c_len);
 595                         c->c_status = CS_KEYS;
 596                         break;
 597                 case CS_KEYS:
 598                         keyprint(c, keygrab_ssh1(c));
 599                         confree(s);
 600                         return;
 601                         break;
 602                 default:
 603                         fatal("conread: invalid status %d", c->c_status);
 604                         break;
 605                 }
 606 
 607         contouch(s);
 608 }
 609 
 610 static void
 611 conloop(void)
 612 {
 613         struct timeval seltime, now;
 614         fd_set *r, *e;
 615         con *c;
 616         int i;
 617 
 618         gettimeofday(&now, NULL);
 619         c = TAILQ_FIRST(&tq);
 620 
 621         if (c && (c->c_tv.tv_sec > now.tv_sec ||
 622             (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
 623                 seltime = c->c_tv;
 624                 seltime.tv_sec -= now.tv_sec;
 625                 seltime.tv_usec -= now.tv_usec;
 626                 if (seltime.tv_usec < 0) {
 627                         seltime.tv_usec += 1000000;
 628                         seltime.tv_sec--;
 629                 }
 630         } else
 631                 seltime.tv_sec = seltime.tv_usec = 0;
 632 
 633         r = xmalloc(read_wait_size);
 634         memcpy(r, read_wait, read_wait_size);
 635         e = xmalloc(read_wait_size);
 636         memcpy(e, read_wait, read_wait_size);
 637 
 638         while (select(maxfd, r, NULL, e, &seltime) == -1 &&
 639             (errno == EAGAIN || errno == EINTR))
 640                 ;
 641 
 642         for (i = 0; i < maxfd; i++) {
 643                 if (FD_ISSET(i, e)) {
 644                         error("%s: exception!", fdcon[i].c_name);
 645                         confree(i);
 646                 } else if (FD_ISSET(i, r))
 647                         conread(i);
 648         }
 649         xfree(r);
 650         xfree(e);
 651 
 652         c = TAILQ_FIRST(&tq);
 653         while (c && (c->c_tv.tv_sec < now.tv_sec ||
 654             (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
 655                 int s = c->c_fd;
 656 
 657                 c = TAILQ_NEXT(c, c_link);
 658                 conrecycle(s);
 659         }
 660 }
 661 
 662 static void
 663 do_host(char *host)
 664 {
 665         char *name = strnnsep(&host, " \t\n");
 666         int j;
 667 
 668         if (name == NULL)
 669                 return;
 670         for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
 671                 if (get_keytypes & j) {
 672                         while (ncon >= MAXCON)
 673                                 conloop();
 674                         conalloc(name, *host ? host : name, j);
 675                 }
 676         }
 677 }
 678 
 679 void
 680 fatal(const char *fmt,...)
 681 {
 682         va_list args;
 683 
 684         va_start(args, fmt);
 685         do_log(SYSLOG_LEVEL_FATAL, fmt, args);
 686         va_end(args);
 687         if (nonfatal_fatal)
 688                 longjmp(kexjmp, -1);
 689         else
 690                 fatal_cleanup();
 691 }
 692 
 693 static void
 694 usage(void)
 695 {
 696         fprintf(stderr,
 697                 gettext("Usage: %s [-v46] [-p port] [-T timeout] [-f file]\n"
 698                         "\t\t   [host | addrlist namelist] [...]\n"),
 699             __progname);
 700         exit(1);
 701 }
 702 
 703 int
 704 main(int argc, char **argv)
 705 {
 706         int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
 707         int opt, fopt_count = 0;
 708         char *tname;
 709 
 710         extern int optind;
 711         extern char *optarg;
 712 
 713         __progname = get_progname(argv[0]);
 714 
 715         (void) g11n_setlocale(LC_ALL, "");
 716 
 717         init_rng();
 718         seed_rng();
 719         TAILQ_INIT(&tq);
 720 
 721         if (argc <= 1)
 722                 usage();
 723 
 724         while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
 725                 switch (opt) {
 726                 case 'p':
 727                         ssh_port = a2port(optarg);
 728                         if (ssh_port == 0) {
 729                                 fprintf(stderr, gettext("Bad port '%s'\n"),
 730                                         optarg);
 731                                 exit(1);
 732                         }
 733                         break;
 734                 case 'T':
 735                         timeout = convtime(optarg);
 736                         if (timeout == -1 || timeout == 0) {
 737                                 fprintf(stderr, gettext("Bad timeout '%s'\n"),
 738                                         optarg);
 739                                 usage();
 740                         }
 741                         break;
 742                 case 'v':
 743                         if (!debug_flag) {
 744                                 debug_flag = 1;
 745                                 log_level = SYSLOG_LEVEL_DEBUG1;
 746                         }
 747                         else if (log_level < SYSLOG_LEVEL_DEBUG3)
 748                                 log_level++;
 749                         else
 750                                 fatal("Too high debugging level.");
 751                         break;
 752                 case 'f':
 753                         if (strcmp(optarg, "-") == 0)
 754                                 optarg = NULL;
 755                         argv[fopt_count++] = optarg;
 756                         break;
 757                 case 't':
 758                         get_keytypes = 0;
 759                         tname = strtok(optarg, ",");
 760                         while (tname) {
 761                                 int type = key_type_from_name(tname);
 762                                 switch (type) {
 763                                 case KEY_RSA1:
 764                                         get_keytypes |= KT_RSA1;
 765                                         break;
 766                                 case KEY_DSA:
 767                                         get_keytypes |= KT_DSA;
 768                                         break;
 769                                 case KEY_RSA:
 770                                         get_keytypes |= KT_RSA;
 771                                         break;
 772                                 case KEY_UNSPEC:
 773                                         fatal("unknown key type %s", tname);
 774                                 }
 775                                 tname = strtok(NULL, ",");
 776                         }
 777                         break;
 778                 case '4':
 779                         IPv4or6 = AF_INET;
 780                         break;
 781                 case '6':
 782                         IPv4or6 = AF_INET6;
 783                         break;
 784                 case '?':
 785                 default:
 786                         usage();
 787                 }
 788         }
 789         if (optind == argc && !fopt_count)
 790                 usage();
 791 
 792         log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
 793 
 794         maxfd = fdlim_get(1);
 795         if (maxfd < 0)
 796                 fatal("%s: fdlim_get: bad value", __progname);
 797         if (maxfd > MAXMAXFD)
 798                 maxfd = MAXMAXFD;
 799         if (MAXCON <= 0)
 800                 fatal("%s: not enough file descriptors", __progname);
 801         if (maxfd > fdlim_get(0))
 802                 fdlim_set(maxfd);
 803         fdcon = xmalloc(maxfd * sizeof(con));
 804         memset(fdcon, 0, maxfd * sizeof(con));
 805 
 806         read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
 807         read_wait = xmalloc(read_wait_size);
 808         memset(read_wait, 0, read_wait_size);
 809 
 810         if (fopt_count) {
 811                 Linebuf *lb;
 812                 char *line;
 813                 int j;
 814 
 815                 for (j = 0; j < fopt_count; j++) {
 816                         lb = Linebuf_alloc(argv[j], error);
 817                         if (!lb)
 818                                 continue;
 819                         while ((line = Linebuf_getline(lb)) != NULL)
 820                                 do_host(line);
 821                         Linebuf_free(lb);
 822                 }
 823         }
 824 
 825         while (optind < argc)
 826                 do_host(argv[optind++]);
 827 
 828         while (ncon > 0)
 829                 conloop();
 830 
 831         return (0);
 832 }