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