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