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