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