1 /* $OpenBSD: ssh-keyscan.c,v 1.106 2016/05/02 10:26:04 djm Exp $ */
3 * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
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.
12 #include <sys/types.h>
13 #include "openbsd-compat/sys-queue.h"
14 #include <sys/resource.h>
15 #ifdef HAVE_SYS_TIME_H
16 # include <sys/time.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
22 #include <openssl/bn.h>
41 #include "myproposal.h"
51 /* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
52 Default value is AF_UNSPEC means both IPv4 and IPv6. */
53 int IPv4or6
= AF_UNSPEC
;
55 int ssh_port
= SSH_DEFAULT_PORT
;
64 int get_keytypes
= KT_RSA
|KT_ECDSA
|KT_ED25519
;
66 int hash_hosts
= 0; /* Hash hostname on output */
70 /* The number of seconds after which to give up on a TCP connection */
74 #define MAXCON (maxfd - 10)
76 extern char *__progname
;
78 size_t read_wait_nfdset
;
81 struct ssh
*active_state
= NULL
; /* XXX needed for linking */
84 * Keep a connection structure for each file descriptor. The state
85 * associated with file descriptor n is held in fdcon[n].
87 typedef struct Connection
{
88 u_char c_status
; /* State of connection on this file desc. */
89 #define CS_UNUSED 0 /* File descriptor unused */
90 #define CS_CON 1 /* Waiting to connect/read greeting */
91 #define CS_SIZE 2 /* Waiting to read initial packet size */
92 #define CS_KEYS 3 /* Waiting to read public key packet */
93 int c_fd
; /* Quick lookup: c->c_fd == c - fdcon */
94 int c_plen
; /* Packet length field for ssh packet */
95 int c_len
; /* Total bytes which must be read. */
96 int c_off
; /* Length of data read so far. */
97 int c_keytype
; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
98 sig_atomic_t c_done
; /* SSH2 done */
99 char *c_namebase
; /* Address to free for c_name and c_namelist */
100 char *c_name
; /* Hostname of connection for errors */
101 char *c_namelist
; /* Pointer to other possible addresses */
102 char *c_output_name
; /* Hostname of connection for output */
103 char *c_data
; /* Data read from this fd */
104 struct ssh
*c_ssh
; /* SSH-connection */
105 struct timeval c_tv
; /* Time at which connection gets aborted */
106 TAILQ_ENTRY(Connection
) c_link
; /* List of connections in timeout order. */
109 TAILQ_HEAD(conlist
, Connection
) tq
; /* Timeout Queue */
112 static void keyprint(con
*c
, struct sshkey
*key
);
117 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
120 if (getrlimit(RLIMIT_NOFILE
, &rlfd
) < 0)
122 if ((hard
? rlfd
.rlim_max
: rlfd
.rlim_cur
) == RLIM_INFINITY
)
125 return hard
? rlfd
.rlim_max
: rlfd
.rlim_cur
;
134 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
140 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
141 if (getrlimit(RLIMIT_NOFILE
, &rlfd
) < 0)
144 if (setrlimit(RLIMIT_NOFILE
, &rlfd
) < 0)
146 #elif defined (HAVE_SETDTABLESIZE)
153 * This is an strsep function that returns a null field for adjacent
154 * separators. This is the same as the 4.4BSD strsep, but different from the
155 * one in the GNU libc.
158 xstrsep(char **str
, const char *delim
)
166 e
= s
+ strcspn(s
, delim
);
176 * Get the next non-null token (like GNU strsep). Strsep() will return a
177 * null token for two adjacent separators, so we may have to loop.
180 strnnsep(char **stringp
, char *delim
)
185 tok
= xstrsep(stringp
, delim
);
186 } while (tok
&& *tok
== '\0');
191 static struct sshkey
*
194 static struct sshkey
*rsa
;
195 static struct sshbuf
*msg
;
200 if ((rsa
= sshkey_new(KEY_RSA1
)) == NULL
) {
201 error("%s: sshkey_new failed", __func__
);
204 if ((msg
= sshbuf_new()) == NULL
)
205 fatal("%s: sshbuf_new failed", __func__
);
207 if ((r
= sshbuf_put(msg
, c
->c_data
, c
->c_plen
)) != 0 ||
208 (r
= sshbuf_consume(msg
, 8 - (c
->c_plen
& 7))) != 0 || /* padding */
209 (r
= sshbuf_get_u8(msg
, &type
)) != 0)
211 if (type
!= (int) SSH_SMSG_PUBLIC_KEY
) {
212 error("%s: invalid packet type", c
->c_name
);
216 if ((r
= sshbuf_consume(msg
, 8)) != 0 || /* cookie */
218 (r
= sshbuf_get_u32(msg
, NULL
)) != 0 ||
219 (r
= sshbuf_get_bignum1(msg
, NULL
)) != 0 ||
220 (r
= sshbuf_get_bignum1(msg
, NULL
)) != 0 ||
222 (r
= sshbuf_get_u32(msg
, NULL
)) != 0 ||
223 (r
= sshbuf_get_bignum1(msg
, rsa
->rsa
->e
)) != 0 ||
224 (r
= sshbuf_get_bignum1(msg
, rsa
->rsa
->n
)) != 0) {
226 error("%s: buffer error: %s", __func__
, ssh_err(r
));
238 key_print_wrapper(struct sshkey
*hostkey
, struct ssh
*ssh
)
242 if ((c
= ssh_get_app_data(ssh
)) != NULL
)
243 keyprint(c
, hostkey
);
244 /* always abort key exchange */
249 ssh2_capable(int remote_major
, int remote_minor
)
251 switch (remote_major
) {
253 if (remote_minor
== 99)
267 char *myproposal
[PROPOSAL_MAX
] = { KEX_CLIENT
};
271 switch (c
->c_keytype
) {
273 myproposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = get_cert
?
274 "ssh-dss-cert-v01@openssh.com" : "ssh-dss";
277 myproposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = get_cert
?
278 "ssh-rsa-cert-v01@openssh.com" : "ssh-rsa";
281 myproposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = get_cert
?
282 "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
285 myproposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = get_cert
?
286 "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
287 "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
288 "ecdsa-sha2-nistp521-cert-v01@openssh.com" :
289 "ecdsa-sha2-nistp256,"
290 "ecdsa-sha2-nistp384,"
291 "ecdsa-sha2-nistp521";
294 fatal("unknown key type %d", c
->c_keytype
);
297 if ((r
= kex_setup(c
->c_ssh
, myproposal
)) != 0) {
299 fprintf(stderr
, "kex_setup: %s\n", ssh_err(r
));
303 c
->c_ssh
->kex
->kex
[KEX_DH_GRP1_SHA1
] = kexdh_client
;
304 c
->c_ssh
->kex
->kex
[KEX_DH_GRP14_SHA1
] = kexdh_client
;
305 c
->c_ssh
->kex
->kex
[KEX_DH_GRP14_SHA256
] = kexdh_client
;
306 c
->c_ssh
->kex
->kex
[KEX_DH_GRP16_SHA512
] = kexdh_client
;
307 c
->c_ssh
->kex
->kex
[KEX_DH_GRP18_SHA512
] = kexdh_client
;
308 c
->c_ssh
->kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_client
;
309 c
->c_ssh
->kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_client
;
310 # ifdef OPENSSL_HAS_ECC
311 c
->c_ssh
->kex
->kex
[KEX_ECDH_SHA2
] = kexecdh_client
;
314 c
->c_ssh
->kex
->kex
[KEX_C25519_SHA256
] = kexc25519_client
;
315 ssh_set_verify_host_key_callback(c
->c_ssh
, key_print_wrapper
);
317 * do the key-exchange until an error occurs or until
318 * the key_print_wrapper() callback sets c_done.
320 ssh_dispatch_run(c
->c_ssh
, DISPATCH_BLOCK
, &c
->c_done
, c
->c_ssh
);
324 keyprint_one(char *host
, struct sshkey
*key
)
328 if (hash_hosts
&& (host
= host_hash(host
, NULL
, 0)) == NULL
)
329 fatal("host_hash failed");
331 hostport
= put_host_port(host
, ssh_port
);
333 fprintf(stdout
, "%s ", hostport
);
334 sshkey_write(key
, stdout
);
340 keyprint(con
*c
, struct sshkey
*key
)
342 char *hosts
= c
->c_output_name
? c
->c_output_name
: c
->c_name
;
347 if (get_cert
|| (!hash_hosts
&& ssh_port
== SSH_DEFAULT_PORT
)) {
348 keyprint_one(hosts
, key
);
351 ohosts
= hosts
= xstrdup(hosts
);
352 while ((host
= strsep(&hosts
, ",")) != NULL
)
353 keyprint_one(host
, key
);
358 tcpconnect(char *host
)
360 struct addrinfo hints
, *ai
, *aitop
;
361 char strport
[NI_MAXSERV
];
364 snprintf(strport
, sizeof strport
, "%d", ssh_port
);
365 memset(&hints
, 0, sizeof(hints
));
366 hints
.ai_family
= IPv4or6
;
367 hints
.ai_socktype
= SOCK_STREAM
;
368 if ((gaierr
= getaddrinfo(host
, strport
, &hints
, &aitop
)) != 0) {
369 error("getaddrinfo %s: %s", host
, ssh_gai_strerror(gaierr
));
372 for (ai
= aitop
; ai
; ai
= ai
->ai_next
) {
373 s
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
375 error("socket: %s", strerror(errno
));
378 if (set_nonblock(s
) == -1)
379 fatal("%s: set_nonblock(%d)", __func__
, s
);
380 if (connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) < 0 &&
381 errno
!= EINPROGRESS
)
382 error("connect (`%s'): %s", host
, strerror(errno
));
393 conalloc(char *iname
, char *oname
, int keytype
)
395 char *namebase
, *name
, *namelist
;
398 namebase
= namelist
= xstrdup(iname
);
401 name
= xstrsep(&namelist
, ",");
406 } while ((s
= tcpconnect(name
)) < 0);
409 fatal("conalloc: fdno %d too high", s
);
410 if (fdcon
[s
].c_status
)
411 fatal("conalloc: attempt to reuse fdno %d", s
);
413 debug3("%s: oname %s kt %d", __func__
, oname
, keytype
);
415 fdcon
[s
].c_status
= CS_CON
;
416 fdcon
[s
].c_namebase
= namebase
;
417 fdcon
[s
].c_name
= name
;
418 fdcon
[s
].c_namelist
= namelist
;
419 fdcon
[s
].c_output_name
= xstrdup(oname
);
420 fdcon
[s
].c_data
= (char *) &fdcon
[s
].c_plen
;
423 fdcon
[s
].c_keytype
= keytype
;
424 gettimeofday(&fdcon
[s
].c_tv
, NULL
);
425 fdcon
[s
].c_tv
.tv_sec
+= timeout
;
426 TAILQ_INSERT_TAIL(&tq
, &fdcon
[s
], c_link
);
427 FD_SET(s
, read_wait
);
435 if (s
>= maxfd
|| fdcon
[s
].c_status
== CS_UNUSED
)
436 fatal("confree: attempt to free bad fdno %d", s
);
438 free(fdcon
[s
].c_namebase
);
439 free(fdcon
[s
].c_output_name
);
440 if (fdcon
[s
].c_status
== CS_KEYS
)
441 free(fdcon
[s
].c_data
);
442 fdcon
[s
].c_status
= CS_UNUSED
;
443 fdcon
[s
].c_keytype
= 0;
444 if (fdcon
[s
].c_ssh
) {
445 ssh_packet_close(fdcon
[s
].c_ssh
);
446 free(fdcon
[s
].c_ssh
);
447 fdcon
[s
].c_ssh
= NULL
;
449 TAILQ_REMOVE(&tq
, &fdcon
[s
], c_link
);
450 FD_CLR(s
, read_wait
);
457 TAILQ_REMOVE(&tq
, &fdcon
[s
], c_link
);
458 gettimeofday(&fdcon
[s
].c_tv
, NULL
);
459 fdcon
[s
].c_tv
.tv_sec
+= timeout
;
460 TAILQ_INSERT_TAIL(&tq
, &fdcon
[s
], c_link
);
469 ret
= conalloc(c
->c_namelist
, c
->c_output_name
, c
->c_keytype
);
477 int n
= 0, remote_major
= 0, remote_minor
= 0;
479 char remote_version
[sizeof buf
];
484 memset(buf
, '\0', sizeof(buf
));
485 bufsiz
= sizeof(buf
);
488 (n
= atomicio(read
, s
, cp
, 1)) == 1 && *cp
!= '\n') {
493 if (n
!= 1 || strncmp(buf
, "SSH-", 4) == 0)
499 error("%s: Connection closed by remote host", c
->c_name
);
504 error("read (%s): %s", c
->c_name
, strerror(errno
));
510 if (*cp
!= '\n' && *cp
!= '\r') {
511 error("%s: bad greeting", c
->c_name
);
516 if ((c
->c_ssh
= ssh_packet_set_connection(NULL
, s
, s
)) == NULL
)
517 fatal("ssh_packet_set_connection failed");
518 ssh_packet_set_timeout(c
->c_ssh
, timeout
, 1);
519 ssh_set_app_data(c
->c_ssh
, c
); /* back link */
520 if (sscanf(buf
, "SSH-%d.%d-%[^\n]\n",
521 &remote_major
, &remote_minor
, remote_version
) == 3)
522 c
->c_ssh
->compat
= compat_datafellows(remote_version
);
524 c
->c_ssh
->compat
= 0;
525 if (c
->c_keytype
!= KT_RSA1
) {
526 if (!ssh2_capable(remote_major
, remote_minor
)) {
527 debug("%s doesn't support ssh2", c
->c_name
);
531 } else if (remote_major
!= 1) {
532 debug("%s doesn't support ssh1", c
->c_name
);
536 fprintf(stderr
, "# %s:%d %s\n", c
->c_name
, ssh_port
, chop(buf
));
537 n
= snprintf(buf
, sizeof buf
, "SSH-%d.%d-OpenSSH-keyscan\r\n",
538 c
->c_keytype
== KT_RSA1
? PROTOCOL_MAJOR_1
: PROTOCOL_MAJOR_2
,
539 c
->c_keytype
== KT_RSA1
? PROTOCOL_MINOR_1
: PROTOCOL_MINOR_2
);
540 if (n
< 0 || (size_t)n
>= sizeof(buf
)) {
541 error("snprintf: buffer too small");
545 if (atomicio(vwrite
, s
, buf
, n
) != (size_t)n
) {
546 error("write (%s): %s", c
->c_name
, strerror(errno
));
550 if (c
->c_keytype
!= KT_RSA1
) {
555 c
->c_status
= CS_SIZE
;
565 if (c
->c_status
== CS_CON
) {
569 n
= atomicio(read
, s
, c
->c_data
+ c
->c_off
, c
->c_len
- c
->c_off
);
571 error("read (%s): %s", c
->c_name
, strerror(errno
));
577 if (c
->c_off
== c
->c_len
)
578 switch (c
->c_status
) {
580 c
->c_plen
= htonl(c
->c_plen
);
581 c
->c_len
= c
->c_plen
+ 8 - (c
->c_plen
& 7);
583 c
->c_data
= xmalloc(c
->c_len
);
584 c
->c_status
= CS_KEYS
;
588 keyprint(c
, keygrab_ssh1(c
));
593 fatal("conread: invalid status %d", c
->c_status
);
603 struct timeval seltime
, now
;
608 gettimeofday(&now
, NULL
);
609 c
= TAILQ_FIRST(&tq
);
611 if (c
&& (c
->c_tv
.tv_sec
> now
.tv_sec
||
612 (c
->c_tv
.tv_sec
== now
.tv_sec
&& c
->c_tv
.tv_usec
> now
.tv_usec
))) {
614 seltime
.tv_sec
-= now
.tv_sec
;
615 seltime
.tv_usec
-= now
.tv_usec
;
616 if (seltime
.tv_usec
< 0) {
617 seltime
.tv_usec
+= 1000000;
621 timerclear(&seltime
);
623 r
= xcalloc(read_wait_nfdset
, sizeof(fd_mask
));
624 e
= xcalloc(read_wait_nfdset
, sizeof(fd_mask
));
625 memcpy(r
, read_wait
, read_wait_nfdset
* sizeof(fd_mask
));
626 memcpy(e
, read_wait
, read_wait_nfdset
* sizeof(fd_mask
));
628 while (select(maxfd
, r
, NULL
, e
, &seltime
) == -1 &&
629 (errno
== EAGAIN
|| errno
== EINTR
|| errno
== EWOULDBLOCK
))
632 for (i
= 0; i
< maxfd
; i
++) {
633 if (FD_ISSET(i
, e
)) {
634 error("%s: exception!", fdcon
[i
].c_name
);
636 } else if (FD_ISSET(i
, r
))
642 c
= TAILQ_FIRST(&tq
);
643 while (c
&& (c
->c_tv
.tv_sec
< now
.tv_sec
||
644 (c
->c_tv
.tv_sec
== now
.tv_sec
&& c
->c_tv
.tv_usec
< now
.tv_usec
))) {
647 c
= TAILQ_NEXT(c
, c_link
);
655 char *name
= strnnsep(&host
, " \t\n");
660 for (j
= KT_RSA1
; j
<= KT_ED25519
; j
*= 2) {
661 if (get_keytypes
& j
) {
662 while (ncon
>= MAXCON
)
664 conalloc(name
, *host
? host
: name
, j
);
670 fatal(const char *fmt
,...)
675 do_log(SYSLOG_LEVEL_FATAL
, fmt
, args
);
684 "usage: %s [-46cHv] [-f file] [-p port] [-T timeout] [-t type]\n"
685 "\t\t [host | addrlist namelist] ...\n",
691 main(int argc
, char **argv
)
693 int debug_flag
= 0, log_level
= SYSLOG_LEVEL_INFO
;
694 int opt
, fopt_count
= 0, j
;
695 char *tname
, *cp
, line
[NI_MAXHOST
];
702 ssh_malloc_init(); /* must be called before any mallocs */
703 __progname
= ssh_get_progname(argv
[0]);
707 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
713 while ((opt
= getopt(argc
, argv
, "cHv46p:T:t:f:")) != -1) {
722 ssh_port
= a2port(optarg
);
724 fprintf(stderr
, "Bad port '%s'\n", optarg
);
729 timeout
= convtime(optarg
);
730 if (timeout
== -1 || timeout
== 0) {
731 fprintf(stderr
, "Bad timeout '%s'\n", optarg
);
738 log_level
= SYSLOG_LEVEL_DEBUG1
;
740 else if (log_level
< SYSLOG_LEVEL_DEBUG3
)
743 fatal("Too high debugging level.");
746 if (strcmp(optarg
, "-") == 0)
748 argv
[fopt_count
++] = optarg
;
752 tname
= strtok(optarg
, ",");
754 int type
= sshkey_type_from_name(tname
);
757 get_keytypes
|= KT_RSA1
;
760 get_keytypes
|= KT_DSA
;
763 get_keytypes
|= KT_ECDSA
;
766 get_keytypes
|= KT_RSA
;
769 get_keytypes
|= KT_ED25519
;
772 fatal("unknown key type %s", tname
);
774 tname
= strtok(NULL
, ",");
788 if (optind
== argc
&& !fopt_count
)
791 log_init("ssh-keyscan", log_level
, SYSLOG_FACILITY_USER
, 1);
793 maxfd
= fdlim_get(1);
795 fatal("%s: fdlim_get: bad value", __progname
);
796 if (maxfd
> MAXMAXFD
)
799 fatal("%s: not enough file descriptors", __progname
);
800 if (maxfd
> fdlim_get(0))
802 fdcon
= xcalloc(maxfd
, sizeof(con
));
804 read_wait_nfdset
= howmany(maxfd
, NFDBITS
);
805 read_wait
= xcalloc(read_wait_nfdset
, sizeof(fd_mask
));
807 for (j
= 0; j
< fopt_count
; j
++) {
810 else if ((fp
= fopen(argv
[j
], "r")) == NULL
)
811 fatal("%s: %s: %s", __progname
, argv
[j
],
815 while (read_keyfile_line(fp
,
816 argv
[j
] == NULL
? "(stdin)" : argv
[j
], line
, sizeof(line
),
818 /* Chomp off trailing whitespace and comments */
819 if ((cp
= strchr(line
, '#')) == NULL
)
820 cp
= line
+ strlen(line
) - 1;
822 if (*cp
== ' ' || *cp
== '\t' ||
823 *cp
== '\n' || *cp
== '#')
829 /* Skip empty lines */
837 fatal("%s: %s: %s", __progname
, argv
[j
],
843 while (optind
< argc
)
844 do_host(argv
[optind
++]);