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