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

unix.superglobalmegacorp.com

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