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

1.1       root        1: /*
                      2:  * Copyright (c) 1985 Regents of the University of California.
                      3:  * All rights reserved.
                      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.