1 /* $OpenBSD: ssh-keyscan.c,v 1.149 2022/12/26 19:16:03 jmc 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 <sys/types.h> 13 #include "openbsd-compat/sys-queue.h" 14 #include <sys/resource.h> 15 #ifdef HAVE_SYS_TIME_H 16 # include <sys/time.h> 17 #endif 18 19 #include <netinet/in.h> 20 #include <arpa/inet.h> 21 22 #ifdef WITH_OPENSSL 23 #include <openssl/bn.h> 24 #endif 25 26 #include <netdb.h> 27 #include <errno.h> 28 #ifdef HAVE_POLL_H 29 #include <poll.h> 30 #endif 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <signal.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "xmalloc.h" 39 #include "ssh.h" 40 #include "sshbuf.h" 41 #include "sshkey.h" 42 #include "cipher.h" 43 #include "kex.h" 44 #include "compat.h" 45 #include "myproposal.h" 46 #include "packet.h" 47 #include "dispatch.h" 48 #include "log.h" 49 #include "atomicio.h" 50 #include "misc.h" 51 #include "hostfile.h" 52 #include "ssherr.h" 53 #include "ssh_api.h" 54 #include "dns.h" 55 #include "addr.h" 56 57 /* Flag indicating whether IPv4 or IPv6. This can be set on the command line. 58 Default value is AF_UNSPEC means both IPv4 and IPv6. */ 59 int IPv4or6 = AF_UNSPEC; 60 61 int ssh_port = SSH_DEFAULT_PORT; 62 63 #define KT_DSA (1) 64 #define KT_RSA (1<<1) 65 #define KT_ECDSA (1<<2) 66 #define KT_ED25519 (1<<3) 67 #define KT_XMSS (1<<4) 68 #define KT_ECDSA_SK (1<<5) 69 #define KT_ED25519_SK (1<<6) 70 71 #define KT_MIN KT_DSA 72 #define KT_MAX KT_ED25519_SK 73 74 int get_cert = 0; 75 int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK; 76 77 int hash_hosts = 0; /* Hash hostname on output */ 78 79 int print_sshfp = 0; /* Print SSHFP records instead of known_hosts */ 80 81 int found_one = 0; /* Successfully found a key */ 82 83 #define MAXMAXFD 256 84 85 /* The number of seconds after which to give up on a TCP connection */ 86 int timeout = 5; 87 88 int maxfd; 89 #define MAXCON (maxfd - 10) 90 91 extern char *__progname; 92 struct pollfd *read_wait; 93 int ncon; 94 95 /* 96 * Keep a connection structure for each file descriptor. The state 97 * associated with file descriptor n is held in fdcon[n]. 98 */ 99 typedef struct Connection { 100 u_char c_status; /* State of connection on this file desc. */ 101 #define CS_UNUSED 0 /* File descriptor unused */ 102 #define CS_CON 1 /* Waiting to connect/read greeting */ 103 #define CS_SIZE 2 /* Waiting to read initial packet size */ 104 #define CS_KEYS 3 /* Waiting to read public key packet */ 105 int c_fd; /* Quick lookup: c->c_fd == c - fdcon */ 106 int c_plen; /* Packet length field for ssh packet */ 107 int c_len; /* Total bytes which must be read. */ 108 int c_off; /* Length of data read so far. */ 109 int c_keytype; /* Only one of KT_* */ 110 sig_atomic_t c_done; /* SSH2 done */ 111 char *c_namebase; /* Address to free for c_name and c_namelist */ 112 char *c_name; /* Hostname of connection for errors */ 113 char *c_namelist; /* Pointer to other possible addresses */ 114 char *c_output_name; /* Hostname of connection for output */ 115 char *c_data; /* Data read from this fd */ 116 struct ssh *c_ssh; /* SSH-connection */ 117 struct timespec c_ts; /* Time at which connection gets aborted */ 118 TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ 119 } con; 120 121 TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ 122 con *fdcon; 123 124 static void keyprint(con *c, struct sshkey *key); 125 126 static int 127 fdlim_get(int hard) 128 { 129 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) 130 struct rlimit rlfd; 131 132 if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1) 133 return (-1); 134 if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) 135 return SSH_SYSFDMAX; 136 else 137 return hard ? rlfd.rlim_max : rlfd.rlim_cur; 138 #else 139 return SSH_SYSFDMAX; 140 #endif 141 } 142 143 static int 144 fdlim_set(int lim) 145 { 146 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) 147 struct rlimit rlfd; 148 #endif 149 150 if (lim <= 0) 151 return (-1); 152 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) 153 if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1) 154 return (-1); 155 rlfd.rlim_cur = lim; 156 if (setrlimit(RLIMIT_NOFILE, &rlfd) == -1) 157 return (-1); 158 #elif defined (HAVE_SETDTABLESIZE) 159 setdtablesize(lim); 160 #endif 161 return (0); 162 } 163 164 /* 165 * This is an strsep function that returns a null field for adjacent 166 * separators. This is the same as the 4.4BSD strsep, but different from the 167 * one in the GNU libc. 168 */ 169 static char * 170 xstrsep(char **str, const char *delim) 171 { 172 char *s, *e; 173 174 if (!**str) 175 return (NULL); 176 177 s = *str; 178 e = s + strcspn(s, delim); 179 180 if (*e != '\0') 181 *e++ = '\0'; 182 *str = e; 183 184 return (s); 185 } 186 187 /* 188 * Get the next non-null token (like GNU strsep). Strsep() will return a 189 * null token for two adjacent separators, so we may have to loop. 190 */ 191 static char * 192 strnnsep(char **stringp, char *delim) 193 { 194 char *tok; 195 196 do { 197 tok = xstrsep(stringp, delim); 198 } while (tok && *tok == '\0'); 199 return (tok); 200 } 201 202 203 static int 204 key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh) 205 { 206 con *c; 207 208 if ((c = ssh_get_app_data(ssh)) != NULL) 209 keyprint(c, hostkey); 210 /* always abort key exchange */ 211 return -1; 212 } 213 214 static int 215 ssh2_capable(int remote_major, int remote_minor) 216 { 217 switch (remote_major) { 218 case 1: 219 if (remote_minor == 99) 220 return 1; 221 break; 222 case 2: 223 return 1; 224 default: 225 break; 226 } 227 return 0; 228 } 229 230 static void 231 keygrab_ssh2(con *c) 232 { 233 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 234 int r; 235 236 switch (c->c_keytype) { 237 case KT_DSA: 238 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 239 "ssh-dss-cert-v01@openssh.com" : "ssh-dss"; 240 break; 241 case KT_RSA: 242 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 243 "rsa-sha2-512-cert-v01@openssh.com," 244 "rsa-sha2-256-cert-v01@openssh.com," 245 "ssh-rsa-cert-v01@openssh.com" : 246 "rsa-sha2-512," 247 "rsa-sha2-256," 248 "ssh-rsa"; 249 break; 250 case KT_ED25519: 251 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 252 "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519"; 253 break; 254 case KT_XMSS: 255 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 256 "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com"; 257 break; 258 case KT_ECDSA: 259 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 260 "ecdsa-sha2-nistp256-cert-v01@openssh.com," 261 "ecdsa-sha2-nistp384-cert-v01@openssh.com," 262 "ecdsa-sha2-nistp521-cert-v01@openssh.com" : 263 "ecdsa-sha2-nistp256," 264 "ecdsa-sha2-nistp384," 265 "ecdsa-sha2-nistp521"; 266 break; 267 case KT_ECDSA_SK: 268 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 269 "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" : 270 "sk-ecdsa-sha2-nistp256@openssh.com"; 271 break; 272 case KT_ED25519_SK: 273 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? 274 "sk-ssh-ed25519-cert-v01@openssh.com" : 275 "sk-ssh-ed25519@openssh.com"; 276 break; 277 default: 278 fatal("unknown key type %d", c->c_keytype); 279 break; 280 } 281 if ((r = kex_setup(c->c_ssh, myproposal)) != 0) { 282 free(c->c_ssh); 283 fprintf(stderr, "kex_setup: %s\n", ssh_err(r)); 284 exit(1); 285 } 286 #ifdef WITH_OPENSSL 287 c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client; 288 c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client; 289 c->c_ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client; 290 c->c_ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client; 291 c->c_ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client; 292 c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 293 c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 294 # ifdef OPENSSL_HAS_ECC 295 c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 296 # endif 297 #endif 298 c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 299 c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; 300 ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper); 301 /* 302 * do the key-exchange until an error occurs or until 303 * the key_print_wrapper() callback sets c_done. 304 */ 305 ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done); 306 } 307 308 static void 309 keyprint_one(const char *host, struct sshkey *key) 310 { 311 char *hostport = NULL, *hashed = NULL; 312 const char *known_host; 313 314 found_one = 1; 315 316 if (print_sshfp) { 317 export_dns_rr(host, key, stdout, 0); 318 return; 319 } 320 321 hostport = put_host_port(host, ssh_port); 322 lowercase(hostport); 323 if (hash_hosts && (hashed = host_hash(hostport, NULL, 0)) == NULL) 324 fatal("host_hash failed"); 325 known_host = hash_hosts ? hashed : hostport; 326 if (!get_cert) 327 fprintf(stdout, "%s ", known_host); 328 sshkey_write(key, stdout); 329 fputs("\n", stdout); 330 free(hashed); 331 free(hostport); 332 } 333 334 static void 335 keyprint(con *c, struct sshkey *key) 336 { 337 char *hosts = c->c_output_name ? c->c_output_name : c->c_name; 338 char *host, *ohosts; 339 340 if (key == NULL) 341 return; 342 if (get_cert || (!hash_hosts && ssh_port == SSH_DEFAULT_PORT)) { 343 keyprint_one(hosts, key); 344 return; 345 } 346 ohosts = hosts = xstrdup(hosts); 347 while ((host = strsep(&hosts, ",")) != NULL) 348 keyprint_one(host, key); 349 free(ohosts); 350 } 351 352 static int 353 tcpconnect(char *host) 354 { 355 struct addrinfo hints, *ai, *aitop; 356 char strport[NI_MAXSERV]; 357 int gaierr, s = -1; 358 359 snprintf(strport, sizeof strport, "%d", ssh_port); 360 memset(&hints, 0, sizeof(hints)); 361 hints.ai_family = IPv4or6; 362 hints.ai_socktype = SOCK_STREAM; 363 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { 364 error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr)); 365 return -1; 366 } 367 for (ai = aitop; ai; ai = ai->ai_next) { 368 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 369 if (s == -1) { 370 error("socket: %s", strerror(errno)); 371 continue; 372 } 373 if (set_nonblock(s) == -1) 374 fatal_f("set_nonblock(%d)", s); 375 if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1 && 376 errno != EINPROGRESS) 377 error("connect (`%s'): %s", host, strerror(errno)); 378 else 379 break; 380 close(s); 381 s = -1; 382 } 383 freeaddrinfo(aitop); 384 return s; 385 } 386 387 static int 388 conalloc(const char *iname, const char *oname, int keytype) 389 { 390 char *namebase, *name, *namelist; 391 int s; 392 393 namebase = namelist = xstrdup(iname); 394 395 do { 396 name = xstrsep(&namelist, ","); 397 if (!name) { 398 free(namebase); 399 return (-1); 400 } 401 } while ((s = tcpconnect(name)) < 0); 402 403 if (s >= maxfd) 404 fatal("conalloc: fdno %d too high", s); 405 if (fdcon[s].c_status) 406 fatal("conalloc: attempt to reuse fdno %d", s); 407 408 debug3_f("oname %s kt %d", oname, keytype); 409 fdcon[s].c_fd = s; 410 fdcon[s].c_status = CS_CON; 411 fdcon[s].c_namebase = namebase; 412 fdcon[s].c_name = name; 413 fdcon[s].c_namelist = namelist; 414 fdcon[s].c_output_name = xstrdup(oname); 415 fdcon[s].c_data = (char *) &fdcon[s].c_plen; 416 fdcon[s].c_len = 4; 417 fdcon[s].c_off = 0; 418 fdcon[s].c_keytype = keytype; 419 monotime_ts(&fdcon[s].c_ts); 420 fdcon[s].c_ts.tv_sec += timeout; 421 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); 422 read_wait[s].fd = s; 423 read_wait[s].events = POLLIN; 424 ncon++; 425 return (s); 426 } 427 428 static void 429 confree(int s) 430 { 431 if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) 432 fatal("confree: attempt to free bad fdno %d", s); 433 free(fdcon[s].c_namebase); 434 free(fdcon[s].c_output_name); 435 if (fdcon[s].c_status == CS_KEYS) 436 free(fdcon[s].c_data); 437 fdcon[s].c_status = CS_UNUSED; 438 fdcon[s].c_keytype = 0; 439 if (fdcon[s].c_ssh) { 440 ssh_packet_close(fdcon[s].c_ssh); 441 free(fdcon[s].c_ssh); 442 fdcon[s].c_ssh = NULL; 443 } else 444 close(s); 445 TAILQ_REMOVE(&tq, &fdcon[s], c_link); 446 read_wait[s].fd = -1; 447 read_wait[s].events = 0; 448 ncon--; 449 } 450 451 static void 452 contouch(int s) 453 { 454 TAILQ_REMOVE(&tq, &fdcon[s], c_link); 455 monotime_ts(&fdcon[s].c_ts); 456 fdcon[s].c_ts.tv_sec += timeout; 457 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); 458 } 459 460 static int 461 conrecycle(int s) 462 { 463 con *c = &fdcon[s]; 464 int ret; 465 466 ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype); 467 confree(s); 468 return (ret); 469 } 470 471 static void 472 congreet(int s) 473 { 474 int n = 0, remote_major = 0, remote_minor = 0; 475 char buf[256], *cp; 476 char remote_version[sizeof buf]; 477 size_t bufsiz; 478 con *c = &fdcon[s]; 479 480 /* send client banner */ 481 n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n", 482 PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2); 483 if (n < 0 || (size_t)n >= sizeof(buf)) { 484 error("snprintf: buffer too small"); 485 confree(s); 486 return; 487 } 488 if (atomicio(vwrite, s, buf, n) != (size_t)n) { 489 error("write (%s): %s", c->c_name, strerror(errno)); 490 confree(s); 491 return; 492 } 493 494 /* 495 * Read the server banner as per RFC4253 section 4.2. The "SSH-" 496 * protocol identification string may be preceeded by an arbitrarily 497 * large banner which we must read and ignore. Loop while reading 498 * newline-terminated lines until we have one starting with "SSH-". 499 * The ID string cannot be longer than 255 characters although the 500 * preceeding banner lines may (in which case they'll be discarded 501 * in multiple iterations of the outer loop). 502 */ 503 for (;;) { 504 memset(buf, '\0', sizeof(buf)); 505 bufsiz = sizeof(buf); 506 cp = buf; 507 while (bufsiz-- && 508 (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') { 509 if (*cp == '\r') 510 *cp = '\n'; 511 cp++; 512 } 513 if (n != 1 || strncmp(buf, "SSH-", 4) == 0) 514 break; 515 } 516 if (n == 0) { 517 switch (errno) { 518 case EPIPE: 519 error("%s: Connection closed by remote host", c->c_name); 520 break; 521 case ECONNREFUSED: 522 break; 523 default: 524 error("read (%s): %s", c->c_name, strerror(errno)); 525 break; 526 } 527 conrecycle(s); 528 return; 529 } 530 if (cp >= buf + sizeof(buf)) { 531 error("%s: greeting exceeds allowable length", c->c_name); 532 confree(s); 533 return; 534 } 535 if (*cp != '\n' && *cp != '\r') { 536 error("%s: bad greeting", c->c_name); 537 confree(s); 538 return; 539 } 540 *cp = '\0'; 541 if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL) 542 fatal("ssh_packet_set_connection failed"); 543 ssh_packet_set_timeout(c->c_ssh, timeout, 1); 544 ssh_set_app_data(c->c_ssh, c); /* back link */ 545 c->c_ssh->compat = 0; 546 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", 547 &remote_major, &remote_minor, remote_version) == 3) 548 compat_banner(c->c_ssh, remote_version); 549 if (!ssh2_capable(remote_major, remote_minor)) { 550 debug("%s doesn't support ssh2", c->c_name); 551 confree(s); 552 return; 553 } 554 fprintf(stderr, "%c %s:%d %s\n", print_sshfp ? ';' : '#', 555 c->c_name, ssh_port, chop(buf)); 556 keygrab_ssh2(c); 557 confree(s); 558 } 559 560 static void 561 conread(int s) 562 { 563 con *c = &fdcon[s]; 564 size_t n; 565 566 if (c->c_status == CS_CON) { 567 congreet(s); 568 return; 569 } 570 n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off); 571 if (n == 0) { 572 error("read (%s): %s", c->c_name, strerror(errno)); 573 confree(s); 574 return; 575 } 576 c->c_off += n; 577 578 if (c->c_off == c->c_len) 579 switch (c->c_status) { 580 case CS_SIZE: 581 c->c_plen = htonl(c->c_plen); 582 c->c_len = c->c_plen + 8 - (c->c_plen & 7); 583 c->c_off = 0; 584 c->c_data = xmalloc(c->c_len); 585 c->c_status = CS_KEYS; 586 break; 587 default: 588 fatal("conread: invalid status %d", c->c_status); 589 break; 590 } 591 592 contouch(s); 593 } 594 595 static void 596 conloop(void) 597 { 598 struct timespec seltime, now; 599 con *c; 600 int i; 601 602 monotime_ts(&now); 603 c = TAILQ_FIRST(&tq); 604 605 if (c && timespeccmp(&c->c_ts, &now, >)) 606 timespecsub(&c->c_ts, &now, &seltime); 607 else 608 timespecclear(&seltime); 609 610 while (ppoll(read_wait, maxfd, &seltime, NULL) == -1) { 611 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) 612 continue; 613 error("poll error"); 614 } 615 616 for (i = 0; i < maxfd; i++) { 617 if (read_wait[i].revents & (POLLHUP|POLLERR|POLLNVAL)) 618 confree(i); 619 else if (read_wait[i].revents & (POLLIN|POLLHUP)) 620 conread(i); 621 } 622 623 c = TAILQ_FIRST(&tq); 624 while (c && timespeccmp(&c->c_ts, &now, <)) { 625 int s = c->c_fd; 626 627 c = TAILQ_NEXT(c, c_link); 628 conrecycle(s); 629 } 630 } 631 632 static void 633 do_one_host(char *host) 634 { 635 char *name = strnnsep(&host, " \t\n"); 636 int j; 637 638 if (name == NULL) 639 return; 640 for (j = KT_MIN; j <= KT_MAX; j *= 2) { 641 if (get_keytypes & j) { 642 while (ncon >= MAXCON) 643 conloop(); 644 conalloc(name, *host ? host : name, j); 645 } 646 } 647 } 648 649 static void 650 do_host(char *host) 651 { 652 char daddr[128]; 653 struct xaddr addr, end_addr; 654 u_int masklen; 655 656 if (host == NULL) 657 return; 658 if (addr_pton_cidr(host, &addr, &masklen) != 0) { 659 /* Assume argument is a hostname */ 660 do_one_host(host); 661 } else { 662 /* Argument is a CIDR range */ 663 debug("CIDR range %s", host); 664 end_addr = addr; 665 if (addr_host_to_all1s(&end_addr, masklen) != 0) 666 goto badaddr; 667 /* 668 * Note: we deliberately include the all-zero/ones addresses. 669 */ 670 for (;;) { 671 if (addr_ntop(&addr, daddr, sizeof(daddr)) != 0) { 672 badaddr: 673 error("Invalid address %s", host); 674 return; 675 } 676 debug("CIDR expand: address %s", daddr); 677 do_one_host(daddr); 678 if (addr_cmp(&addr, &end_addr) == 0) 679 break; 680 addr_increment(&addr); 681 }; 682 } 683 } 684 685 void 686 sshfatal(const char *file, const char *func, int line, int showfunc, 687 LogLevel level, const char *suffix, const char *fmt, ...) 688 { 689 va_list args; 690 691 va_start(args, fmt); 692 sshlogv(file, func, line, showfunc, level, suffix, fmt, args); 693 va_end(args); 694 cleanup_exit(255); 695 } 696 697 static void 698 usage(void) 699 { 700 fprintf(stderr, 701 "usage: %s [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]\n" 702 "\t\t [host | addrlist namelist]\n", 703 __progname); 704 exit(1); 705 } 706 707 int 708 main(int argc, char **argv) 709 { 710 int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO; 711 int opt, fopt_count = 0, j; 712 char *tname, *cp, *line = NULL; 713 size_t linesize = 0; 714 FILE *fp; 715 716 extern int optind; 717 extern char *optarg; 718 719 __progname = ssh_get_progname(argv[0]); 720 seed_rng(); 721 TAILQ_INIT(&tq); 722 723 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 724 sanitise_stdfd(); 725 726 if (argc <= 1) 727 usage(); 728 729 while ((opt = getopt(argc, argv, "cDHv46p:T:t:f:")) != -1) { 730 switch (opt) { 731 case 'H': 732 hash_hosts = 1; 733 break; 734 case 'c': 735 get_cert = 1; 736 break; 737 case 'D': 738 print_sshfp = 1; 739 break; 740 case 'p': 741 ssh_port = a2port(optarg); 742 if (ssh_port <= 0) { 743 fprintf(stderr, "Bad port '%s'\n", optarg); 744 exit(1); 745 } 746 break; 747 case 'T': 748 timeout = convtime(optarg); 749 if (timeout == -1 || timeout == 0) { 750 fprintf(stderr, "Bad timeout '%s'\n", optarg); 751 usage(); 752 } 753 break; 754 case 'v': 755 if (!debug_flag) { 756 debug_flag = 1; 757 log_level = SYSLOG_LEVEL_DEBUG1; 758 } 759 else if (log_level < SYSLOG_LEVEL_DEBUG3) 760 log_level++; 761 else 762 fatal("Too high debugging level."); 763 break; 764 case 'f': 765 if (strcmp(optarg, "-") == 0) 766 optarg = NULL; 767 argv[fopt_count++] = optarg; 768 break; 769 case 't': 770 get_keytypes = 0; 771 tname = strtok(optarg, ","); 772 while (tname) { 773 int type = sshkey_type_from_name(tname); 774 775 switch (type) { 776 case KEY_DSA: 777 get_keytypes |= KT_DSA; 778 break; 779 case KEY_ECDSA: 780 get_keytypes |= KT_ECDSA; 781 break; 782 case KEY_RSA: 783 get_keytypes |= KT_RSA; 784 break; 785 case KEY_ED25519: 786 get_keytypes |= KT_ED25519; 787 break; 788 case KEY_XMSS: 789 get_keytypes |= KT_XMSS; 790 break; 791 case KEY_ED25519_SK: 792 get_keytypes |= KT_ED25519_SK; 793 break; 794 case KEY_ECDSA_SK: 795 get_keytypes |= KT_ECDSA_SK; 796 break; 797 case KEY_UNSPEC: 798 default: 799 fatal("Unknown key type \"%s\"", tname); 800 } 801 tname = strtok(NULL, ","); 802 } 803 break; 804 case '4': 805 IPv4or6 = AF_INET; 806 break; 807 case '6': 808 IPv4or6 = AF_INET6; 809 break; 810 default: 811 usage(); 812 } 813 } 814 if (optind == argc && !fopt_count) 815 usage(); 816 817 log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1); 818 819 maxfd = fdlim_get(1); 820 if (maxfd < 0) 821 fatal("%s: fdlim_get: bad value", __progname); 822 if (maxfd > MAXMAXFD) 823 maxfd = MAXMAXFD; 824 if (MAXCON <= 0) 825 fatal("%s: not enough file descriptors", __progname); 826 if (maxfd > fdlim_get(0)) 827 fdlim_set(maxfd); 828 fdcon = xcalloc(maxfd, sizeof(con)); 829 read_wait = xcalloc(maxfd, sizeof(struct pollfd)); 830 for (j = 0; j < maxfd; j++) 831 read_wait[j].fd = -1; 832 833 for (j = 0; j < fopt_count; j++) { 834 if (argv[j] == NULL) 835 fp = stdin; 836 else if ((fp = fopen(argv[j], "r")) == NULL) 837 fatal("%s: %s: %s", __progname, argv[j], strerror(errno)); 838 839 while (getline(&line, &linesize, fp) != -1) { 840 /* Chomp off trailing whitespace and comments */ 841 if ((cp = strchr(line, '#')) == NULL) 842 cp = line + strlen(line) - 1; 843 while (cp >= line) { 844 if (*cp == ' ' || *cp == '\t' || 845 *cp == '\n' || *cp == '#') 846 *cp-- = '\0'; 847 else 848 break; 849 } 850 851 /* Skip empty lines */ 852 if (*line == '\0') 853 continue; 854 855 do_host(line); 856 } 857 858 if (ferror(fp)) 859 fatal("%s: %s: %s", __progname, argv[j], strerror(errno)); 860 861 fclose(fp); 862 } 863 free(line); 864 865 while (optind < argc) 866 do_host(argv[optind++]); 867 868 while (ncon > 0) 869 conloop(); 870 871 return found_one ? 0 : 1; 872 } 873