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