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