Annotation of 43BSDTahoe/etc/ftpd/ftpd.c, revision 1.1

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

unix.superglobalmegacorp.com

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