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