source: trunk/third/openssh/ssh-keyscan.c @ 18759

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