Annotation of 43BSD/etc/ftpd/ftpd.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1985 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: char copyright[] =
                      9: "@(#) Copyright (c) 1985 Regents of the University of California.\n\
                     10:  All rights reserved.\n";
                     11: #endif not lint
                     12: 
                     13: #ifndef lint
                     14: static char sccsid[] = "@(#)ftpd.c     5.7 (Berkeley) 5/28/86";
                     15: #endif not lint
                     16: 
                     17: /*
                     18:  * FTP server.
                     19:  */
                     20: #include <sys/param.h>
                     21: #include <sys/stat.h>
                     22: #include <sys/ioctl.h>
                     23: #include <sys/socket.h>
                     24: #include <sys/file.h>
                     25: #include <sys/wait.h>
                     26: 
                     27: #include <netinet/in.h>
                     28: 
                     29: #include <arpa/ftp.h>
                     30: #include <arpa/inet.h>
                     31: #include <arpa/telnet.h>
                     32: 
                     33: #include <stdio.h>
                     34: #include <signal.h>
                     35: #include <pwd.h>
                     36: #include <setjmp.h>
                     37: #include <netdb.h>
                     38: #include <errno.h>
                     39: #include <strings.h>
                     40: #include <syslog.h>
                     41: 
                     42: /*
                     43:  * File containing login names
                     44:  * NOT to be used on this machine.
                     45:  * Commonly used to disallow uucp.
                     46:  */
                     47: #define        FTPUSERS        "/etc/ftpusers"
                     48: 
                     49: extern int errno;
                     50: extern char *sys_errlist[];
                     51: extern char *crypt();
                     52: extern char version[];
                     53: extern char *home;             /* pointer to home directory for glob */
                     54: extern FILE *popen(), *fopen(), *freopen();
                     55: extern int  pclose(), fclose();
                     56: extern char *getline();
                     57: extern char cbuf[];
                     58: 
                     59: struct sockaddr_in ctrl_addr;
                     60: struct sockaddr_in data_source;
                     61: struct sockaddr_in data_dest;
                     62: struct sockaddr_in his_addr;
                     63: 
                     64: int    data;
                     65: jmp_buf        errcatch, urgcatch;
                     66: int    logged_in;
                     67: struct passwd *pw;
                     68: int    debug;
                     69: int    timeout = 900;    /* timeout after 15 minutes of inactivity */
                     70: int    logging;
                     71: int    guest;
                     72: int    wtmp;
                     73: int    type;
                     74: int    form;
                     75: int    stru;                   /* avoid C keyword */
                     76: int    mode;
                     77: int    usedefault = 1;         /* for data transfers */
                     78: int    pdata;                  /* for passive mode */
                     79: int    unique;
                     80: int    transflag;
                     81: char   tmpline[7];
                     82: char   hostname[32];
                     83: char   remotehost[32];
                     84: 
                     85: /*
                     86:  * Timeout intervals for retrying connections
                     87:  * to hosts that don't accept PORT cmds.  This
                     88:  * is a kludge, but given the problems with TCP...
                     89:  */
                     90: #define        SWAITMAX        90      /* wait at most 90 seconds */
                     91: #define        SWAITINT        5       /* interval between retries */
                     92: 
                     93: int    swaitmax = SWAITMAX;
                     94: int    swaitint = SWAITINT;
                     95: 
                     96: int    lostconn();
                     97: int    myoob();
                     98: FILE   *getdatasock(), *dataconn();
                     99: 
                    100: main(argc, argv)
                    101:        int argc;
                    102:        char *argv[];
                    103: {
                    104:        int addrlen, on = 1;
                    105:        long pgid;
                    106:        char *cp;
                    107: 
                    108:        addrlen = sizeof (his_addr);
                    109:        if (getpeername(0, &his_addr, &addrlen) < 0) {
                    110:                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
                    111:                exit(1);
                    112:        }
                    113:        addrlen = sizeof (ctrl_addr);
                    114:        if (getsockname(0, (char *) &ctrl_addr, &addrlen) < 0) {
                    115:                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
                    116:                exit(1);
                    117:        }
                    118:        data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
                    119:        debug = 0;
                    120:        openlog("ftpd", LOG_PID, LOG_DAEMON);
                    121:        argc--, argv++;
                    122:        while (argc > 0 && *argv[0] == '-') {
                    123:                for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
                    124: 
                    125:                case 'v':
                    126:                        debug = 1;
                    127:                        break;
                    128: 
                    129:                case 'd':
                    130:                        debug = 1;
                    131:                        break;
                    132: 
                    133:                case 'l':
                    134:                        logging = 1;
                    135:                        break;
                    136: 
                    137:                case 't':
                    138:                        timeout = atoi(++cp);
                    139:                        goto nextopt;
                    140:                        break;
                    141: 
                    142:                default:
                    143:                        fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
                    144:                             *cp);
                    145:                        break;
                    146:                }
                    147: nextopt:
                    148:                argc--, argv++;
                    149:        }
                    150:        (void) signal(SIGPIPE, lostconn);
                    151:        (void) signal(SIGCHLD, SIG_IGN);
                    152:        if (signal(SIGURG, myoob) < 0) {
                    153:                syslog(LOG_ERR, "signal: %m");
                    154:        }
                    155:        /* handle urgent data inline */
                    156: #ifdef SO_OOBINLINE
                    157:        if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) {
                    158:                syslog(LOG_ERR, "setsockopt: %m");
                    159:        }
                    160: #endif SO_OOBINLINE
                    161:        pgid = getpid();
                    162:        if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
                    163:                syslog(LOG_ERR, "ioctl: %m");
                    164:        }
                    165:        dolog(&his_addr);
                    166:        /* do telnet option negotiation here */
                    167:        /*
                    168:         * Set up default state
                    169:         */
                    170:        logged_in = 0;
                    171:        data = -1;
                    172:        type = TYPE_A;
                    173:        form = FORM_N;
                    174:        stru = STRU_F;
                    175:        mode = MODE_S;
                    176:        tmpline[0] = '\0';
                    177:        (void) gethostname(hostname, sizeof (hostname));
                    178:        reply(220, "%s FTP server (%s) ready.",
                    179:                hostname, version);
                    180:        for (;;) {
                    181:                (void) setjmp(errcatch);
                    182:                (void) yyparse();
                    183:        }
                    184: }
                    185: 
                    186: lostconn()
                    187: {
                    188: 
                    189:        if (debug)
                    190:                syslog(LOG_DEBUG, "lost connection");
                    191:        dologout(-1);
                    192: }
                    193: 
                    194: pass(passwd)
                    195:        char *passwd;
                    196: {
                    197:        char *xpasswd, *savestr();
                    198:        static struct passwd save;
                    199: 
                    200:        if (logged_in || pw == NULL) {
                    201:                reply(503, "Login with USER first.");
                    202:                return;
                    203:        }
                    204:        if (!guest) {           /* "ftp" is only account allowed no password */
                    205:                xpasswd = crypt(passwd, pw->pw_passwd);
                    206:                /* The strcmp does not catch null passwords! */
                    207:                if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
                    208:                        reply(530, "Login incorrect.");
                    209:                        pw = NULL;
                    210:                        return;
                    211:                }
                    212:        }
                    213:        setegid(pw->pw_gid);
                    214:        initgroups(pw->pw_name, pw->pw_gid);
                    215:        if (chdir(pw->pw_dir)) {
                    216:                reply(530, "User %s: can't change directory to %s.",
                    217:                        pw->pw_name, pw->pw_dir);
                    218:                goto bad;
                    219:        }
                    220: 
                    221:        /* grab wtmp before chroot */
                    222:        wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
                    223:        if (guest && chroot(pw->pw_dir) < 0) {
                    224:                reply(550, "Can't set guest privileges.");
                    225:                if (wtmp >= 0) {
                    226:                        (void) close(wtmp);
                    227:                        wtmp = -1;
                    228:                }
                    229:                goto bad;
                    230:        }
                    231:        if (!guest)
                    232:                reply(230, "User %s logged in.", pw->pw_name);
                    233:        else
                    234:                reply(230, "Guest login ok, access restrictions apply.");
                    235:        logged_in = 1;
                    236:        dologin(pw);
                    237:        seteuid(pw->pw_uid);
                    238:        /*
                    239:         * Save everything so globbing doesn't
                    240:         * clobber the fields.
                    241:         */
                    242:        save = *pw;
                    243:        save.pw_name = savestr(pw->pw_name);
                    244:        save.pw_passwd = savestr(pw->pw_passwd);
                    245:        save.pw_comment = savestr(pw->pw_comment);
                    246:        save.pw_gecos = savestr(pw->pw_gecos);
                    247:        save.pw_dir = savestr(pw->pw_dir);
                    248:        save.pw_shell = savestr(pw->pw_shell);
                    249:        pw = &save;
                    250:        home = pw->pw_dir;              /* home dir for globbing */
                    251:        return;
                    252: bad:
                    253:        seteuid(0);
                    254:        pw = NULL;
                    255: }
                    256: 
                    257: char *
                    258: savestr(s)
                    259:        char *s;
                    260: {
                    261:        char *malloc();
                    262:        char *new = malloc((unsigned) strlen(s) + 1);
                    263:        
                    264:        if (new != NULL)
                    265:                (void) strcpy(new, s);
                    266:        return (new);
                    267: }
                    268: 
                    269: retrieve(cmd, name)
                    270:        char *cmd, *name;
                    271: {
                    272:        FILE *fin, *dout;
                    273:        struct stat st;
                    274:        int (*closefunc)(), tmp;
                    275: 
                    276:        if (cmd == 0) {
                    277: #ifdef notdef
                    278:                /* no remote command execution -- it's a security hole */
                    279:                if (*name == '|')
                    280:                        fin = popen(name + 1, "r"), closefunc = pclose;
                    281:                else
                    282: #endif
                    283:                        fin = fopen(name, "r"), closefunc = fclose;
                    284:        } else {
                    285:                char line[BUFSIZ];
                    286: 
                    287:                (void) sprintf(line, cmd, name), name = line;
                    288:                fin = popen(line, "r"), closefunc = pclose;
                    289:        }
                    290:        if (fin == NULL) {
                    291:                if (errno != 0)
                    292:                        reply(550, "%s: %s.", name, sys_errlist[errno]);
                    293:                return;
                    294:        }
                    295:        st.st_size = 0;
                    296:        if (cmd == 0 &&
                    297:            (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
                    298:                reply(550, "%s: not a plain file.", name);
                    299:                goto done;
                    300:        }
                    301:        dout = dataconn(name, st.st_size, "w");
                    302:        if (dout == NULL)
                    303:                goto done;
                    304:        if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
                    305:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    306:        }
                    307:        else if (tmp == 0) {
                    308:                reply(226, "Transfer complete.");
                    309:        }
                    310:        (void) fclose(dout);
                    311:        data = -1;
                    312:        pdata = -1;
                    313: done:
                    314:        (*closefunc)(fin);
                    315: }
                    316: 
                    317: store(name, mode)
                    318:        char *name, *mode;
                    319: {
                    320:        FILE *fout, *din;
                    321:        int (*closefunc)(), dochown = 0, tmp;
                    322:        char *gunique(), *local;
                    323: 
                    324: #ifdef notdef
                    325:        /* no remote command execution -- it's a security hole */
                    326:        if (name[0] == '|')
                    327:                fout = popen(&name[1], "w"), closefunc = pclose;
                    328:        else
                    329: #endif
                    330:        {
                    331:                struct stat st;
                    332: 
                    333:                local = name;
                    334:                if (stat(name, &st) < 0) {
                    335:                        dochown++;
                    336:                }
                    337:                else if (unique) {
                    338:                        if ((local = gunique(name)) == NULL) {
                    339:                                return;
                    340:                        }
                    341:                        dochown++;
                    342:                }
                    343:                fout = fopen(local, mode), closefunc = fclose;
                    344:        }
                    345:        if (fout == NULL) {
                    346:                reply(553, "%s: %s.", local, sys_errlist[errno]);
                    347:                return;
                    348:        }
                    349:        din = dataconn(local, (off_t)-1, "r");
                    350:        if (din == NULL)
                    351:                goto done;
                    352:        if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) {
                    353:                reply(552, "%s: %s.", local, sys_errlist[errno]);
                    354:        }
                    355:        else if (tmp == 0 && !unique) {
                    356:                reply(226, "Transfer complete.");
                    357:        }
                    358:        else if (tmp == 0 && unique) {
                    359:                reply(226, "Transfer complete (unique file name:%s).", local);
                    360:        }
                    361:        (void) fclose(din);
                    362:        data = -1;
                    363:        pdata = -1;
                    364: done:
                    365:        if (dochown)
                    366:                (void) chown(local, pw->pw_uid, -1);
                    367:        (*closefunc)(fout);
                    368: }
                    369: 
                    370: FILE *
                    371: getdatasock(mode)
                    372:        char *mode;
                    373: {
                    374:        int s, on = 1;
                    375: 
                    376:        if (data >= 0)
                    377:                return (fdopen(data, mode));
                    378:        s = socket(AF_INET, SOCK_STREAM, 0);
                    379:        if (s < 0)
                    380:                return (NULL);
                    381:        seteuid(0);
                    382:        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0)
                    383:                goto bad;
                    384:        /* anchor socket to avoid multi-homing problems */
                    385:        data_source.sin_family = AF_INET;
                    386:        data_source.sin_addr = ctrl_addr.sin_addr;
                    387:        if (bind(s, &data_source, sizeof (data_source)) < 0)
                    388:                goto bad;
                    389:        seteuid(pw->pw_uid);
                    390:        return (fdopen(s, mode));
                    391: bad:
                    392:        seteuid(pw->pw_uid);
                    393:        (void) close(s);
                    394:        return (NULL);
                    395: }
                    396: 
                    397: FILE *
                    398: dataconn(name, size, mode)
                    399:        char *name;
                    400:        off_t size;
                    401:        char *mode;
                    402: {
                    403:        char sizebuf[32];
                    404:        FILE *file;
                    405:        int retry = 0;
                    406: 
                    407:        if (size >= 0)
                    408:                (void) sprintf (sizebuf, " (%ld bytes)", size);
                    409:        else
                    410:                (void) strcpy(sizebuf, "");
                    411:        if (pdata > 0) {
                    412:                struct sockaddr_in from;
                    413:                int s, fromlen = sizeof(from);
                    414: 
                    415:                s = accept(pdata, &from, &fromlen);
                    416:                if (s < 0) {
                    417:                        reply(425, "Can't open data connection.");
                    418:                        (void) close(pdata);
                    419:                        pdata = -1;
                    420:                        return(NULL);
                    421:                }
                    422:                (void) close(pdata);
                    423:                pdata = s;
                    424:                reply(150, "Openning data connection for %s (%s,%d)%s.",
                    425:                     name, inet_ntoa(from.sin_addr),
                    426:                     ntohs(from.sin_port), sizebuf);
                    427:                return(fdopen(pdata, mode));
                    428:        }
                    429:        if (data >= 0) {
                    430:                reply(125, "Using existing data connection for %s%s.",
                    431:                    name, sizebuf);
                    432:                usedefault = 1;
                    433:                return (fdopen(data, mode));
                    434:        }
                    435:        if (usedefault)
                    436:                data_dest = his_addr;
                    437:        usedefault = 1;
                    438:        file = getdatasock(mode);
                    439:        if (file == NULL) {
                    440:                reply(425, "Can't create data socket (%s,%d): %s.",
                    441:                    inet_ntoa(data_source.sin_addr),
                    442:                    ntohs(data_source.sin_port),
                    443:                    sys_errlist[errno]);
                    444:                return (NULL);
                    445:        }
                    446:        data = fileno(file);
                    447:        while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
                    448:                if (errno == EADDRINUSE && retry < swaitmax) {
                    449:                        sleep((unsigned) swaitint);
                    450:                        retry += swaitint;
                    451:                        continue;
                    452:                }
                    453:                reply(425, "Can't build data connection: %s.",
                    454:                    sys_errlist[errno]);
                    455:                (void) fclose(file);
                    456:                data = -1;
                    457:                return (NULL);
                    458:        }
                    459:        reply(150, "Opening data connection for %s (%s,%d)%s.",
                    460:            name, inet_ntoa(data_dest.sin_addr),
                    461:            ntohs(data_dest.sin_port), sizebuf);
                    462:        return (file);
                    463: }
                    464: 
                    465: /*
                    466:  * Tranfer the contents of "instr" to
                    467:  * "outstr" peer using the appropriate
                    468:  * encapulation of the date subject
                    469:  * to Mode, Structure, and Type.
                    470:  *
                    471:  * NB: Form isn't handled.
                    472:  */
                    473: send_data(instr, outstr)
                    474:        FILE *instr, *outstr;
                    475: {
                    476:        register int c;
                    477:        int netfd, filefd, cnt;
                    478:        char buf[BUFSIZ];
                    479: 
                    480:        transflag++;
                    481:        if (setjmp(urgcatch)) {
                    482:                transflag = 0;
                    483:                return(-1);
                    484:        }
                    485:        switch (type) {
                    486: 
                    487:        case TYPE_A:
                    488:                while ((c = getc(instr)) != EOF) {
                    489:                        if (c == '\n') {
                    490:                                if (ferror (outstr)) {
                    491:                                        transflag = 0;
                    492:                                        return (1);
                    493:                                }
                    494:                                (void) putc('\r', outstr);
                    495:                        }
                    496:                        (void) putc(c, outstr);
                    497:                /*      if (c == '\r')                  */
                    498:                /*              putc ('\0', outstr);    */
                    499:                }
                    500:                transflag = 0;
                    501:                if (ferror (instr) || ferror (outstr)) {
                    502:                        return (1);
                    503:                }
                    504:                return (0);
                    505:                
                    506:        case TYPE_I:
                    507:        case TYPE_L:
                    508:                netfd = fileno(outstr);
                    509:                filefd = fileno(instr);
                    510: 
                    511:                while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
                    512:                        if (write(netfd, buf, cnt) < 0) {
                    513:                                transflag = 0;
                    514:                                return (1);
                    515:                        }
                    516:                }
                    517:                transflag = 0;
                    518:                return (cnt < 0);
                    519:        }
                    520:        reply(550, "Unimplemented TYPE %d in send_data", type);
                    521:        transflag = 0;
                    522:        return (-1);
                    523: }
                    524: 
                    525: /*
                    526:  * Transfer data from peer to
                    527:  * "outstr" using the appropriate
                    528:  * encapulation of the data subject
                    529:  * to Mode, Structure, and Type.
                    530:  *
                    531:  * N.B.: Form isn't handled.
                    532:  */
                    533: receive_data(instr, outstr)
                    534:        FILE *instr, *outstr;
                    535: {
                    536:        register int c;
                    537:        int cnt;
                    538:        char buf[BUFSIZ];
                    539: 
                    540: 
                    541:        transflag++;
                    542:        if (setjmp(urgcatch)) {
                    543:                transflag = 0;
                    544:                return(-1);
                    545:        }
                    546:        switch (type) {
                    547: 
                    548:        case TYPE_I:
                    549:        case TYPE_L:
                    550:                while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
                    551:                        if (write(fileno(outstr), buf, cnt) < 0) {
                    552:                                transflag = 0;
                    553:                                return (1);
                    554:                        }
                    555:                }
                    556:                transflag = 0;
                    557:                return (cnt < 0);
                    558: 
                    559:        case TYPE_E:
                    560:                reply(553, "TYPE E not implemented.");
                    561:                transflag = 0;
                    562:                return (-1);
                    563: 
                    564:        case TYPE_A:
                    565:                while ((c = getc(instr)) != EOF) {
                    566:                        while (c == '\r') {
                    567:                                if (ferror (outstr)) {
                    568:                                        transflag = 0;
                    569:                                        return (1);
                    570:                                }
                    571:                                if ((c = getc(instr)) != '\n')
                    572:                                        (void) putc ('\r', outstr);
                    573:                        /*      if (c == '\0')                  */
                    574:                        /*              continue;               */
                    575:                        }
                    576:                        (void) putc (c, outstr);
                    577:                }
                    578:                transflag = 0;
                    579:                if (ferror (instr) || ferror (outstr))
                    580:                        return (1);
                    581:                return (0);
                    582:        }
                    583:        transflag = 0;
                    584:        fatal("Unknown type in receive_data.");
                    585:        /*NOTREACHED*/
                    586: }
                    587: 
                    588: fatal(s)
                    589:        char *s;
                    590: {
                    591:        reply(451, "Error in server: %s\n", s);
                    592:        reply(221, "Closing connection due to server error.");
                    593:        dologout(0);
                    594: }
                    595: 
                    596: /*VARARGS2*/
                    597: reply(n, s, args)
                    598:        int n;
                    599:        char *s;
                    600: {
                    601: 
                    602:        printf("%d ", n);
                    603:        _doprnt(s, &args, stdout);
                    604:        printf("\r\n");
                    605:        (void) fflush(stdout);
                    606:        if (debug) {
                    607:                syslog(LOG_DEBUG, "<--- %d ", n);
                    608:                syslog(LOG_DEBUG, s, &args);
                    609:        }
                    610: }
                    611: 
                    612: /*VARARGS2*/
                    613: lreply(n, s, args)
                    614:        int n;
                    615:        char *s;
                    616: {
                    617:        printf("%d-", n);
                    618:        _doprnt(s, &args, stdout);
                    619:        printf("\r\n");
                    620:        (void) fflush(stdout);
                    621:        if (debug) {
                    622:                syslog(LOG_DEBUG, "<--- %d- ", n);
                    623:                syslog(LOG_DEBUG, s, &args);
                    624:        }
                    625: }
                    626: 
                    627: ack(s)
                    628:        char *s;
                    629: {
                    630:        reply(250, "%s command successful.", s);
                    631: }
                    632: 
                    633: nack(s)
                    634:        char *s;
                    635: {
                    636:        reply(502, "%s command not implemented.", s);
                    637: }
                    638: 
                    639: yyerror(s)
                    640:        char *s;
                    641: {
                    642:        char *cp;
                    643: 
                    644:        cp = index(cbuf,'\n');
                    645:        *cp = '\0';
                    646:        reply(500, "'%s': command not understood.",cbuf);
                    647: }
                    648: 
                    649: delete(name)
                    650:        char *name;
                    651: {
                    652:        struct stat st;
                    653: 
                    654:        if (stat(name, &st) < 0) {
                    655:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    656:                return;
                    657:        }
                    658:        if ((st.st_mode&S_IFMT) == S_IFDIR) {
                    659:                if (rmdir(name) < 0) {
                    660:                        reply(550, "%s: %s.", name, sys_errlist[errno]);
                    661:                        return;
                    662:                }
                    663:                goto done;
                    664:        }
                    665:        if (unlink(name) < 0) {
                    666:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    667:                return;
                    668:        }
                    669: done:
                    670:        ack("DELE");
                    671: }
                    672: 
                    673: cwd(path)
                    674:        char *path;
                    675: {
                    676: 
                    677:        if (chdir(path) < 0) {
                    678:                reply(550, "%s: %s.", path, sys_errlist[errno]);
                    679:                return;
                    680:        }
                    681:        ack("CWD");
                    682: }
                    683: 
                    684: makedir(name)
                    685:        char *name;
                    686: {
                    687:        struct stat st;
                    688:        int dochown = stat(name, &st) < 0;
                    689:        
                    690:        if (mkdir(name, 0777) < 0) {
                    691:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    692:                return;
                    693:        }
                    694:        if (dochown)
                    695:                (void) chown(name, pw->pw_uid, -1);
                    696:        reply(257, "MKD command successful.");
                    697: }
                    698: 
                    699: removedir(name)
                    700:        char *name;
                    701: {
                    702: 
                    703:        if (rmdir(name) < 0) {
                    704:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    705:                return;
                    706:        }
                    707:        ack("RMD");
                    708: }
                    709: 
                    710: pwd()
                    711: {
                    712:        char path[MAXPATHLEN + 1];
                    713: 
                    714:        if (getwd(path) == NULL) {
                    715:                reply(550, "%s.", path);
                    716:                return;
                    717:        }
                    718:        reply(257, "\"%s\" is current directory.", path);
                    719: }
                    720: 
                    721: char *
                    722: renamefrom(name)
                    723:        char *name;
                    724: {
                    725:        struct stat st;
                    726: 
                    727:        if (stat(name, &st) < 0) {
                    728:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    729:                return ((char *)0);
                    730:        }
                    731:        reply(350, "File exists, ready for destination name");
                    732:        return (name);
                    733: }
                    734: 
                    735: renamecmd(from, to)
                    736:        char *from, *to;
                    737: {
                    738: 
                    739:        if (rename(from, to) < 0) {
                    740:                reply(550, "rename: %s.", sys_errlist[errno]);
                    741:                return;
                    742:        }
                    743:        ack("RNTO");
                    744: }
                    745: 
                    746: dolog(sin)
                    747:        struct sockaddr_in *sin;
                    748: {
                    749:        struct hostent *hp = gethostbyaddr(&sin->sin_addr,
                    750:                sizeof (struct in_addr), AF_INET);
                    751:        time_t t;
                    752:        extern char *ctime();
                    753: 
                    754:        if (hp) {
                    755:                (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
                    756:                endhostent();
                    757:        } else
                    758:                (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
                    759:                    sizeof (remotehost));
                    760:        if (!logging)
                    761:                return;
                    762:        t = time((time_t *) 0);
                    763:        syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, ctime(&t));
                    764: }
                    765: 
                    766: #include <utmp.h>
                    767: 
                    768: #define        SCPYN(a, b)     (void) strncpy(a, b, sizeof (a))
                    769: struct utmp utmp;
                    770: 
                    771: /*
                    772:  * Record login in wtmp file.
                    773:  */
                    774: dologin(pw)
                    775:        struct passwd *pw;
                    776: {
                    777:        char line[32];
                    778: 
                    779:        if (wtmp >= 0) {
                    780:                /* hack, but must be unique and no tty line */
                    781:                (void) sprintf(line, "ftp%d", getpid());
                    782:                SCPYN(utmp.ut_line, line);
                    783:                SCPYN(utmp.ut_name, pw->pw_name);
                    784:                SCPYN(utmp.ut_host, remotehost);
                    785:                utmp.ut_time = (long) time((time_t *) 0);
                    786:                (void) write(wtmp, (char *)&utmp, sizeof (utmp));
                    787:                if (!guest) {           /* anon must hang on */
                    788:                        (void) close(wtmp);
                    789:                        wtmp = -1;
                    790:                }
                    791:        }
                    792: }
                    793: 
                    794: /*
                    795:  * Record logout in wtmp file
                    796:  * and exit with supplied status.
                    797:  */
                    798: dologout(status)
                    799:        int status;
                    800: {
                    801: 
                    802:        if (logged_in) {
                    803:                (void) seteuid(0);
                    804:                if (wtmp < 0)
                    805:                        wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
                    806:                if (wtmp >= 0) {
                    807:                        SCPYN(utmp.ut_name, "");
                    808:                        SCPYN(utmp.ut_host, "");
                    809:                        utmp.ut_time = (long) time((time_t *) 0);
                    810:                        (void) write(wtmp, (char *)&utmp, sizeof (utmp));
                    811:                        (void) close(wtmp);
                    812:                }
                    813:        }
                    814:        /* beware of flushing buffers after a SIGPIPE */
                    815:        _exit(status);
                    816: }
                    817: 
                    818: /*
                    819:  * Special version of popen which avoids
                    820:  * call to shell.  This insures noone may 
                    821:  * create a pipe to a hidden program as a side
                    822:  * effect of a list or dir command.
                    823:  */
                    824: #define        tst(a,b)        (*mode == 'r'? (b) : (a))
                    825: #define        RDR     0
                    826: #define        WTR     1
                    827: static int popen_pid[5];
                    828: 
                    829: static char *
                    830: nextarg(cpp)
                    831:        char *cpp;
                    832: {
                    833:        register char *cp = cpp;
                    834: 
                    835:        if (cp == 0)
                    836:                return (cp);
                    837:        while (*cp && *cp != ' ' && *cp != '\t')
                    838:                cp++;
                    839:        if (*cp == ' ' || *cp == '\t') {
                    840:                *cp++ = '\0';
                    841:                while (*cp == ' ' || *cp == '\t')
                    842:                        cp++;
                    843:        }
                    844:        if (cp == cpp)
                    845:                return ((char *)0);
                    846:        return (cp);
                    847: }
                    848: 
                    849: FILE *
                    850: popen(cmd, mode)
                    851:        char *cmd, *mode;
                    852: {
                    853:        int p[2], ac, gac;
                    854:        register myside, hisside, pid;
                    855:        char *av[20], *gav[512];
                    856:        register char *cp;
                    857: 
                    858:        if (pipe(p) < 0)
                    859:                return (NULL);
                    860:        cp = cmd, ac = 0;
                    861:        /* break up string into pieces */
                    862:        do {
                    863:                av[ac++] = cp;
                    864:                cp = nextarg(cp);
                    865:        } while (cp && *cp && ac < 20);
                    866:        av[ac] = (char *)0;
                    867:        gav[0] = av[0];
                    868:        /* glob each piece */
                    869:        for (gac = ac = 1; av[ac] != NULL; ac++) {
                    870:                char **pop;
                    871:                extern char **glob(), **copyblk();
                    872: 
                    873:                pop = glob(av[ac]);
                    874:                if (pop == (char **)NULL) {     /* globbing failed */
                    875:                        char *vv[2];
                    876: 
                    877:                        vv[0] = av[ac];
                    878:                        vv[1] = 0;
                    879:                        pop = copyblk(vv);
                    880:                }
                    881:                av[ac] = (char *)pop;           /* save to free later */
                    882:                while (*pop && gac < 512)
                    883:                        gav[gac++] = *pop++;
                    884:        }
                    885:        gav[gac] = (char *)0;
                    886:        myside = tst(p[WTR], p[RDR]);
                    887:        hisside = tst(p[RDR], p[WTR]);
                    888:        if ((pid = fork()) == 0) {
                    889:                /* myside and hisside reverse roles in child */
                    890:                (void) close(myside);
                    891:                (void) dup2(hisside, tst(0, 1));
                    892:                (void) close(hisside);
                    893:                execv(gav[0], gav);
                    894:                _exit(1);
                    895:        }
                    896:        for (ac = 1; av[ac] != NULL; ac++)
                    897:                blkfree((char **)av[ac]);
                    898:        if (pid == -1)
                    899:                return (NULL);
                    900:        popen_pid[myside] = pid;
                    901:        (void) close(hisside);
                    902:        return (fdopen(myside, mode));
                    903: }
                    904: 
                    905: pclose(ptr)
                    906:        FILE *ptr;
                    907: {
                    908:        register f, r, (*hstat)(), (*istat)(), (*qstat)();
                    909:        int status;
                    910: 
                    911:        f = fileno(ptr);
                    912:        (void) fclose(ptr);
                    913:        istat = signal(SIGINT, SIG_IGN);
                    914:        qstat = signal(SIGQUIT, SIG_IGN);
                    915:        hstat = signal(SIGHUP, SIG_IGN);
                    916:        while ((r = wait(&status)) != popen_pid[f] && r != -1)
                    917:                ;
                    918:        if (r == -1)
                    919:                status = -1;
                    920:        (void) signal(SIGINT, istat);
                    921:        (void) signal(SIGQUIT, qstat);
                    922:        (void) signal(SIGHUP, hstat);
                    923:        return (status);
                    924: }
                    925: 
                    926: /*
                    927:  * Check user requesting login priviledges.
                    928:  * Disallow anyone who does not have a standard
                    929:  * shell returned by getusershell() (/etc/shells).
                    930:  * Disallow anyone mentioned in the file FTPUSERS
                    931:  * to allow people such as uucp to be avoided.
                    932:  */
                    933: checkuser(name)
                    934:        register char *name;
                    935: {
                    936:        register char *cp;
                    937:        char line[BUFSIZ], *index(), *getusershell();
                    938:        FILE *fd;
                    939:        struct passwd *pw;
                    940:        int found = 0;
                    941: 
                    942:        pw = getpwnam(name);
                    943:        if (pw == NULL)
                    944:                return (0);
                    945:        while ((cp = getusershell()) != NULL)
                    946:                if (strcmp(cp, pw->pw_shell) == 0)
                    947:                        break;
                    948:        endpwent();
                    949:        endusershell();
                    950:        if (cp == NULL)
                    951:                return (0);
                    952:        fd = fopen(FTPUSERS, "r");
                    953:        if (fd == NULL)
                    954:                return (1);
                    955:        while (fgets(line, sizeof (line), fd) != NULL) {
                    956:                cp = index(line, '\n');
                    957:                if (cp)
                    958:                        *cp = '\0';
                    959:                if (strcmp(line, name) == 0) {
                    960:                        found++;
                    961:                        break;
                    962:                }
                    963:        }
                    964:        (void) fclose(fd);
                    965:        return (!found);
                    966: }
                    967: 
                    968: myoob()
                    969: {
                    970:        char *cp;
                    971: 
                    972:        /* only process if transfer occurring */
                    973:        if (!transflag) {
                    974:                return;
                    975:        }
                    976:        cp = tmpline;
                    977:        if (getline(cp, 7, stdin) == NULL) {
                    978:                reply(221, "You could at least say goodby.");
                    979:                dologout(0);
                    980:        }
                    981:        upper(cp);
                    982:        if (strcmp(cp, "ABOR\r\n"))
                    983:                return;
                    984:        tmpline[0] = '\0';
                    985:        reply(426,"Transfer aborted. Data connection closed.");
                    986:        reply(226,"Abort successful");
                    987:        longjmp(urgcatch, 1);
                    988: }
                    989: 
                    990: /*
                    991:  * Note: The 530 reply codes could be 4xx codes, except nothing is
                    992:  * given in the state tables except 421 which implies an exit.  (RFC959)
                    993:  */
                    994: passive()
                    995: {
                    996:        int len;
                    997:        struct sockaddr_in tmp;
                    998:        register char *p, *a;
                    999: 
                   1000:        pdata = socket(AF_INET, SOCK_STREAM, 0);
                   1001:        if (pdata < 0) {
                   1002:                reply(530, "Can't open passive connection");
                   1003:                return;
                   1004:        }
                   1005:        tmp = ctrl_addr;
                   1006:        tmp.sin_port = 0;
                   1007:        seteuid(0);
                   1008:        if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
                   1009:                seteuid(pw->pw_uid);
                   1010:                (void) close(pdata);
                   1011:                pdata = -1;
                   1012:                reply(530, "Can't open passive connection");
                   1013:                return;
                   1014:        }
                   1015:        seteuid(pw->pw_uid);
                   1016:        len = sizeof(tmp);
                   1017:        if (getsockname(pdata, (char *) &tmp, &len) < 0) {
                   1018:                (void) close(pdata);
                   1019:                pdata = -1;
                   1020:                reply(530, "Can't open passive connection");
                   1021:                return;
                   1022:        }
                   1023:        if (listen(pdata, 1) < 0) {
                   1024:                (void) close(pdata);
                   1025:                pdata = -1;
                   1026:                reply(530, "Can't open passive connection");
                   1027:                return;
                   1028:        }
                   1029:        a = (char *) &tmp.sin_addr;
                   1030:        p = (char *) &tmp.sin_port;
                   1031: 
                   1032: #define UC(b) (((int) b) & 0xff)
                   1033: 
                   1034:        reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
                   1035:                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
                   1036: }
                   1037: 
                   1038: char *
                   1039: gunique(local)
                   1040:        char *local;
                   1041: {
                   1042:        static char new[MAXPATHLEN];
                   1043:        char *cp = rindex(local, '/');
                   1044:        int d, count=0;
                   1045:        char ext = '1';
                   1046: 
                   1047:        if (cp) {
                   1048:                *cp = '\0';
                   1049:        }
                   1050:        d = access(cp ? local : ".", 2);
                   1051:        if (cp) {
                   1052:                *cp = '/';
                   1053:        }
                   1054:        if (d < 0) {
                   1055:                syslog(LOG_ERR, "%s: %m", local);
                   1056:                return((char *) 0);
                   1057:        }
                   1058:        (void) strcpy(new, local);
                   1059:        cp = new + strlen(new);
                   1060:        *cp++ = '.';
                   1061:        while (!d) {
                   1062:                if (++count == 100) {
                   1063:                        reply(452, "Unique file name not cannot be created.");
                   1064:                        return((char *) 0);
                   1065:                }
                   1066:                *cp++ = ext;
                   1067:                *cp = '\0';
                   1068:                if (ext == '9') {
                   1069:                        ext = '0';
                   1070:                }
                   1071:                else {
                   1072:                        ext++;
                   1073:                }
                   1074:                if ((d = access(new, 0)) < 0) {
                   1075:                        break;
                   1076:                }
                   1077:                if (ext != '0') {
                   1078:                        cp--;
                   1079:                }
                   1080:                else if (*(cp - 2) == '.') {
                   1081:                        *(cp - 1) = '1';
                   1082:                }
                   1083:                else {
                   1084:                        *(cp - 2) = *(cp - 2) + 1;
                   1085:                        cp--;
                   1086:                }
                   1087:        }
                   1088:        return(new);
                   1089: }

unix.superglobalmegacorp.com

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