GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/ssh-keyscan/../ssh-keyscan.c Lines: 0 353 0.0 %
Date: 2017-11-07 Branches: 0 229 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: ssh-keyscan.c,v 1.115 2017/06/30 04:17:23 dtucker 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 <sys/types.h>
11
#include <sys/socket.h>
12
#include <sys/queue.h>
13
#include <sys/time.h>
14
#include <sys/resource.h>
15
16
#include <openssl/bn.h>
17
18
#include <errno.h>
19
#include <netdb.h>
20
#include <stdarg.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <signal.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "xmalloc.h"
28
#include "ssh.h"
29
#include "sshbuf.h"
30
#include "sshkey.h"
31
#include "cipher.h"
32
#include "kex.h"
33
#include "compat.h"
34
#include "myproposal.h"
35
#include "packet.h"
36
#include "dispatch.h"
37
#include "log.h"
38
#include "atomicio.h"
39
#include "misc.h"
40
#include "hostfile.h"
41
#include "ssherr.h"
42
#include "ssh_api.h"
43
44
/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
45
   Default value is AF_UNSPEC means both IPv4 and IPv6. */
46
int IPv4or6 = AF_UNSPEC;
47
48
int ssh_port = SSH_DEFAULT_PORT;
49
50
#define KT_DSA		(1)
51
#define KT_RSA		(1<<1)
52
#define KT_ECDSA	(1<<2)
53
#define KT_ED25519	(1<<3)
54
55
#define KT_MIN		KT_DSA
56
#define KT_MAX		KT_ED25519
57
58
int get_cert = 0;
59
int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519;
60
61
int 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 */
66
int timeout = 5;
67
68
int maxfd;
69
#define MAXCON (maxfd - 10)
70
71
extern char *__progname;
72
fd_set *read_wait;
73
size_t read_wait_nfdset;
74
int ncon;
75
76
/*
77
 * Keep a connection structure for each file descriptor.  The state
78
 * associated with file descriptor n is held in fdcon[n].
79
 */
80
typedef struct Connection {
81
	u_char c_status;	/* State of connection on this file desc. */
82
#define CS_UNUSED 0		/* File descriptor unused */
83
#define CS_CON 1		/* Waiting to connect/read greeting */
84
#define CS_SIZE 2		/* Waiting to read initial packet size */
85
#define CS_KEYS 3		/* Waiting to read public key packet */
86
	int c_fd;		/* Quick lookup: c->c_fd == c - fdcon */
87
	int c_plen;		/* Packet length field for ssh packet */
88
	int c_len;		/* Total bytes which must be read. */
89
	int c_off;		/* Length of data read so far. */
90
	int c_keytype;		/* Only one of KT_* */
91
	sig_atomic_t c_done;	/* SSH2 done */
92
	char *c_namebase;	/* Address to free for c_name and c_namelist */
93
	char *c_name;		/* Hostname of connection for errors */
94
	char *c_namelist;	/* Pointer to other possible addresses */
95
	char *c_output_name;	/* Hostname of connection for output */
96
	char *c_data;		/* Data read from this fd */
97
	struct ssh *c_ssh;	/* SSH-connection */
98
	struct timeval c_tv;	/* Time at which connection gets aborted */
99
	TAILQ_ENTRY(Connection) c_link;	/* List of connections in timeout order. */
100
} con;
101
102
TAILQ_HEAD(conlist, Connection) tq;	/* Timeout Queue */
103
con *fdcon;
104
105
static void keyprint(con *c, struct sshkey *key);
106
107
static int
108
fdlim_get(int hard)
109
{
110
	struct rlimit rlfd;
111
112
	if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
113
		return (-1);
114
	if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
115
		return sysconf(_SC_OPEN_MAX);
116
	else
117
		return hard ? rlfd.rlim_max : rlfd.rlim_cur;
118
}
119
120
static int
121
fdlim_set(int lim)
122
{
123
	struct rlimit rlfd;
124
125
	if (lim <= 0)
126
		return (-1);
127
	if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
128
		return (-1);
129
	rlfd.rlim_cur = lim;
130
	if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
131
		return (-1);
132
	return (0);
133
}
134
135
/*
136
 * This is an strsep function that returns a null field for adjacent
137
 * separators.  This is the same as the 4.4BSD strsep, but different from the
138
 * one in the GNU libc.
139
 */
140
static char *
141
xstrsep(char **str, const char *delim)
142
{
143
	char *s, *e;
144
145
	if (!**str)
146
		return (NULL);
147
148
	s = *str;
149
	e = s + strcspn(s, delim);
150
151
	if (*e != '\0')
152
		*e++ = '\0';
153
	*str = e;
154
155
	return (s);
156
}
157
158
/*
159
 * Get the next non-null token (like GNU strsep).  Strsep() will return a
160
 * null token for two adjacent separators, so we may have to loop.
161
 */
162
static char *
163
strnnsep(char **stringp, char *delim)
164
{
165
	char *tok;
166
167
	do {
168
		tok = xstrsep(stringp, delim);
169
	} while (tok && *tok == '\0');
170
	return (tok);
171
}
172
173
174
static int
175
key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh)
176
{
177
	con *c;
178
179
	if ((c = ssh_get_app_data(ssh)) != NULL)
180
		keyprint(c, hostkey);
181
	/* always abort key exchange */
182
	return -1;
183
}
184
185
static int
186
ssh2_capable(int remote_major, int remote_minor)
187
{
188
	switch (remote_major) {
189
	case 1:
190
		if (remote_minor == 99)
191
			return 1;
192
		break;
193
	case 2:
194
		return 1;
195
	default:
196
		break;
197
	}
198
	return 0;
199
}
200
201
static void
202
keygrab_ssh2(con *c)
203
{
204
	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
205
	int r;
206
207
	switch (c->c_keytype) {
208
	case KT_DSA:
209
		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
210
		    "ssh-dss-cert-v01@openssh.com" : "ssh-dss";
211
		break;
212
	case KT_RSA:
213
		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
214
		    "ssh-rsa-cert-v01@openssh.com" : "ssh-rsa";
215
		break;
216
	case KT_ED25519:
217
		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
218
		    "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
219
		break;
220
	case KT_ECDSA:
221
		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
222
		    "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
223
		    "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
224
		    "ecdsa-sha2-nistp521-cert-v01@openssh.com" :
225
		    "ecdsa-sha2-nistp256,"
226
		    "ecdsa-sha2-nistp384,"
227
		    "ecdsa-sha2-nistp521";
228
		break;
229
	default:
230
		fatal("unknown key type %d", c->c_keytype);
231
		break;
232
	}
233
	if ((r = kex_setup(c->c_ssh, myproposal)) != 0) {
234
		free(c->c_ssh);
235
		fprintf(stderr, "kex_setup: %s\n", ssh_err(r));
236
		exit(1);
237
	}
238
#ifdef WITH_OPENSSL
239
	c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
240
	c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
241
	c->c_ssh->kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client;
242
	c->c_ssh->kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client;
243
	c->c_ssh->kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client;
244
	c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
245
	c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
246
	c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
247
#endif
248
	c->c_ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_client;
249
	ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
250
	/*
251
	 * do the key-exchange until an error occurs or until
252
	 * the key_print_wrapper() callback sets c_done.
253
	 */
254
	ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done);
255
}
256
257
static void
258
keyprint_one(const char *host, struct sshkey *key)
259
{
260
	char *hostport;
261
	const char *known_host, *hashed;
262
263
	hostport = put_host_port(host, ssh_port);
264
	lowercase(hostport);
265
	if (hash_hosts && (hashed = host_hash(host, NULL, 0)) == NULL)
266
		fatal("host_hash failed");
267
	known_host = hash_hosts ? hashed : hostport;
268
	if (!get_cert)
269
		fprintf(stdout, "%s ", known_host);
270
	sshkey_write(key, stdout);
271
	fputs("\n", stdout);
272
	free(hostport);
273
}
274
275
static void
276
keyprint(con *c, struct sshkey *key)
277
{
278
	char *hosts = c->c_output_name ? c->c_output_name : c->c_name;
279
	char *host, *ohosts;
280
281
	if (key == NULL)
282
		return;
283
	if (get_cert || (!hash_hosts && ssh_port == SSH_DEFAULT_PORT)) {
284
		keyprint_one(hosts, key);
285
		return;
286
	}
287
	ohosts = hosts = xstrdup(hosts);
288
	while ((host = strsep(&hosts, ",")) != NULL)
289
		keyprint_one(host, key);
290
	free(ohosts);
291
}
292
293
static int
294
tcpconnect(char *host)
295
{
296
	struct addrinfo hints, *ai, *aitop;
297
	char strport[NI_MAXSERV];
298
	int gaierr, s = -1;
299
300
	snprintf(strport, sizeof strport, "%d", ssh_port);
301
	memset(&hints, 0, sizeof(hints));
302
	hints.ai_family = IPv4or6;
303
	hints.ai_socktype = SOCK_STREAM;
304
	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
305
		error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
306
		return -1;
307
	}
308
	for (ai = aitop; ai; ai = ai->ai_next) {
309
		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
310
		if (s < 0) {
311
			error("socket: %s", strerror(errno));
312
			continue;
313
		}
314
		if (set_nonblock(s) == -1)
315
			fatal("%s: set_nonblock(%d)", __func__, s);
316
		if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
317
		    errno != EINPROGRESS)
318
			error("connect (`%s'): %s", host, strerror(errno));
319
		else
320
			break;
321
		close(s);
322
		s = -1;
323
	}
324
	freeaddrinfo(aitop);
325
	return s;
326
}
327
328
static int
329
conalloc(char *iname, char *oname, int keytype)
330
{
331
	char *namebase, *name, *namelist;
332
	int s;
333
334
	namebase = namelist = xstrdup(iname);
335
336
	do {
337
		name = xstrsep(&namelist, ",");
338
		if (!name) {
339
			free(namebase);
340
			return (-1);
341
		}
342
	} while ((s = tcpconnect(name)) < 0);
343
344
	if (s >= maxfd)
345
		fatal("conalloc: fdno %d too high", s);
346
	if (fdcon[s].c_status)
347
		fatal("conalloc: attempt to reuse fdno %d", s);
348
349
	debug3("%s: oname %s kt %d", __func__, oname, keytype);
350
	fdcon[s].c_fd = s;
351
	fdcon[s].c_status = CS_CON;
352
	fdcon[s].c_namebase = namebase;
353
	fdcon[s].c_name = name;
354
	fdcon[s].c_namelist = namelist;
355
	fdcon[s].c_output_name = xstrdup(oname);
356
	fdcon[s].c_data = (char *) &fdcon[s].c_plen;
357
	fdcon[s].c_len = 4;
358
	fdcon[s].c_off = 0;
359
	fdcon[s].c_keytype = keytype;
360
	gettimeofday(&fdcon[s].c_tv, NULL);
361
	fdcon[s].c_tv.tv_sec += timeout;
362
	TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
363
	FD_SET(s, read_wait);
364
	ncon++;
365
	return (s);
366
}
367
368
static void
369
confree(int s)
370
{
371
	if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
372
		fatal("confree: attempt to free bad fdno %d", s);
373
	free(fdcon[s].c_namebase);
374
	free(fdcon[s].c_output_name);
375
	if (fdcon[s].c_status == CS_KEYS)
376
		free(fdcon[s].c_data);
377
	fdcon[s].c_status = CS_UNUSED;
378
	fdcon[s].c_keytype = 0;
379
	if (fdcon[s].c_ssh) {
380
		ssh_packet_close(fdcon[s].c_ssh);
381
		free(fdcon[s].c_ssh);
382
		fdcon[s].c_ssh = NULL;
383
	} else
384
		close(s);
385
	TAILQ_REMOVE(&tq, &fdcon[s], c_link);
386
	FD_CLR(s, read_wait);
387
	ncon--;
388
}
389
390
static void
391
contouch(int s)
392
{
393
	TAILQ_REMOVE(&tq, &fdcon[s], c_link);
394
	gettimeofday(&fdcon[s].c_tv, NULL);
395
	fdcon[s].c_tv.tv_sec += timeout;
396
	TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
397
}
398
399
static int
400
conrecycle(int s)
401
{
402
	con *c = &fdcon[s];
403
	int ret;
404
405
	ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
406
	confree(s);
407
	return (ret);
408
}
409
410
static void
411
congreet(int s)
412
{
413
	int n = 0, remote_major = 0, remote_minor = 0;
414
	char buf[256], *cp;
415
	char remote_version[sizeof buf];
416
	size_t bufsiz;
417
	con *c = &fdcon[s];
418
419
	/* send client banner */
420
	n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
421
	    PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
422
	if (n < 0 || (size_t)n >= sizeof(buf)) {
423
		error("snprintf: buffer too small");
424
		confree(s);
425
		return;
426
	}
427
	if (atomicio(vwrite, s, buf, n) != (size_t)n) {
428
		error("write (%s): %s", c->c_name, strerror(errno));
429
		confree(s);
430
		return;
431
	}
432
433
	for (;;) {
434
		memset(buf, '\0', sizeof(buf));
435
		bufsiz = sizeof(buf);
436
		cp = buf;
437
		while (bufsiz-- &&
438
		    (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
439
			if (*cp == '\r')
440
				*cp = '\n';
441
			cp++;
442
		}
443
		if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
444
			break;
445
	}
446
	if (n == 0) {
447
		switch (errno) {
448
		case EPIPE:
449
			error("%s: Connection closed by remote host", c->c_name);
450
			break;
451
		case ECONNREFUSED:
452
			break;
453
		default:
454
			error("read (%s): %s", c->c_name, strerror(errno));
455
			break;
456
		}
457
		conrecycle(s);
458
		return;
459
	}
460
	if (*cp != '\n' && *cp != '\r') {
461
		error("%s: bad greeting", c->c_name);
462
		confree(s);
463
		return;
464
	}
465
	*cp = '\0';
466
	if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL)
467
		fatal("ssh_packet_set_connection failed");
468
	ssh_packet_set_timeout(c->c_ssh, timeout, 1);
469
	ssh_set_app_data(c->c_ssh, c);	/* back link */
470
	if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
471
	    &remote_major, &remote_minor, remote_version) == 3)
472
		c->c_ssh->compat = compat_datafellows(remote_version);
473
	else
474
		c->c_ssh->compat = 0;
475
	if (!ssh2_capable(remote_major, remote_minor)) {
476
		debug("%s doesn't support ssh2", c->c_name);
477
		confree(s);
478
		return;
479
	}
480
	fprintf(stderr, "# %s:%d %s\n", c->c_name, ssh_port, chop(buf));
481
	keygrab_ssh2(c);
482
	confree(s);
483
}
484
485
static void
486
conread(int s)
487
{
488
	con *c = &fdcon[s];
489
	size_t n;
490
491
	if (c->c_status == CS_CON) {
492
		congreet(s);
493
		return;
494
	}
495
	n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
496
	if (n == 0) {
497
		error("read (%s): %s", c->c_name, strerror(errno));
498
		confree(s);
499
		return;
500
	}
501
	c->c_off += n;
502
503
	if (c->c_off == c->c_len)
504
		switch (c->c_status) {
505
		case CS_SIZE:
506
			c->c_plen = htonl(c->c_plen);
507
			c->c_len = c->c_plen + 8 - (c->c_plen & 7);
508
			c->c_off = 0;
509
			c->c_data = xmalloc(c->c_len);
510
			c->c_status = CS_KEYS;
511
			break;
512
		default:
513
			fatal("conread: invalid status %d", c->c_status);
514
			break;
515
		}
516
517
	contouch(s);
518
}
519
520
static void
521
conloop(void)
522
{
523
	struct timeval seltime, now;
524
	fd_set *r, *e;
525
	con *c;
526
	int i;
527
528
	gettimeofday(&now, NULL);
529
	c = TAILQ_FIRST(&tq);
530
531
	if (c && (c->c_tv.tv_sec > now.tv_sec ||
532
	    (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
533
		seltime = c->c_tv;
534
		seltime.tv_sec -= now.tv_sec;
535
		seltime.tv_usec -= now.tv_usec;
536
		if (seltime.tv_usec < 0) {
537
			seltime.tv_usec += 1000000;
538
			seltime.tv_sec--;
539
		}
540
	} else
541
		timerclear(&seltime);
542
543
	r = xcalloc(read_wait_nfdset, sizeof(fd_mask));
544
	e = xcalloc(read_wait_nfdset, sizeof(fd_mask));
545
	memcpy(r, read_wait, read_wait_nfdset * sizeof(fd_mask));
546
	memcpy(e, read_wait, read_wait_nfdset * sizeof(fd_mask));
547
548
	while (select(maxfd, r, NULL, e, &seltime) == -1 &&
549
	    (errno == EAGAIN || errno == EINTR))
550
		;
551
552
	for (i = 0; i < maxfd; i++) {
553
		if (FD_ISSET(i, e)) {
554
			error("%s: exception!", fdcon[i].c_name);
555
			confree(i);
556
		} else if (FD_ISSET(i, r))
557
			conread(i);
558
	}
559
	free(r);
560
	free(e);
561
562
	c = TAILQ_FIRST(&tq);
563
	while (c && (c->c_tv.tv_sec < now.tv_sec ||
564
	    (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
565
		int s = c->c_fd;
566
567
		c = TAILQ_NEXT(c, c_link);
568
		conrecycle(s);
569
	}
570
}
571
572
static void
573
do_host(char *host)
574
{
575
	char *name = strnnsep(&host, " \t\n");
576
	int j;
577
578
	if (name == NULL)
579
		return;
580
	for (j = KT_MIN; j <= KT_MAX; j *= 2) {
581
		if (get_keytypes & j) {
582
			while (ncon >= MAXCON)
583
				conloop();
584
			conalloc(name, *host ? host : name, j);
585
		}
586
	}
587
}
588
589
void
590
fatal(const char *fmt,...)
591
{
592
	va_list args;
593
594
	va_start(args, fmt);
595
	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
596
	va_end(args);
597
	exit(255);
598
}
599
600
static void
601
usage(void)
602
{
603
	fprintf(stderr,
604
	    "usage: %s [-46cHv] [-f file] [-p port] [-T timeout] [-t type]\n"
605
	    "\t\t   [host | addrlist namelist] ...\n",
606
	    __progname);
607
	exit(1);
608
}
609
610
int
611
main(int argc, char **argv)
612
{
613
	int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
614
	int opt, fopt_count = 0, j;
615
	char *tname, *cp, line[NI_MAXHOST];
616
	FILE *fp;
617
	u_long linenum;
618
619
	extern int optind;
620
	extern char *optarg;
621
622
	ssh_malloc_init();	/* must be called before any mallocs */
623
	TAILQ_INIT(&tq);
624
625
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
626
	sanitise_stdfd();
627
628
	if (argc <= 1)
629
		usage();
630
631
	while ((opt = getopt(argc, argv, "cHv46p:T:t:f:")) != -1) {
632
		switch (opt) {
633
		case 'H':
634
			hash_hosts = 1;
635
			break;
636
		case 'c':
637
			get_cert = 1;
638
			break;
639
		case 'p':
640
			ssh_port = a2port(optarg);
641
			if (ssh_port <= 0) {
642
				fprintf(stderr, "Bad port '%s'\n", optarg);
643
				exit(1);
644
			}
645
			break;
646
		case 'T':
647
			timeout = convtime(optarg);
648
			if (timeout == -1 || timeout == 0) {
649
				fprintf(stderr, "Bad timeout '%s'\n", optarg);
650
				usage();
651
			}
652
			break;
653
		case 'v':
654
			if (!debug_flag) {
655
				debug_flag = 1;
656
				log_level = SYSLOG_LEVEL_DEBUG1;
657
			}
658
			else if (log_level < SYSLOG_LEVEL_DEBUG3)
659
				log_level++;
660
			else
661
				fatal("Too high debugging level.");
662
			break;
663
		case 'f':
664
			if (strcmp(optarg, "-") == 0)
665
				optarg = NULL;
666
			argv[fopt_count++] = optarg;
667
			break;
668
		case 't':
669
			get_keytypes = 0;
670
			tname = strtok(optarg, ",");
671
			while (tname) {
672
				int type = sshkey_type_from_name(tname);
673
674
				switch (type) {
675
				case KEY_DSA:
676
					get_keytypes |= KT_DSA;
677
					break;
678
				case KEY_ECDSA:
679
					get_keytypes |= KT_ECDSA;
680
					break;
681
				case KEY_RSA:
682
					get_keytypes |= KT_RSA;
683
					break;
684
				case KEY_ED25519:
685
					get_keytypes |= KT_ED25519;
686
					break;
687
				case KEY_UNSPEC:
688
				default:
689
					fatal("Unknown key type \"%s\"", tname);
690
				}
691
				tname = strtok(NULL, ",");
692
			}
693
			break;
694
		case '4':
695
			IPv4or6 = AF_INET;
696
			break;
697
		case '6':
698
			IPv4or6 = AF_INET6;
699
			break;
700
		case '?':
701
		default:
702
			usage();
703
		}
704
	}
705
	if (optind == argc && !fopt_count)
706
		usage();
707
708
	log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
709
710
	maxfd = fdlim_get(1);
711
	if (maxfd < 0)
712
		fatal("%s: fdlim_get: bad value", __progname);
713
	if (maxfd > MAXMAXFD)
714
		maxfd = MAXMAXFD;
715
	if (MAXCON <= 0)
716
		fatal("%s: not enough file descriptors", __progname);
717
	if (maxfd > fdlim_get(0))
718
		fdlim_set(maxfd);
719
	fdcon = xcalloc(maxfd, sizeof(con));
720
721
	read_wait_nfdset = howmany(maxfd, NFDBITS);
722
	read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask));
723
724
	for (j = 0; j < fopt_count; j++) {
725
		if (argv[j] == NULL)
726
			fp = stdin;
727
		else if ((fp = fopen(argv[j], "r")) == NULL)
728
			fatal("%s: %s: %s", __progname, argv[j],
729
			    strerror(errno));
730
		linenum = 0;
731
732
		while (read_keyfile_line(fp,
733
		    argv[j] == NULL ? "(stdin)" : argv[j], line, sizeof(line),
734
		    &linenum) != -1) {
735
			/* Chomp off trailing whitespace and comments */
736
			if ((cp = strchr(line, '#')) == NULL)
737
				cp = line + strlen(line) - 1;
738
			while (cp >= line) {
739
				if (*cp == ' ' || *cp == '\t' ||
740
				    *cp == '\n' || *cp == '#')
741
					*cp-- = '\0';
742
				else
743
					break;
744
			}
745
746
			/* Skip empty lines */
747
			if (*line == '\0')
748
				continue;
749
750
			do_host(line);
751
		}
752
753
		if (ferror(fp))
754
			fatal("%s: %s: %s", __progname, argv[j],
755
			    strerror(errno));
756
757
		fclose(fp);
758
	}
759
760
	while (optind < argc)
761
		do_host(argv[optind++]);
762
763
	while (ncon > 0)
764
		conloop();
765
766
	return (0);
767
}