Annotation of 42BSD/etc/tftpd.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char sccsid[] = "@(#)tftpd.c    4.11 (Berkeley) 7/2/83";
        !             3: #endif
        !             4: 
        !             5: /*
        !             6:  * Trivial file transfer protocol server.
        !             7:  */
        !             8: #include <sys/types.h>
        !             9: #include <sys/socket.h>
        !            10: #include <sys/ioctl.h>
        !            11: #include <sys/wait.h>
        !            12: #include <sys/stat.h>
        !            13: 
        !            14: #include <netinet/in.h>
        !            15: 
        !            16: #include <arpa/tftp.h>
        !            17: 
        !            18: #include <signal.h>
        !            19: #include <stdio.h>
        !            20: #include <errno.h>
        !            21: #include <ctype.h>
        !            22: #include <netdb.h>
        !            23: #include <setjmp.h>
        !            24: 
        !            25: #define        TIMEOUT         5
        !            26: 
        !            27: extern int errno;
        !            28: struct sockaddr_in sin = { AF_INET };
        !            29: int    f;
        !            30: int    rexmtval = TIMEOUT;
        !            31: int    maxtimeout = 5*TIMEOUT;
        !            32: char   buf[BUFSIZ];
        !            33: int    reapchild();
        !            34: 
        !            35: main(argc, argv)
        !            36:        char *argv[];
        !            37: {
        !            38:        struct sockaddr_in from;
        !            39:        register struct tftphdr *tp;
        !            40:        register int n;
        !            41:        struct servent *sp;
        !            42: 
        !            43:        sp = getservbyname("tftp", "udp");
        !            44:        if (sp == 0) {
        !            45:                fprintf(stderr, "tftpd: udp/tftp: unknown service\n");
        !            46:                exit(1);
        !            47:        }
        !            48:        sin.sin_port = sp->s_port;
        !            49: #ifndef DEBUG
        !            50:        if (fork())
        !            51:                exit(0);
        !            52:        for (f = 0; f < 10; f++)
        !            53:                (void) close(f);
        !            54:        (void) open("/", 0);
        !            55:        (void) dup2(0, 1);
        !            56:        (void) dup2(0, 2);
        !            57:        { int t = open("/dev/tty", 2);
        !            58:          if (t >= 0) {
        !            59:                ioctl(t, TIOCNOTTY, (char *)0);
        !            60:                (void) close(t);
        !            61:          }
        !            62:        }
        !            63: #endif
        !            64:        signal(SIGCHLD, reapchild);
        !            65:        for (;;) {
        !            66:                int fromlen;
        !            67: 
        !            68:                f = socket(AF_INET, SOCK_DGRAM, 0);
        !            69:                if (f < 0) {
        !            70:                        perror("tftpd: socket");
        !            71:                        sleep(5);
        !            72:                        continue;
        !            73:                }
        !            74:                if (setsockopt(f, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
        !            75:                        perror("tftpd: setsockopt (SO_REUSEADDR)");
        !            76:                sleep(1);                       /* let child do connect */
        !            77:                while (bind(f, (caddr_t)&sin, sizeof (sin), 0) < 0) {
        !            78:                        perror("tftpd: bind");
        !            79:                        sleep(5);
        !            80:                }
        !            81:                do {
        !            82:                        fromlen = sizeof (from);
        !            83:                        n = recvfrom(f, buf, sizeof (buf), 0,
        !            84:                            (caddr_t)&from, &fromlen);
        !            85:                } while (n <= 0);
        !            86:                tp = (struct tftphdr *)buf;
        !            87:                tp->th_opcode = ntohs(tp->th_opcode);
        !            88:                if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
        !            89:                        if (fork() == 0)
        !            90:                                tftp(&from, tp, n);
        !            91:                (void) close(f);
        !            92:        }
        !            93: }
        !            94: 
        !            95: reapchild()
        !            96: {
        !            97:        union wait status;
        !            98: 
        !            99:        while (wait3(&status, WNOHANG, 0) > 0)
        !           100:                ;
        !           101: }
        !           102: 
        !           103: int    validate_access();
        !           104: int    sendfile(), recvfile();
        !           105: 
        !           106: struct formats {
        !           107:        char    *f_mode;
        !           108:        int     (*f_validate)();
        !           109:        int     (*f_send)();
        !           110:        int     (*f_recv)();
        !           111: } formats[] = {
        !           112:        { "netascii",   validate_access,        sendfile,       recvfile },
        !           113:        { "octet",      validate_access,        sendfile,       recvfile },
        !           114: #ifdef notdef
        !           115:        { "mail",       validate_user,          sendmail,       recvmail },
        !           116: #endif
        !           117:        { 0 }
        !           118: };
        !           119: 
        !           120: int    fd;                     /* file being transferred */
        !           121: 
        !           122: /*
        !           123:  * Handle initial connection protocol.
        !           124:  */
        !           125: tftp(client, tp, size)
        !           126:        struct sockaddr_in *client;
        !           127:        struct tftphdr *tp;
        !           128:        int size;
        !           129: {
        !           130:        register char *cp;
        !           131:        int first = 1, ecode;
        !           132:        register struct formats *pf;
        !           133:        char *filename, *mode;
        !           134: 
        !           135:        if (connect(f, (caddr_t)client, sizeof (*client), 0) < 0) {
        !           136:                perror("connect");
        !           137:                exit(1);
        !           138:        }
        !           139:        filename = cp = tp->th_stuff;
        !           140: again:
        !           141:        while (cp < buf + size) {
        !           142:                if (*cp == '\0')
        !           143:                        break;
        !           144:                cp++;
        !           145:        }
        !           146:        if (*cp != '\0') {
        !           147:                nak(EBADOP);
        !           148:                exit(1);
        !           149:        }
        !           150:        if (first) {
        !           151:                mode = ++cp;
        !           152:                first = 0;
        !           153:                goto again;
        !           154:        }
        !           155:        for (cp = mode; *cp; cp++)
        !           156:                if (isupper(*cp))
        !           157:                        *cp = tolower(*cp);
        !           158:        for (pf = formats; pf->f_mode; pf++)
        !           159:                if (strcmp(pf->f_mode, mode) == 0)
        !           160:                        break;
        !           161:        if (pf->f_mode == 0) {
        !           162:                nak(EBADOP);
        !           163:                exit(1);
        !           164:        }
        !           165:        ecode = (*pf->f_validate)(filename, client, tp->th_opcode);
        !           166:        if (ecode) {
        !           167:                nak(ecode);
        !           168:                exit(1);
        !           169:        }
        !           170:        if (tp->th_opcode == WRQ)
        !           171:                (*pf->f_recv)(pf);
        !           172:        else
        !           173:                (*pf->f_send)(pf);
        !           174:        exit(0);
        !           175: }
        !           176: 
        !           177: /*
        !           178:  * Validate file access.  Since we
        !           179:  * have no uid or gid, for now require
        !           180:  * file to exist and be publicly
        !           181:  * readable/writable.
        !           182:  * Note also, full path name must be
        !           183:  * given as we have no login directory.
        !           184:  */
        !           185: validate_access(file, client, mode)
        !           186:        char *file;
        !           187:        struct sockaddr_in *client;
        !           188:        int mode;
        !           189: {
        !           190:        struct stat stbuf;
        !           191: 
        !           192:        if (*file != '/')
        !           193:                return (EACCESS);
        !           194:        if (stat(file, &stbuf) < 0)
        !           195:                return (errno == ENOENT ? ENOTFOUND : EACCESS);
        !           196:        if (mode == RRQ) {
        !           197:                if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
        !           198:                        return (EACCESS);
        !           199:        } else {
        !           200:                if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
        !           201:                        return (EACCESS);
        !           202:        }
        !           203:        fd = open(file, mode == RRQ ? 0 : 1);
        !           204:        if (fd < 0)
        !           205:                return (errno + 100);
        !           206:        return (0);
        !           207: }
        !           208: 
        !           209: int    timeout;
        !           210: jmp_buf        timeoutbuf;
        !           211: 
        !           212: timer()
        !           213: {
        !           214: 
        !           215:        timeout += rexmtval;
        !           216:        if (timeout >= maxtimeout)
        !           217:                exit(1);
        !           218:        longjmp(timeoutbuf, 1);
        !           219: }
        !           220: 
        !           221: /*
        !           222:  * Send the requested file.
        !           223:  */
        !           224: sendfile(pf)
        !           225:        struct format *pf;
        !           226: {
        !           227:        register struct tftphdr *tp;
        !           228:        register int block = 1, size, n;
        !           229: 
        !           230:        signal(SIGALRM, timer);
        !           231:        tp = (struct tftphdr *)buf;
        !           232:        do {
        !           233:                size = read(fd, tp->th_data, SEGSIZE);
        !           234:                if (size < 0) {
        !           235:                        nak(errno + 100);
        !           236:                        goto abort;
        !           237:                }
        !           238:                tp->th_opcode = htons((u_short)DATA);
        !           239:                tp->th_block = htons((u_short)block);
        !           240:                timeout = 0;
        !           241:                (void) setjmp(timeoutbuf);
        !           242:                if (write(f, buf, size + 4) != size + 4) {
        !           243:                        perror("tftpd: write");
        !           244:                        goto abort;
        !           245:                }
        !           246:                do {
        !           247:                        alarm(rexmtval);
        !           248:                        n = read(f, buf, sizeof (buf));
        !           249:                        alarm(0);
        !           250:                        if (n < 0) {
        !           251:                                perror("tftpd: read");
        !           252:                                goto abort;
        !           253:                        }
        !           254:                        tp->th_opcode = ntohs((u_short)tp->th_opcode);
        !           255:                        tp->th_block = ntohs((u_short)tp->th_block);
        !           256:                        if (tp->th_opcode == ERROR)
        !           257:                                goto abort;
        !           258:                } while (tp->th_opcode != ACK || tp->th_block != block);
        !           259:                block++;
        !           260:        } while (size == SEGSIZE);
        !           261: abort:
        !           262:        (void) close(fd);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * Receive a file.
        !           267:  */
        !           268: recvfile(pf)
        !           269:        struct format *pf;
        !           270: {
        !           271:        register struct tftphdr *tp;
        !           272:        register int block = 0, n, size;
        !           273: 
        !           274:        signal(SIGALRM, timer);
        !           275:        tp = (struct tftphdr *)buf;
        !           276:        do {
        !           277:                timeout = 0;
        !           278:                tp->th_opcode = htons((u_short)ACK);
        !           279:                tp->th_block = htons((u_short)block);
        !           280:                block++;
        !           281:                (void) setjmp(timeoutbuf);
        !           282:                if (write(f, buf, 4) != 4) {
        !           283:                        perror("tftpd: write");
        !           284:                        goto abort;
        !           285:                }
        !           286:                do {
        !           287:                        alarm(rexmtval);
        !           288:                        n = read(f, buf, sizeof (buf));
        !           289:                        alarm(0);
        !           290:                        if (n < 0) {
        !           291:                                perror("tftpd: read");
        !           292:                                goto abort;
        !           293:                        }
        !           294:                        tp->th_opcode = ntohs((u_short)tp->th_opcode);
        !           295:                        tp->th_block = ntohs((u_short)tp->th_block);
        !           296:                        if (tp->th_opcode == ERROR)
        !           297:                                goto abort;
        !           298:                } while (tp->th_opcode != DATA || block != tp->th_block);
        !           299:                size = write(fd, tp->th_data, n - 4);
        !           300:                if (size < 0) {
        !           301:                        nak(errno + 100);
        !           302:                        goto abort;
        !           303:                }
        !           304:        } while (size == SEGSIZE);
        !           305: abort:
        !           306:        tp->th_opcode = htons((u_short)ACK);
        !           307:        tp->th_block = htons((u_short)(block));
        !           308:        (void) write(f, buf, 4);
        !           309:        (void) close(fd);
        !           310: }
        !           311: 
        !           312: struct errmsg {
        !           313:        int     e_code;
        !           314:        char    *e_msg;
        !           315: } errmsgs[] = {
        !           316:        { EUNDEF,       "Undefined error code" },
        !           317:        { ENOTFOUND,    "File not found" },
        !           318:        { EACCESS,      "Access violation" },
        !           319:        { ENOSPACE,     "Disk full or allocation exceeded" },
        !           320:        { EBADOP,       "Illegal TFTP operation" },
        !           321:        { EBADID,       "Unknown transfer ID" },
        !           322:        { EEXISTS,      "File already exists" },
        !           323:        { ENOUSER,      "No such user" },
        !           324:        { -1,           0 }
        !           325: };
        !           326: 
        !           327: /*
        !           328:  * Send a nak packet (error message).
        !           329:  * Error code passed in is one of the
        !           330:  * standard TFTP codes, or a UNIX errno
        !           331:  * offset by 100.
        !           332:  */
        !           333: nak(error)
        !           334:        int error;
        !           335: {
        !           336:        register struct tftphdr *tp;
        !           337:        int length;
        !           338:        register struct errmsg *pe;
        !           339:        extern char *sys_errlist[];
        !           340: 
        !           341:        tp = (struct tftphdr *)buf;
        !           342:        tp->th_opcode = htons((u_short)ERROR);
        !           343:        tp->th_code = htons((u_short)error);
        !           344:        for (pe = errmsgs; pe->e_code >= 0; pe++)
        !           345:                if (pe->e_code == error)
        !           346:                        break;
        !           347:        if (pe->e_code < 0)
        !           348:                pe->e_msg = sys_errlist[error - 100];
        !           349:        strcpy(tp->th_msg, pe->e_msg);
        !           350:        length = strlen(pe->e_msg);
        !           351:        tp->th_msg[length] = '\0';
        !           352:        length += 5;
        !           353:        if (write(f, buf, length) != length)
        !           354:                perror("nak");
        !           355: }

unix.superglobalmegacorp.com

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