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