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

Defined functions

justquit defined in line 362; used 1 times
main defined in line 70; never used
nak defined in line 464; used 6 times
recvfile defined in line 371; used 3 times
sendfile defined in line 303; used 3 times
tftp defined in line 187; used 1 times
timer defined in line 291; used 2 times
validate_access defined in line 248; used 3 times

Defined variables

ackbuf defined in line 63; used 7 times
buf defined in line 62; used 10 times
copyright defined in line 21; never used
dirs defined in line 68; used 3 times
errmsgs defined in line 446; used 1 times
formats defined in line 175; used 1 times
from defined in line 64; used 7 times
fromlen defined in line 65; used 3 times
maxtimeout defined in line 59; used 1 times
peer defined in line 57; used 14 times
rexmtval defined in line 58; used 4 times
sccsid defined in line 25; never used
sin defined in line 56; used 2 times
  • in line 151(2)
timeout defined in line 288; used 4 times
timeoutbuf defined in line 289; used 3 times

Defined struct's

errmsg defined in line 443; used 2 times
  • in line 469(2)
formats defined in line 169; used 6 times

Defined macros

MAXARG defined in line 67; used 2 times
PKTSIZE defined in line 61; used 3 times
TIMEOUT defined in line 53; used 2 times
Last modified: 1994-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2543
Valid CSS Valid XHTML 1.0 Strict