diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | ssh-keyscan.1 | 75 | ||||
-rw-r--r-- | ssh-keyscan.c | 320 |
3 files changed, 302 insertions, 98 deletions
@@ -138,6 +138,9 @@ | |||
138 | - jakob@cvs.openbsd.org 2001/08/03 10:31:30 | 138 | - jakob@cvs.openbsd.org 2001/08/03 10:31:30 |
139 | [ssh-add.c ssh-agent.c ssh-keyscan.c] | 139 | [ssh-add.c ssh-agent.c ssh-keyscan.c] |
140 | improve usage(). ok markus@ | 140 | improve usage(). ok markus@ |
141 | - markus@cvs.openbsd.org 2001/08/05 23:18:20 | ||
142 | [ssh-keyscan.1 ssh-keyscan.c] | ||
143 | ssh 2 support; from wayned@users.sourceforge.net | ||
141 | 144 | ||
142 | 20010803 | 145 | 20010803 |
143 | - (djm) Fix interrupted read in entropy gatherer. Spotted by markus@ on | 146 | - (djm) Fix interrupted read in entropy gatherer. Spotted by markus@ on |
@@ -6248,4 +6251,4 @@ | |||
6248 | - Wrote replacements for strlcpy and mkdtemp | 6251 | - Wrote replacements for strlcpy and mkdtemp |
6249 | - Released 1.0pre1 | 6252 | - Released 1.0pre1 |
6250 | 6253 | ||
6251 | $Id: ChangeLog,v 1.1462 2001/08/06 22:06:35 mouring Exp $ | 6254 | $Id: ChangeLog,v 1.1463 2001/08/06 22:41:30 mouring Exp $ |
diff --git a/ssh-keyscan.1 b/ssh-keyscan.1 index 80119aa21..b348bc252 100644 --- a/ssh-keyscan.1 +++ b/ssh-keyscan.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ssh-keyscan.1,v 1.9 2001/08/02 18:37:35 mpech Exp $ | 1 | .\" $OpenBSD: ssh-keyscan.1,v 1.10 2001/08/05 23:18:20 markus Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. | 3 | .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. |
4 | .\" | 4 | .\" |
@@ -14,9 +14,13 @@ | |||
14 | .Nd gather ssh public keys | 14 | .Nd gather ssh public keys |
15 | .Sh SYNOPSIS | 15 | .Sh SYNOPSIS |
16 | .Nm ssh-keyscan | 16 | .Nm ssh-keyscan |
17 | .Op Fl t Ar timeout | 17 | .Op Fl v46 |
18 | .Op Ar -- | host | addrlist namelist | 18 | .Op Fl p Ar port |
19 | .Op Fl f Ar files ... | 19 | .Op Fl T Ar timeout |
20 | .Op Fl t Ar type | ||
21 | .Op Fl f Ar file | ||
22 | .Op Ar host | addrlist namelist | ||
23 | .Op Ar ... | ||
20 | .Sh DESCRIPTION | 24 | .Sh DESCRIPTION |
21 | .Nm | 25 | .Nm |
22 | is a utility for gathering the public ssh host keys of a number of | 26 | is a utility for gathering the public ssh host keys of a number of |
@@ -37,14 +41,28 @@ any encryption. | |||
37 | .Pp | 41 | .Pp |
38 | The options are as follows: | 42 | The options are as follows: |
39 | .Bl -tag -width Ds | 43 | .Bl -tag -width Ds |
40 | .It Fl t | 44 | .It Fl p Ar port |
45 | Port to connect to on the remote host. | ||
46 | .It Fl T | ||
41 | Set the timeout for connection attempts. If | 47 | Set the timeout for connection attempts. If |
42 | .Pa timeout | 48 | .Pa timeout |
43 | seconds have elapsed since a connection was initiated to a host or since the | 49 | seconds have elapsed since a connection was initiated to a host or since the |
44 | last time anything was read from that host, then the connection is | 50 | last time anything was read from that host, then the connection is |
45 | closed and the host in question considered unavailable. Default is 5 | 51 | closed and the host in question considered unavailable. Default is 5 |
46 | seconds. | 52 | seconds. |
47 | .It Fl f | 53 | .It Fl t Ar type |
54 | Specifies the type of the key to fetch from the following hosts. | ||
55 | The possible values are | ||
56 | .Dq rsa1 | ||
57 | for protocol version 1 and | ||
58 | .Dq rsa | ||
59 | or | ||
60 | .Dq dsa | ||
61 | for protocol version 2. | ||
62 | Multiple values may be specified by separating them with commas. | ||
63 | The default is | ||
64 | .Dq rsa1 . | ||
65 | .It Fl f Ar filename | ||
48 | Read hosts or | 66 | Read hosts or |
49 | .Pa addrlist namelist | 67 | .Pa addrlist namelist |
50 | pairs from this file, one per line. | 68 | pairs from this file, one per line. |
@@ -55,6 +73,19 @@ is supplied instead of a filename, | |||
55 | will read hosts or | 73 | will read hosts or |
56 | .Pa addrlist namelist | 74 | .Pa addrlist namelist |
57 | pairs from the standard input. | 75 | pairs from the standard input. |
76 | .It Fl v | ||
77 | Verbose mode. | ||
78 | Causes | ||
79 | .Nm | ||
80 | to print debugging messages about its progress. | ||
81 | .It Fl 4 | ||
82 | Forces | ||
83 | .Nm | ||
84 | to use IPv4 addresses only. | ||
85 | .It Fl 6 | ||
86 | Forces | ||
87 | .Nm | ||
88 | to use IPv6 addresses only. | ||
58 | .El | 89 | .El |
59 | .Sh SECURITY | 90 | .Sh SECURITY |
60 | If you make an ssh_known_hosts file using | 91 | If you make an ssh_known_hosts file using |
@@ -67,7 +98,10 @@ On the other hand, if your security model allows such a risk, | |||
67 | can help you detect tampered keyfiles or man in the middle attacks which | 98 | can help you detect tampered keyfiles or man in the middle attacks which |
68 | have begun after you created your ssh_known_hosts file. | 99 | have begun after you created your ssh_known_hosts file. |
69 | .Sh EXAMPLES | 100 | .Sh EXAMPLES |
70 | Print the host key for machine | 101 | .Pp |
102 | Print the | ||
103 | .Pa rsa1 | ||
104 | host key for machine | ||
71 | .Pa hostname : | 105 | .Pa hostname : |
72 | .Bd -literal | 106 | .Bd -literal |
73 | ssh-keyscan hostname | 107 | ssh-keyscan hostname |
@@ -78,20 +112,36 @@ Find all hosts from the file | |||
78 | which have new or different keys from those in the sorted file | 112 | which have new or different keys from those in the sorted file |
79 | .Pa ssh_known_hosts : | 113 | .Pa ssh_known_hosts : |
80 | .Bd -literal | 114 | .Bd -literal |
81 | $ ssh-keyscan -f ssh_hosts | sort -u - ssh_known_hosts | \e\ | 115 | ssh-keyscan -t rsa,dsa -f ssh_hosts | \e\ |
82 | diff ssh_known_hosts - | 116 | sort -u - ssh_known_hosts | diff ssh_known_hosts - |
83 | .Ed | 117 | .Ed |
84 | .Sh FILES | 118 | .Sh FILES |
85 | .Pa Input format: | 119 | .Pa Input format: |
120 | .Bd -literal | ||
86 | 1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 | 121 | 1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 |
122 | .Ed | ||
87 | .Pp | 123 | .Pp |
88 | .Pa Output format: | 124 | .Pa Output format for rsa1 keys: |
125 | .Bd -literal | ||
89 | host-or-namelist bits exponent modulus | 126 | host-or-namelist bits exponent modulus |
127 | .Ed | ||
128 | .Pp | ||
129 | .Pa Output format for rsa and dsa keys: | ||
130 | .Bd -literal | ||
131 | host-or-namelist keytype base64-encoded-key | ||
132 | .Ed | ||
133 | .Pp | ||
134 | Where | ||
135 | .Pa keytype | ||
136 | is either | ||
137 | .Dq ssh-rsa | ||
138 | or | ||
139 | .Dq ssh-dsa . | ||
90 | .Pp | 140 | .Pp |
91 | .Pa /etc/ssh_known_hosts | 141 | .Pa /etc/ssh_known_hosts |
92 | .Sh BUGS | 142 | .Sh BUGS |
93 | It generates "Connection closed by remote host" messages on the consoles | 143 | It generates "Connection closed by remote host" messages on the consoles |
94 | of all the machines it scans. | 144 | of all the machines it scans if the server is older than version 2.9. |
95 | This is because it opens a connection to the ssh port, reads the public | 145 | This is because it opens a connection to the ssh port, reads the public |
96 | key, and drops the connection as soon as it gets the key. | 146 | key, and drops the connection as soon as it gets the key. |
97 | .Sh SEE ALSO | 147 | .Sh SEE ALSO |
@@ -99,3 +149,6 @@ key, and drops the connection as soon as it gets the key. | |||
99 | .Xr sshd 8 | 149 | .Xr sshd 8 |
100 | .Sh AUTHORS | 150 | .Sh AUTHORS |
101 | David Mazieres <dm@lcs.mit.edu> | 151 | David Mazieres <dm@lcs.mit.edu> |
152 | wrote the initial version, and | ||
153 | Wayne Davison <wayned@users.sourceforge.net> | ||
154 | added support for protocol version 2. | ||
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" |
10 | RCSID("$OpenBSD: ssh-keyscan.c,v 1.25 2001/08/03 10:31:30 jakob Exp $"); | 10 | RCSID("$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 | ||
30 | static 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 | ||
40 | int IPv4or6 = AF_INET; | ||
41 | #else | ||
42 | int IPv4or6 = AF_UNSPEC; | ||
43 | #endif | ||
31 | 44 | ||
32 | int family = AF_UNSPEC; /* IPv4, IPv6 or both */ | 45 | int ssh_port = SSH_DEFAULT_PORT; |
46 | |||
47 | #define KT_RSA1 1 | ||
48 | #define KT_DSA 2 | ||
49 | #define KT_RSA 4 | ||
50 | |||
51 | int 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; | |||
47 | fd_set *read_wait; | 66 | fd_set *read_wait; |
48 | size_t read_wait_size; | 67 | size_t read_wait_size; |
49 | int ncon; | 68 | int ncon; |
69 | int nonfatal_fatal = 0; | ||
70 | jmp_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 | ||
265 | static void | 288 | static Key * |
266 | keyprint(char *host, char *output_name, char *kd, int len) | 289 | keygrab_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 | |||
322 | static int | ||
323 | hostjump(Key *hostkey) | ||
324 | { | ||
325 | longjmp(kexjmp, (int)hostkey); | ||
326 | } | ||
327 | |||
328 | static int | ||
329 | ssh2_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 | |||
344 | static Key * | ||
345 | keygrab_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 | |||
372 | static void | ||
373 | keyprint(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 | ||
333 | static int | 416 | static int |
334 | conalloc(char *iname, char *oname) | 417 | conalloc(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 | ||
412 | static void | 492 | static void |
413 | congreet(int s) | 493 | congreet(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 | ||
539 | static char * | 641 | static void |
540 | nexthost(int argc, char **argv) | 642 | do_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 | ||
582 | static void | 656 | static void |
657 | fatal_callback(void *arg) | ||
658 | { | ||
659 | if (nonfatal_fatal) | ||
660 | longjmp(kexjmp, -1); | ||
661 | } | ||
662 | |||
663 | static void | ||
583 | usage(void) | 664 | usage(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 | ||
593 | int | 679 | int |
594 | main(int argc, char **argv) | 680 | main(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 | ||