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