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: }