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

unix.superglobalmegacorp.com

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