ssh-keyscan.c 18 KB

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