Annotation of src/usr.bin/ssh/ssh-keyscan.c, Revision 1.28
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.28 ! danh 10: RCSID("$OpenBSD: ssh-keyscan.c,v 1.27 2001/08/05 23:29:58 markus 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;
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: }