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