Annotation of researchv10no/ipc/servers/ftpd.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char sccsid[] = "@(#)ftpd.c     4.28 (Berkeley) 9/22/83";
                      3: #endif
                      4: 
                      5: #define        CHOOSE_PORT
                      6: #define DEBUG
                      7: /*
                      8:  * FTP server.
                      9:  */
                     10: #include <sys/param.h>
                     11: #include <sys/stat.h>
                     12: #include <sys/file.h>
                     13: #include <wait.h>
                     14: 
                     15: #include <sys/inet/in.h>
                     16: #include <sys/inet/tcp_user.h>
                     17: 
                     18: #include <stdio.h>
                     19: #include <signal.h>
                     20: #include <pwd.h>
                     21: #include <setjmp.h>
                     22: #include <errno.h>
                     23: #include <utsname.h>
                     24: 
                     25: #include <libc.h>
                     26: 
                     27: #include "ftp.h"
                     28: 
                     29: /*
                     30:  * File containing login names
                     31:  * NOT to be used on this machine.
                     32:  * Commonly used to disallow uucp.
                     33:  */
                     34: #define CTLPORT                21
                     35: 
                     36: extern int errno;
                     37: extern char *sys_errlist[];
                     38: extern char *crypt();
                     39: extern FILE *popen(), *fopen();
                     40: extern int pclose(), fclose();
                     41: 
                     42: char   *defdest;
                     43: extern char    dest[];
                     44: 
                     45: int    data;
                     46: jmp_buf        errcatch;
                     47: int    logged_in;
                     48: struct passwd *pw;
                     49: int    debug;
                     50: int    timeout;
                     51: int    logging;
                     52: int    type;
                     53: int    form;
                     54: int    stru;                   /* avoid C keyword */
                     55: int    mode;
                     56: int    usedefault = 1;         /* for data transfers */
                     57: char   hostname[32];
                     58: char   remotehost[32];
                     59: int    pasv;
                     60: char   *home;          /* pointer to home directory for glob */
                     61: 
                     62: /*
                     63:  * Timeout intervals for retrying connections
                     64:  * to hosts that don't accept PORT cmds.  This
                     65:  * is a kludge, but given the problems with TCP...
                     66:  */
                     67: #define        SWAITMAX        90      /* wait at most 90 seconds */
                     68: #define        SWAITINT        5       /* interval between retries */
                     69: 
                     70: int    swaitmax = SWAITMAX;
                     71: int    swaitint = SWAITINT;
                     72: 
                     73: int    lostconn();
                     74: int    reapchild();
                     75: FILE   *dataconn();
                     76: 
                     77: main(argc, argv)
                     78:        int argc;
                     79:        char *argv[];
                     80: {
                     81:        int ctrl, s, options = 0;
                     82:        char *cp;
                     83:        int dev;
                     84:        int status;
                     85:        struct utsname uts;
                     86: 
                     87:        if(argc==2 && strcmp(argv[1], "-d")==0)
                     88:                debug = 1;
                     89: 
                     90:        signal(SIGPIPE, SIG_IGN); /* used to be lostconn */
                     91:        signal(SIGHUP, SIG_IGN);
                     92:        signal (SIGCHLD, SIG_IGN);
                     93: 
                     94:        /*
                     95:         *  get source address
                     96:         */
                     97:        getsource();
                     98: 
                     99:        /*
                    100:         * Set up default state
                    101:         */
                    102:        logged_in = 0;
                    103:        data = -1;
                    104:        type = TYPE_A;
                    105:        form = FORM_N;
                    106:        stru = STRU_F;
                    107:        mode = MODE_S;
                    108:        uname(&uts);
                    109:        strcpy(hostname, uts.sysname);
                    110:        reply(220, "%s FTP server ready.", hostname);
                    111:        for (;;) {
                    112:                setjmp(errcatch);
                    113:                yyparse();
                    114:                fprintf(stderr, "out of yyparse\n");
                    115:        }
                    116: }
                    117: 
                    118: /*
                    119:  *  parse the source string and extract system and network
                    120:  */
                    121: getsource()
                    122: {
                    123:        char *s;
                    124:        char *e;
                    125: 
                    126:        e = getenv("CSOURCE");
                    127:        if(e == 0){
                    128:                fprintf(stderr, "Can't get source address\n");
                    129:                exit(1);
                    130:        }
                    131:        s = strchr(e, ' ');
                    132:        if(s)
                    133:                *s = 0;
                    134:        defdest = e;
                    135: }
                    136: 
                    137: reapchild()
                    138: {
                    139:        union wait status;
                    140: 
                    141:        while (wait3(&status, WNOHANG, 0) > 0)
                    142:                ;
                    143: }
                    144: 
                    145: lostconn()
                    146: {
                    147: 
                    148:        if (debug)
                    149:                fprintf(stderr, "Lost connection.\n");
                    150:        dologout(-1);
                    151: }
                    152: 
                    153: pass(passwd)
                    154:        char *passwd;
                    155: {
                    156:        char *xpasswd, *savestr();
                    157:        static struct passwd save;
                    158: 
                    159:        if (logged_in) {
                    160:                reply(503, "already logged in.");
                    161:                return;
                    162:        }
                    163:        xpasswd = crypt(passwd, pw->pw_passwd);
                    164:        if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
                    165:                reply(530, "Login incorrect.");
                    166:                pw = NULL;
                    167:                return;
                    168:        }
                    169:        dologin(pw);
                    170:        setgid(pw->pw_gid);
                    171:        setuid(pw->pw_uid);
                    172:        if (chdir(pw->pw_dir)) {
                    173:                reply(550, "User %s: can't change directory to $s.",
                    174:                        pw->pw_name, pw->pw_dir);
                    175:                dologout(-1);
                    176:                exit(1);
                    177:        }
                    178:        logged_in = 1;
                    179:        /*
                    180:         * Save everything so globbing doesn't
                    181:         * clobber the fields.
                    182:         */
                    183:        save = *pw;
                    184:        save.pw_name = savestr(pw->pw_name);
                    185:        save.pw_passwd = savestr(pw->pw_passwd);
                    186:        save.pw_comment = savestr(pw->pw_comment);
                    187:        save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos);
                    188:        save.pw_dir = savestr(pw->pw_dir);
                    189:        save.pw_shell = savestr(pw->pw_shell);
                    190:        pw = &save;
                    191:        home = pw->pw_dir;              /* home dir for globbing */
                    192:        ack("login");
                    193:        return;
                    194: bad:
                    195:        pw = NULL;
                    196: }
                    197: 
                    198: char *
                    199: savestr(s)
                    200:        char *s;
                    201: {
                    202:        char *malloc();
                    203:        char *new = malloc(strlen(s) + 1);
                    204:        
                    205:        if (new != NULL)
                    206:                strcpy(new, s);
                    207:        return (new);
                    208: }
                    209: 
                    210: 
                    211: openfile(name)
                    212: char *name;
                    213: {
                    214:        reply(550, "%s: can't open", name);
                    215: }
                    216: 
                    217: pipette()
                    218: {
                    219:        signal(SIGPIPE, pipette);
                    220: }
                    221: 
                    222: retrieve(cmd, name)
                    223:        char *cmd, *name;
                    224: {
                    225:        FILE *fin, *dout;
                    226:        struct stat st;
                    227:        int (*closefunc)();
                    228: 
                    229:        if(!logged_in){
                    230:                reply(550, "%s: login required.", name);
                    231:                return;
                    232:        }
                    233:        if (cmd == 0) {
                    234:                fin = fopen(name, "r"), closefunc = fclose;
                    235:        } else {
                    236:                char line[BUFSIZ];
                    237: 
                    238:                sprintf(line, cmd, name), name = line;
                    239:                if(debug)
                    240:                        fprintf(stderr,"cmd is %s\n", line);
                    241:                fin = popen(line, "r"), closefunc = pclose;
                    242:        }
                    243:        if (fin == NULL) {
                    244:                if(debug)
                    245:                        fprintf(stderr, "bad popen()\n");
                    246:                if (errno != 0)
                    247:                        reply(550, "%s: %s.", name, sys_errlist[errno]);
                    248:                return;
                    249:        }
                    250: 
                    251:        st.st_size = 0;
                    252:        if (cmd == 0
                    253:        &&  (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
                    254:                reply(550, "%s: not a plain file.", name);
                    255:                goto done;
                    256:        }
                    257:        dout = dataconn(name, st.st_size, "w");
                    258:        if (dout == NULL)
                    259:                goto done;
                    260:        if (send_data(fin, dout) || ferror(dout))
                    261:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    262: 
                    263:        else {
                    264:                fclose(dout);
                    265:                delay(timeout);
                    266:                reply(226, "Transfer complete.");
                    267:        }
                    268:        data = -1;
                    269: done:
                    270:        (*closefunc)(fin);
                    271: }
                    272: 
                    273: store(name, mode)
                    274:        char *name, *mode;
                    275: {
                    276:        FILE *fout, *din;
                    277:        int (*closefunc)(), dochown = 0;
                    278: 
                    279:        if(!logged_in){
                    280:                reply(550, "%s: login required.", name);
                    281:                return;
                    282:        }
                    283:        fout = fopen(name, mode), closefunc = fclose;
                    284:        if (fout == NULL) {
                    285:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    286:                return;
                    287:        }
                    288:        din = dataconn(name, (off_t)-1, "r");
                    289:        if (din == NULL)
                    290:                goto done;
                    291:        if (receive_data(din, fout) || ferror(fout))
                    292:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    293:        else {
                    294:                fflush(fout);
                    295:                delay(timeout);
                    296:                reply(226, "Transfer complete.");
                    297:        }
                    298:        fclose(din);
                    299:        data = -1;
                    300: done:
                    301:        (*closefunc)(fout);
                    302: }
                    303: 
                    304: FILE *
                    305: dataconn(name, size, mode)
                    306:        char *name;
                    307:        off_t size;
                    308:        char *mode;
                    309: {
                    310:        char sizebuf[32];
                    311:        char dialstr[128];
                    312:        char params[32];
                    313:        FILE *file;
                    314:        int retries;
                    315: 
                    316:        if (size >= 0)
                    317:                sprintf (sizebuf, " (%ld bytes)", size);
                    318:        else
                    319:                (void) strcpy(sizebuf, "");
                    320: 
                    321:        if (data >= 0) {
                    322:                reply(125, "Using existing data connection for %s%s.",
                    323:                    name, sizebuf);
                    324:                usedefault = 1;
                    325:                return (fdopen(data, mode));
                    326:        }
                    327:        if (usedefault)
                    328:                sprintf(dialstr, "/cs/%s", defdest);
                    329:        else
                    330:                sprintf(dialstr, "/cs/%s", dest);
                    331: 
                    332:        /* make the connection */
                    333:        /*sprintf(params, "port=%d", pasv?0:(CTLPORT - 1));/**/
                    334:        for(retries=0; retries<5; retries++){
                    335:                data = ipcopen(dialstr, params);
                    336:                if(data>=0)
                    337:                        break;
                    338:                sleep(1);
                    339:        }
                    340:        if(data<0 || (file=fdopen(data, mode))==NULL){
                    341:                reply(425, "Can't open data socket (%s): %s.",
                    342:                        dialstr,
                    343:                        sys_errlist[errno]);
                    344:                return (NULL);
                    345:        }
                    346:        reply(150, "Opening data connection for %s (%s,%d)%s.",
                    347:                name,
                    348:                dialstr,
                    349:                sizebuf);
                    350:        return (file);
                    351: }
                    352: 
                    353: /*
                    354:  * Tranfer the contents of "instr" to
                    355:  * "outstr" peer using the appropriate
                    356:  * encapulation of the date subject
                    357:  * to Mode, Structure, and Type.
                    358:  *
                    359:  * NB: Form isn't handled.
                    360:  */
                    361: send_data(instr, outstr)
                    362:        FILE *instr, *outstr;
                    363: {
                    364:        register int c;
                    365:        int netfd, filefd, cnt = 0;
                    366:        char buf[BUFSIZ];
                    367: 
                    368:        signal(SIGPIPE, pipette);
                    369:        switch (type) {
                    370: 
                    371:        case TYPE_A:
                    372:                while ((c = getc(instr)) != EOF) {
                    373:                        if (c == '\n') {
                    374:                                if (ferror (outstr))
                    375:                                        return (1);
                    376:                                putc('\r', outstr);
                    377:                        }
                    378:                        putc(c, outstr);
                    379:                        if (c == '\r')
                    380:                                putc ('\0', outstr);
                    381: /*                     cnt++;
                    382:                        if (!(cnt%1000)) { fprintf(stderr, "%d ", cnt); fflush(stderr); } */
                    383:                }
                    384:                if (ferror (instr) || ferror (outstr)) {
                    385:                        fprintf(stderr,"error: inst %d, outstr %d\n", ferror(instr), ferror(outstr));
                    386:                        return (1);
                    387:                }
                    388:                return (0);
                    389:                
                    390:        case TYPE_I:
                    391:        case TYPE_L:
                    392:                netfd = fileno(outstr);
                    393:                filefd = fileno(instr);
                    394: 
                    395:                while ((cnt = read(filefd, buf, sizeof (buf))) > 0)
                    396:                        if (write(netfd, buf, cnt) < 0) {
                    397:                                fprintf(stderr, "write error, cnt=%d\n", cnt);
                    398:                                return (1);
                    399:                }
                    400:                return (cnt < 0);
                    401:        }
                    402:        reply(504,"Unimplemented TYPE %d in send_data", type);
                    403:        return (1);
                    404: }
                    405: 
                    406: /*
                    407:  * Transfer data from peer to
                    408:  * "outstr" using the appropriate
                    409:  * encapulation of the data subject
                    410:  * to Mode, Structure, and Type.
                    411:  *
                    412:  * N.B.: Form isn't handled.
                    413:  */
                    414: receive_data(instr, outstr)
                    415:        FILE *instr, *outstr;
                    416: {
                    417:        register int c;
                    418:        int cnt;
                    419:        char buf[BUFSIZ];
                    420: 
                    421: 
                    422:        signal(SIGPIPE, pipette);
                    423:        switch (type) {
                    424: 
                    425:        case TYPE_I:
                    426:        case TYPE_L:
                    427:                while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0)
                    428:                        if (write(fileno(outstr), buf, cnt) < 0)
                    429:                                return (1);
                    430:                return (cnt < 0);
                    431: 
                    432:        case TYPE_E:
                    433:                reply(504, "TYPE E not implemented.");
                    434:                return (1);
                    435: 
                    436:        case TYPE_A:
                    437:                while ((c = getc(instr)) != EOF) {
                    438:                        if (c == '\r') {
                    439:                                if (ferror (outstr))
                    440:                                        return (1);
                    441:                                if ((c = getc(instr)) != '\n')
                    442:                                        putc ('\r', outstr);
                    443:                                if (c == '\0')
                    444:                                        continue;
                    445:                        }
                    446:                        putc (c, outstr);
                    447:                }
                    448:                if (ferror (instr) || ferror (outstr))
                    449:                        return (1);
                    450:                return (0);
                    451:        }
                    452:        fatal("Unknown type in receive_data.");
                    453:        /*NOTREACHED*/
                    454: }
                    455: 
                    456: fatal(s)
                    457:        char *s;
                    458: {
                    459:        reply(451, "Error in server: %s\n", s);
                    460:        reply(221, "Closing connection due to server error.");
                    461:        dologout(0);
                    462: }
                    463: 
                    464: reply(n, s, args)
                    465:        int n;
                    466:        char *s;
                    467: {
                    468: 
                    469:        printf("%d ", n);
                    470:        _doprnt(s, &args, stdout);
                    471:        printf("\r\n");
                    472:        fflush(stdout);
                    473:        if (debug) {
                    474:                fprintf(stderr, "<--- %d ", n);
                    475:                _doprnt(s, &args, stderr);
                    476:                fprintf(stderr, "\n");
                    477:                fflush(stderr);
                    478:        }
                    479: }
                    480: 
                    481: lreply(n, s, args)
                    482:        int n;
                    483:        char *s;
                    484: {
                    485:        printf("%d-", n);
                    486:        _doprnt(s, &args, stdout);
                    487:        printf("\r\n");
                    488:        fflush(stdout);
                    489:        if (debug) {
                    490:                fprintf(stderr, "<--- %d-", n);
                    491:                _doprnt(s, &args, stderr);
                    492:                fprintf(stderr, "\n");
                    493:        }
                    494: }
                    495: 
                    496: replystr(s)
                    497:        char *s;
                    498: {
                    499:        printf("%s\r\n", s);
                    500:        fflush(stdout);
                    501:        if (debug)
                    502:                fprintf(stderr, "<--- %s\n", s);
                    503: }
                    504: 
                    505: ack(s)
                    506:        char *s;
                    507: {
                    508:        reply(200, "%s command okay.", s);
                    509: }
                    510: 
                    511: nack(s)
                    512:        char *s;
                    513: {
                    514:        reply(502, "%s command not implemented.", s);
                    515: }
                    516: 
                    517: yyerror()
                    518: {
                    519:        reply(500, "Command not understood.");
                    520: }
                    521: 
                    522: delete(name)
                    523:        char *name;
                    524: {
                    525:        struct stat st;
                    526: 
                    527:        if(!logged_in){
                    528:                reply(550, "delete: login required.");
                    529:                return;
                    530:        }
                    531:        if (stat(name, &st) < 0) {
                    532:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    533:                return;
                    534:        }
                    535:        if ((st.st_mode&S_IFMT) == S_IFDIR) {
                    536:                if (rmdir(name) < 0) {
                    537:                        reply(550, "%s: %s.", name, sys_errlist[errno]);
                    538:                        return;
                    539:                }
                    540:                goto done;
                    541:        }
                    542:        if (unlink(name) < 0) {
                    543:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    544:                return;
                    545:        }
                    546: done:
                    547:        ack("DELE");
                    548: }
                    549: 
                    550: cwd(path)
                    551:        char *path;
                    552: {
                    553: 
                    554:        if(!logged_in){
                    555:                reply(550, "cwd: login required.");
                    556:                return;
                    557:        }
                    558:        if (chdir(path) < 0) {
                    559:                reply(550, "%s: %s.", path, sys_errlist[errno]);
                    560:                return;
                    561:        }
                    562:        ack("CWD");
                    563: }
                    564: 
                    565: makedir(name)
                    566:        char *name;
                    567: {
                    568:        struct stat st;
                    569:        int dochown = stat(name, &st) < 0;
                    570: 
                    571:        if(!logged_in){
                    572:                reply(550, "makedir: login required.");
                    573:                return;
                    574:        }
                    575:        if (mkdir(name, 0777) < 0) {
                    576:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    577:                return;
                    578:        }
                    579:        ack("MKDIR");
                    580: }
                    581: 
                    582: removedir(name)
                    583:        char *name;
                    584: {
                    585: 
                    586:        if(!logged_in){
                    587:                reply(550, "removedir: login required.");
                    588:                return;
                    589:        }
                    590:        if (rmdir(name) < 0) {
                    591:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    592:                return;
                    593:        }
                    594:        ack("RMDIR");
                    595: }
                    596: 
                    597: #define        MAXPATHLEN      256
                    598: pwd()
                    599: {
                    600:        char path[MAXPATHLEN + 1];
                    601: 
                    602:        if (getwd(path) == NULL) {
                    603:                reply(451, "%s.", path);
                    604:                return;
                    605:        }
                    606:        reply(251, "\"%s\" is current directory.", path);
                    607: }
                    608: 
                    609: char *
                    610: renamefrom(name)
                    611:        char *name;
                    612: {
                    613:        struct stat st;
                    614: 
                    615:        if(!logged_in){
                    616:                reply(550, "rename: login required.");
                    617:                return;
                    618:        }
                    619:        if (stat(name, &st) < 0) {
                    620:                reply(550, "%s: %s.", name, sys_errlist[errno]);
                    621:                return ((char *)0);
                    622:        }
                    623:        reply(350, "File exists, ready for destination name");
                    624:        return (name);
                    625: }
                    626: 
                    627: renamecmd(from, to)
                    628:        char *from, *to;
                    629: {
                    630: 
                    631:        if(!logged_in){
                    632:                reply(550, "rename: login required.");
                    633:                return;
                    634:        }
                    635:        if (rename(from, to) < 0) {
                    636:                reply(550, "rename: %s.", sys_errlist[errno]);
                    637:                return;
                    638:        }
                    639:        ack("RNTO");
                    640: }
                    641: 
                    642: #include <utmp.h>
                    643: 
                    644: #define        SCPYN(a, b)     strncpy(a, b, sizeof (a))
                    645: struct utmp utmp;
                    646: 
                    647: /*
                    648:  * Record login in wtmp file.
                    649:  */
                    650: 
                    651: #define        O_WRONLY        1
                    652: #define O_APPEND       1
                    653: dologin(pw)
                    654:        struct passwd *pw;
                    655: {
                    656:        int wtmp;
                    657:        char line[32];
                    658: 
                    659:        pasv = 0;
                    660:        wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
                    661:        if (wtmp >= 0) {
                    662:                /* hack, but must be unique and no tty line */
                    663:                sprintf(line, "ftp%d", getpid());
                    664:                SCPYN(utmp.ut_line, line);
                    665:                SCPYN(utmp.ut_name, pw->pw_name);
                    666:                utmp.ut_time = time(0);
                    667:                (void) write(wtmp, (char *)&utmp, sizeof (utmp));
                    668:                (void) close(wtmp);
                    669:        }
                    670: }
                    671: 
                    672: /*
                    673:  * Record logout in wtmp file
                    674:  * and exit with supplied status.
                    675:  */
                    676: dologout(status)
                    677:        int status;
                    678: {
                    679:        int wtmp;
                    680: 
                    681:        if (!logged_in)
                    682:                _exit(status);
                    683:        wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
                    684:        if (wtmp >= 0) {
                    685:                SCPYN(utmp.ut_name, "");
                    686:                utmp.ut_time = time(0);
                    687:                (void) write(wtmp, (char *)&utmp, sizeof (utmp));
                    688:                (void) close(wtmp);
                    689:        }
                    690:        /* beware of flushing buffers after a SIGPIPE */
                    691:        _exit(status);
                    692: }
                    693: 
                    694: static char *
                    695: nextarg(cpp)
                    696:        char *cpp;
                    697: {
                    698:        register char *cp = cpp;
                    699: 
                    700:        if (cp == 0)
                    701:                return (cp);
                    702:        while (*cp && *cp != ' ' && *cp != '\t')
                    703:                cp++;
                    704:        if (*cp == ' ' || *cp == '\t') {
                    705:                *cp++ = '\0';
                    706:                while (*cp == ' ' || *cp == '\t')
                    707:                        cp++;
                    708:        }
                    709:        if (cp == cpp)
                    710:                return ((char *)0);
                    711:        return (cp);
                    712: }
                    713: 
                    714: rename(from, to)
                    715: {
                    716:        if (-1 == link(from, to))
                    717:                return(-1);
                    718:        return(unlink(from));
                    719: }
                    720: inet_ntoa(addr)
                    721: long addr;
                    722: {
                    723:        static char b[32];
                    724:        unsigned char *xp = (unsigned char *)&addr;
                    725: 
                    726:        sprintf(b, "%d.%d.%d.%d", xp[3], xp[2], xp[1], xp[0]);
                    727:        return(b);
                    728: }
                    729: delay()
                    730: {
                    731: }

unix.superglobalmegacorp.com

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