Annotation of 43BSDReno/libexec/tftpd/tftpd.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that: (1) source distributions retain this entire copyright
                      7:  * notice and comment, and (2) distributions including binaries display
                      8:  * the following acknowledgement:  ``This product includes software
                      9:  * developed by the University of California, Berkeley and its contributors''
                     10:  * in the documentation or other materials provided with the distribution
                     11:  * and in all advertising materials mentioning features or use of this
                     12:  * software. Neither the name of the University nor the names of its
                     13:  * contributors may be used to endorse or promote products derived
                     14:  * from this software without specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     16:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: char copyright[] =
                     22: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
                     23:  All rights reserved.\n";
                     24: #endif /* not lint */
                     25: 
                     26: #ifndef lint
                     27: static char sccsid[] = "@(#)tftpd.c    5.12 (Berkeley) 6/1/90";
                     28: #endif /* not lint */
                     29: 
                     30: /*
                     31:  * Trivial file transfer protocol server.
                     32:  *
                     33:  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
                     34:  */
                     35: 
                     36: #include <sys/types.h>
                     37: #include <sys/socket.h>
                     38: #include <sys/ioctl.h>
                     39: #include <sys/wait.h>
                     40: #include <sys/stat.h>
                     41: #include <sys/signal.h>
                     42: 
                     43: #include <netinet/in.h>
                     44: 
                     45: #include <arpa/tftp.h>
                     46: 
                     47: #include <netdb.h>
                     48: #include <setjmp.h>
                     49: #include <stdio.h>
                     50: #include <errno.h>
                     51: #include <ctype.h>
                     52: #include <syslog.h>
                     53: #include <string.h>
                     54: 
                     55: #define        TIMEOUT         5
                     56: 
                     57: extern int errno;
                     58: struct sockaddr_in sin = { AF_INET };
                     59: int    peer;
                     60: int    rexmtval = TIMEOUT;
                     61: int    maxtimeout = 5*TIMEOUT;
                     62: 
                     63: #define        PKTSIZE SEGSIZE+4
                     64: char   buf[PKTSIZE];
                     65: char   ackbuf[PKTSIZE];
                     66: struct sockaddr_in from;
                     67: int    fromlen;
                     68: 
                     69: #define MAXARG 4
                     70: char   *dirs[MAXARG+1];
                     71: 
                     72: main(ac, av)
                     73:        char **av;
                     74: {
                     75:        register struct tftphdr *tp;
                     76:        register int n = 0;
                     77:        int on = 1;
                     78: 
                     79:        ac--; av++;
                     80:        while (ac-- > 0 && n < MAXARG)
                     81:                dirs[n++] = *av++;
                     82:        openlog("tftpd", LOG_PID, LOG_DAEMON);
                     83:        if (ioctl(0, FIONBIO, &on) < 0) {
                     84:                syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
                     85:                exit(1);
                     86:        }
                     87:        fromlen = sizeof (from);
                     88:        n = recvfrom(0, buf, sizeof (buf), 0,
                     89:            (caddr_t)&from, &fromlen);
                     90:        if (n < 0) {
                     91:                syslog(LOG_ERR, "recvfrom: %m\n");
                     92:                exit(1);
                     93:        }
                     94:        /*
                     95:         * Now that we have read the message out of the UDP
                     96:         * socket, we fork and exit.  Thus, inetd will go back
                     97:         * to listening to the tftp port, and the next request
                     98:         * to come in will start up a new instance of tftpd.
                     99:         *
                    100:         * We do this so that inetd can run tftpd in "wait" mode.
                    101:         * The problem with tftpd running in "nowait" mode is that
                    102:         * inetd may get one or more successful "selects" on the
                    103:         * tftp port before we do our receive, so more than one
                    104:         * instance of tftpd may be started up.  Worse, if tftpd
                    105:         * break before doing the above "recvfrom", inetd would
                    106:         * spawn endless instances, clogging the system.
                    107:         */
                    108:        {
                    109:                int pid;
                    110:                int i, j;
                    111: 
                    112:                for (i = 1; i < 20; i++) {
                    113:                    pid = fork();
                    114:                    if (pid < 0) {
                    115:                                sleep(i);
                    116:                                /*
                    117:                                 * flush out to most recently sent request.
                    118:                                 *
                    119:                                 * This may drop some request, but those
                    120:                                 * will be resent by the clients when
                    121:                                 * they timeout.  The positive effect of
                    122:                                 * this flush is to (try to) prevent more
                    123:                                 * than one tftpd being started up to service
                    124:                                 * a single request from a single client.
                    125:                                 */
                    126:                                j = sizeof from;
                    127:                                i = recvfrom(0, buf, sizeof (buf), 0,
                    128:                                    (caddr_t)&from, &j);
                    129:                                if (i > 0) {
                    130:                                        n = i;
                    131:                                        fromlen = j;
                    132:                                }
                    133:                    } else {
                    134:                                break;
                    135:                    }
                    136:                }
                    137:                if (pid < 0) {
                    138:                        syslog(LOG_ERR, "fork: %m\n");
                    139:                        exit(1);
                    140:                } else if (pid != 0) {
                    141:                        exit(0);
                    142:                }
                    143:        }
                    144:        from.sin_family = AF_INET;
                    145:        alarm(0);
                    146:        close(0);
                    147:        close(1);
                    148:        peer = socket(AF_INET, SOCK_DGRAM, 0);
                    149:        if (peer < 0) {
                    150:                syslog(LOG_ERR, "socket: %m\n");
                    151:                exit(1);
                    152:        }
                    153:        if (bind(peer, (caddr_t)&sin, sizeof (sin)) < 0) {
                    154:                syslog(LOG_ERR, "bind: %m\n");
                    155:                exit(1);
                    156:        }
                    157:        if (connect(peer, (caddr_t)&from, sizeof(from)) < 0) {
                    158:                syslog(LOG_ERR, "connect: %m\n");
                    159:                exit(1);
                    160:        }
                    161:        tp = (struct tftphdr *)buf;
                    162:        tp->th_opcode = ntohs(tp->th_opcode);
                    163:        if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
                    164:                tftp(tp, n);
                    165:        exit(1);
                    166: }
                    167: 
                    168: int    validate_access();
                    169: int    sendfile(), recvfile();
                    170: 
                    171: struct formats {
                    172:        char    *f_mode;
                    173:        int     (*f_validate)();
                    174:        int     (*f_send)();
                    175:        int     (*f_recv)();
                    176:        int     f_convert;
                    177: } formats[] = {
                    178:        { "netascii",   validate_access,        sendfile,       recvfile, 1 },
                    179:        { "octet",      validate_access,        sendfile,       recvfile, 0 },
                    180: #ifdef notdef
                    181:        { "mail",       validate_user,          sendmail,       recvmail, 1 },
                    182: #endif
                    183:        { 0 }
                    184: };
                    185: 
                    186: /*
                    187:  * Handle initial connection protocol.
                    188:  */
                    189: tftp(tp, size)
                    190:        struct tftphdr *tp;
                    191:        int size;
                    192: {
                    193:        register char *cp;
                    194:        int first = 1, ecode;
                    195:        register struct formats *pf;
                    196:        char *filename, *mode;
                    197: 
                    198:        filename = cp = tp->th_stuff;
                    199: again:
                    200:        while (cp < buf + size) {
                    201:                if (*cp == '\0')
                    202:                        break;
                    203:                cp++;
                    204:        }
                    205:        if (*cp != '\0') {
                    206:                nak(EBADOP);
                    207:                exit(1);
                    208:        }
                    209:        if (first) {
                    210:                mode = ++cp;
                    211:                first = 0;
                    212:                goto again;
                    213:        }
                    214:        for (cp = mode; *cp; cp++)
                    215:                if (isupper(*cp))
                    216:                        *cp = tolower(*cp);
                    217:        for (pf = formats; pf->f_mode; pf++)
                    218:                if (strcmp(pf->f_mode, mode) == 0)
                    219:                        break;
                    220:        if (pf->f_mode == 0) {
                    221:                nak(EBADOP);
                    222:                exit(1);
                    223:        }
                    224:        ecode = (*pf->f_validate)(filename, tp->th_opcode);
                    225:        if (ecode) {
                    226:                nak(ecode);
                    227:                exit(1);
                    228:        }
                    229:        if (tp->th_opcode == WRQ)
                    230:                (*pf->f_recv)(pf);
                    231:        else
                    232:                (*pf->f_send)(pf);
                    233:        exit(0);
                    234: }
                    235: 
                    236: 
                    237: FILE *file;
                    238: 
                    239: /*
                    240:  * Validate file access.  Since we
                    241:  * have no uid or gid, for now require
                    242:  * file to exist and be publicly
                    243:  * readable/writable.
                    244:  * If we were invoked with arguments
                    245:  * from inetd then the file must also be
                    246:  * in one of the given directory prefixes.
                    247:  * Note also, full path name must be
                    248:  * given as we have no login directory.
                    249:  */
                    250: validate_access(filename, mode)
                    251:        char *filename;
                    252:        int mode;
                    253: {
                    254:        struct stat stbuf;
                    255:        int     fd;
                    256:        char *cp, **dirp;
                    257: 
                    258:        if (*filename != '/')
                    259:                return (EACCESS);
                    260:        /*
                    261:         * prevent tricksters from getting around the directory restrictions
                    262:         */
                    263:        for (cp = filename + 1; *cp; cp++)
                    264:                if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)
                    265:                        return(EACCESS);
                    266:        for (dirp = dirs; *dirp; dirp++)
                    267:                if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
                    268:                        break;
                    269:        if (*dirp==0 && dirp!=dirs)
                    270:                return (EACCESS);
                    271:        if (stat(filename, &stbuf) < 0)
                    272:                return (errno == ENOENT ? ENOTFOUND : EACCESS);
                    273:        if (mode == RRQ) {
                    274:                if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
                    275:                        return (EACCESS);
                    276:        } else {
                    277:                if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
                    278:                        return (EACCESS);
                    279:        }
                    280:        fd = open(filename, mode == RRQ ? 0 : 1);
                    281:        if (fd < 0)
                    282:                return (errno + 100);
                    283:        file = fdopen(fd, (mode == RRQ)? "r":"w");
                    284:        if (file == NULL) {
                    285:                return errno+100;
                    286:        }
                    287:        return (0);
                    288: }
                    289: 
                    290: int    timeout;
                    291: jmp_buf        timeoutbuf;
                    292: 
                    293: timer()
                    294: {
                    295: 
                    296:        timeout += rexmtval;
                    297:        if (timeout >= maxtimeout)
                    298:                exit(1);
                    299:        longjmp(timeoutbuf, 1);
                    300: }
                    301: 
                    302: /*
                    303:  * Send the requested file.
                    304:  */
                    305: sendfile(pf)
                    306:        struct formats *pf;
                    307: {
                    308:        struct tftphdr *dp, *r_init();
                    309:        register struct tftphdr *ap;    /* ack packet */
                    310:        register int block = 1, size, n;
                    311: 
                    312:        signal(SIGALRM, timer);
                    313:        dp = r_init();
                    314:        ap = (struct tftphdr *)ackbuf;
                    315:        do {
                    316:                size = readit(file, &dp, pf->f_convert);
                    317:                if (size < 0) {
                    318:                        nak(errno + 100);
                    319:                        goto abort;
                    320:                }
                    321:                dp->th_opcode = htons((u_short)DATA);
                    322:                dp->th_block = htons((u_short)block);
                    323:                timeout = 0;
                    324:                (void) setjmp(timeoutbuf);
                    325: 
                    326: send_data:
                    327:                if (send(peer, dp, size + 4, 0) != size + 4) {
                    328:                        syslog(LOG_ERR, "tftpd: write: %m\n");
                    329:                        goto abort;
                    330:                }
                    331:                read_ahead(file, pf->f_convert);
                    332:                for ( ; ; ) {
                    333:                        alarm(rexmtval);        /* read the ack */
                    334:                        n = recv(peer, ackbuf, sizeof (ackbuf), 0);
                    335:                        alarm(0);
                    336:                        if (n < 0) {
                    337:                                syslog(LOG_ERR, "tftpd: read: %m\n");
                    338:                                goto abort;
                    339:                        }
                    340:                        ap->th_opcode = ntohs((u_short)ap->th_opcode);
                    341:                        ap->th_block = ntohs((u_short)ap->th_block);
                    342: 
                    343:                        if (ap->th_opcode == ERROR)
                    344:                                goto abort;
                    345:                        
                    346:                        if (ap->th_opcode == ACK) {
                    347:                                if (ap->th_block == block) {
                    348:                                        break;
                    349:                                }
                    350:                                /* Re-synchronize with the other side */
                    351:                                (void) synchnet(peer);
                    352:                                if (ap->th_block == (block -1)) {
                    353:                                        goto send_data;
                    354:                                }
                    355:                        }
                    356: 
                    357:                }
                    358:                block++;
                    359:        } while (size == SEGSIZE);
                    360: abort:
                    361:        (void) fclose(file);
                    362: }
                    363: 
                    364: justquit()
                    365: {
                    366:        exit(0);
                    367: }
                    368: 
                    369: 
                    370: /*
                    371:  * Receive a file.
                    372:  */
                    373: recvfile(pf)
                    374:        struct formats *pf;
                    375: {
                    376:        struct tftphdr *dp, *w_init();
                    377:        register struct tftphdr *ap;    /* ack buffer */
                    378:        register int block = 0, n, size;
                    379: 
                    380:        signal(SIGALRM, timer);
                    381:        dp = w_init();
                    382:        ap = (struct tftphdr *)ackbuf;
                    383:        do {
                    384:                timeout = 0;
                    385:                ap->th_opcode = htons((u_short)ACK);
                    386:                ap->th_block = htons((u_short)block);
                    387:                block++;
                    388:                (void) setjmp(timeoutbuf);
                    389: send_ack:
                    390:                if (send(peer, ackbuf, 4, 0) != 4) {
                    391:                        syslog(LOG_ERR, "tftpd: write: %m\n");
                    392:                        goto abort;
                    393:                }
                    394:                write_behind(file, pf->f_convert);
                    395:                for ( ; ; ) {
                    396:                        alarm(rexmtval);
                    397:                        n = recv(peer, dp, PKTSIZE, 0);
                    398:                        alarm(0);
                    399:                        if (n < 0) {            /* really? */
                    400:                                syslog(LOG_ERR, "tftpd: read: %m\n");
                    401:                                goto abort;
                    402:                        }
                    403:                        dp->th_opcode = ntohs((u_short)dp->th_opcode);
                    404:                        dp->th_block = ntohs((u_short)dp->th_block);
                    405:                        if (dp->th_opcode == ERROR)
                    406:                                goto abort;
                    407:                        if (dp->th_opcode == DATA) {
                    408:                                if (dp->th_block == block) {
                    409:                                        break;   /* normal */
                    410:                                }
                    411:                                /* Re-synchronize with the other side */
                    412:                                (void) synchnet(peer);
                    413:                                if (dp->th_block == (block-1))
                    414:                                        goto send_ack;          /* rexmit */
                    415:                        }
                    416:                }
                    417:                /*  size = write(file, dp->th_data, n - 4); */
                    418:                size = writeit(file, &dp, n - 4, pf->f_convert);
                    419:                if (size != (n-4)) {                    /* ahem */
                    420:                        if (size < 0) nak(errno + 100);
                    421:                        else nak(ENOSPACE);
                    422:                        goto abort;
                    423:                }
                    424:        } while (size == SEGSIZE);
                    425:        write_behind(file, pf->f_convert);
                    426:        (void) fclose(file);            /* close data file */
                    427: 
                    428:        ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
                    429:        ap->th_block = htons((u_short)(block));
                    430:        (void) send(peer, ackbuf, 4, 0);
                    431: 
                    432:        signal(SIGALRM, justquit);      /* just quit on timeout */
                    433:        alarm(rexmtval);
                    434:        n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
                    435:        alarm(0);
                    436:        if (n >= 4 &&                   /* if read some data */
                    437:            dp->th_opcode == DATA &&    /* and got a data block */
                    438:            block == dp->th_block) {    /* then my last ack was lost */
                    439:                (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
                    440:        }
                    441: abort:
                    442:        return;
                    443: }
                    444: 
                    445: struct errmsg {
                    446:        int     e_code;
                    447:        char    *e_msg;
                    448: } errmsgs[] = {
                    449:        { EUNDEF,       "Undefined error code" },
                    450:        { ENOTFOUND,    "File not found" },
                    451:        { EACCESS,      "Access violation" },
                    452:        { ENOSPACE,     "Disk full or allocation exceeded" },
                    453:        { EBADOP,       "Illegal TFTP operation" },
                    454:        { EBADID,       "Unknown transfer ID" },
                    455:        { EEXISTS,      "File already exists" },
                    456:        { ENOUSER,      "No such user" },
                    457:        { -1,           0 }
                    458: };
                    459: 
                    460: /*
                    461:  * Send a nak packet (error message).
                    462:  * Error code passed in is one of the
                    463:  * standard TFTP codes, or a UNIX errno
                    464:  * offset by 100.
                    465:  */
                    466: nak(error)
                    467:        int error;
                    468: {
                    469:        register struct tftphdr *tp;
                    470:        int length;
                    471:        register struct errmsg *pe;
                    472: 
                    473:        tp = (struct tftphdr *)buf;
                    474:        tp->th_opcode = htons((u_short)ERROR);
                    475:        tp->th_code = htons((u_short)error);
                    476:        for (pe = errmsgs; pe->e_code >= 0; pe++)
                    477:                if (pe->e_code == error)
                    478:                        break;
                    479:        if (pe->e_code < 0) {
                    480:                pe->e_msg = strerror(error - 100);
                    481:                tp->th_code = EUNDEF;   /* set 'undef' errorcode */
                    482:        }
                    483:        strcpy(tp->th_msg, pe->e_msg);
                    484:        length = strlen(pe->e_msg);
                    485:        tp->th_msg[length] = '\0';
                    486:        length += 5;
                    487:        if (send(peer, buf, length, 0) != length)
                    488:                syslog(LOG_ERR, "nak: %m\n");
                    489: }

unix.superglobalmegacorp.com

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