Annotation of 43BSDReno/libexec/ftpd/ftpd.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.