Annotation of 42BSD/etc/tftpd.c, revision 1.1.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.