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