Annotation of cci/usr/src/etc/ftpd/ftpd.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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