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