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