]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/ssh-keyscan.c
zfs: merge openzfs/zfs@431083f75
[FreeBSD/FreeBSD.git] / crypto / openssh / ssh-keyscan.c
1 /* $OpenBSD: ssh-keyscan.c,v 1.151 2023/02/10 06:41:53 jmc 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 "includes.h"
11  
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>
17 #endif
18
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21
22 #ifdef WITH_OPENSSL
23 #include <openssl/bn.h>
24 #endif
25
26 #include <netdb.h>
27 #include <errno.h>
28 #ifdef HAVE_POLL_H
29 #include <poll.h>
30 #endif
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "xmalloc.h"
39 #include "ssh.h"
40 #include "sshbuf.h"
41 #include "sshkey.h"
42 #include "cipher.h"
43 #include "digest.h"
44 #include "kex.h"
45 #include "compat.h"
46 #include "myproposal.h"
47 #include "packet.h"
48 #include "dispatch.h"
49 #include "log.h"
50 #include "atomicio.h"
51 #include "misc.h"
52 #include "hostfile.h"
53 #include "ssherr.h"
54 #include "ssh_api.h"
55 #include "dns.h"
56 #include "addr.h"
57
58 /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
59    Default value is AF_UNSPEC means both IPv4 and IPv6. */
60 int IPv4or6 = AF_UNSPEC;
61
62 int ssh_port = SSH_DEFAULT_PORT;
63
64 #define KT_DSA          (1)
65 #define KT_RSA          (1<<1)
66 #define KT_ECDSA        (1<<2)
67 #define KT_ED25519      (1<<3)
68 #define KT_XMSS         (1<<4)
69 #define KT_ECDSA_SK     (1<<5)
70 #define KT_ED25519_SK   (1<<6)
71
72 #define KT_MIN          KT_DSA
73 #define KT_MAX          KT_ED25519_SK
74
75 int get_cert = 0;
76 int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK;
77
78 int hash_hosts = 0;             /* Hash hostname on output */
79
80 int print_sshfp = 0;            /* Print SSHFP records instead of known_hosts */
81
82 int found_one = 0;              /* Successfully found a key */
83
84 int hashalg = -1;               /* Hash for SSHFP records or -1 for all */
85
86 #define MAXMAXFD 256
87
88 /* The number of seconds after which to give up on a TCP connection */
89 int timeout = 5;
90
91 int maxfd;
92 #define MAXCON (maxfd - 10)
93
94 extern char *__progname;
95 struct pollfd *read_wait;
96 int ncon;
97
98 /*
99  * Keep a connection structure for each file descriptor.  The state
100  * associated with file descriptor n is held in fdcon[n].
101  */
102 typedef struct Connection {
103         u_char c_status;        /* State of connection on this file desc. */
104 #define CS_UNUSED 0             /* File descriptor unused */
105 #define CS_CON 1                /* Waiting to connect/read greeting */
106 #define CS_SIZE 2               /* Waiting to read initial packet size */
107 #define CS_KEYS 3               /* Waiting to read public key packet */
108         int c_fd;               /* Quick lookup: c->c_fd == c - fdcon */
109         int c_plen;             /* Packet length field for ssh packet */
110         int c_len;              /* Total bytes which must be read. */
111         int c_off;              /* Length of data read so far. */
112         int c_keytype;          /* Only one of KT_* */
113         sig_atomic_t c_done;    /* SSH2 done */
114         char *c_namebase;       /* Address to free for c_name and c_namelist */
115         char *c_name;           /* Hostname of connection for errors */
116         char *c_namelist;       /* Pointer to other possible addresses */
117         char *c_output_name;    /* Hostname of connection for output */
118         char *c_data;           /* Data read from this fd */
119         struct ssh *c_ssh;      /* SSH-connection */
120         struct timespec c_ts;   /* Time at which connection gets aborted */
121         TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
122 } con;
123
124 TAILQ_HEAD(conlist, Connection) tq;     /* Timeout Queue */
125 con *fdcon;
126
127 static void keyprint(con *c, struct sshkey *key);
128
129 static int
130 fdlim_get(int hard)
131 {
132 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
133         struct rlimit rlfd;
134
135         if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
136                 return (-1);
137         if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
138                 return SSH_SYSFDMAX;
139         else
140                 return hard ? rlfd.rlim_max : rlfd.rlim_cur;
141 #else
142         return SSH_SYSFDMAX;
143 #endif
144 }
145
146 static int
147 fdlim_set(int lim)
148 {
149 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
150         struct rlimit rlfd;
151 #endif
152
153         if (lim <= 0)
154                 return (-1);
155 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
156         if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
157                 return (-1);
158         rlfd.rlim_cur = lim;
159         if (setrlimit(RLIMIT_NOFILE, &rlfd) == -1)
160                 return (-1);
161 #elif defined (HAVE_SETDTABLESIZE)
162         setdtablesize(lim);
163 #endif
164         return (0);
165 }
166
167 /*
168  * This is an strsep function that returns a null field for adjacent
169  * separators.  This is the same as the 4.4BSD strsep, but different from the
170  * one in the GNU libc.
171  */
172 static char *
173 xstrsep(char **str, const char *delim)
174 {
175         char *s, *e;
176
177         if (!**str)
178                 return (NULL);
179
180         s = *str;
181         e = s + strcspn(s, delim);
182
183         if (*e != '\0')
184                 *e++ = '\0';
185         *str = e;
186
187         return (s);
188 }
189
190 /*
191  * Get the next non-null token (like GNU strsep).  Strsep() will return a
192  * null token for two adjacent separators, so we may have to loop.
193  */
194 static char *
195 strnnsep(char **stringp, char *delim)
196 {
197         char *tok;
198
199         do {
200                 tok = xstrsep(stringp, delim);
201         } while (tok && *tok == '\0');
202         return (tok);
203 }
204
205
206 static int
207 key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh)
208 {
209         con *c;
210
211         if ((c = ssh_get_app_data(ssh)) != NULL)
212                 keyprint(c, hostkey);
213         /* always abort key exchange */
214         return -1;
215 }
216
217 static int
218 ssh2_capable(int remote_major, int remote_minor)
219 {
220         switch (remote_major) {
221         case 1:
222                 if (remote_minor == 99)
223                         return 1;
224                 break;
225         case 2:
226                 return 1;
227         default:
228                 break;
229         }
230         return 0;
231 }
232
233 static void
234 keygrab_ssh2(con *c)
235 {
236         char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
237         int r;
238
239         switch (c->c_keytype) {
240         case KT_DSA:
241                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
242                     "ssh-dss-cert-v01@openssh.com" : "ssh-dss";
243                 break;
244         case KT_RSA:
245                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
246                     "rsa-sha2-512-cert-v01@openssh.com,"
247                     "rsa-sha2-256-cert-v01@openssh.com,"
248                     "ssh-rsa-cert-v01@openssh.com" :
249                     "rsa-sha2-512,"
250                     "rsa-sha2-256,"
251                     "ssh-rsa";
252                 break;
253         case KT_ED25519:
254                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
255                     "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
256                 break;
257         case KT_XMSS:
258                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
259                     "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com";
260                 break;
261         case KT_ECDSA:
262                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
263                     "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
264                     "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
265                     "ecdsa-sha2-nistp521-cert-v01@openssh.com" :
266                     "ecdsa-sha2-nistp256,"
267                     "ecdsa-sha2-nistp384,"
268                     "ecdsa-sha2-nistp521";
269                 break;
270         case KT_ECDSA_SK:
271                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
272                     "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" :
273                     "sk-ecdsa-sha2-nistp256@openssh.com";
274                 break;
275         case KT_ED25519_SK:
276                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
277                     "sk-ssh-ed25519-cert-v01@openssh.com" :
278                     "sk-ssh-ed25519@openssh.com";
279                 break;
280         default:
281                 fatal("unknown key type %d", c->c_keytype);
282                 break;
283         }
284         if ((r = kex_setup(c->c_ssh, myproposal)) != 0) {
285                 free(c->c_ssh);
286                 fprintf(stderr, "kex_setup: %s\n", ssh_err(r));
287                 exit(1);
288         }
289 #ifdef WITH_OPENSSL
290         c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
291         c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
292         c->c_ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
293         c->c_ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
294         c->c_ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
295         c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
296         c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
297 # ifdef OPENSSL_HAS_ECC
298         c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
299 # endif
300 #endif
301         c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
302         c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
303         ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
304         /*
305          * do the key-exchange until an error occurs or until
306          * the key_print_wrapper() callback sets c_done.
307          */
308         ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done);
309 }
310
311 static void
312 keyprint_one(const char *host, struct sshkey *key)
313 {
314         char *hostport = NULL, *hashed = NULL;
315         const char *known_host;
316
317         found_one = 1;
318
319         if (print_sshfp) {
320                 export_dns_rr(host, key, stdout, 0, hashalg);
321                 return;
322         }
323
324         hostport = put_host_port(host, ssh_port);
325         lowercase(hostport);
326         if (hash_hosts && (hashed = host_hash(hostport, NULL, 0)) == NULL)
327                 fatal("host_hash failed");
328         known_host = hash_hosts ? hashed : hostport;
329         if (!get_cert)
330                 fprintf(stdout, "%s ", known_host);
331         sshkey_write(key, stdout);
332         fputs("\n", stdout);
333         free(hashed);
334         free(hostport);
335 }
336
337 static void
338 keyprint(con *c, struct sshkey *key)
339 {
340         char *hosts = c->c_output_name ? c->c_output_name : c->c_name;
341         char *host, *ohosts;
342
343         if (key == NULL)
344                 return;
345         if (get_cert || (!hash_hosts && ssh_port == SSH_DEFAULT_PORT)) {
346                 keyprint_one(hosts, key);
347                 return;
348         }
349         ohosts = hosts = xstrdup(hosts);
350         while ((host = strsep(&hosts, ",")) != NULL)
351                 keyprint_one(host, key);
352         free(ohosts);
353 }
354
355 static int
356 tcpconnect(char *host)
357 {
358         struct addrinfo hints, *ai, *aitop;
359         char strport[NI_MAXSERV];
360         int gaierr, s = -1;
361
362         snprintf(strport, sizeof strport, "%d", ssh_port);
363         memset(&hints, 0, sizeof(hints));
364         hints.ai_family = IPv4or6;
365         hints.ai_socktype = SOCK_STREAM;
366         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
367                 error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
368                 return -1;
369         }
370         for (ai = aitop; ai; ai = ai->ai_next) {
371                 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
372                 if (s == -1) {
373                         error("socket: %s", strerror(errno));
374                         continue;
375                 }
376                 if (set_nonblock(s) == -1)
377                         fatal_f("set_nonblock(%d)", s);
378                 if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1 &&
379                     errno != EINPROGRESS)
380                         error("connect (`%s'): %s", host, strerror(errno));
381                 else
382                         break;
383                 close(s);
384                 s = -1;
385         }
386         freeaddrinfo(aitop);
387         return s;
388 }
389
390 static int
391 conalloc(const char *iname, const char *oname, int keytype)
392 {
393         char *namebase, *name, *namelist;
394         int s;
395
396         namebase = namelist = xstrdup(iname);
397
398         do {
399                 name = xstrsep(&namelist, ",");
400                 if (!name) {
401                         free(namebase);
402                         return (-1);
403                 }
404         } while ((s = tcpconnect(name)) < 0);
405
406         if (s >= maxfd)
407                 fatal("conalloc: fdno %d too high", s);
408         if (fdcon[s].c_status)
409                 fatal("conalloc: attempt to reuse fdno %d", s);
410
411         debug3_f("oname %s kt %d", oname, keytype);
412         fdcon[s].c_fd = s;
413         fdcon[s].c_status = CS_CON;
414         fdcon[s].c_namebase = namebase;
415         fdcon[s].c_name = name;
416         fdcon[s].c_namelist = namelist;
417         fdcon[s].c_output_name = xstrdup(oname);
418         fdcon[s].c_data = (char *) &fdcon[s].c_plen;
419         fdcon[s].c_len = 4;
420         fdcon[s].c_off = 0;
421         fdcon[s].c_keytype = keytype;
422         monotime_ts(&fdcon[s].c_ts);
423         fdcon[s].c_ts.tv_sec += timeout;
424         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
425         read_wait[s].fd = s;
426         read_wait[s].events = POLLIN;
427         ncon++;
428         return (s);
429 }
430
431 static void
432 confree(int s)
433 {
434         if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
435                 fatal("confree: attempt to free bad fdno %d", s);
436         free(fdcon[s].c_namebase);
437         free(fdcon[s].c_output_name);
438         if (fdcon[s].c_status == CS_KEYS)
439                 free(fdcon[s].c_data);
440         fdcon[s].c_status = CS_UNUSED;
441         fdcon[s].c_keytype = 0;
442         if (fdcon[s].c_ssh) {
443                 ssh_packet_close(fdcon[s].c_ssh);
444                 free(fdcon[s].c_ssh);
445                 fdcon[s].c_ssh = NULL;
446         } else
447                 close(s);
448         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
449         read_wait[s].fd = -1;
450         read_wait[s].events = 0;
451         ncon--;
452 }
453
454 static void
455 contouch(int s)
456 {
457         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
458         monotime_ts(&fdcon[s].c_ts);
459         fdcon[s].c_ts.tv_sec += timeout;
460         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
461 }
462
463 static int
464 conrecycle(int s)
465 {
466         con *c = &fdcon[s];
467         int ret;
468
469         ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
470         confree(s);
471         return (ret);
472 }
473
474 static void
475 congreet(int s)
476 {
477         int n = 0, remote_major = 0, remote_minor = 0;
478         char buf[256], *cp;
479         char remote_version[sizeof buf];
480         size_t bufsiz;
481         con *c = &fdcon[s];
482
483         /* send client banner */
484         n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
485             PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
486         if (n < 0 || (size_t)n >= sizeof(buf)) {
487                 error("snprintf: buffer too small");
488                 confree(s);
489                 return;
490         }
491         if (atomicio(vwrite, s, buf, n) != (size_t)n) {
492                 error("write (%s): %s", c->c_name, strerror(errno));
493                 confree(s);
494                 return;
495         }
496
497         /*
498          * Read the server banner as per RFC4253 section 4.2.  The "SSH-"
499          * protocol identification string may be preceeded by an arbitrarily
500          * large banner which we must read and ignore.  Loop while reading
501          * newline-terminated lines until we have one starting with "SSH-".
502          * The ID string cannot be longer than 255 characters although the
503          * preceeding banner lines may (in which case they'll be discarded
504          * in multiple iterations of the outer loop).
505          */
506         for (;;) {
507                 memset(buf, '\0', sizeof(buf));
508                 bufsiz = sizeof(buf);
509                 cp = buf;
510                 while (bufsiz-- &&
511                     (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
512                         if (*cp == '\r')
513                                 *cp = '\n';
514                         cp++;
515                 }
516                 if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
517                         break;
518         }
519         if (n == 0) {
520                 switch (errno) {
521                 case EPIPE:
522                         error("%s: Connection closed by remote host", c->c_name);
523                         break;
524                 case ECONNREFUSED:
525                         break;
526                 default:
527                         error("read (%s): %s", c->c_name, strerror(errno));
528                         break;
529                 }
530                 conrecycle(s);
531                 return;
532         }
533         if (cp >= buf + sizeof(buf)) {
534                 error("%s: greeting exceeds allowable length", c->c_name);
535                 confree(s);
536                 return;
537         }
538         if (*cp != '\n' && *cp != '\r') {
539                 error("%s: bad greeting", c->c_name);
540                 confree(s);
541                 return;
542         }
543         *cp = '\0';
544         if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL)
545                 fatal("ssh_packet_set_connection failed");
546         ssh_packet_set_timeout(c->c_ssh, timeout, 1);
547         ssh_set_app_data(c->c_ssh, c);  /* back link */
548         c->c_ssh->compat = 0;
549         if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
550             &remote_major, &remote_minor, remote_version) == 3)
551                 compat_banner(c->c_ssh, remote_version);
552         if (!ssh2_capable(remote_major, remote_minor)) {
553                 debug("%s doesn't support ssh2", c->c_name);
554                 confree(s);
555                 return;
556         }
557         fprintf(stderr, "%c %s:%d %s\n", print_sshfp ? ';' : '#',
558             c->c_name, ssh_port, chop(buf));
559         keygrab_ssh2(c);
560         confree(s);
561 }
562
563 static void
564 conread(int s)
565 {
566         con *c = &fdcon[s];
567         size_t n;
568
569         if (c->c_status == CS_CON) {
570                 congreet(s);
571                 return;
572         }
573         n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
574         if (n == 0) {
575                 error("read (%s): %s", c->c_name, strerror(errno));
576                 confree(s);
577                 return;
578         }
579         c->c_off += n;
580
581         if (c->c_off == c->c_len)
582                 switch (c->c_status) {
583                 case CS_SIZE:
584                         c->c_plen = htonl(c->c_plen);
585                         c->c_len = c->c_plen + 8 - (c->c_plen & 7);
586                         c->c_off = 0;
587                         c->c_data = xmalloc(c->c_len);
588                         c->c_status = CS_KEYS;
589                         break;
590                 default:
591                         fatal("conread: invalid status %d", c->c_status);
592                         break;
593                 }
594
595         contouch(s);
596 }
597
598 static void
599 conloop(void)
600 {
601         struct timespec seltime, now;
602         con *c;
603         int i;
604
605         monotime_ts(&now);
606         c = TAILQ_FIRST(&tq);
607
608         if (c && timespeccmp(&c->c_ts, &now, >))
609                 timespecsub(&c->c_ts, &now, &seltime);
610         else
611                 timespecclear(&seltime);
612
613         while (ppoll(read_wait, maxfd, &seltime, NULL) == -1) {
614                 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
615                         continue;
616                 error("poll error");
617         }
618
619         for (i = 0; i < maxfd; i++) {
620                 if (read_wait[i].revents & (POLLHUP|POLLERR|POLLNVAL))
621                         confree(i);
622                 else if (read_wait[i].revents & (POLLIN|POLLHUP))
623                         conread(i);
624         }
625
626         c = TAILQ_FIRST(&tq);
627         while (c && timespeccmp(&c->c_ts, &now, <)) {
628                 int s = c->c_fd;
629
630                 c = TAILQ_NEXT(c, c_link);
631                 conrecycle(s);
632         }
633 }
634
635 static void
636 do_one_host(char *host)
637 {
638         char *name = strnnsep(&host, " \t\n");
639         int j;
640
641         if (name == NULL)
642                 return;
643         for (j = KT_MIN; j <= KT_MAX; j *= 2) {
644                 if (get_keytypes & j) {
645                         while (ncon >= MAXCON)
646                                 conloop();
647                         conalloc(name, *host ? host : name, j);
648                 }
649         }
650 }
651
652 static void
653 do_host(char *host)
654 {
655         char daddr[128];
656         struct xaddr addr, end_addr;
657         u_int masklen;
658
659         if (host == NULL)
660                 return;
661         if (addr_pton_cidr(host, &addr, &masklen) != 0) {
662                 /* Assume argument is a hostname */
663                 do_one_host(host);
664         } else {
665                 /* Argument is a CIDR range */
666                 debug("CIDR range %s", host);
667                 end_addr = addr;
668                 if (addr_host_to_all1s(&end_addr, masklen) != 0)
669                         goto badaddr;
670                 /*
671                  * Note: we deliberately include the all-zero/ones addresses.
672                  */
673                 for (;;) {
674                         if (addr_ntop(&addr, daddr, sizeof(daddr)) != 0) {
675  badaddr:
676                                 error("Invalid address %s", host);
677                                 return;
678                         }
679                         debug("CIDR expand: address %s", daddr);
680                         do_one_host(daddr);
681                         if (addr_cmp(&addr, &end_addr) == 0)
682                                 break;
683                         addr_increment(&addr);
684                 };
685         }
686 }
687
688 void
689 sshfatal(const char *file, const char *func, int line, int showfunc,
690     LogLevel level, const char *suffix, const char *fmt, ...)
691 {
692         va_list args;
693
694         va_start(args, fmt);
695         sshlogv(file, func, line, showfunc, level, suffix, fmt, args);
696         va_end(args);
697         cleanup_exit(255);
698 }
699
700 static void
701 usage(void)
702 {
703         fprintf(stderr,
704             "usage: ssh-keyscan [-46cDHv] [-f file] [-O option] [-p port] [-T timeout]\n"
705             "                   [-t type] [host | addrlist namelist]\n");
706         exit(1);
707 }
708
709 int
710 main(int argc, char **argv)
711 {
712         int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
713         int opt, fopt_count = 0, j;
714         char *tname, *cp, *line = NULL;
715         size_t linesize = 0;
716         FILE *fp;
717
718         extern int optind;
719         extern char *optarg;
720
721         __progname = ssh_get_progname(argv[0]);
722         seed_rng();
723         TAILQ_INIT(&tq);
724
725         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
726         sanitise_stdfd();
727
728         if (argc <= 1)
729                 usage();
730
731         while ((opt = getopt(argc, argv, "cDHv46O:p:T:t:f:")) != -1) {
732                 switch (opt) {
733                 case 'H':
734                         hash_hosts = 1;
735                         break;
736                 case 'c':
737                         get_cert = 1;
738                         break;
739                 case 'D':
740                         print_sshfp = 1;
741                         break;
742                 case 'p':
743                         ssh_port = a2port(optarg);
744                         if (ssh_port <= 0) {
745                                 fprintf(stderr, "Bad port '%s'\n", optarg);
746                                 exit(1);
747                         }
748                         break;
749                 case 'T':
750                         timeout = convtime(optarg);
751                         if (timeout == -1 || timeout == 0) {
752                                 fprintf(stderr, "Bad timeout '%s'\n", optarg);
753                                 usage();
754                         }
755                         break;
756                 case 'v':
757                         if (!debug_flag) {
758                                 debug_flag = 1;
759                                 log_level = SYSLOG_LEVEL_DEBUG1;
760                         }
761                         else if (log_level < SYSLOG_LEVEL_DEBUG3)
762                                 log_level++;
763                         else
764                                 fatal("Too high debugging level.");
765                         break;
766                 case 'f':
767                         if (strcmp(optarg, "-") == 0)
768                                 optarg = NULL;
769                         argv[fopt_count++] = optarg;
770                         break;
771                 case 'O':
772                         /* Maybe other misc options in the future too */
773                         if (strncmp(optarg, "hashalg=", 8) != 0)
774                                 fatal("Unsupported -O option");
775                         if ((hashalg = ssh_digest_alg_by_name(
776                             optarg + 8)) == -1)
777                                 fatal("Unsupported hash algorithm");
778                         break;
779                 case 't':
780                         get_keytypes = 0;
781                         tname = strtok(optarg, ",");
782                         while (tname) {
783                                 int type = sshkey_type_from_name(tname);
784
785                                 switch (type) {
786                                 case KEY_DSA:
787                                         get_keytypes |= KT_DSA;
788                                         break;
789                                 case KEY_ECDSA:
790                                         get_keytypes |= KT_ECDSA;
791                                         break;
792                                 case KEY_RSA:
793                                         get_keytypes |= KT_RSA;
794                                         break;
795                                 case KEY_ED25519:
796                                         get_keytypes |= KT_ED25519;
797                                         break;
798                                 case KEY_XMSS:
799                                         get_keytypes |= KT_XMSS;
800                                         break;
801                                 case KEY_ED25519_SK:
802                                         get_keytypes |= KT_ED25519_SK;
803                                         break;
804                                 case KEY_ECDSA_SK:
805                                         get_keytypes |= KT_ECDSA_SK;
806                                         break;
807                                 case KEY_UNSPEC:
808                                 default:
809                                         fatal("Unknown key type \"%s\"", tname);
810                                 }
811                                 tname = strtok(NULL, ",");
812                         }
813                         break;
814                 case '4':
815                         IPv4or6 = AF_INET;
816                         break;
817                 case '6':
818                         IPv4or6 = AF_INET6;
819                         break;
820                 default:
821                         usage();
822                 }
823         }
824         if (optind == argc && !fopt_count)
825                 usage();
826
827         log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
828
829         maxfd = fdlim_get(1);
830         if (maxfd < 0)
831                 fatal("%s: fdlim_get: bad value", __progname);
832         if (maxfd > MAXMAXFD)
833                 maxfd = MAXMAXFD;
834         if (MAXCON <= 0)
835                 fatal("%s: not enough file descriptors", __progname);
836         if (maxfd > fdlim_get(0))
837                 fdlim_set(maxfd);
838         fdcon = xcalloc(maxfd, sizeof(con));
839         read_wait = xcalloc(maxfd, sizeof(struct pollfd));
840         for (j = 0; j < maxfd; j++)
841                 read_wait[j].fd = -1;
842
843         for (j = 0; j < fopt_count; j++) {
844                 if (argv[j] == NULL)
845                         fp = stdin;
846                 else if ((fp = fopen(argv[j], "r")) == NULL)
847                         fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
848
849                 while (getline(&line, &linesize, fp) != -1) {
850                         /* Chomp off trailing whitespace and comments */
851                         if ((cp = strchr(line, '#')) == NULL)
852                                 cp = line + strlen(line) - 1;
853                         while (cp >= line) {
854                                 if (*cp == ' ' || *cp == '\t' ||
855                                     *cp == '\n' || *cp == '#')
856                                         *cp-- = '\0';
857                                 else
858                                         break;
859                         }
860
861                         /* Skip empty lines */
862                         if (*line == '\0')
863                                 continue;
864
865                         do_host(line);
866                 }
867
868                 if (ferror(fp))
869                         fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
870
871                 fclose(fp);
872         }
873         free(line);
874
875         while (optind < argc)
876                 do_host(argv[optind++]);
877
878         while (ncon > 0)
879                 conloop();
880
881         return found_one ? 0 : 1;
882 }