[BACK]Return to ftpd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / ftpd

Annotation of src/libexec/ftpd/ftpd.c, Revision 1.1

1.1     ! cgd         1: /*
        !             2:  * Copyright (c) 1985, 1988, 1990 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: #ifndef lint
        !            35: char copyright[] =
        !            36: "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
        !            37:  All rights reserved.\n";
        !            38: #endif /* not lint */
        !            39:
        !            40: #ifndef lint
        !            41: static char sccsid[] = "@(#)ftpd.c     5.40 (Berkeley) 7/2/91";
        !            42: #endif /* not lint */
        !            43:
        !            44: /*
        !            45:  * FTP server.
        !            46:  */
        !            47: #include <sys/param.h>
        !            48: #include <sys/stat.h>
        !            49: #include <sys/ioctl.h>
        !            50: #include <sys/socket.h>
        !            51: #include <sys/wait.h>
        !            52:
        !            53: #include <netinet/in.h>
        !            54: #include <netinet/in_systm.h>
        !            55: #include <netinet/ip.h>
        !            56:
        !            57: #define        FTP_NAMES
        !            58: #include <arpa/ftp.h>
        !            59: #include <arpa/inet.h>
        !            60: #include <arpa/telnet.h>
        !            61:
        !            62: #include <signal.h>
        !            63: #include <dirent.h>
        !            64: #include <fcntl.h>
        !            65: #include <time.h>
        !            66: #include <pwd.h>
        !            67: #include <setjmp.h>
        !            68: #include <netdb.h>
        !            69: #include <errno.h>
        !            70: #include <syslog.h>
        !            71: #include <varargs.h>
        !            72: #include <unistd.h>
        !            73: #include <stdio.h>
        !            74: #include <ctype.h>
        !            75: #include <stdlib.h>
        !            76: #include <string.h>
        !            77: #include "pathnames.h"
        !            78:
        !            79: /*
        !            80:  * File containing login names
        !            81:  * NOT to be used on this machine.
        !            82:  * Commonly used to disallow uucp.
        !            83:  */
        !            84: extern int errno;
        !            85: extern char *crypt();
        !            86: extern char version[];
        !            87: extern char *home;             /* pointer to home directory for glob */
        !            88: extern FILE *ftpd_popen(), *fopen(), *freopen();
        !            89: extern int  ftpd_pclose(), fclose();
        !            90: extern char *getline();
        !            91: extern char cbuf[];
        !            92: extern off_t restart_point;
        !            93:
        !            94: struct sockaddr_in ctrl_addr;
        !            95: struct sockaddr_in data_source;
        !            96: struct sockaddr_in data_dest;
        !            97: struct sockaddr_in his_addr;
        !            98: struct sockaddr_in pasv_addr;
        !            99:
        !           100: int    data;
        !           101: jmp_buf        errcatch, urgcatch;
        !           102: int    logged_in;
        !           103: struct passwd *pw;
        !           104: int    debug;
        !           105: int    timeout = 900;    /* timeout after 15 minutes of inactivity */
        !           106: int    maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
        !           107: int    logging;
        !           108: int    guest;
        !           109: int    type;
        !           110: int    form;
        !           111: int    stru;                   /* avoid C keyword */
        !           112: int    mode;
        !           113: int    usedefault = 1;         /* for data transfers */
        !           114: int    pdata = -1;             /* for passive mode */
        !           115: int    transflag;
        !           116: off_t  file_size;
        !           117: off_t  byte_count;
        !           118: #if !defined(CMASK) || CMASK == 0
        !           119: #undef CMASK
        !           120: #define CMASK 027
        !           121: #endif
        !           122: int    defumask = CMASK;               /* default umask value */
        !           123: char   tmpline[7];
        !           124: char   hostname[MAXHOSTNAMELEN];
        !           125: char   remotehost[MAXHOSTNAMELEN];
        !           126:
        !           127: /*
        !           128:  * Timeout intervals for retrying connections
        !           129:  * to hosts that don't accept PORT cmds.  This
        !           130:  * is a kludge, but given the problems with TCP...
        !           131:  */
        !           132: #define        SWAITMAX        90      /* wait at most 90 seconds */
        !           133: #define        SWAITINT        5       /* interval between retries */
        !           134:
        !           135: int    swaitmax = SWAITMAX;
        !           136: int    swaitint = SWAITINT;
        !           137:
        !           138: void   lostconn(), myoob();
        !           139: FILE   *getdatasock(), *dataconn();
        !           140:
        !           141: #ifdef SETPROCTITLE
        !           142: char   **Argv = NULL;          /* pointer to argument vector */
        !           143: char   *LastArgv = NULL;       /* end of argv */
        !           144: char   proctitle[BUFSIZ];      /* initial part of title */
        !           145: #endif /* SETPROCTITLE */
        !           146:
        !           147: main(argc, argv, envp)
        !           148:        int argc;
        !           149:        char *argv[];
        !           150:        char **envp;
        !           151: {
        !           152:        int addrlen, on = 1, tos;
        !           153:        char *cp;
        !           154:
        !           155:        /*
        !           156:         * LOG_NDELAY sets up the logging connection immediately,
        !           157:         * necessary for anonymous ftp's that chroot and can't do it later.
        !           158:         */
        !           159:        openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
        !           160:        addrlen = sizeof (his_addr);
        !           161:        if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
        !           162:                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
        !           163:                exit(1);
        !           164:        }
        !           165:        addrlen = sizeof (ctrl_addr);
        !           166:        if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
        !           167:                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
        !           168:                exit(1);
        !           169:        }
        !           170: #ifdef IP_TOS
        !           171:        tos = IPTOS_LOWDELAY;
        !           172:        if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
        !           173:                syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
        !           174: #endif
        !           175:        data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
        !           176:        debug = 0;
        !           177: #ifdef SETPROCTITLE
        !           178:        /*
        !           179:         *  Save start and extent of argv for setproctitle.
        !           180:         */
        !           181:        Argv = argv;
        !           182:        while (*envp)
        !           183:                envp++;
        !           184:        LastArgv = envp[-1] + strlen(envp[-1]);
        !           185: #endif /* SETPROCTITLE */
        !           186:
        !           187:        argc--, argv++;
        !           188:        while (argc > 0 && *argv[0] == '-') {
        !           189:                for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
        !           190:
        !           191:                case 'v':
        !           192:                        debug = 1;
        !           193:                        break;
        !           194:
        !           195:                case 'd':
        !           196:                        debug = 1;
        !           197:                        break;
        !           198:
        !           199:                case 'l':
        !           200:                        logging = 1;
        !           201:                        break;
        !           202:
        !           203:                case 't':
        !           204:                        timeout = atoi(++cp);
        !           205:                        if (maxtimeout < timeout)
        !           206:                                maxtimeout = timeout;
        !           207:                        goto nextopt;
        !           208:
        !           209:                case 'T':
        !           210:                        maxtimeout = atoi(++cp);
        !           211:                        if (timeout > maxtimeout)
        !           212:                                timeout = maxtimeout;
        !           213:                        goto nextopt;
        !           214:
        !           215:                case 'u':
        !           216:                    {
        !           217:                        int val = 0;
        !           218:
        !           219:                        while (*++cp && *cp >= '0' && *cp <= '9')
        !           220:                                val = val*8 + *cp - '0';
        !           221:                        if (*cp)
        !           222:                                fprintf(stderr, "ftpd: Bad value for -u\n");
        !           223:                        else
        !           224:                                defumask = val;
        !           225:                        goto nextopt;
        !           226:                    }
        !           227:
        !           228:                default:
        !           229:                        fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
        !           230:                             *cp);
        !           231:                        break;
        !           232:                }
        !           233: nextopt:
        !           234:                argc--, argv++;
        !           235:        }
        !           236:        (void) freopen(_PATH_DEVNULL, "w", stderr);
        !           237:        (void) signal(SIGPIPE, lostconn);
        !           238:        (void) signal(SIGCHLD, SIG_IGN);
        !           239:        if ((int)signal(SIGURG, myoob) < 0)
        !           240:                syslog(LOG_ERR, "signal: %m");
        !           241:
        !           242:        /* Try to handle urgent data inline */
        !           243: #ifdef SO_OOBINLINE
        !           244:        if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
        !           245:                syslog(LOG_ERR, "setsockopt: %m");
        !           246: #endif
        !           247:
        !           248: #ifdef F_SETOWN
        !           249:        if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
        !           250:                syslog(LOG_ERR, "fcntl F_SETOWN: %m");
        !           251: #endif
        !           252:        dolog(&his_addr);
        !           253:        /*
        !           254:         * Set up default state
        !           255:         */
        !           256:        data = -1;
        !           257:        type = TYPE_A;
        !           258:        form = FORM_N;
        !           259:        stru = STRU_F;
        !           260:        mode = MODE_S;
        !           261:        tmpline[0] = '\0';
        !           262:        (void) gethostname(hostname, sizeof (hostname));
        !           263:        reply(220, "%s FTP server (%s) ready.", hostname, version);
        !           264:        (void) setjmp(errcatch);
        !           265:        for (;;)
        !           266:                (void) yyparse();
        !           267:        /* NOTREACHED */
        !           268: }
        !           269:
        !           270: void
        !           271: lostconn()
        !           272: {
        !           273:        if (debug)
        !           274:                syslog(LOG_DEBUG, "lost connection");
        !           275:        dologout(-1);
        !           276: }
        !           277:
        !           278: static char ttyline[20];
        !           279:
        !           280: /*
        !           281:  * Helper function for sgetpwnam().
        !           282:  */
        !           283: char *
        !           284: sgetsave(s)
        !           285:        char *s;
        !           286: {
        !           287:        char *new = malloc((unsigned) strlen(s) + 1);
        !           288:
        !           289:        if (new == NULL) {
        !           290:                perror_reply(421, "Local resource failure: malloc");
        !           291:                dologout(1);
        !           292:                /* NOTREACHED */
        !           293:        }
        !           294:        (void) strcpy(new, s);
        !           295:        return (new);
        !           296: }
        !           297:
        !           298: /*
        !           299:  * Save the result of a getpwnam.  Used for USER command, since
        !           300:  * the data returned must not be clobbered by any other command
        !           301:  * (e.g., globbing).
        !           302:  */
        !           303: struct passwd *
        !           304: sgetpwnam(name)
        !           305:        char *name;
        !           306: {
        !           307:        static struct passwd save;
        !           308:        register struct passwd *p;
        !           309:        char *sgetsave();
        !           310:
        !           311:        if ((p = getpwnam(name)) == NULL)
        !           312:                return (p);
        !           313:        if (save.pw_name) {
        !           314:                free(save.pw_name);
        !           315:                free(save.pw_passwd);
        !           316:                free(save.pw_gecos);
        !           317:                free(save.pw_dir);
        !           318:                free(save.pw_shell);
        !           319:        }
        !           320:        save = *p;
        !           321:        save.pw_name = sgetsave(p->pw_name);
        !           322:        save.pw_passwd = sgetsave(p->pw_passwd);
        !           323:        save.pw_gecos = sgetsave(p->pw_gecos);
        !           324:        save.pw_dir = sgetsave(p->pw_dir);
        !           325:        save.pw_shell = sgetsave(p->pw_shell);
        !           326:        return (&save);
        !           327: }
        !           328:
        !           329: int login_attempts;            /* number of failed login attempts */
        !           330: int askpasswd;                 /* had user command, ask for passwd */
        !           331:
        !           332: /*
        !           333:  * USER command.
        !           334:  * Sets global passwd pointer pw if named account exists and is acceptable;
        !           335:  * sets askpasswd if a PASS command is expected.  If logged in previously,
        !           336:  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
        !           337:  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
        !           338:  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
        !           339:  * requesting login privileges.  Disallow anyone who does not have a standard
        !           340:  * shell as returned by getusershell().  Disallow anyone mentioned in the file
        !           341:  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
        !           342:  */
        !           343: user(name)
        !           344:        char *name;
        !           345: {
        !           346:        register char *cp;
        !           347:        char *shell;
        !           348:        char *getusershell();
        !           349:
        !           350:        if (logged_in) {
        !           351:                if (guest) {
        !           352:                        reply(530, "Can't change user from guest login.");
        !           353:                        return;
        !           354:                }
        !           355:                end_login();
        !           356:        }
        !           357:
        !           358:        guest = 0;
        !           359:        if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
        !           360:                if (checkuser("ftp") || checkuser("anonymous"))
        !           361:                        reply(530, "User %s access denied.", name);
        !           362:                else if ((pw = sgetpwnam("ftp")) != NULL) {
        !           363:                        guest = 1;
        !           364:                        askpasswd = 1;
        !           365:                        reply(331, "Guest login ok, send ident as password.");
        !           366:                } else
        !           367:                        reply(530, "User %s unknown.", name);
        !           368:                return;
        !           369:        }
        !           370:        if (pw = sgetpwnam(name)) {
        !           371:                if ((shell = pw->pw_shell) == NULL || *shell == 0)
        !           372:                        shell = _PATH_BSHELL;
        !           373:                while ((cp = getusershell()) != NULL)
        !           374:                        if (strcmp(cp, shell) == 0)
        !           375:                                break;
        !           376:                endusershell();
        !           377:                if (cp == NULL || checkuser(name)) {
        !           378:                        reply(530, "User %s access denied.", name);
        !           379:                        if (logging)
        !           380:                                syslog(LOG_NOTICE,
        !           381:                                    "FTP LOGIN REFUSED FROM %s, %s",
        !           382:                                    remotehost, name);
        !           383:                        pw = (struct passwd *) NULL;
        !           384:                        return;
        !           385:                }
        !           386:        }
        !           387:        reply(331, "Password required for %s.", name);
        !           388:        askpasswd = 1;
        !           389:        /*
        !           390:         * Delay before reading passwd after first failed
        !           391:         * attempt to slow down passwd-guessing programs.
        !           392:         */
        !           393:        if (login_attempts)
        !           394:                sleep((unsigned) login_attempts);
        !           395: }
        !           396:
        !           397: /*
        !           398:  * Check if a user is in the file _PATH_FTPUSERS
        !           399:  */
        !           400: checkuser(name)
        !           401:        char *name;
        !           402: {
        !           403:        register FILE *fd;
        !           404:        register char *p;
        !           405:        char line[BUFSIZ];
        !           406:
        !           407:        if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
        !           408:                while (fgets(line, sizeof(line), fd) != NULL)
        !           409:                        if ((p = index(line, '\n')) != NULL) {
        !           410:                                *p = '\0';
        !           411:                                if (line[0] == '#')
        !           412:                                        continue;
        !           413:                                if (strcmp(line, name) == 0)
        !           414:                                        return (1);
        !           415:                        }
        !           416:                (void) fclose(fd);
        !           417:        }
        !           418:        return (0);
        !           419: }
        !           420:
        !           421: /*
        !           422:  * Terminate login as previous user, if any, resetting state;
        !           423:  * used when USER command is given or login fails.
        !           424:  */
        !           425: end_login()
        !           426: {
        !           427:
        !           428:        (void) seteuid((uid_t)0);
        !           429:        if (logged_in)
        !           430:                logwtmp(ttyline, "", "");
        !           431:        pw = NULL;
        !           432:        logged_in = 0;
        !           433:        guest = 0;
        !           434: }
        !           435:
        !           436: pass(passwd)
        !           437:        char *passwd;
        !           438: {
        !           439:        char *xpasswd, *salt;
        !           440:
        !           441:        if (logged_in || askpasswd == 0) {
        !           442:                reply(503, "Login with USER first.");
        !           443:                return;
        !           444:        }
        !           445:        askpasswd = 0;
        !           446:        if (!guest) {           /* "ftp" is only account allowed no password */
        !           447:                if (pw == NULL)
        !           448:                        salt = "xx";
        !           449:                else
        !           450:                        salt = pw->pw_passwd;
        !           451: #ifdef DES
        !           452:                xpasswd = crypt(passwd, salt);
        !           453: #else
        !           454:                xpasswd = passwd;
        !           455: #endif
        !           456:                /* The strcmp does not catch null passwords! */
        !           457:                if (pw == NULL || *pw->pw_passwd == '\0' ||
        !           458:                    strcmp(xpasswd, pw->pw_passwd)) {
        !           459:                        reply(530, "Login incorrect.");
        !           460:                        pw = NULL;
        !           461:                        if (login_attempts++ >= 5) {
        !           462:                                syslog(LOG_NOTICE,
        !           463:                                    "repeated login failures from %s",
        !           464:                                    remotehost);
        !           465:                                exit(0);
        !           466:                        }
        !           467:                        return;
        !           468:                }
        !           469:        }
        !           470:        login_attempts = 0;             /* this time successful */
        !           471:        (void) setegid((gid_t)pw->pw_gid);
        !           472:        (void) initgroups(pw->pw_name, pw->pw_gid);
        !           473:
        !           474:        /* open wtmp before chroot */
        !           475:        (void)sprintf(ttyline, "ftp%d", getpid());
        !           476:        logwtmp(ttyline, pw->pw_name, remotehost);
        !           477:        logged_in = 1;
        !           478:
        !           479:        if (guest) {
        !           480:                /*
        !           481:                 * We MUST do a chdir() after the chroot. Otherwise
        !           482:                 * the old current directory will be accessible as "."
        !           483:                 * outside the new root!
        !           484:                 */
        !           485:                if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
        !           486:                        reply(550, "Can't set guest privileges.");
        !           487:                        goto bad;
        !           488:                }
        !           489:        } else if (chdir(pw->pw_dir) < 0) {
        !           490:                if (chdir("/") < 0) {
        !           491:                        reply(530, "User %s: can't change directory to %s.",
        !           492:                            pw->pw_name, pw->pw_dir);
        !           493:                        goto bad;
        !           494:                } else
        !           495:                        lreply(230, "No directory! Logging in with home=/");
        !           496:        }
        !           497:        if (seteuid((uid_t)pw->pw_uid) < 0) {
        !           498:                reply(550, "Can't set uid.");
        !           499:                goto bad;
        !           500:        }
        !           501:        if (guest) {
        !           502:                reply(230, "Guest login ok, access restrictions apply.");
        !           503: #ifdef SETPROCTITLE
        !           504:                sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
        !           505:                    sizeof(proctitle) - sizeof(remotehost) -
        !           506:                    sizeof(": anonymous/"), passwd);
        !           507:                setproctitle(proctitle);
        !           508: #endif /* SETPROCTITLE */
        !           509:                if (logging)
        !           510:                        syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
        !           511:                            remotehost, passwd);
        !           512:        } else {
        !           513:                reply(230, "User %s logged in.", pw->pw_name);
        !           514: #ifdef SETPROCTITLE
        !           515:                sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
        !           516:                setproctitle(proctitle);
        !           517: #endif /* SETPROCTITLE */
        !           518:                if (logging)
        !           519:                        syslog(LOG_INFO, "FTP LOGIN FROM %s, %s",
        !           520:                            remotehost, pw->pw_name);
        !           521:        }
        !           522:        home = pw->pw_dir;              /* home dir for globbing */
        !           523:        (void) umask(defumask);
        !           524:        return;
        !           525: bad:
        !           526:        /* Forget all about it... */
        !           527:        end_login();
        !           528: }
        !           529:
        !           530: retrieve(cmd, name)
        !           531:        char *cmd, *name;
        !           532: {
        !           533:        FILE *fin, *dout;
        !           534:        struct stat st;
        !           535:        int (*closefunc)();
        !           536:
        !           537:        if (cmd == 0) {
        !           538:                fin = fopen(name, "r"), closefunc = fclose;
        !           539:                st.st_size = 0;
        !           540:        } else {
        !           541:                char line[BUFSIZ];
        !           542:
        !           543:                (void) sprintf(line, cmd, name), name = line;
        !           544:                fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
        !           545:                st.st_size = -1;
        !           546:                st.st_blksize = BUFSIZ;
        !           547:        }
        !           548:        if (fin == NULL) {
        !           549:                if (errno != 0)
        !           550:                        perror_reply(550, name);
        !           551:                return;
        !           552:        }
        !           553:        if (cmd == 0 &&
        !           554:            (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
        !           555:                reply(550, "%s: not a plain file.", name);
        !           556:                goto done;
        !           557:        }
        !           558:        if (restart_point) {
        !           559:                if (type == TYPE_A) {
        !           560:                        register int i, n, c;
        !           561:
        !           562:                        n = restart_point;
        !           563:                        i = 0;
        !           564:                        while (i++ < n) {
        !           565:                                if ((c=getc(fin)) == EOF) {
        !           566:                                        perror_reply(550, name);
        !           567:                                        goto done;
        !           568:                                }
        !           569:                                if (c == '\n')
        !           570:                                        i++;
        !           571:                        }
        !           572:                } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
        !           573:                        perror_reply(550, name);
        !           574:                        goto done;
        !           575:                }
        !           576:        }
        !           577:        dout = dataconn(name, st.st_size, "w");
        !           578:        if (dout == NULL)
        !           579:                goto done;
        !           580:        send_data(fin, dout, st.st_blksize);
        !           581:        (void) fclose(dout);
        !           582:        data = -1;
        !           583:        pdata = -1;
        !           584: done:
        !           585:        (*closefunc)(fin);
        !           586: }
        !           587:
        !           588: store(name, mode, unique)
        !           589:        char *name, *mode;
        !           590:        int unique;
        !           591: {
        !           592:        FILE *fout, *din;
        !           593:        struct stat st;
        !           594:        int (*closefunc)();
        !           595:        char *gunique();
        !           596:
        !           597:        if (unique && stat(name, &st) == 0 &&
        !           598:            (name = gunique(name)) == NULL)
        !           599:                return;
        !           600:
        !           601:        if (restart_point)
        !           602:                mode = "r+w";
        !           603:        fout = fopen(name, mode);
        !           604:        closefunc = fclose;
        !           605:        if (fout == NULL) {
        !           606:                perror_reply(553, name);
        !           607:                return;
        !           608:        }
        !           609:        if (restart_point) {
        !           610:                if (type == TYPE_A) {
        !           611:                        register int i, n, c;
        !           612:
        !           613:                        n = restart_point;
        !           614:                        i = 0;
        !           615:                        while (i++ < n) {
        !           616:                                if ((c=getc(fout)) == EOF) {
        !           617:                                        perror_reply(550, name);
        !           618:                                        goto done;
        !           619:                                }
        !           620:                                if (c == '\n')
        !           621:                                        i++;
        !           622:                        }
        !           623:                        /*
        !           624:                         * We must do this seek to "current" position
        !           625:                         * because we are changing from reading to
        !           626:                         * writing.
        !           627:                         */
        !           628:                        if (fseek(fout, 0L, L_INCR) < 0) {
        !           629:                                perror_reply(550, name);
        !           630:                                goto done;
        !           631:                        }
        !           632:                } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
        !           633:                        perror_reply(550, name);
        !           634:                        goto done;
        !           635:                }
        !           636:        }
        !           637:        din = dataconn(name, (off_t)-1, "r");
        !           638:        if (din == NULL)
        !           639:                goto done;
        !           640:        if (receive_data(din, fout) == 0) {
        !           641:                if (unique)
        !           642:                        reply(226, "Transfer complete (unique file name:%s).",
        !           643:                            name);
        !           644:                else
        !           645:                        reply(226, "Transfer complete.");
        !           646:        }
        !           647:        (void) fclose(din);
        !           648:        data = -1;
        !           649:        pdata = -1;
        !           650: done:
        !           651:        (*closefunc)(fout);
        !           652: }
        !           653:
        !           654: FILE *
        !           655: getdatasock(mode)
        !           656:        char *mode;
        !           657: {
        !           658:        int s, on = 1, tries;
        !           659:
        !           660:        if (data >= 0)
        !           661:                return (fdopen(data, mode));
        !           662:        (void) seteuid((uid_t)0);
        !           663:        s = socket(AF_INET, SOCK_STREAM, 0);
        !           664:        if (s < 0)
        !           665:                goto bad;
        !           666:        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
        !           667:            (char *) &on, sizeof (on)) < 0)
        !           668:                goto bad;
        !           669:        /* anchor socket to avoid multi-homing problems */
        !           670:        data_source.sin_family = AF_INET;
        !           671:        data_source.sin_addr = ctrl_addr.sin_addr;
        !           672:        for (tries = 1; ; tries++) {
        !           673:                if (bind(s, (struct sockaddr *)&data_source,
        !           674:                    sizeof (data_source)) >= 0)
        !           675:                        break;
        !           676:                if (errno != EADDRINUSE || tries > 10)
        !           677:                        goto bad;
        !           678:                sleep(tries);
        !           679:        }
        !           680:        (void) seteuid((uid_t)pw->pw_uid);
        !           681: #ifdef IP_TOS
        !           682:        on = IPTOS_THROUGHPUT;
        !           683:        if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
        !           684:                syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
        !           685: #endif
        !           686:        return (fdopen(s, mode));
        !           687: bad:
        !           688:        (void) seteuid((uid_t)pw->pw_uid);
        !           689:        (void) close(s);
        !           690:        return (NULL);
        !           691: }
        !           692:
        !           693: FILE *
        !           694: dataconn(name, size, mode)
        !           695:        char *name;
        !           696:        off_t size;
        !           697:        char *mode;
        !           698: {
        !           699:        char sizebuf[32];
        !           700:        FILE *file;
        !           701:        int retry = 0, tos;
        !           702:
        !           703:        file_size = size;
        !           704:        byte_count = 0;
        !           705:        if (size != (off_t) -1)
        !           706:                (void) sprintf (sizebuf, " (%ld bytes)", size);
        !           707:        else
        !           708:                (void) strcpy(sizebuf, "");
        !           709:        if (pdata >= 0) {
        !           710:                struct sockaddr_in from;
        !           711:                int s, fromlen = sizeof(from);
        !           712:
        !           713:                s = accept(pdata, (struct sockaddr *)&from, &fromlen);
        !           714:                if (s < 0) {
        !           715:                        reply(425, "Can't open data connection.");
        !           716:                        (void) close(pdata);
        !           717:                        pdata = -1;
        !           718:                        return(NULL);
        !           719:                }
        !           720:                (void) close(pdata);
        !           721:                pdata = s;
        !           722: #ifdef IP_TOS
        !           723:                tos = IPTOS_LOWDELAY;
        !           724:                (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
        !           725:                    sizeof(int));
        !           726: #endif
        !           727:                reply(150, "Opening %s mode data connection for %s%s.",
        !           728:                     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
        !           729:                return(fdopen(pdata, mode));
        !           730:        }
        !           731:        if (data >= 0) {
        !           732:                reply(125, "Using existing data connection for %s%s.",
        !           733:                    name, sizebuf);
        !           734:                usedefault = 1;
        !           735:                return (fdopen(data, mode));
        !           736:        }
        !           737:        if (usedefault)
        !           738:                data_dest = his_addr;
        !           739:        usedefault = 1;
        !           740:        file = getdatasock(mode);
        !           741:        if (file == NULL) {
        !           742:                reply(425, "Can't create data socket (%s,%d): %s.",
        !           743:                    inet_ntoa(data_source.sin_addr),
        !           744:                    ntohs(data_source.sin_port), strerror(errno));
        !           745:                return (NULL);
        !           746:        }
        !           747:        data = fileno(file);
        !           748:        while (connect(data, (struct sockaddr *)&data_dest,
        !           749:            sizeof (data_dest)) < 0) {
        !           750:                if (errno == EADDRINUSE && retry < swaitmax) {
        !           751:                        sleep((unsigned) swaitint);
        !           752:                        retry += swaitint;
        !           753:                        continue;
        !           754:                }
        !           755:                perror_reply(425, "Can't build data connection");
        !           756:                (void) fclose(file);
        !           757:                data = -1;
        !           758:                return (NULL);
        !           759:        }
        !           760:        reply(150, "Opening %s mode data connection for %s%s.",
        !           761:             type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
        !           762:        return (file);
        !           763: }
        !           764:
        !           765: /*
        !           766:  * Tranfer the contents of "instr" to
        !           767:  * "outstr" peer using the appropriate
        !           768:  * encapsulation of the data subject
        !           769:  * to Mode, Structure, and Type.
        !           770:  *
        !           771:  * NB: Form isn't handled.
        !           772:  */
        !           773: send_data(instr, outstr, blksize)
        !           774:        FILE *instr, *outstr;
        !           775:        off_t blksize;
        !           776: {
        !           777:        register int c, cnt;
        !           778:        register char *buf;
        !           779:        int netfd, filefd;
        !           780:
        !           781:        transflag++;
        !           782:        if (setjmp(urgcatch)) {
        !           783:                transflag = 0;
        !           784:                return;
        !           785:        }
        !           786:        switch (type) {
        !           787:
        !           788:        case TYPE_A:
        !           789:                while ((c = getc(instr)) != EOF) {
        !           790:                        byte_count++;
        !           791:                        if (c == '\n') {
        !           792:                                if (ferror(outstr))
        !           793:                                        goto data_err;
        !           794:                                (void) putc('\r', outstr);
        !           795:                        }
        !           796:                        (void) putc(c, outstr);
        !           797:                }
        !           798:                fflush(outstr);
        !           799:                transflag = 0;
        !           800:                if (ferror(instr))
        !           801:                        goto file_err;
        !           802:                if (ferror(outstr))
        !           803:                        goto data_err;
        !           804:                reply(226, "Transfer complete.");
        !           805:                return;
        !           806:
        !           807:        case TYPE_I:
        !           808:        case TYPE_L:
        !           809:                if ((buf = malloc((u_int)blksize)) == NULL) {
        !           810:                        transflag = 0;
        !           811:                        perror_reply(451, "Local resource failure: malloc");
        !           812:                        return;
        !           813:                }
        !           814:                netfd = fileno(outstr);
        !           815:                filefd = fileno(instr);
        !           816:                while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
        !           817:                    write(netfd, buf, cnt) == cnt)
        !           818:                        byte_count += cnt;
        !           819:                transflag = 0;
        !           820:                (void)free(buf);
        !           821:                if (cnt != 0) {
        !           822:                        if (cnt < 0)
        !           823:                                goto file_err;
        !           824:                        goto data_err;
        !           825:                }
        !           826:                reply(226, "Transfer complete.");
        !           827:                return;
        !           828:        default:
        !           829:                transflag = 0;
        !           830:                reply(550, "Unimplemented TYPE %d in send_data", type);
        !           831:                return;
        !           832:        }
        !           833:
        !           834: data_err:
        !           835:        transflag = 0;
        !           836:        perror_reply(426, "Data connection");
        !           837:        return;
        !           838:
        !           839: file_err:
        !           840:        transflag = 0;
        !           841:        perror_reply(551, "Error on input file");
        !           842: }
        !           843:
        !           844: /*
        !           845:  * Transfer data from peer to
        !           846:  * "outstr" using the appropriate
        !           847:  * encapulation of the data subject
        !           848:  * to Mode, Structure, and Type.
        !           849:  *
        !           850:  * N.B.: Form isn't handled.
        !           851:  */
        !           852: receive_data(instr, outstr)
        !           853:        FILE *instr, *outstr;
        !           854: {
        !           855:        register int c;
        !           856:        int cnt, bare_lfs = 0;
        !           857:        char buf[BUFSIZ];
        !           858:
        !           859:        transflag++;
        !           860:        if (setjmp(urgcatch)) {
        !           861:                transflag = 0;
        !           862:                return (-1);
        !           863:        }
        !           864:        switch (type) {
        !           865:
        !           866:        case TYPE_I:
        !           867:        case TYPE_L:
        !           868:                while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
        !           869:                        if (write(fileno(outstr), buf, cnt) != cnt)
        !           870:                                goto file_err;
        !           871:                        byte_count += cnt;
        !           872:                }
        !           873:                if (cnt < 0)
        !           874:                        goto data_err;
        !           875:                transflag = 0;
        !           876:                return (0);
        !           877:
        !           878:        case TYPE_E:
        !           879:                reply(553, "TYPE E not implemented.");
        !           880:                transflag = 0;
        !           881:                return (-1);
        !           882:
        !           883:        case TYPE_A:
        !           884:                while ((c = getc(instr)) != EOF) {
        !           885:                        byte_count++;
        !           886:                        if (c == '\n')
        !           887:                                bare_lfs++;
        !           888:                        while (c == '\r') {
        !           889:                                if (ferror(outstr))
        !           890:                                        goto data_err;
        !           891:                                if ((c = getc(instr)) != '\n') {
        !           892:                                        (void) putc ('\r', outstr);
        !           893:                                        if (c == '\0' || c == EOF)
        !           894:                                                goto contin2;
        !           895:                                }
        !           896:                        }
        !           897:                        (void) putc(c, outstr);
        !           898:        contin2:        ;
        !           899:                }
        !           900:                fflush(outstr);
        !           901:                if (ferror(instr))
        !           902:                        goto data_err;
        !           903:                if (ferror(outstr))
        !           904:                        goto file_err;
        !           905:                transflag = 0;
        !           906:                if (bare_lfs) {
        !           907:                        lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
        !           908:                        printf("   File may not have transferred correctly.\r\n");
        !           909:                }
        !           910:                return (0);
        !           911:        default:
        !           912:                reply(550, "Unimplemented TYPE %d in receive_data", type);
        !           913:                transflag = 0;
        !           914:                return (-1);
        !           915:        }
        !           916:
        !           917: data_err:
        !           918:        transflag = 0;
        !           919:        perror_reply(426, "Data Connection");
        !           920:        return (-1);
        !           921:
        !           922: file_err:
        !           923:        transflag = 0;
        !           924:        perror_reply(452, "Error writing file");
        !           925:        return (-1);
        !           926: }
        !           927:
        !           928: statfilecmd(filename)
        !           929:        char *filename;
        !           930: {
        !           931:        char line[BUFSIZ];
        !           932:        FILE *fin;
        !           933:        int c;
        !           934:
        !           935:        (void) sprintf(line, "/bin/ls -lgA %s", filename);
        !           936:        fin = ftpd_popen(line, "r");
        !           937:        lreply(211, "status of %s:", filename);
        !           938:        while ((c = getc(fin)) != EOF) {
        !           939:                if (c == '\n') {
        !           940:                        if (ferror(stdout)){
        !           941:                                perror_reply(421, "control connection");
        !           942:                                (void) ftpd_pclose(fin);
        !           943:                                dologout(1);
        !           944:                                /* NOTREACHED */
        !           945:                        }
        !           946:                        if (ferror(fin)) {
        !           947:                                perror_reply(551, filename);
        !           948:                                (void) ftpd_pclose(fin);
        !           949:                                return;
        !           950:                        }
        !           951:                        (void) putc('\r', stdout);
        !           952:                }
        !           953:                (void) putc(c, stdout);
        !           954:        }
        !           955:        (void) ftpd_pclose(fin);
        !           956:        reply(211, "End of Status");
        !           957: }
        !           958:
        !           959: statcmd()
        !           960: {
        !           961:        struct sockaddr_in *sin;
        !           962:        u_char *a, *p;
        !           963:
        !           964:        lreply(211, "%s FTP server status:", hostname, version);
        !           965:        printf("     %s\r\n", version);
        !           966:        printf("     Connected to %s", remotehost);
        !           967:        if (!isdigit(remotehost[0]))
        !           968:                printf(" (%s)", inet_ntoa(his_addr.sin_addr));
        !           969:        printf("\r\n");
        !           970:        if (logged_in) {
        !           971:                if (guest)
        !           972:                        printf("     Logged in anonymously\r\n");
        !           973:                else
        !           974:                        printf("     Logged in as %s\r\n", pw->pw_name);
        !           975:        } else if (askpasswd)
        !           976:                printf("     Waiting for password\r\n");
        !           977:        else
        !           978:                printf("     Waiting for user name\r\n");
        !           979:        printf("     TYPE: %s", typenames[type]);
        !           980:        if (type == TYPE_A || type == TYPE_E)
        !           981:                printf(", FORM: %s", formnames[form]);
        !           982:        if (type == TYPE_L)
        !           983: #if NBBY == 8
        !           984:                printf(" %d", NBBY);
        !           985: #else
        !           986:                printf(" %d", bytesize);        /* need definition! */
        !           987: #endif
        !           988:        printf("; STRUcture: %s; transfer MODE: %s\r\n",
        !           989:            strunames[stru], modenames[mode]);
        !           990:        if (data != -1)
        !           991:                printf("     Data connection open\r\n");
        !           992:        else if (pdata != -1) {
        !           993:                printf("     in Passive mode");
        !           994:                sin = &pasv_addr;
        !           995:                goto printaddr;
        !           996:        } else if (usedefault == 0) {
        !           997:                printf("     PORT");
        !           998:                sin = &data_dest;
        !           999: printaddr:
        !          1000:                a = (u_char *) &sin->sin_addr;
        !          1001:                p = (u_char *) &sin->sin_port;
        !          1002: #define UC(b) (((int) b) & 0xff)
        !          1003:                printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
        !          1004:                        UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
        !          1005: #undef UC
        !          1006:        } else
        !          1007:                printf("     No data connection\r\n");
        !          1008:        reply(211, "End of status");
        !          1009: }
        !          1010:
        !          1011: fatal(s)
        !          1012:        char *s;
        !          1013: {
        !          1014:        reply(451, "Error in server: %s\n", s);
        !          1015:        reply(221, "Closing connection due to server error.");
        !          1016:        dologout(0);
        !          1017:        /* NOTREACHED */
        !          1018: }
        !          1019:
        !          1020: /* VARARGS2 */
        !          1021: reply(n, fmt, p0, p1, p2, p3, p4, p5)
        !          1022:        int n;
        !          1023:        char *fmt;
        !          1024: {
        !          1025:        printf("%d ", n);
        !          1026:        printf(fmt, p0, p1, p2, p3, p4, p5);
        !          1027:        printf("\r\n");
        !          1028:        (void)fflush(stdout);
        !          1029:        if (debug) {
        !          1030:                syslog(LOG_DEBUG, "<--- %d ", n);
        !          1031:                syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
        !          1032: }
        !          1033: }
        !          1034:
        !          1035: /* VARARGS2 */
        !          1036: lreply(n, fmt, p0, p1, p2, p3, p4, p5)
        !          1037:        int n;
        !          1038:        char *fmt;
        !          1039: {
        !          1040:        printf("%d- ", n);
        !          1041:        printf(fmt, p0, p1, p2, p3, p4, p5);
        !          1042:        printf("\r\n");
        !          1043:        (void)fflush(stdout);
        !          1044:        if (debug) {
        !          1045:                syslog(LOG_DEBUG, "<--- %d- ", n);
        !          1046:                syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
        !          1047:        }
        !          1048: }
        !          1049:
        !          1050: ack(s)
        !          1051:        char *s;
        !          1052: {
        !          1053:        reply(250, "%s command successful.", s);
        !          1054: }
        !          1055:
        !          1056: nack(s)
        !          1057:        char *s;
        !          1058: {
        !          1059:        reply(502, "%s command not implemented.", s);
        !          1060: }
        !          1061:
        !          1062: /* ARGSUSED */
        !          1063: yyerror(s)
        !          1064:        char *s;
        !          1065: {
        !          1066:        char *cp;
        !          1067:
        !          1068:        if (cp = index(cbuf,'\n'))
        !          1069:                *cp = '\0';
        !          1070:        reply(500, "'%s': command not understood.", cbuf);
        !          1071: }
        !          1072:
        !          1073: delete(name)
        !          1074:        char *name;
        !          1075: {
        !          1076:        struct stat st;
        !          1077:
        !          1078:        if (stat(name, &st) < 0) {
        !          1079:                perror_reply(550, name);
        !          1080:                return;
        !          1081:        }
        !          1082:        if ((st.st_mode&S_IFMT) == S_IFDIR) {
        !          1083:                if (rmdir(name) < 0) {
        !          1084:                        perror_reply(550, name);
        !          1085:                        return;
        !          1086:                }
        !          1087:                goto done;
        !          1088:        }
        !          1089:        if (unlink(name) < 0) {
        !          1090:                perror_reply(550, name);
        !          1091:                return;
        !          1092:        }
        !          1093: done:
        !          1094:        ack("DELE");
        !          1095: }
        !          1096:
        !          1097: cwd(path)
        !          1098:        char *path;
        !          1099: {
        !          1100:        if (chdir(path) < 0)
        !          1101:                perror_reply(550, path);
        !          1102:        else
        !          1103:                ack("CWD");
        !          1104: }
        !          1105:
        !          1106: makedir(name)
        !          1107:        char *name;
        !          1108: {
        !          1109:        if (mkdir(name, 0777) < 0)
        !          1110:                perror_reply(550, name);
        !          1111:        else
        !          1112:                reply(257, "MKD command successful.");
        !          1113: }
        !          1114:
        !          1115: removedir(name)
        !          1116:        char *name;
        !          1117: {
        !          1118:        if (rmdir(name) < 0)
        !          1119:                perror_reply(550, name);
        !          1120:        else
        !          1121:                ack("RMD");
        !          1122: }
        !          1123:
        !          1124: pwd()
        !          1125: {
        !          1126:        char path[MAXPATHLEN + 1];
        !          1127:        extern char *getwd();
        !          1128:
        !          1129:        if (getwd(path) == (char *)NULL)
        !          1130:                reply(550, "%s.", path);
        !          1131:        else
        !          1132:                reply(257, "\"%s\" is current directory.", path);
        !          1133: }
        !          1134:
        !          1135: char *
        !          1136: renamefrom(name)
        !          1137:        char *name;
        !          1138: {
        !          1139:        struct stat st;
        !          1140:
        !          1141:        if (stat(name, &st) < 0) {
        !          1142:                perror_reply(550, name);
        !          1143:                return ((char *)0);
        !          1144:        }
        !          1145:        reply(350, "File exists, ready for destination name");
        !          1146:        return (name);
        !          1147: }
        !          1148:
        !          1149: renamecmd(from, to)
        !          1150:        char *from, *to;
        !          1151: {
        !          1152:        if (rename(from, to) < 0)
        !          1153:                perror_reply(550, "rename");
        !          1154:        else
        !          1155:                ack("RNTO");
        !          1156: }
        !          1157:
        !          1158: dolog(sin)
        !          1159:        struct sockaddr_in *sin;
        !          1160: {
        !          1161:        struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
        !          1162:                sizeof (struct in_addr), AF_INET);
        !          1163:        time_t t, time();
        !          1164:        extern char *ctime();
        !          1165:
        !          1166:        if (hp)
        !          1167:                (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
        !          1168:        else
        !          1169:                (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
        !          1170:                    sizeof (remotehost));
        !          1171: #ifdef SETPROCTITLE
        !          1172:        sprintf(proctitle, "%s: connected", remotehost);
        !          1173:        setproctitle(proctitle);
        !          1174: #endif /* SETPROCTITLE */
        !          1175:
        !          1176:        if (logging) {
        !          1177:                t = time((time_t *) 0);
        !          1178:                syslog(LOG_INFO, "connection from %s at %s",
        !          1179:                    remotehost, ctime(&t));
        !          1180:        }
        !          1181: }
        !          1182:
        !          1183: /*
        !          1184:  * Record logout in wtmp file
        !          1185:  * and exit with supplied status.
        !          1186:  */
        !          1187: dologout(status)
        !          1188:        int status;
        !          1189: {
        !          1190:        if (logged_in) {
        !          1191:                (void) seteuid((uid_t)0);
        !          1192:                logwtmp(ttyline, "", "");
        !          1193:        }
        !          1194:        /* beware of flushing buffers after a SIGPIPE */
        !          1195:        _exit(status);
        !          1196: }
        !          1197:
        !          1198: void
        !          1199: myoob()
        !          1200: {
        !          1201:        char *cp;
        !          1202:
        !          1203:        /* only process if transfer occurring */
        !          1204:        if (!transflag)
        !          1205:                return;
        !          1206:        cp = tmpline;
        !          1207:        if (getline(cp, 7, stdin) == NULL) {
        !          1208:                reply(221, "You could at least say goodbye.");
        !          1209:                dologout(0);
        !          1210:        }
        !          1211:        upper(cp);
        !          1212:        if (strcmp(cp, "ABOR\r\n") == 0) {
        !          1213:                tmpline[0] = '\0';
        !          1214:                reply(426, "Transfer aborted. Data connection closed.");
        !          1215:                reply(226, "Abort successful");
        !          1216:                longjmp(urgcatch, 1);
        !          1217:        }
        !          1218:        if (strcmp(cp, "STAT\r\n") == 0) {
        !          1219:                if (file_size != (off_t) -1)
        !          1220:                        reply(213, "Status: %lu of %lu bytes transferred",
        !          1221:                            byte_count, file_size);
        !          1222:                else
        !          1223:                        reply(213, "Status: %lu bytes transferred", byte_count);
        !          1224:        }
        !          1225: }
        !          1226:
        !          1227: /*
        !          1228:  * Note: a response of 425 is not mentioned as a possible response to
        !          1229:  *     the PASV command in RFC959. However, it has been blessed as
        !          1230:  *     a legitimate response by Jon Postel in a telephone conversation
        !          1231:  *     with Rick Adams on 25 Jan 89.
        !          1232:  */
        !          1233: passive()
        !          1234: {
        !          1235:        int len;
        !          1236:        register char *p, *a;
        !          1237:
        !          1238:        pdata = socket(AF_INET, SOCK_STREAM, 0);
        !          1239:        if (pdata < 0) {
        !          1240:                perror_reply(425, "Can't open passive connection");
        !          1241:                return;
        !          1242:        }
        !          1243:        pasv_addr = ctrl_addr;
        !          1244:        pasv_addr.sin_port = 0;
        !          1245:        (void) seteuid((uid_t)0);
        !          1246:        if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
        !          1247:                (void) seteuid((uid_t)pw->pw_uid);
        !          1248:                goto pasv_error;
        !          1249:        }
        !          1250:        (void) seteuid((uid_t)pw->pw_uid);
        !          1251:        len = sizeof(pasv_addr);
        !          1252:        if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
        !          1253:                goto pasv_error;
        !          1254:        if (listen(pdata, 1) < 0)
        !          1255:                goto pasv_error;
        !          1256:        a = (char *) &pasv_addr.sin_addr;
        !          1257:        p = (char *) &pasv_addr.sin_port;
        !          1258:
        !          1259: #define UC(b) (((int) b) & 0xff)
        !          1260:
        !          1261:        reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
        !          1262:                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
        !          1263:        return;
        !          1264:
        !          1265: pasv_error:
        !          1266:        (void) close(pdata);
        !          1267:        pdata = -1;
        !          1268:        perror_reply(425, "Can't open passive connection");
        !          1269:        return;
        !          1270: }
        !          1271:
        !          1272: /*
        !          1273:  * Generate unique name for file with basename "local".
        !          1274:  * The file named "local" is already known to exist.
        !          1275:  * Generates failure reply on error.
        !          1276:  */
        !          1277: char *
        !          1278: gunique(local)
        !          1279:        char *local;
        !          1280: {
        !          1281:        static char new[MAXPATHLEN];
        !          1282:        struct stat st;
        !          1283:        char *cp = rindex(local, '/');
        !          1284:        int count = 0;
        !          1285:
        !          1286:        if (cp)
        !          1287:                *cp = '\0';
        !          1288:        if (stat(cp ? local : ".", &st) < 0) {
        !          1289:                perror_reply(553, cp ? local : ".");
        !          1290:                return((char *) 0);
        !          1291:        }
        !          1292:        if (cp)
        !          1293:                *cp = '/';
        !          1294:        (void) strcpy(new, local);
        !          1295:        cp = new + strlen(new);
        !          1296:        *cp++ = '.';
        !          1297:        for (count = 1; count < 100; count++) {
        !          1298:                (void) sprintf(cp, "%d", count);
        !          1299:                if (stat(new, &st) < 0)
        !          1300:                        return(new);
        !          1301:        }
        !          1302:        reply(452, "Unique file name cannot be created.");
        !          1303:        return((char *) 0);
        !          1304: }
        !          1305:
        !          1306: /*
        !          1307:  * Format and send reply containing system error number.
        !          1308:  */
        !          1309: perror_reply(code, string)
        !          1310:        int code;
        !          1311:        char *string;
        !          1312: {
        !          1313:        reply(code, "%s: %s.", string, strerror(errno));
        !          1314: }
        !          1315:
        !          1316: static char *onefile[] = {
        !          1317:        "",
        !          1318:        0
        !          1319: };
        !          1320:
        !          1321: send_file_list(whichfiles)
        !          1322:        char *whichfiles;
        !          1323: {
        !          1324:        struct stat st;
        !          1325:        DIR *dirp = NULL;
        !          1326:        struct dirent *dir;
        !          1327:        FILE *dout = NULL;
        !          1328:        register char **dirlist, *dirname;
        !          1329:        int simple = 0;
        !          1330:        char *strpbrk();
        !          1331:
        !          1332:        if (strpbrk(whichfiles, "~{[*?") != NULL) {
        !          1333:                extern char **ftpglob(), *globerr;
        !          1334:
        !          1335:                globerr = NULL;
        !          1336:                dirlist = ftpglob(whichfiles);
        !          1337:                if (globerr != NULL) {
        !          1338:                        reply(550, globerr);
        !          1339:                        return;
        !          1340:                } else if (dirlist == NULL) {
        !          1341:                        errno = ENOENT;
        !          1342:                        perror_reply(550, whichfiles);
        !          1343:                        return;
        !          1344:                }
        !          1345:        } else {
        !          1346:                onefile[0] = whichfiles;
        !          1347:                dirlist = onefile;
        !          1348:                simple = 1;
        !          1349:        }
        !          1350:
        !          1351:        if (setjmp(urgcatch)) {
        !          1352:                transflag = 0;
        !          1353:                return;
        !          1354:        }
        !          1355:        while (dirname = *dirlist++) {
        !          1356:                if (stat(dirname, &st) < 0) {
        !          1357:                        /*
        !          1358:                         * If user typed "ls -l", etc, and the client
        !          1359:                         * used NLST, do what the user meant.
        !          1360:                         */
        !          1361:                        if (dirname[0] == '-' && *dirlist == NULL &&
        !          1362:                            transflag == 0) {
        !          1363:                                retrieve("/bin/ls %s", dirname);
        !          1364:                                return;
        !          1365:                        }
        !          1366:                        perror_reply(550, whichfiles);
        !          1367:                        if (dout != NULL) {
        !          1368:                                (void) fclose(dout);
        !          1369:                                transflag = 0;
        !          1370:                                data = -1;
        !          1371:                                pdata = -1;
        !          1372:                        }
        !          1373:                        return;
        !          1374:                }
        !          1375:
        !          1376:                if ((st.st_mode&S_IFMT) == S_IFREG) {
        !          1377:                        if (dout == NULL) {
        !          1378:                                dout = dataconn("file list", (off_t)-1, "w");
        !          1379:                                if (dout == NULL)
        !          1380:                                        return;
        !          1381:                                transflag++;
        !          1382:                        }
        !          1383:                        fprintf(dout, "%s%s\n", dirname,
        !          1384:                                type == TYPE_A ? "\r" : "");
        !          1385:                        byte_count += strlen(dirname) + 1;
        !          1386:                        continue;
        !          1387:                } else if ((st.st_mode&S_IFMT) != S_IFDIR)
        !          1388:                        continue;
        !          1389:
        !          1390:                if ((dirp = opendir(dirname)) == NULL)
        !          1391:                        continue;
        !          1392:
        !          1393:                while ((dir = readdir(dirp)) != NULL) {
        !          1394:                        char nbuf[MAXPATHLEN];
        !          1395:
        !          1396:                        if (dir->d_name[0] == '.' && dir->d_namlen == 1)
        !          1397:                                continue;
        !          1398:                        if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
        !          1399:                            dir->d_namlen == 2)
        !          1400:                                continue;
        !          1401:
        !          1402:                        sprintf(nbuf, "%s/%s", dirname, dir->d_name);
        !          1403:
        !          1404:                        /*
        !          1405:                         * We have to do a stat to insure it's
        !          1406:                         * not a directory or special file.
        !          1407:                         */
        !          1408:                        if (simple || (stat(nbuf, &st) == 0 &&
        !          1409:                            (st.st_mode&S_IFMT) == S_IFREG)) {
        !          1410:                                if (dout == NULL) {
        !          1411:                                        dout = dataconn("file list", (off_t)-1,
        !          1412:                                                "w");
        !          1413:                                        if (dout == NULL)
        !          1414:                                                return;
        !          1415:                                        transflag++;
        !          1416:                                }
        !          1417:                                if (nbuf[0] == '.' && nbuf[1] == '/')
        !          1418:                                        fprintf(dout, "%s%s\n", &nbuf[2],
        !          1419:                                                type == TYPE_A ? "\r" : "");
        !          1420:                                else
        !          1421:                                        fprintf(dout, "%s%s\n", nbuf,
        !          1422:                                                type == TYPE_A ? "\r" : "");
        !          1423:                                byte_count += strlen(nbuf) + 1;
        !          1424:                        }
        !          1425:                }
        !          1426:                (void) closedir(dirp);
        !          1427:        }
        !          1428:
        !          1429:        if (dout == NULL)
        !          1430:                reply(550, "No files found.");
        !          1431:        else if (ferror(dout) != 0)
        !          1432:                perror_reply(550, "Data connection");
        !          1433:        else
        !          1434:                reply(226, "Transfer complete.");
        !          1435:
        !          1436:        transflag = 0;
        !          1437:        if (dout != NULL)
        !          1438:                (void) fclose(dout);
        !          1439:        data = -1;
        !          1440:        pdata = -1;
        !          1441: }
        !          1442:
        !          1443: #ifdef SETPROCTITLE
        !          1444: /*
        !          1445:  * clobber argv so ps will show what we're doing.
        !          1446:  * (stolen from sendmail)
        !          1447:  * warning, since this is usually started from inetd.conf, it
        !          1448:  * often doesn't have much of an environment or arglist to overwrite.
        !          1449:  */
        !          1450:
        !          1451: /*VARARGS1*/
        !          1452: setproctitle(fmt, a, b, c)
        !          1453: char *fmt;
        !          1454: {
        !          1455:        register char *p, *bp, ch;
        !          1456:        register int i;
        !          1457:        char buf[BUFSIZ];
        !          1458:
        !          1459:        (void) sprintf(buf, fmt, a, b, c);
        !          1460:
        !          1461:        /* make ps print our process name */
        !          1462:        p = Argv[0];
        !          1463:        *p++ = '-';
        !          1464:
        !          1465:        i = strlen(buf);
        !          1466:        if (i > LastArgv - p - 2) {
        !          1467:                i = LastArgv - p - 2;
        !          1468:                buf[i] = '\0';
        !          1469:        }
        !          1470:        bp = buf;
        !          1471:        while (ch = *bp++)
        !          1472:                if (ch != '\n' && ch != '\r')
        !          1473:                        *p++ = ch;
        !          1474:        while (p < LastArgv)
        !          1475:                *p++ = ' ';
        !          1476: }
        !          1477: #endif /* SETPROCTITLE */

CVSweb <webmaster@jp.NetBSD.org>