summaryrefslogtreecommitdiff
path: root/ssh-keyscan.c
diff options
context:
space:
mode:
authorBen Lindstrom <mouring@eviladmin.org>2001-08-06 22:41:30 +0000
committerBen Lindstrom <mouring@eviladmin.org>2001-08-06 22:41:30 +0000
commit325e70c90f3896eff8df5676b500532ec8407789 (patch)
treea0c9cb9101c3a4b447321dc6ab667e39656a6241 /ssh-keyscan.c
parentddfb1e3a892f450178093964f11cdc534340a56a (diff)
- markus@cvs.openbsd.org 2001/08/05 23:18:20
[ssh-keyscan.1 ssh-keyscan.c] ssh 2 support; from wayned@users.sourceforge.net
Diffstat (limited to 'ssh-keyscan.c')
-rw-r--r--ssh-keyscan.c320
1 files changed, 234 insertions, 86 deletions
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index 9908baac4..5a992515e 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -7,7 +7,7 @@
7 */ 7 */
8 8
9#include "includes.h" 9#include "includes.h"
10RCSID("$OpenBSD: ssh-keyscan.c,v 1.25 2001/08/03 10:31:30 jakob Exp $"); 10RCSID("$OpenBSD: ssh-keyscan.c,v 1.26 2001/08/05 23:18:20 markus Exp $");
11 11
12#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) 12#if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H)
13#include <sys/queue.h> 13#include <sys/queue.h>
@@ -18,18 +18,37 @@ RCSID("$OpenBSD: ssh-keyscan.c,v 1.25 2001/08/03 10:31:30 jakob Exp $");
18 18
19#include <openssl/bn.h> 19#include <openssl/bn.h>
20 20
21#include <setjmp.h>
21#include "xmalloc.h" 22#include "xmalloc.h"
22#include "ssh.h" 23#include "ssh.h"
23#include "ssh1.h" 24#include "ssh1.h"
24#include "key.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"
25#include "buffer.h" 31#include "buffer.h"
26#include "bufaux.h" 32#include "bufaux.h"
27#include "log.h" 33#include "log.h"
28#include "atomicio.h" 34#include "atomicio.h"
35#include "misc.h"
29 36
30static int argno = 1; /* Number of argument currently being parsed */ 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
31 44
32int family = AF_UNSPEC; /* IPv4, IPv6 or both */ 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 */
33 52
34#define MAXMAXFD 256 53#define MAXMAXFD 256
35 54
@@ -47,6 +66,8 @@ char *__progname;
47fd_set *read_wait; 66fd_set *read_wait;
48size_t read_wait_size; 67size_t read_wait_size;
49int ncon; 68int ncon;
69int nonfatal_fatal = 0;
70jmp_buf kexjmp;
50 71
51/* 72/*
52 * Keep a connection structure for each file descriptor. The state 73 * Keep a connection structure for each file descriptor. The state
@@ -62,11 +83,13 @@ typedef struct Connection {
62 int c_plen; /* Packet length field for ssh packet */ 83 int c_plen; /* Packet length field for ssh packet */
63 int c_len; /* Total bytes which must be read. */ 84 int c_len; /* Total bytes which must be read. */
64 int c_off; /* Length of data read so far. */ 85 int c_off; /* Length of data read so far. */
86 int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
65 char *c_namebase; /* Address to free for c_name and c_namelist */ 87 char *c_namebase; /* Address to free for c_name and c_namelist */
66 char *c_name; /* Hostname of connection for errors */ 88 char *c_name; /* Hostname of connection for errors */
67 char *c_namelist; /* Pointer to other possible addresses */ 89 char *c_namelist; /* Pointer to other possible addresses */
68 char *c_output_name; /* Hostname of connection for output */ 90 char *c_output_name; /* Hostname of connection for output */
69 char *c_data; /* Data read from this fd */ 91 char *c_data; /* Data read from this fd */
92 Kex *c_kex; /* The key-exchange struct for ssh2 */
70 struct timeval c_tv; /* Time at which connection gets aborted */ 93 struct timeval c_tv; /* Time at which connection gets aborted */
71 TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ 94 TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
72} con; 95} con;
@@ -262,8 +285,8 @@ strnnsep(char **stringp, char *delim)
262 return (tok); 285 return (tok);
263} 286}
264 287
265static void 288static Key *
266keyprint(char *host, char *output_name, char *kd, int len) 289keygrab_ssh1(con *c)
267{ 290{
268 static Key *rsa; 291 static Key *rsa;
269 static Buffer msg; 292 static Buffer msg;
@@ -272,12 +295,12 @@ keyprint(char *host, char *output_name, char *kd, int len)
272 buffer_init(&msg); 295 buffer_init(&msg);
273 rsa = key_new(KEY_RSA1); 296 rsa = key_new(KEY_RSA1);
274 } 297 }
275 buffer_append(&msg, kd, len); 298 buffer_append(&msg, c->c_data, c->c_plen);
276 buffer_consume(&msg, 8 - (len & 7)); /* padding */ 299 buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */
277 if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { 300 if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
278 error("%s: invalid packet type", host); 301 error("%s: invalid packet type", c->c_name);
279 buffer_clear(&msg); 302 buffer_clear(&msg);
280 return; 303 return NULL;
281 } 304 }
282 buffer_consume(&msg, 8); /* cookie */ 305 buffer_consume(&msg, 8); /* cookie */
283 306
@@ -290,10 +313,70 @@ keyprint(char *host, char *output_name, char *kd, int len)
290 (void) buffer_get_int(&msg); 313 (void) buffer_get_int(&msg);
291 buffer_get_bignum(&msg, rsa->rsa->e); 314 buffer_get_bignum(&msg, rsa->rsa->e);
292 buffer_get_bignum(&msg, rsa->rsa->n); 315 buffer_get_bignum(&msg, rsa->rsa->n);
316
293 buffer_clear(&msg); 317 buffer_clear(&msg);
294 318
295 fprintf(stdout, "%s ", output_name ? output_name : host); 319 return (rsa);
296 key_write(rsa, stdout); 320}
321
322static int
323hostjump(Key *hostkey)
324{
325 longjmp(kexjmp, (int)hostkey);
326}
327
328static int
329ssh2_capable(int remote_major, int remote_minor)
330{
331 switch (remote_major) {
332 case 1:
333 if (remote_minor == 99)
334 return 1;
335 break;
336 case 2:
337 return 1;
338 default:
339 break;
340 }
341 return 0;
342}
343
344static Key *
345keygrab_ssh2(con *c)
346{
347 int j;
348
349 packet_set_connection(c->c_fd, c->c_fd);
350 enable_compat20();
351 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
352 "ssh-dss": "ssh-rsa";
353 c->c_kex = kex_setup(myproposal);
354 c->c_kex->verify_host_key = hostjump;
355
356 if (!(j = setjmp(kexjmp))) {
357 nonfatal_fatal = 1;
358 dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
359 fprintf(stderr, "Impossible! dispatch_run() returned!\n");
360 exit(1);
361 }
362 nonfatal_fatal = 0;
363 xfree(c->c_kex);
364 c->c_kex = NULL;
365 packet_close();
366 if (j < 0)
367 j = 0;
368
369 return (Key*)(j);
370}
371
372static void
373keyprint(con *c, Key *key)
374{
375 if (!key)
376 return;
377
378 fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
379 key_write(key, stdout);
297 fputs("\n", stdout); 380 fputs("\n", stdout);
298} 381}
299 382
@@ -304,9 +387,9 @@ tcpconnect(char *host)
304 char strport[NI_MAXSERV]; 387 char strport[NI_MAXSERV];
305 int gaierr, s = -1; 388 int gaierr, s = -1;
306 389
307 snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT); 390 snprintf(strport, sizeof strport, "%d", ssh_port);
308 memset(&hints, 0, sizeof(hints)); 391 memset(&hints, 0, sizeof(hints));
309 hints.ai_family = family; 392 hints.ai_family = IPv4or6;
310 hints.ai_socktype = SOCK_STREAM; 393 hints.ai_socktype = SOCK_STREAM;
311 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) 394 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
312 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); 395 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
@@ -331,7 +414,7 @@ tcpconnect(char *host)
331} 414}
332 415
333static int 416static int
334conalloc(char *iname, char *oname) 417conalloc(char *iname, char *oname, int keytype)
335{ 418{
336 int s; 419 int s;
337 char *namebase, *name, *namelist; 420 char *namebase, *name, *namelist;
@@ -360,6 +443,7 @@ conalloc(char *iname, char *oname)
360 fdcon[s].c_data = (char *) &fdcon[s].c_plen; 443 fdcon[s].c_data = (char *) &fdcon[s].c_plen;
361 fdcon[s].c_len = 4; 444 fdcon[s].c_len = 4;
362 fdcon[s].c_off = 0; 445 fdcon[s].c_off = 0;
446 fdcon[s].c_keytype = keytype;
363 gettimeofday(&fdcon[s].c_tv, NULL); 447 gettimeofday(&fdcon[s].c_tv, NULL);
364 fdcon[s].c_tv.tv_sec += timeout; 448 fdcon[s].c_tv.tv_sec += timeout;
365 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); 449 TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
@@ -379,6 +463,7 @@ confree(int s)
379 if (fdcon[s].c_status == CS_KEYS) 463 if (fdcon[s].c_status == CS_KEYS)
380 xfree(fdcon[s].c_data); 464 xfree(fdcon[s].c_data);
381 fdcon[s].c_status = CS_UNUSED; 465 fdcon[s].c_status = CS_UNUSED;
466 fdcon[s].c_keytype = 0;
382 TAILQ_REMOVE(&tq, &fdcon[s], c_link); 467 TAILQ_REMOVE(&tq, &fdcon[s], c_link);
383 FD_CLR(s, read_wait); 468 FD_CLR(s, read_wait);
384 ncon--; 469 ncon--;
@@ -398,21 +483,16 @@ conrecycle(int s)
398{ 483{
399 int ret; 484 int ret;
400 con *c = &fdcon[s]; 485 con *c = &fdcon[s];
401 char *iname, *oname;
402 486
403 iname = xstrdup(c->c_namelist); 487 ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
404 oname = xstrdup(c->c_output_name);
405 confree(s); 488 confree(s);
406 ret = conalloc(iname, oname);
407 xfree(iname);
408 xfree(oname);
409 return (ret); 489 return (ret);
410} 490}
411 491
412static void 492static void
413congreet(int s) 493congreet(int s)
414{ 494{
415 char buf[80], *cp; 495 char buf[256], *cp;
416 size_t bufsiz; 496 size_t bufsiz;
417 int n = 0; 497 int n = 0;
418 con *c = &fdcon[s]; 498 con *c = &fdcon[s];
@@ -434,12 +514,34 @@ congreet(int s)
434 } 514 }
435 *cp = '\0'; 515 *cp = '\0';
436 fprintf(stderr, "# %s %s\n", c->c_name, buf); 516 fprintf(stderr, "# %s %s\n", c->c_name, buf);
437 n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); 517 if (c->c_keytype != KT_RSA1) {
518 int remote_major, remote_minor;
519 char remote_version[sizeof buf];
520
521 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
522 &remote_major, &remote_minor, remote_version) == 3)
523 compat_datafellows(remote_version);
524 else
525 datafellows = 0;
526 if (!ssh2_capable(remote_major, remote_minor)) {
527 debug("%s doesn't support ssh2", c->c_name);
528 confree(s);
529 return;
530 }
531 }
532 n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
533 c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
534 c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
438 if (atomicio(write, s, buf, n) != n) { 535 if (atomicio(write, s, buf, n) != n) {
439 error("write (%s): %s", c->c_name, strerror(errno)); 536 error("write (%s): %s", c->c_name, strerror(errno));
440 confree(s); 537 confree(s);
441 return; 538 return;
442 } 539 }
540 if (c->c_keytype != KT_RSA1) {
541 keyprint(c, keygrab_ssh2(c));
542 confree(s);
543 return;
544 }
443 c->c_status = CS_SIZE; 545 c->c_status = CS_SIZE;
444 contouch(s); 546 contouch(s);
445} 547}
@@ -472,7 +574,7 @@ conread(int s)
472 c->c_status = CS_KEYS; 574 c->c_status = CS_KEYS;
473 break; 575 break;
474 case CS_KEYS: 576 case CS_KEYS:
475 keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen); 577 keyprint(c, keygrab_ssh1(c));
476 confree(s); 578 confree(s);
477 return; 579 return;
478 break; 580 break;
@@ -536,86 +638,128 @@ conloop(void)
536 } 638 }
537} 639}
538 640
539static char * 641static void
540nexthost(int argc, char **argv) 642do_host(char *host)
541{ 643{
542 static Linebuf *lb; 644 char *name = strnnsep(&host, " \t\n");
543 645 int j;
544 for (;;) { 646
545 if (!lb) { 647 for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
546 if (argno >= argc) 648 if (get_keytypes & j) {
547 return (NULL); 649 while (ncon >= MAXCON)
548 if (argv[argno][0] != '-') 650 conloop();
549 return (argv[argno++]); 651 conalloc(name, *host ? host : name, j);
550 if (!strcmp(argv[argno], "--")) {
551 if (++argno >= argc)
552 return (NULL);
553 return (argv[argno++]);
554 } else if (!strncmp(argv[argno], "-f", 2)) {
555 char *fname;
556
557 if (argv[argno][2])
558 fname = &argv[argno++][2];
559 else if (++argno >= argc) {
560 error("missing filename for `-f'");
561 return (NULL);
562 } else
563 fname = argv[argno++];
564 if (!strcmp(fname, "-"))
565 fname = NULL;
566 lb = Linebuf_alloc(fname, error);
567 } else
568 error("ignoring invalid/misplaced option `%s'",
569 argv[argno++]);
570 } else {
571 char *line;
572
573 line = Linebuf_getline(lb);
574 if (line)
575 return (line);
576 Linebuf_free(lb);
577 lb = NULL;
578 } 652 }
579 } 653 }
580} 654}
581 655
582static void 656static void
657fatal_callback(void *arg)
658{
659 if (nonfatal_fatal)
660 longjmp(kexjmp, -1);
661}
662
663static void
583usage(void) 664usage(void)
584{ 665{
585 fprintf(stderr, "Usage: %s [options] [ host | addrlist namelist ]\n", 666 fprintf(stderr, "Usage: %s [options] host ...\n",
586 __progname); 667 __progname);
587 fprintf(stderr, "Options:\n"); 668 fprintf(stderr, "Options:\n");
588 fprintf(stderr, " -t timeout Set connection timeout.\n");
589 fprintf(stderr, " -f file Read hosts or addresses from file.\n"); 669 fprintf(stderr, " -f file Read hosts or addresses from file.\n");
670 fprintf(stderr, " -p port Connect to the specified port.\n");
671 fprintf(stderr, " -t keytype Specify the host key type.\n");
672 fprintf(stderr, " -T timeout Set connection timeout.\n");
673 fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
674 fprintf(stderr, " -4 Use IPv4 only.\n");
675 fprintf(stderr, " -6 Use IPv6 only.\n");
590 exit(1); 676 exit(1);
591} 677}
592 678
593int 679int
594main(int argc, char **argv) 680main(int argc, char **argv)
595{ 681{
596 char *host = NULL; 682 int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
683 int opt, fopt_count = 0;
684 char *tname;
685
686 extern int optind;
687 extern char *optarg;
597 688
598 __progname = get_progname(argv[0]); 689 __progname = get_progname(argv[0]);
599 TAILQ_INIT(&tq); 690 TAILQ_INIT(&tq);
600 691
601 if (argc <= argno) 692 if (argc <= 1)
602 usage(); 693 usage();
603 694
604 if (argv[1][0] == '-' && argv[1][1] == 't') { 695 while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
605 argno++; 696 switch (opt) {
606 if (argv[1][2]) 697 case 'p':
607 timeout = atoi(&argv[1][2]); 698 ssh_port = a2port(optarg);
608 else { 699 if (ssh_port == 0) {
609 if (argno >= argc) 700 fprintf(stderr, "Bad port '%s'\n", optarg);
701 exit(1);
702 }
703 break;
704 case 'T':
705 timeout = atoi(optarg);
706 if (timeout <= 0)
610 usage(); 707 usage();
611 timeout = atoi(argv[argno++]); 708 break;
612 } 709 case 'v':
613 if (timeout <= 0) 710 if (!debug_flag) {
711 debug_flag = 1;
712 log_level = SYSLOG_LEVEL_DEBUG1;
713 }
714 else if (log_level < SYSLOG_LEVEL_DEBUG3)
715 log_level++;
716 else
717 fatal("Too high debugging level.");
718 break;
719 case 'f':
720 if (strcmp(optarg, "-") == 0)
721 optarg = NULL;
722 argv[fopt_count++] = optarg;
723 break;
724 case 't':
725 get_keytypes = 0;
726 tname = strtok(optarg, ",");
727 while (tname) {
728 int type = key_type_from_name(tname);
729 switch (type) {
730 case KEY_RSA1:
731 get_keytypes |= KT_RSA1;
732 break;
733 case KEY_DSA:
734 get_keytypes |= KT_DSA;
735 break;
736 case KEY_RSA:
737 get_keytypes |= KT_RSA;
738 break;
739 case KEY_UNSPEC:
740 fatal("unknown key type %s\n", tname);
741 }
742 tname = strtok(NULL, ",");
743 }
744 break;
745 case '4':
746 IPv4or6 = AF_INET;
747 break;
748 case '6':
749 IPv4or6 = AF_INET6;
750 break;
751 case '?':
752 default:
614 usage(); 753 usage();
754 }
615 } 755 }
616 if (argc <= argno) 756 if (optind == argc && !fopt_count)
617 usage(); 757 usage();
618 758
759 log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
760 fatal_add_cleanup(fatal_callback, NULL);
761
762
619 maxfd = fdlim_get(1); 763 maxfd = fdlim_get(1);
620 if (maxfd < 0) 764 if (maxfd < 0)
621 fatal("%s: fdlim_get: bad value", __progname); 765 fatal("%s: fdlim_get: bad value", __progname);
@@ -632,18 +776,22 @@ main(int argc, char **argv)
632 read_wait = xmalloc(read_wait_size); 776 read_wait = xmalloc(read_wait_size);
633 memset(read_wait, 0, read_wait_size); 777 memset(read_wait, 0, read_wait_size);
634 778
635 do { 779 if (fopt_count) {
636 while (ncon < MAXCON) { 780 Linebuf *lb;
637 char *name; 781 char *line;
638 782 int j;
639 host = nexthost(argc, argv); 783
640 if (host == NULL) 784 for (j = 0; j < fopt_count; j++) {
641 break; 785 lb = Linebuf_alloc(argv[j], error);
642 name = strnnsep(&host, " \t\n"); 786 while ((line = Linebuf_getline(lb)) != NULL)
643 conalloc(name, *host ? host : name); 787 do_host(line);
788 Linebuf_free(lb);
644 } 789 }
645 conloop(); 790 }
646 } while (host); 791
792 while (optind < argc)
793 do_host(argv[optind++]);
794
647 while (ncon > 0) 795 while (ncon > 0)
648 conloop(); 796 conloop();
649 797