[BACK]Return to main.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ftp

Annotation of src/usr.bin/ftp/main.c, Revision 1.129

1.129   ! florian     1: /*     $OpenBSD: main.c,v 1.120 2018/02/10 06:25:16 jsing Exp $        */
        !             2: /*     $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $  */
1.122     jasper      3:
1.1       deraadt     4: /*
1.129   ! florian     5:  * Copyright (C) 1997 and 1998 WIDE Project.
        !             6:  * All rights reserved.
1.118     krw         7:  *
1.129   ! florian     8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the project nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
1.118     krw        19:  *
1.129   ! florian    20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
1.44      itojun     31:  */
                     32:
1.129   ! florian    33: /*
        !            34:  * Copyright (c) 1985, 1989, 1993, 1994
        !            35:  *     The Regents of the University of California.  All rights reserved.
        !            36:  *
        !            37:  * Redistribution and use in source and binary forms, with or without
        !            38:  * modification, are permitted provided that the following conditions
        !            39:  * are met:
        !            40:  * 1. Redistributions of source code must retain the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer.
        !            42:  * 2. Redistributions in binary form must reproduce the above copyright
        !            43:  *    notice, this list of conditions and the following disclaimer in the
        !            44:  *    documentation and/or other materials provided with the distribution.
        !            45:  * 3. Neither the name of the University nor the names of its contributors
        !            46:  *    may be used to endorse or promote products derived from this software
        !            47:  *    without specific prior written permission.
        !            48:  *
        !            49:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            52:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            53:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            59:  * SUCH DAMAGE.
        !            60:  */
        !            61:
        !            62: /*
        !            63:  * FTP User Program -- Command Interface.
        !            64:  */
1.1       deraadt    65: #include <sys/types.h>
                     66: #include <sys/socket.h>
                     67:
1.129   ! florian    68: #include <ctype.h>
1.1       deraadt    69: #include <err.h>
1.120     jsing      70: #include <fcntl.h>
1.129   ! florian    71: #include <netdb.h>
        !            72: #include <pwd.h>
1.1       deraadt    73: #include <stdio.h>
1.129   ! florian    74: #include <errno.h>
1.18      millert    75: #include <stdlib.h>
1.1       deraadt    76: #include <string.h>
                     77: #include <unistd.h>
                     78:
1.129   ! florian    79: #include <tls.h>
1.91      jsing      80:
1.129   ! florian    81: #include "cmds.h"
        !            82: #include "ftp_var.h"
        !            83:
        !            84: int connect_timeout;
        !            85:
        !            86: #ifndef NOSSL
        !            87: char * const ssl_verify_opts[] = {
        !            88: #define SSL_CAFILE             0
        !            89:        "cafile",
        !            90: #define SSL_CAPATH             1
        !            91:        "capath",
        !            92: #define SSL_CIPHERS            2
        !            93:        "ciphers",
        !            94: #define SSL_DONTVERIFY         3
        !            95:        "dont",
        !            96: #define SSL_DOVERIFY           4
        !            97:        "do",
        !            98: #define SSL_VERIFYDEPTH                5
        !            99:        "depth",
        !           100: #define SSL_MUSTSTAPLE         6
        !           101:        "muststaple",
        !           102: #define SSL_NOVERIFYTIME       7
        !           103:        "noverifytime",
        !           104: #define SSL_SESSION            8
        !           105:        "session",
        !           106:        NULL
        !           107: };
        !           108:
        !           109: struct tls_config *tls_config;
        !           110: int tls_session_fd = -1;
        !           111:
        !           112: static void
        !           113: process_ssl_options(char *cp)
        !           114: {
        !           115:        const char *errstr;
        !           116:        long long depth;
        !           117:        char *str;
        !           118:
        !           119:        while (*cp) {
        !           120:                switch (getsubopt(&cp, ssl_verify_opts, &str)) {
        !           121:                case SSL_CAFILE:
        !           122:                        if (str == NULL)
        !           123:                                errx(1, "missing CA file");
        !           124:                        if (tls_config_set_ca_file(tls_config, str) != 0)
        !           125:                                errx(1, "tls ca file failed: %s",
        !           126:                                    tls_config_error(tls_config));
        !           127:                        break;
        !           128:                case SSL_CAPATH:
        !           129:                        if (str == NULL)
        !           130:                                errx(1, "missing CA directory path");
        !           131:                        if (tls_config_set_ca_path(tls_config, str) != 0)
        !           132:                                errx(1, "tls ca path failed: %s",
        !           133:                                    tls_config_error(tls_config));
        !           134:                        break;
        !           135:                case SSL_CIPHERS:
        !           136:                        if (str == NULL)
        !           137:                                errx(1, "missing cipher list");
        !           138:                        if (tls_config_set_ciphers(tls_config, str) != 0)
        !           139:                                errx(1, "tls ciphers failed: %s",
        !           140:                                    tls_config_error(tls_config));
        !           141:                        break;
        !           142:                case SSL_DONTVERIFY:
        !           143:                        tls_config_insecure_noverifycert(tls_config);
        !           144:                        tls_config_insecure_noverifyname(tls_config);
        !           145:                        break;
        !           146:                case SSL_DOVERIFY:
        !           147:                        tls_config_verify(tls_config);
        !           148:                        break;
        !           149:                case SSL_VERIFYDEPTH:
        !           150:                        if (str == NULL)
        !           151:                                errx(1, "missing depth");
        !           152:                        depth = strtonum(str, 0, INT_MAX, &errstr);
        !           153:                        if (errstr)
        !           154:                                errx(1, "certificate validation depth is %s",
        !           155:                                    errstr);
        !           156:                        tls_config_set_verify_depth(tls_config, (int)depth);
        !           157:                        break;
        !           158:                case SSL_MUSTSTAPLE:
        !           159:                        tls_config_ocsp_require_stapling(tls_config);
        !           160:                        break;
        !           161:                case SSL_NOVERIFYTIME:
        !           162:                        tls_config_insecure_noverifytime(tls_config);
        !           163:                        break;
        !           164:                case SSL_SESSION:
        !           165:                        if (str == NULL)
        !           166:                                errx(1, "missing session file");
        !           167:                        if ((tls_session_fd = open(str, O_RDWR|O_CREAT,
        !           168:                            0600)) == -1)
        !           169:                                err(1, "failed to open or create session file "
        !           170:                                    "'%s'", str);
        !           171:                        if (tls_config_set_session_fd(tls_config,
        !           172:                            tls_session_fd) == -1)
        !           173:                                errx(1, "failed to set session: %s",
        !           174:                                    tls_config_error(tls_config));
        !           175:                        break;
        !           176:                default:
        !           177:                        errx(1, "unknown -S suboption `%s'",
        !           178:                            suboptarg ? suboptarg : "");
        !           179:                        /* NOTREACHED */
        !           180:                }
        !           181:        }
        !           182: }
        !           183: #endif /* !NOSSL */
        !           184:
        !           185: int family = PF_UNSPEC;
        !           186: int pipeout;
1.49      deraadt   187:
1.1       deraadt   188: int
1.129   ! florian   189: main(volatile int argc, char *argv[])
1.1       deraadt   190: {
1.129   ! florian   191:        int ch, rval;
        !           192: #ifndef SMALL
        !           193:        int top;
        !           194: #endif
        !           195:        struct passwd *pw = NULL;
        !           196:        char *cp, homedir[PATH_MAX];
        !           197:        char *outfile = NULL;
        !           198:        const char *errstr;
        !           199:        int dumb_terminal = 0;
        !           200:
        !           201:        ftpport = "ftp";
        !           202:        httpport = "http";
        !           203: #ifndef NOSSL
        !           204:        httpsport = "https";
        !           205: #endif /* !NOSSL */
        !           206:        gateport = getenv("FTPSERVERPORT");
        !           207:        if (gateport == NULL || *gateport == '\0')
        !           208:                gateport = "ftpgate";
        !           209:        doglob = 1;
        !           210:        interactive = 1;
        !           211:        autologin = 1;
        !           212:        passivemode = 1;
        !           213:        activefallback = 1;
        !           214:        preserve = 1;
        !           215:        verbose = 0;
        !           216:        progress = 0;
        !           217:        gatemode = 0;
        !           218: #ifndef NOSSL
        !           219:        cookiefile = NULL;
        !           220: #endif /* NOSSL */
        !           221: #ifndef SMALL
        !           222:        editing = 0;
        !           223:        el = NULL;
        !           224:        hist = NULL;
        !           225:        resume = 0;
        !           226:        srcaddr = NULL;
        !           227:        marg_sl = sl_init();
        !           228: #endif /* !SMALL */
        !           229:        mark = HASHBYTES;
        !           230:        epsv4 = 1;
        !           231:        epsv4bad = 0;
        !           232:
        !           233:        /* Set default operation mode based on FTPMODE environment variable */
        !           234:        if ((cp = getenv("FTPMODE")) != NULL && *cp != '\0') {
        !           235:                if (strcmp(cp, "passive") == 0) {
        !           236:                        passivemode = 1;
        !           237:                        activefallback = 0;
        !           238:                } else if (strcmp(cp, "active") == 0) {
        !           239:                        passivemode = 0;
        !           240:                        activefallback = 0;
        !           241:                } else if (strcmp(cp, "gate") == 0) {
        !           242:                        gatemode = 1;
        !           243:                } else if (strcmp(cp, "auto") == 0) {
        !           244:                        passivemode = 1;
        !           245:                        activefallback = 1;
        !           246:                } else
        !           247:                        warnx("unknown FTPMODE: %s.  Using defaults", cp);
        !           248:        }
        !           249:
        !           250:        if (strcmp(__progname, "gate-ftp") == 0)
        !           251:                gatemode = 1;
        !           252:        gateserver = getenv("FTPSERVER");
        !           253:        if (gateserver == NULL)
        !           254:                gateserver = "";
        !           255:        if (gatemode) {
        !           256:                if (*gateserver == '\0') {
        !           257:                        warnx(
        !           258: "Neither $FTPSERVER nor $GATE_SERVER is defined; disabling gate-ftp");
        !           259:                        gatemode = 0;
        !           260:                }
        !           261:        }
        !           262:
        !           263:        cp = getenv("TERM");
        !           264:        dumb_terminal = (cp == NULL || *cp == '\0' || !strcmp(cp, "dumb") ||
        !           265:            !strcmp(cp, "emacs") || !strcmp(cp, "su"));
        !           266:        fromatty = isatty(fileno(stdin));
        !           267:        if (fromatty) {
        !           268:                verbose = 1;            /* verbose if from a tty */
        !           269: #ifndef SMALL
        !           270:                if (!dumb_terminal)
        !           271:                        editing = 1;    /* editing mode on if tty is usable */
        !           272: #endif /* !SMALL */
        !           273:        }
        !           274:
        !           275:        ttyout = stdout;
        !           276:        if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc())
        !           277:                progress = 1;           /* progress bar on if tty is usable */
        !           278:
        !           279: #ifndef NOSSL
        !           280:        cookiefile = getenv("http_cookies");
        !           281:        if (tls_init() != 0)
        !           282:                errx(1, "tls init failed");
        !           283:        if (tls_config == NULL) {
        !           284:                tls_config = tls_config_new();
        !           285:                if (tls_config == NULL)
        !           286:                        errx(1, "tls config failed");
        !           287:                if (tls_config_set_protocols(tls_config,
        !           288:                    TLS_PROTOCOLS_ALL) != 0)
        !           289:                        errx(1, "tls set protocols failed: %s",
        !           290:                            tls_config_error(tls_config));
        !           291:                if (tls_config_set_ciphers(tls_config, "legacy") != 0)
        !           292:                        errx(1, "tls set ciphers failed: %s",
        !           293:                            tls_config_error(tls_config));
        !           294:        }
        !           295: #endif /* !NOSSL */
        !           296:
        !           297:        httpuseragent = NULL;
        !           298:
1.86      jca       299:        while ((ch = getopt(argc, argv,
1.129   ! florian   300:                    "46AaCc:dD:Eegik:Mmno:pP:r:S:s:tU:vVw:")) != -1) {
1.1       deraadt   301:                switch (ch) {
1.49      deraadt   302:                case '4':
1.129   ! florian   303:                        family = PF_INET;
1.49      deraadt   304:                        break;
                    305:                case '6':
1.129   ! florian   306:                        family = PF_INET6;
1.49      deraadt   307:                        break;
1.37      millert   308:                case 'A':
1.129   ! florian   309:                        activefallback = 0;
        !           310:                        passivemode = 0;
        !           311:                        break;
        !           312:
        !           313:                case 'a':
        !           314:                        anonftp = 1;
1.37      millert   315:                        break;
1.129   ! florian   316:
1.67      martynas  317:                case 'C':
1.129   ! florian   318: #ifndef SMALL
1.67      martynas  319:                        resume = 1;
1.129   ! florian   320: #endif /* !SMALL */
1.63      pyr       321:                        break;
1.129   ! florian   322:
        !           323:                case 'c':
        !           324: #ifndef SMALL
        !           325:                        cookiefile = optarg;
        !           326: #endif /* !SMALL */
        !           327:                        break;
        !           328:
1.87      deraadt   329:                case 'D':
1.129   ! florian   330:                        action = optarg;
        !           331:                        break;
        !           332:                case 'd':
        !           333: #ifndef SMALL
        !           334:                        options |= SO_DEBUG;
        !           335:                        debug++;
        !           336: #endif /* !SMALL */
        !           337:                        break;
        !           338:
        !           339:                case 'E':
        !           340:                        epsv4 = 0;
        !           341:                        break;
        !           342:
        !           343:                case 'e':
        !           344: #ifndef SMALL
        !           345:                        editing = 0;
        !           346: #endif /* !SMALL */
        !           347:                        break;
        !           348:
        !           349:                case 'g':
        !           350:                        doglob = 0;
        !           351:                        break;
        !           352:
        !           353:                case 'i':
        !           354:                        interactive = 0;
1.87      deraadt   355:                        break;
1.129   ! florian   356:
        !           357:                case 'k':
        !           358:                        keep_alive_timeout = strtonum(optarg, 0, INT_MAX,
        !           359:                            &errstr);
        !           360:                        if (errstr != NULL) {
        !           361:                                warnx("keep alive amount is %s: %s", errstr,
        !           362:                                        optarg);
        !           363:                                usage();
        !           364:                        }
1.1       deraadt   365:                        break;
1.121     kmos      366:                case 'M':
1.129   ! florian   367:                        progress = 0;
1.59      fgsch     368:                        break;
1.121     kmos      369:                case 'm':
1.129   ! florian   370:                        progress = -1;
1.21      kstailey  371:                        break;
1.129   ! florian   372:
        !           373:                case 'n':
        !           374:                        autologin = 0;
        !           375:                        break;
        !           376:
        !           377:                case 'o':
        !           378:                        outfile = optarg;
        !           379:                        if (*outfile == '\0') {
        !           380:                                pipeout = 0;
        !           381:                                outfile = NULL;
        !           382:                                ttyout = stdout;
        !           383:                        } else {
        !           384:                                pipeout = strcmp(outfile, "-") == 0;
        !           385:                                ttyout = pipeout ? stderr : stdout;
        !           386:                        }
        !           387:                        break;
        !           388:
        !           389:                case 'p':
        !           390:                        passivemode = 1;
        !           391:                        activefallback = 0;
        !           392:                        break;
        !           393:
        !           394:                case 'P':
        !           395:                        ftpport = optarg;
        !           396:                        break;
        !           397:
        !           398:                case 'r':
        !           399:                        retry_connect = strtonum(optarg, 0, INT_MAX, &errstr);
        !           400:                        if (errstr != NULL) {
        !           401:                                warnx("retry amount is %s: %s", errstr,
        !           402:                                        optarg);
        !           403:                                usage();
        !           404:                        }
        !           405:                        break;
        !           406:
1.121     kmos      407:                case 'S':
1.129   ! florian   408: #ifndef NOSSL
        !           409:                        process_ssl_options(optarg);
        !           410: #endif /* !NOSSL */
        !           411:                        break;
        !           412:
        !           413:                case 's':
        !           414: #ifndef SMALL
        !           415:                        srcaddr = optarg;
        !           416: #endif /* !SMALL */
        !           417:                        break;
        !           418:
        !           419:                case 't':
        !           420:                        trace = 1;
1.1       deraadt   421:                        break;
1.129   ! florian   422:
        !           423: #ifndef SMALL
1.121     kmos      424:                case 'U':
1.129   ! florian   425:                        free (httpuseragent);
        !           426:                        if (strcspn(optarg, "\r\n") != strlen(optarg))
        !           427:                                errx(1, "Invalid User-Agent: %s.", optarg);
        !           428:                        if (asprintf(&httpuseragent, "User-Agent: %s",
        !           429:                            optarg) == -1)
        !           430:                                errx(1, "Can't allocate memory for HTTP(S) "
        !           431:                                    "User-Agent");
        !           432:                        break;
        !           433: #endif /* !SMALL */
        !           434:
        !           435:                case 'v':
        !           436:                        verbose = 1;
1.41      millert   437:                        break;
1.129   ! florian   438:
1.121     kmos      439:                case 'V':
                    440:                        verbose = 0;
1.65      espie     441:                        break;
1.129   ! florian   442:
1.121     kmos      443:                case 'w':
1.129   ! florian   444:                        connect_timeout = strtonum(optarg, 0, 200, &errstr);
        !           445:                        if (errstr)
        !           446:                                errx(1, "-w: %s", errstr);
1.116     deraadt   447:                        break;
1.1       deraadt   448:                default:
1.17      millert   449:                        usage();
1.1       deraadt   450:                }
                    451:        }
                    452:        argc -= optind;
                    453:        argv += optind;
1.63      pyr       454:
1.129   ! florian   455: #ifndef NOSSL
        !           456:        cookie_load();
        !           457: #endif /* !NOSSL */
        !           458:        if (httpuseragent == NULL)
        !           459:                httpuseragent = HTTP_USER_AGENT;
        !           460:
        !           461:        cpend = 0;      /* no pending replies */
        !           462:        proxy = 0;      /* proxy not active */
        !           463:        crflag = 1;     /* strip c.r. on ascii gets */
        !           464:        sendport = -1;  /* not using ports */
        !           465:        /*
        !           466:         * Set up the home directory in case we're globbing.
        !           467:         */
        !           468:        cp = getlogin();
        !           469:        if (cp != NULL) {
        !           470:                pw = getpwnam(cp);
        !           471:        }
        !           472:        if (pw == NULL)
        !           473:                pw = getpwuid(getuid());
        !           474:        if (pw != NULL) {
        !           475:                (void)strlcpy(homedir, pw->pw_dir, sizeof homedir);
        !           476:                home = homedir;
        !           477:        }
        !           478:
        !           479:        setttywidth(0);
        !           480:        (void)signal(SIGWINCH, setttywidth);
1.9       michaels  481:
1.129   ! florian   482:        if (argc > 0) {
        !           483:                if (isurl(argv[0])) {
        !           484:                        if (pipeout) {
        !           485: #ifndef SMALL
        !           486:                                if (pledge("stdio rpath dns tty inet proc exec fattr",
        !           487:                                    NULL) == -1)
        !           488:                                        err(1, "pledge");
        !           489: #else
        !           490:                                if (pledge("stdio rpath dns tty inet fattr",
        !           491:                                    NULL) == -1)
        !           492:                                        err(1, "pledge");
        !           493: #endif
        !           494:                        } else {
1.103     doug      495: #ifndef SMALL
1.129   ! florian   496:                                if (pledge("stdio rpath wpath cpath dns tty inet proc exec fattr",
        !           497:                                    NULL) == -1)
        !           498:                                        err(1, "pledge");
        !           499: #else
        !           500:                                if (pledge("stdio rpath wpath cpath dns tty inet fattr",
        !           501:                                    NULL) == -1)
        !           502:                                        err(1, "pledge");
        !           503: #endif
        !           504:                        }
1.103     doug      505:
1.129   ! florian   506:                        rval = auto_fetch(argc, argv, outfile);
        !           507:                        if (rval >= 0)          /* -1 == connected and cd-ed */
        !           508:                                exit(rval);
        !           509:                } else {
        !           510: #ifndef SMALL
        !           511:                        char *xargv[5];
1.3       deraadt   512:
1.129   ! florian   513:                        if (setjmp(toplevel))
        !           514:                                exit(0);
        !           515:                        (void)signal(SIGINT, (sig_t)intr);
        !           516:                        (void)signal(SIGPIPE, (sig_t)lostpeer);
        !           517:                        xargv[0] = __progname;
        !           518:                        xargv[1] = argv[0];
        !           519:                        xargv[2] = argv[1];
        !           520:                        xargv[3] = argv[2];
        !           521:                        xargv[4] = NULL;
        !           522:                        do {
        !           523:                                setpeer(argc+1, xargv);
        !           524:                                if (!retry_connect)
        !           525:                                        break;
        !           526:                                if (!connected) {
        !           527:                                        macnum = 0;
        !           528:                                        fputs("Retrying...\n", ttyout);
        !           529:                                        sleep(retry_connect);
        !           530:                                }
        !           531:                        } while (!connected);
        !           532:                        retry_connect = 0; /* connected, stop hiding msgs */
        !           533: #endif /* !SMALL */
1.3       deraadt   534:                }
1.1       deraadt   535:        }
1.129   ! florian   536: #ifndef SMALL
        !           537:        controlediting();
        !           538:        top = setjmp(toplevel) == 0;
        !           539:        if (top) {
        !           540:                (void)signal(SIGINT, (sig_t)intr);
        !           541:                (void)signal(SIGPIPE, (sig_t)lostpeer);
        !           542:        }
        !           543:        for (;;) {
        !           544:                cmdscanner(top);
        !           545:                top = 1;
        !           546:        }
        !           547: #else /* !SMALL */
        !           548:        usage();
        !           549: #endif /* !SMALL */
        !           550: }
        !           551:
        !           552: void
        !           553: intr(void)
        !           554: {
        !           555:        int save_errno = errno;
        !           556:
        !           557:        write(fileno(ttyout), "\n\r", 2);
        !           558:        alarmtimer(0);
1.121     kmos      559:
1.129   ! florian   560:        errno = save_errno;
        !           561:        longjmp(toplevel, 1);
1.1       deraadt   562: }
                    563:
1.129   ! florian   564: void
        !           565: lostpeer(void)
1.1       deraadt   566: {
1.129   ! florian   567:        int save_errno = errno;
1.121     kmos      568:
1.129   ! florian   569:        alarmtimer(0);
        !           570:        if (connected) {
        !           571:                if (cout != NULL) {
        !           572:                        (void)shutdown(fileno(cout), SHUT_RDWR);
        !           573:                        (void)fclose(cout);
        !           574:                        cout = NULL;
        !           575:                }
        !           576:                if (data >= 0) {
        !           577:                        (void)shutdown(data, SHUT_RDWR);
        !           578:                        (void)close(data);
        !           579:                        data = -1;
        !           580:                }
        !           581:                connected = 0;
        !           582:        }
        !           583:        pswitch(1);
        !           584:        if (connected) {
        !           585:                if (cout != NULL) {
        !           586:                        (void)shutdown(fileno(cout), SHUT_RDWR);
        !           587:                        (void)fclose(cout);
        !           588:                        cout = NULL;
        !           589:                }
        !           590:                connected = 0;
1.121     kmos      591:        }
1.129   ! florian   592:        proxflag = 0;
        !           593:        pswitch(0);
        !           594:        errno = save_errno;
        !           595: }
1.90      deraadt   596:
1.129   ! florian   597: #ifndef SMALL
        !           598: /*
        !           599:  * Generate a prompt
        !           600:  */
        !           601: char *
        !           602: prompt(void)
        !           603: {
        !           604:        return ("ftp> ");
1.1       deraadt   605: }
                    606:
1.129   ! florian   607: /*
        !           608:  * Command parser.
        !           609:  */
        !           610: void
        !           611: cmdscanner(int top)
1.1       deraadt   612: {
1.129   ! florian   613:        struct cmd *c;
        !           614:        int num;
        !           615:        HistEvent hev;
1.1       deraadt   616:
1.129   ! florian   617:        if (!top && !editing)
        !           618:                (void)putc('\n', ttyout);
        !           619:        for (;;) {
        !           620:                if (!editing) {
        !           621:                        if (fromatty) {
        !           622:                                fputs(prompt(), ttyout);
        !           623:                                (void)fflush(ttyout);
        !           624:                        }
        !           625:                        if (fgets(line, sizeof(line), stdin) == NULL)
        !           626:                                quit(0, 0);
        !           627:                        num = strlen(line);
        !           628:                        if (num == 0)
        !           629:                                break;
        !           630:                        if (line[--num] == '\n') {
        !           631:                                if (num == 0)
        !           632:                                        break;
        !           633:                                line[num] = '\0';
        !           634:                        } else if (num == sizeof(line) - 2) {
        !           635:                                fputs("sorry, input line too long.\n", ttyout);
        !           636:                                while ((num = getchar()) != '\n' && num != EOF)
        !           637:                                        /* void */;
        !           638:                                break;
        !           639:                        } /* else it was a line without a newline */
        !           640:                } else {
        !           641:                        const char *buf;
        !           642:                        cursor_pos = NULL;
        !           643:
        !           644:                        if ((buf = el_gets(el, &num)) == NULL || num == 0) {
        !           645:                                putc('\n', ttyout);
        !           646:                                fflush(ttyout);
        !           647:                                quit(0, 0);
        !           648:                        }
        !           649:                        if (buf[--num] == '\n') {
        !           650:                                if (num == 0)
        !           651:                                        break;
        !           652:                        }
        !           653:                        if (num >= sizeof(line)) {
        !           654:                                fputs("sorry, input line too long.\n", ttyout);
        !           655:                                break;
        !           656:                        }
        !           657:                        memcpy(line, buf, (size_t)num);
        !           658:                        line[num] = '\0';
        !           659:                        history(hist, &hev, H_ENTER, buf);
        !           660:                }
        !           661:
        !           662:                makeargv();
        !           663:                if (margc == 0)
        !           664:                        continue;
        !           665:                c = getcmd(margv[0]);
        !           666:                if (c == (struct cmd *)-1) {
        !           667:                        fputs("?Ambiguous command.\n", ttyout);
        !           668:                        continue;
        !           669:                }
        !           670:                if (c == 0) {
        !           671:                        /*
        !           672:                         * Give editline(3) a shot at unknown commands.
        !           673:                         * XXX - bogus commands with a colon in
        !           674:                         *       them will not elicit an error.
        !           675:                         */
        !           676:                        if (editing &&
        !           677:                            el_parse(el, margc, (const char **)margv) != 0)
        !           678:                                fputs("?Invalid command.\n", ttyout);
        !           679:                        continue;
        !           680:                }
        !           681:                if (c->c_conn && !connected) {
        !           682:                        fputs("Not connected.\n", ttyout);
        !           683:                        continue;
        !           684:                }
        !           685:                confirmrest = 0;
        !           686:                (*c->c_handler)(margc, margv);
        !           687:                if (bell && c->c_bell)
        !           688:                        (void)putc('\007', ttyout);
        !           689:                if (c->c_handler != help)
        !           690:                        break;
        !           691:        }
        !           692:        (void)signal(SIGINT, (sig_t)intr);
        !           693:        (void)signal(SIGPIPE, (sig_t)lostpeer);
        !           694: }
1.1       deraadt   695:
1.129   ! florian   696: struct cmd *
        !           697: getcmd(const char *name)
        !           698: {
        !           699:        const char *p, *q;
        !           700:        struct cmd *c, *found;
        !           701:        int nmatches, longest;
        !           702:
        !           703:        if (name == NULL)
        !           704:                return (0);
        !           705:
        !           706:        longest = 0;
        !           707:        nmatches = 0;
        !           708:        found = 0;
        !           709:        for (c = cmdtab; (p = c->c_name) != NULL; c++) {
        !           710:                for (q = name; *q == *p++; q++)
        !           711:                        if (*q == 0)            /* exact match? */
        !           712:                                return (c);
        !           713:                if (!*q) {                      /* the name was a prefix */
        !           714:                        if (q - name > longest) {
        !           715:                                longest = q - name;
        !           716:                                nmatches = 1;
        !           717:                                found = c;
        !           718:                        } else if (q - name == longest)
        !           719:                                nmatches++;
        !           720:                }
        !           721:        }
        !           722:        if (nmatches > 1)
        !           723:                return ((struct cmd *)-1);
        !           724:        return (found);
1.1       deraadt   725: }
                    726:
1.129   ! florian   727: /*
        !           728:  * Slice a string up into argc/argv.
        !           729:  */
        !           730:
        !           731: int slrflag;
        !           732:
        !           733: void
        !           734: makeargv(void)
1.1       deraadt   735: {
1.129   ! florian   736:        char *argp;
1.1       deraadt   737:
1.129   ! florian   738:        stringbase = line;              /* scan from first of buffer */
        !           739:        argbase = argbuf;               /* store from first of buffer */
        !           740:        slrflag = 0;
        !           741:        marg_sl->sl_cur = 0;            /* reset to start of marg_sl */
        !           742:        for (margc = 0; ; margc++) {
        !           743:                argp = slurpstring();
        !           744:                sl_add(marg_sl, argp);
        !           745:                if (argp == NULL)
1.121     kmos      746:                        break;
1.129   ! florian   747:        }
        !           748:        if (cursor_pos == line) {
        !           749:                cursor_argc = 0;
        !           750:                cursor_argo = 0;
        !           751:        } else if (cursor_pos != NULL) {
        !           752:                cursor_argc = margc;
        !           753:                cursor_argo = strlen(margv[margc-1]);
        !           754:        }
        !           755: }
1.121     kmos      756:
1.129   ! florian   757: #define INC_CHKCURSOR(x)       { (x)++ ; \
        !           758:                                if (x == cursor_pos) { \
        !           759:                                        cursor_argc = margc; \
        !           760:                                        cursor_argo = ap-argbase; \
        !           761:                                        cursor_pos = NULL; \
        !           762:                                } }
1.121     kmos      763:
1.129   ! florian   764: /*
        !           765:  * Parse string into argbuf;
        !           766:  * implemented with FSM to
        !           767:  * handle quoting and strings
        !           768:  */
        !           769: char *
        !           770: slurpstring(void)
        !           771: {
        !           772:        int got_one = 0;
        !           773:        char *sb = stringbase;
        !           774:        char *ap = argbase;
        !           775:        char *tmp = argbase;            /* will return this if token found */
        !           776:
        !           777:        if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
        !           778:                switch (slrflag) {      /* and $ as token for macro invoke */
        !           779:                        case 0:
        !           780:                                slrflag++;
        !           781:                                INC_CHKCURSOR(stringbase);
        !           782:                                return ((*sb == '!') ? "!" : "$");
        !           783:                                /* NOTREACHED */
        !           784:                        case 1:
        !           785:                                slrflag++;
        !           786:                                altarg = stringbase;
        !           787:                                break;
        !           788:                        default:
        !           789:                                break;
1.17      millert   790:                }
1.1       deraadt   791:        }
1.121     kmos      792:
1.129   ! florian   793: S0:
        !           794:        switch (*sb) {
1.121     kmos      795:
1.129   ! florian   796:        case '\0':
        !           797:                goto OUT;
1.121     kmos      798:
1.129   ! florian   799:        case ' ':
        !           800:        case '\t':
        !           801:                INC_CHKCURSOR(sb);
        !           802:                goto S0;
1.1       deraadt   803:
1.129   ! florian   804:        default:
        !           805:                switch (slrflag) {
        !           806:                        case 0:
        !           807:                                slrflag++;
        !           808:                                break;
        !           809:                        case 1:
        !           810:                                slrflag++;
        !           811:                                altarg = sb;
        !           812:                                break;
        !           813:                        default:
        !           814:                                break;
        !           815:                }
        !           816:                goto S1;
        !           817:        }
1.1       deraadt   818:
1.129   ! florian   819: S1:
        !           820:        switch (*sb) {
1.1       deraadt   821:
1.129   ! florian   822:        case ' ':
        !           823:        case '\t':
        !           824:        case '\0':
        !           825:                goto OUT;       /* end of token */
        !           826:
        !           827:        case '\\':
        !           828:                INC_CHKCURSOR(sb);
        !           829:                goto S2;        /* slurp next character */
        !           830:
        !           831:        case '"':
        !           832:                INC_CHKCURSOR(sb);
        !           833:                goto S3;        /* slurp quoted string */
1.1       deraadt   834:
1.129   ! florian   835:        default:
        !           836:                *ap = *sb;      /* add character to token */
        !           837:                ap++;
        !           838:                INC_CHKCURSOR(sb);
        !           839:                got_one = 1;
        !           840:                goto S1;
1.1       deraadt   841:        }
                    842:
1.129   ! florian   843: S2:
        !           844:        switch (*sb) {
1.1       deraadt   845:
1.129   ! florian   846:        case '\0':
        !           847:                goto OUT;
1.1       deraadt   848:
                    849:        default:
1.129   ! florian   850:                *ap = *sb;
        !           851:                ap++;
        !           852:                INC_CHKCURSOR(sb);
        !           853:                got_one = 1;
        !           854:                goto S1;
1.1       deraadt   855:        }
                    856:
1.129   ! florian   857: S3:
        !           858:        switch (*sb) {
        !           859:
        !           860:        case '\0':
        !           861:                goto OUT;
        !           862:
        !           863:        case '"':
        !           864:                INC_CHKCURSOR(sb);
        !           865:                goto S1;
        !           866:
        !           867:        default:
        !           868:                *ap = *sb;
        !           869:                ap++;
        !           870:                INC_CHKCURSOR(sb);
        !           871:                got_one = 1;
        !           872:                goto S3;
        !           873:        }
1.1       deraadt   874:
1.129   ! florian   875: OUT:
        !           876:        if (got_one)
        !           877:                *ap++ = '\0';
        !           878:        argbase = ap;                   /* update storage pointer */
        !           879:        stringbase = sb;                /* update scan pointer */
        !           880:        if (got_one) {
        !           881:                return (tmp);
        !           882:        }
        !           883:        switch (slrflag) {
        !           884:                case 0:
        !           885:                        slrflag++;
        !           886:                        break;
        !           887:                case 1:
        !           888:                        slrflag++;
        !           889:                        altarg = (char *) 0;
        !           890:                        break;
        !           891:                default:
        !           892:                        break;
        !           893:        }
        !           894:        return (NULL);
1.1       deraadt   895: }
                    896:
1.129   ! florian   897: /*
        !           898:  * Help command.
        !           899:  * Call each command handler with argc == 0 and argv[0] == name.
        !           900:  */
        !           901: void
        !           902: help(int argc, char *argv[])
1.1       deraadt   903: {
1.129   ! florian   904:        struct cmd *c;
1.1       deraadt   905:
1.129   ! florian   906:        if (argc == 1) {
        !           907:                StringList *buf;
1.1       deraadt   908:
1.129   ! florian   909:                buf = sl_init();
        !           910:                fprintf(ttyout, "%sommands may be abbreviated.  Commands are:\n\n",
        !           911:                    proxy ? "Proxy c" : "C");
        !           912:                for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
        !           913:                        if (c->c_name && (!proxy || c->c_proxy))
        !           914:                                sl_add(buf, c->c_name);
        !           915:                list_vertical(buf);
        !           916:                sl_free(buf, 0);
        !           917:                return;
        !           918:        }
1.17      millert   919:
1.129   ! florian   920: #define HELPINDENT ((int) sizeof("disconnect"))
1.17      millert   921:
1.129   ! florian   922:        while (--argc > 0) {
        !           923:                char *arg;
1.17      millert   924:
1.129   ! florian   925:                arg = *++argv;
        !           926:                c = getcmd(arg);
        !           927:                if (c == (struct cmd *)-1)
        !           928:                        fprintf(ttyout, "?Ambiguous help command %s\n", arg);
        !           929:                else if (c == NULL)
        !           930:                        fprintf(ttyout, "?Invalid help command %s\n", arg);
        !           931:                else
        !           932:                        fprintf(ttyout, "%-*s\t%s\n", HELPINDENT,
        !           933:                                c->c_name, c->c_help);
        !           934:        }
1.17      millert   935: }
1.129   ! florian   936: #endif /* !SMALL */
1.17      millert   937:
1.129   ! florian   938: __dead void
1.58      deraadt   939: usage(void)
1.17      millert   940: {
1.129   ! florian   941:        fprintf(stderr, "usage: "
        !           942: #ifndef SMALL
        !           943:            "ftp [-46AadEegiMmnptVv] [-D title] [-k seconds] [-P port] "
        !           944:            "[-r seconds]\n"
        !           945:            "           [-s srcaddr] [host [port]]\n"
        !           946:            "       ftp [-C] [-o output] [-s srcaddr]\n"
        !           947:            "           ftp://[user:password@]host[:port]/file[/] ...\n"
        !           948:            "       ftp [-C] [-c cookie] [-o output] [-S ssl_options] "
        !           949:            "[-s srcaddr]\n"
        !           950:            "           [-U useragent] [-w seconds] "
        !           951:            "http[s]://[user:password@]host[:port]/file ...\n"
        !           952:            "       ftp [-C] [-o output] [-s srcaddr] file:file ...\n"
        !           953:            "       ftp [-C] [-o output] [-s srcaddr] host:/file[/] ...\n"
        !           954: #else /* !SMALL */
        !           955:            "ftp [-o output] "
        !           956:            "ftp://[user:password@]host[:port]/file[/] ...\n"
        !           957: #ifndef NOSSL
        !           958:            "       ftp [-o output] [-S ssl_options] [-w seconds] "
        !           959:            "http[s]://[user:password@]host[:port]/file ...\n"
        !           960: #else
        !           961:            "       ftp [-o output] [-w seconds] http://host[:port]/file ...\n"
        !           962: #endif /* NOSSL */
        !           963:            "       ftp [-o output] file:file ...\n"
        !           964:            "       ftp [-o output] host:/file[/] ...\n"
        !           965: #endif /* !SMALL */
        !           966:            );
1.17      millert   967:        exit(1);
1.1       deraadt   968: }