Annotation of 43BSDReno/libexec/ftpd/ftpd.c, revision 1.1.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.