Annotation of 42BSD/etc/ftpd/ftpd.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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