Annotation of src/usr.bin/ssh/ssh-keyscan.c, Revision 1.29
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.29 ! markus 10: RCSID("$OpenBSD: ssh-keyscan.c,v 1.28 2001/08/27 22:02:13 danh 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.29 ! markus 63: Key *kexjmp_key;
1.1 markus 64:
65: /*
66: * Keep a connection structure for each file descriptor. The state
67: * associated with file descriptor n is held in fdcon[n].
68: */
69: typedef struct Connection {
1.6 markus 70: u_char c_status; /* State of connection on this file desc. */
1.1 markus 71: #define CS_UNUSED 0 /* File descriptor unused */
72: #define CS_CON 1 /* Waiting to connect/read greeting */
73: #define CS_SIZE 2 /* Waiting to read initial packet size */
74: #define CS_KEYS 3 /* Waiting to read public key packet */
75: int c_fd; /* Quick lookup: c->c_fd == c - fdcon */
76: int c_plen; /* Packet length field for ssh packet */
77: int c_len; /* Total bytes which must be read. */
78: int c_off; /* Length of data read so far. */
1.26 markus 79: int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
1.1 markus 80: char *c_namebase; /* Address to free for c_name and c_namelist */
81: char *c_name; /* Hostname of connection for errors */
82: char *c_namelist; /* Pointer to other possible addresses */
83: char *c_output_name; /* Hostname of connection for output */
84: char *c_data; /* Data read from this fd */
1.26 markus 85: Kex *c_kex; /* The key-exchange struct for ssh2 */
1.1 markus 86: struct timeval c_tv; /* Time at which connection gets aborted */
87: TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
88: } con;
89:
90: TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */
91: con *fdcon;
92:
93: /*
94: * This is just a wrapper around fgets() to make it usable.
95: */
96:
97: /* Stress-test. Increase this later. */
98: #define LINEBUF_SIZE 16
99:
100: typedef struct {
101: char *buf;
1.6 markus 102: u_int size;
1.1 markus 103: int lineno;
104: const char *filename;
105: FILE *stream;
106: void (*errfun) (const char *,...);
107: } Linebuf;
108:
1.24 itojun 109: static Linebuf *
1.1 markus 110: Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
111: {
112: Linebuf *lb;
113:
114: if (!(lb = malloc(sizeof(*lb)))) {
115: if (errfun)
116: (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
117: return (NULL);
118: }
119: if (filename) {
120: lb->filename = filename;
121: if (!(lb->stream = fopen(filename, "r"))) {
1.9 markus 122: xfree(lb);
1.1 markus 123: if (errfun)
124: (*errfun) ("%s: %s\n", filename, strerror(errno));
125: return (NULL);
126: }
127: } else {
128: lb->filename = "(stdin)";
129: lb->stream = stdin;
130: }
131:
132: if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) {
133: if (errfun)
134: (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
1.9 markus 135: xfree(lb);
1.1 markus 136: return (NULL);
137: }
138: lb->errfun = errfun;
139: lb->lineno = 0;
140: return (lb);
141: }
142:
1.24 itojun 143: static void
1.1 markus 144: Linebuf_free(Linebuf * lb)
145: {
146: fclose(lb->stream);
1.9 markus 147: xfree(lb->buf);
148: xfree(lb);
1.1 markus 149: }
150:
1.24 itojun 151: #if 0
152: static void
1.1 markus 153: Linebuf_restart(Linebuf * lb)
154: {
155: clearerr(lb->stream);
156: rewind(lb->stream);
157: lb->lineno = 0;
158: }
159:
1.24 itojun 160: static int
1.1 markus 161: Linebuf_lineno(Linebuf * lb)
162: {
163: return (lb->lineno);
164: }
1.24 itojun 165: #endif
1.1 markus 166:
1.24 itojun 167: static char *
1.14 markus 168: Linebuf_getline(Linebuf * lb)
1.1 markus 169: {
170: int n = 0;
171:
172: lb->lineno++;
173: for (;;) {
174: /* Read a line */
175: if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
176: if (ferror(lb->stream) && lb->errfun)
1.17 deraadt 177: (*lb->errfun) ("%s: %s\n", lb->filename,
178: strerror(errno));
1.1 markus 179: return (NULL);
180: }
181: n = strlen(lb->buf);
182:
183: /* Return it or an error if it fits */
184: if (n > 0 && lb->buf[n - 1] == '\n') {
185: lb->buf[n - 1] = '\0';
186: return (lb->buf);
187: }
188: if (n != lb->size - 1) {
189: if (lb->errfun)
1.17 deraadt 190: (*lb->errfun) ("%s: skipping incomplete last line\n",
191: lb->filename);
1.1 markus 192: return (NULL);
193: }
194: /* Double the buffer if we need more space */
195: if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) {
196: if (lb->errfun)
1.17 deraadt 197: (*lb->errfun) ("linebuf (%s): realloc failed\n",
198: lb->filename);
1.1 markus 199: return (NULL);
200: }
201: }
202: }
203:
1.24 itojun 204: static int
1.1 markus 205: fdlim_get(int hard)
206: {
207: struct rlimit rlfd;
1.17 deraadt 208:
1.1 markus 209: if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
210: return (-1);
211: if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
212: return 10000;
213: else
214: return hard ? rlfd.rlim_max : rlfd.rlim_cur;
215: }
216:
1.24 itojun 217: static int
1.1 markus 218: fdlim_set(int lim)
219: {
220: struct rlimit rlfd;
221: if (lim <= 0)
222: return (-1);
223: if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
224: return (-1);
225: rlfd.rlim_cur = lim;
226: if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
227: return (-1);
228: return (0);
229: }
230:
231: /*
232: * This is an strsep function that returns a null field for adjacent
233: * separators. This is the same as the 4.4BSD strsep, but different from the
234: * one in the GNU libc.
235: */
1.24 itojun 236: static char *
1.1 markus 237: xstrsep(char **str, const char *delim)
238: {
239: char *s, *e;
240:
241: if (!**str)
242: return (NULL);
243:
244: s = *str;
245: e = s + strcspn(s, delim);
246:
247: if (*e != '\0')
248: *e++ = '\0';
249: *str = e;
250:
251: return (s);
252: }
253:
254: /*
255: * Get the next non-null token (like GNU strsep). Strsep() will return a
256: * null token for two adjacent separators, so we may have to loop.
257: */
1.24 itojun 258: static char *
1.1 markus 259: strnnsep(char **stringp, char *delim)
260: {
261: char *tok;
262:
263: do {
264: tok = xstrsep(stringp, delim);
265: } while (tok && *tok == '\0');
266: return (tok);
267: }
268:
1.26 markus 269: static Key *
270: keygrab_ssh1(con *c)
1.1 markus 271: {
272: static Key *rsa;
273: static Buffer msg;
274:
275: if (rsa == NULL) {
276: buffer_init(&msg);
277: rsa = key_new(KEY_RSA1);
278: }
1.26 markus 279: buffer_append(&msg, c->c_data, c->c_plen);
280: buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */
1.1 markus 281: if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
1.26 markus 282: error("%s: invalid packet type", c->c_name);
1.1 markus 283: buffer_clear(&msg);
1.26 markus 284: return NULL;
1.1 markus 285: }
286: buffer_consume(&msg, 8); /* cookie */
287:
288: /* server key */
289: (void) buffer_get_int(&msg);
290: buffer_get_bignum(&msg, rsa->rsa->e);
291: buffer_get_bignum(&msg, rsa->rsa->n);
292:
293: /* host key */
294: (void) buffer_get_int(&msg);
295: buffer_get_bignum(&msg, rsa->rsa->e);
296: buffer_get_bignum(&msg, rsa->rsa->n);
1.26 markus 297:
1.1 markus 298: buffer_clear(&msg);
299:
1.26 markus 300: return (rsa);
301: }
302:
303: static int
304: hostjump(Key *hostkey)
305: {
1.29 ! markus 306: kexjmp_key = hostkey;
! 307: longjmp(kexjmp, 1);
1.26 markus 308: }
309:
310: static int
311: ssh2_capable(int remote_major, int remote_minor)
312: {
313: switch (remote_major) {
314: case 1:
315: if (remote_minor == 99)
316: return 1;
317: break;
318: case 2:
319: return 1;
320: default:
321: break;
322: }
323: return 0;
324: }
325:
326: static Key *
327: keygrab_ssh2(con *c)
328: {
329: int j;
330:
331: packet_set_connection(c->c_fd, c->c_fd);
332: enable_compat20();
333: myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
334: "ssh-dss": "ssh-rsa";
335: c->c_kex = kex_setup(myproposal);
336: c->c_kex->verify_host_key = hostjump;
337:
338: if (!(j = setjmp(kexjmp))) {
339: nonfatal_fatal = 1;
340: dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
341: fprintf(stderr, "Impossible! dispatch_run() returned!\n");
342: exit(1);
343: }
344: nonfatal_fatal = 0;
345: xfree(c->c_kex);
346: c->c_kex = NULL;
347: packet_close();
348:
1.29 ! markus 349: return j < 0? NULL : kexjmp_key;
1.26 markus 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;
1.27 markus 482: while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n') {
483: if (*cp == '\r')
484: *cp = '\n';
1.21 millert 485: cp++;
1.27 markus 486: }
1.1 markus 487: if (n < 0) {
488: if (errno != ECONNREFUSED)
489: error("read (%s): %s", c->c_name, strerror(errno));
490: conrecycle(s);
491: return;
492: }
1.21 millert 493: if (*cp != '\n' && *cp != '\r') {
1.1 markus 494: error("%s: bad greeting", c->c_name);
495: confree(s);
496: return;
497: }
1.21 millert 498: *cp = '\0';
1.26 markus 499: if (c->c_keytype != KT_RSA1) {
500: int remote_major, remote_minor;
501: char remote_version[sizeof buf];
502:
503: if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
504: &remote_major, &remote_minor, remote_version) == 3)
505: compat_datafellows(remote_version);
506: else
507: datafellows = 0;
508: if (!ssh2_capable(remote_major, remote_minor)) {
509: debug("%s doesn't support ssh2", c->c_name);
510: confree(s);
511: return;
512: }
513: }
1.27 markus 514: fprintf(stderr, "# %s %s\n", c->c_name, chop(buf));
1.26 markus 515: n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
516: c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
517: c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
1.18 deraadt 518: if (atomicio(write, s, buf, n) != n) {
1.1 markus 519: error("write (%s): %s", c->c_name, strerror(errno));
520: confree(s);
521: return;
522: }
1.26 markus 523: if (c->c_keytype != KT_RSA1) {
524: keyprint(c, keygrab_ssh2(c));
525: confree(s);
526: return;
527: }
1.1 markus 528: c->c_status = CS_SIZE;
529: contouch(s);
530: }
531:
1.24 itojun 532: static void
1.1 markus 533: conread(int s)
534: {
535: int n;
536: con *c = &fdcon[s];
537:
538: if (c->c_status == CS_CON) {
539: congreet(s);
540: return;
541: }
542: n = read(s, c->c_data + c->c_off, c->c_len - c->c_off);
543: if (n < 0) {
544: error("read (%s): %s", c->c_name, strerror(errno));
545: confree(s);
546: return;
547: }
548: c->c_off += n;
549:
550: if (c->c_off == c->c_len)
551: switch (c->c_status) {
552: case CS_SIZE:
553: c->c_plen = htonl(c->c_plen);
554: c->c_len = c->c_plen + 8 - (c->c_plen & 7);
555: c->c_off = 0;
556: c->c_data = xmalloc(c->c_len);
557: c->c_status = CS_KEYS;
558: break;
559: case CS_KEYS:
1.26 markus 560: keyprint(c, keygrab_ssh1(c));
1.1 markus 561: confree(s);
562: return;
563: break;
564: default:
1.4 markus 565: fatal("conread: invalid status %d", c->c_status);
1.1 markus 566: break;
567: }
568:
569: contouch(s);
570: }
571:
1.24 itojun 572: static void
1.1 markus 573: conloop(void)
574: {
1.19 millert 575: fd_set *r, *e;
1.1 markus 576: struct timeval seltime, now;
577: int i;
578: con *c;
579:
580: gettimeofday(&now, NULL);
581: c = tq.tqh_first;
582:
1.18 deraadt 583: if (c && (c->c_tv.tv_sec > now.tv_sec ||
584: (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
1.1 markus 585: seltime = c->c_tv;
586: seltime.tv_sec -= now.tv_sec;
587: seltime.tv_usec -= now.tv_usec;
1.13 itojun 588: if (seltime.tv_usec < 0) {
1.1 markus 589: seltime.tv_usec += 1000000;
590: seltime.tv_sec--;
591: }
592: } else
593: seltime.tv_sec = seltime.tv_usec = 0;
594:
1.19 millert 595: r = xmalloc(read_wait_size);
596: memcpy(r, read_wait, read_wait_size);
597: e = xmalloc(read_wait_size);
598: memcpy(e, read_wait, read_wait_size);
599:
600: while (select(maxfd, r, NULL, e, &seltime) == -1 &&
1.16 deraadt 601: (errno == EAGAIN || errno == EINTR))
602: ;
603:
1.18 deraadt 604: for (i = 0; i < maxfd; i++) {
1.19 millert 605: if (FD_ISSET(i, e)) {
1.1 markus 606: error("%s: exception!", fdcon[i].c_name);
607: confree(i);
1.19 millert 608: } else if (FD_ISSET(i, r))
1.1 markus 609: conread(i);
1.18 deraadt 610: }
1.19 millert 611: xfree(r);
612: xfree(e);
1.1 markus 613:
614: c = tq.tqh_first;
1.18 deraadt 615: while (c && (c->c_tv.tv_sec < now.tv_sec ||
616: (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
1.1 markus 617: int s = c->c_fd;
1.18 deraadt 618:
1.1 markus 619: c = c->c_link.tqe_next;
620: conrecycle(s);
621: }
622: }
623:
1.26 markus 624: static void
625: do_host(char *host)
1.1 markus 626: {
1.26 markus 627: char *name = strnnsep(&host, " \t\n");
628: int j;
1.1 markus 629:
1.26 markus 630: for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
631: if (get_keytypes & j) {
632: while (ncon >= MAXCON)
633: conloop();
634: conalloc(name, *host ? host : name, j);
1.1 markus 635: }
636: }
637: }
638:
1.24 itojun 639: static void
1.26 markus 640: fatal_callback(void *arg)
641: {
642: if (nonfatal_fatal)
643: longjmp(kexjmp, -1);
644: }
645:
646: static void
1.1 markus 647: usage(void)
648: {
1.26 markus 649: fprintf(stderr, "Usage: %s [options] host ...\n",
1.25 jakob 650: __progname);
651: fprintf(stderr, "Options:\n");
652: fprintf(stderr, " -f file Read hosts or addresses from file.\n");
1.26 markus 653: fprintf(stderr, " -p port Connect to the specified port.\n");
654: fprintf(stderr, " -t keytype Specify the host key type.\n");
655: fprintf(stderr, " -T timeout Set connection timeout.\n");
656: fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
657: fprintf(stderr, " -4 Use IPv4 only.\n");
658: fprintf(stderr, " -6 Use IPv6 only.\n");
1.25 jakob 659: exit(1);
1.1 markus 660: }
661:
662: int
663: main(int argc, char **argv)
664: {
1.26 markus 665: int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
666: int opt, fopt_count = 0;
667: char *tname;
668:
669: extern int optind;
670: extern char *optarg;
1.1 markus 671:
672: TAILQ_INIT(&tq);
673:
1.26 markus 674: if (argc <= 1)
1.1 markus 675: usage();
676:
1.26 markus 677: while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
678: switch (opt) {
679: case 'p':
680: ssh_port = a2port(optarg);
681: if (ssh_port == 0) {
682: fprintf(stderr, "Bad port '%s'\n", optarg);
683: exit(1);
684: }
685: break;
686: case 'T':
687: timeout = atoi(optarg);
688: if (timeout <= 0)
1.1 markus 689: usage();
1.26 markus 690: break;
691: case 'v':
692: if (!debug_flag) {
693: debug_flag = 1;
694: log_level = SYSLOG_LEVEL_DEBUG1;
695: }
696: else if (log_level < SYSLOG_LEVEL_DEBUG3)
697: log_level++;
698: else
699: fatal("Too high debugging level.");
700: break;
701: case 'f':
702: if (strcmp(optarg, "-") == 0)
703: optarg = NULL;
704: argv[fopt_count++] = optarg;
705: break;
706: case 't':
707: get_keytypes = 0;
708: tname = strtok(optarg, ",");
709: while (tname) {
710: int type = key_type_from_name(tname);
711: switch (type) {
712: case KEY_RSA1:
713: get_keytypes |= KT_RSA1;
714: break;
715: case KEY_DSA:
716: get_keytypes |= KT_DSA;
717: break;
718: case KEY_RSA:
719: get_keytypes |= KT_RSA;
720: break;
721: case KEY_UNSPEC:
722: fatal("unknown key type %s\n", tname);
723: }
724: tname = strtok(NULL, ",");
725: }
726: break;
727: case '4':
728: IPv4or6 = AF_INET;
729: break;
730: case '6':
731: IPv4or6 = AF_INET6;
732: break;
733: case '?':
734: default:
735: usage();
1.1 markus 736: }
737: }
1.26 markus 738: if (optind == argc && !fopt_count)
1.1 markus 739: usage();
740:
1.26 markus 741: log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
742: fatal_add_cleanup(fatal_callback, NULL);
743:
1.1 markus 744: maxfd = fdlim_get(1);
745: if (maxfd < 0)
1.4 markus 746: fatal("%s: fdlim_get: bad value", __progname);
1.1 markus 747: if (maxfd > MAXMAXFD)
748: maxfd = MAXMAXFD;
1.18 deraadt 749: if (MAXCON <= 0)
1.4 markus 750: fatal("%s: not enough file descriptors", __progname);
1.1 markus 751: if (maxfd > fdlim_get(0))
752: fdlim_set(maxfd);
753: fdcon = xmalloc(maxfd * sizeof(con));
1.15 itojun 754: memset(fdcon, 0, maxfd * sizeof(con));
1.19 millert 755:
756: read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
757: read_wait = xmalloc(read_wait_size);
758: memset(read_wait, 0, read_wait_size);
1.1 markus 759:
1.26 markus 760: if (fopt_count) {
761: Linebuf *lb;
762: char *line;
763: int j;
764:
765: for (j = 0; j < fopt_count; j++) {
766: lb = Linebuf_alloc(argv[j], error);
1.28 danh 767: if (!lb)
768: continue;
1.26 markus 769: while ((line = Linebuf_getline(lb)) != NULL)
770: do_host(line);
771: Linebuf_free(lb);
772: }
773: }
774:
775: while (optind < argc)
776: do_host(argv[optind++]);
1.1 markus 777:
778: while (ncon > 0)
779: conloop();
780:
781: return (0);
782: }