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, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/ 42 static char rcsid[] = "$Id: tftpd.c,v 1.5 1994/03/01 08:27:44 cgd Exp $"; 43 #endif /* not lint */ 44 45 /* 46 * Trivial file transfer protocol server. 47 * 48 * This version includes many modifications by Jim Guyton <guyton@rand-unix> 49 */ 50 51 #include <sys/types.h> 52 #include <sys/ioctl.h> 53 #include <sys/stat.h> 54 #include <signal.h> 55 #include <fcntl.h> 56 57 #include <sys/socket.h> 58 #include <netinet/in.h> 59 #include <arpa/tftp.h> 60 #include <netdb.h> 61 62 #include <setjmp.h> 63 #include <syslog.h> 64 #include <stdio.h> 65 #include <errno.h> 66 #include <ctype.h> 67 #include <string.h> 68 #include <stdlib.h> 69 70 #define TIMEOUT 5 71 72 extern int errno; 73 extern char *__progname; 74 struct sockaddr_in s_in = { AF_INET }; 75 int peer; 76 int rexmtval = TIMEOUT; 77 int maxtimeout = 5*TIMEOUT; 78 79 #define PKTSIZE SEGSIZE+4 80 char buf[PKTSIZE]; 81 char ackbuf[PKTSIZE]; 82 struct sockaddr_in from; 83 int fromlen; 84 85 #define MAXARG 4 86 char *dirs[MAXARG+1]; 87 88 int secure = 0; 89 90 static void 91 usage() 92 { 93 syslog(LOG_ERR, "Usage: %s [-s] [directory ...]\n", __progname); 94 exit(1); 95 } 96 97 main(argc, argv) 98 int argc; 99 char **argv; 100 { 101 register struct tftphdr *tp; 102 register int n = 0; 103 int on = 1; 104 int fd = 0; 105 int c; 106 107 openlog("tftpd", LOG_PID, LOG_DAEMON); 108 109 while ((c = getopt(argc, argv, "s")) != -1) 110 switch (c) { 111 case 's': 112 secure = 1; 113 break; 114 115 default: 116 usage(); 117 break; 118 } 119 120 for (; optind != argc; optind++) { 121 if (!secure) { 122 if (n >= MAXARG) { 123 syslog(LOG_ERR, "too many directories\n"); 124 exit(1); 125 } else 126 dirs[n++] = argv[optind]; 127 } 128 if (chdir(argv[optind])) { 129 syslog(LOG_ERR, "%s: %m\n", argv[optind]); 130 exit(1); 131 } 132 } 133 134 if (secure && chroot(".")) { 135 syslog(LOG_ERR, "chroot: %m\n"); 136 exit(1); 137 } 138 139 if (ioctl(fd, FIONBIO, &on) < 0) { 140 syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); 141 exit(1); 142 } 143 fromlen = sizeof (from); 144 n = recvfrom(fd, buf, sizeof (buf), 0, 145 (struct sockaddr *)&from, &fromlen); 146 if (n < 0) { 147 syslog(LOG_ERR, "recvfrom: %m\n"); 148 exit(1); 149 } 150 /* 151 * Now that we have read the message out of the UDP 152 * socket, we fork and exit. Thus, inetd will go back 153 * to listening to the tftp port, and the next request 154 * to come in will start up a new instance of tftpd. 155 * 156 * We do this so that inetd can run tftpd in "wait" mode. 157 * The problem with tftpd running in "nowait" mode is that 158 * inetd may get one or more successful "selects" on the 159 * tftp port before we do our receive, so more than one 160 * instance of tftpd may be started up. Worse, if tftpd 161 * break before doing the above "recvfrom", inetd would 162 * spawn endless instances, clogging the system. 163 */ 164 { 165 int pid; 166 int i, j; 167 168 for (i = 1; i < 20; i++) { 169 pid = fork(); 170 if (pid < 0) { 171 sleep(i); 172 /* 173 * flush out to most recently sent request. 174 * 175 * This may drop some request, but those 176 * will be resent by the clients when 177 * they timeout. The positive effect of 178 * this flush is to (try to) prevent more 179 * than one tftpd being started up to service 180 * a single request from a single client. 181 */ 182 j = sizeof from; 183 i = recvfrom(fd, buf, sizeof (buf), 0, 184 (struct sockaddr *)&from, &j); 185 if (i > 0) { 186 n = i; 187 fromlen = j; 188 } 189 } else { 190 break; 191 } 192 } 193 if (pid < 0) { 194 syslog(LOG_ERR, "fork: %m\n"); 195 exit(1); 196 } else if (pid != 0) { 197 exit(0); 198 } 199 } 200 from.sin_family = AF_INET; 201 alarm(0); 202 close(fd); 203 close(1); 204 peer = socket(AF_INET, SOCK_DGRAM, 0); 205 if (peer < 0) { 206 syslog(LOG_ERR, "socket: %m\n"); 207 exit(1); 208 } 209 if (bind(peer, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) { 210 syslog(LOG_ERR, "bind: %m\n"); 211 exit(1); 212 } 213 if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { 214 syslog(LOG_ERR, "connect: %m\n"); 215 exit(1); 216 } 217 tp = (struct tftphdr *)buf; 218 tp->th_opcode = ntohs(tp->th_opcode); 219 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 220 tftp(tp, n); 221 exit(1); 222 } 223 224 int validate_access(); 225 int sendfile(), recvfile(); 226 227 struct formats { 228 char *f_mode; 229 int (*f_validate)(); 230 int (*f_send)(); 231 int (*f_recv)(); 232 int f_convert; 233 } formats[] = { 234 { "netascii", validate_access, sendfile, recvfile, 1 }, 235 { "octet", validate_access, sendfile, recvfile, 0 }, 236 #ifdef notdef 237 { "mail", validate_user, sendmail, recvmail, 1 }, 238 #endif 239 { 0 } 240 }; 241 242 /* 243 * Handle initial connection protocol. 244 */ 245 tftp(tp, size) 246 struct tftphdr *tp; 247 int size; 248 { 249 register char *cp; 250 int first = 1, ecode; 251 register struct formats *pf; 252 char *filename, *mode; 253 254 filename = cp = tp->th_stuff; 255 again: 256 while (cp < buf + size) { 257 if (*cp == '\0') 258 break; 259 cp++; 260 } 261 if (*cp != '\0') { 262 nak(EBADOP); 263 exit(1); 264 } 265 if (first) { 266 mode = ++cp; 267 first = 0; 268 goto again; 269 } 270 for (cp = mode; *cp; cp++) 271 if (isupper(*cp)) 272 *cp = tolower(*cp); 273 for (pf = formats; pf->f_mode; pf++) 274 if (strcmp(pf->f_mode, mode) == 0) 275 break; 276 if (pf->f_mode == 0) { 277 nak(EBADOP); 278 exit(1); 279 } 280 ecode = (*pf->f_validate)(filename, tp->th_opcode); 281 if (ecode) { 282 nak(ecode); 283 exit(1); 284 } 285 if (tp->th_opcode == WRQ) 286 (*pf->f_recv)(pf); 287 else 288 (*pf->f_send)(pf); 289 exit(0); 290 } 291 292 293 FILE *file; 294 295 /* 296 * Validate file access. Since we 297 * have no uid or gid, for now require 298 * file to exist and be publicly 299 * readable/writable. 300 * If we were invoked with arguments 301 * from inetd then the file must also be 302 * in one of the given directory prefixes. 303 * Note also, full path name must be 304 * given as we have no login directory. 305 */ 306 validate_access(filename, mode) 307 char *filename; 308 int mode; 309 { 310 struct stat stbuf; 311 int fd; 312 char *cp, **dirp; 313 314 if (!secure) { 315 if (*filename != '/') 316 return (EACCESS); 317 /* 318 * prevent tricksters from getting around the directory 319 * restrictions 320 */ 321 for (cp = filename + 1; *cp; cp++) 322 if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0) 323 return(EACCESS); 324 for (dirp = dirs; *dirp; dirp++) 325 if (strncmp(filename, *dirp, strlen(*dirp)) == 0) 326 break; 327 if (*dirp==0 && dirp!=dirs) 328 return (EACCESS); 329 } 330 if (stat(filename, &stbuf) < 0) 331 return (errno == ENOENT ? ENOTFOUND : EACCESS); 332 if (mode == RRQ) { 333 if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) 334 return (EACCESS); 335 } else { 336 if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) 337 return (EACCESS); 338 } 339 fd = open(filename, mode == RRQ ? 0 : 1); 340 if (fd < 0) 341 return (errno + 100); 342 file = fdopen(fd, (mode == RRQ)? "r":"w"); 343 if (file == NULL) { 344 return errno+100; 345 } 346 return (0); 347 } 348 349 int timeout; 350 jmp_buf timeoutbuf; 351 352 void 353 timer() 354 { 355 356 timeout += rexmtval; 357 if (timeout >= maxtimeout) 358 exit(1); 359 longjmp(timeoutbuf, 1); 360 } 361 362 /* 363 * Send the requested file. 364 */ 365 sendfile(pf) 366 struct formats *pf; 367 { 368 struct tftphdr *dp, *r_init(); 369 register struct tftphdr *ap; /* ack packet */ 370 register int block = 1, size, n; 371 372 signal(SIGALRM, timer); 373 dp = r_init(); 374 ap = (struct tftphdr *)ackbuf; 375 do { 376 size = readit(file, &dp, pf->f_convert); 377 if (size < 0) { 378 nak(errno + 100); 379 goto abort; 380 } 381 dp->th_opcode = htons((u_short)DATA); 382 dp->th_block = htons((u_short)block); 383 timeout = 0; 384 (void) setjmp(timeoutbuf); 385 386 send_data: 387 if (send(peer, dp, size + 4, 0) != size + 4) { 388 syslog(LOG_ERR, "tftpd: write: %m\n"); 389 goto abort; 390 } 391 read_ahead(file, pf->f_convert); 392 for ( ; ; ) { 393 alarm(rexmtval); /* read the ack */ 394 n = recv(peer, ackbuf, sizeof (ackbuf), 0); 395 alarm(0); 396 if (n < 0) { 397 syslog(LOG_ERR, "tftpd: read: %m\n"); 398 goto abort; 399 } 400 ap->th_opcode = ntohs((u_short)ap->th_opcode); 401 ap->th_block = ntohs((u_short)ap->th_block); 402 403 if (ap->th_opcode == ERROR) 404 goto abort; 405 406 if (ap->th_opcode == ACK) { 407 if (ap->th_block == block) { 408 break; 409 } 410 /* Re-synchronize with the other side */ 411 (void) synchnet(peer); 412 if (ap->th_block == (block -1)) { 413 goto send_data; 414 } 415 } 416 417 } 418 block++; 419 } while (size == SEGSIZE); 420 abort: 421 (void) fclose(file); 422 } 423 424 void 425 justquit() 426 { 427 exit(0); 428 } 429 430 431 /* 432 * Receive a file. 433 */ 434 recvfile(pf) 435 struct formats *pf; 436 { 437 struct tftphdr *dp, *w_init(); 438 register struct tftphdr *ap; /* ack buffer */ 439 register int block = 0, n, size; 440 441 signal(SIGALRM, timer); 442 dp = w_init(); 443 ap = (struct tftphdr *)ackbuf; 444 do { 445 timeout = 0; 446 ap->th_opcode = htons((u_short)ACK); 447 ap->th_block = htons((u_short)block); 448 block++; 449 (void) setjmp(timeoutbuf); 450 send_ack: 451 if (send(peer, ackbuf, 4, 0) != 4) { 452 syslog(LOG_ERR, "tftpd: write: %m\n"); 453 goto abort; 454 } 455 write_behind(file, pf->f_convert); 456 for ( ; ; ) { 457 alarm(rexmtval); 458 n = recv(peer, dp, PKTSIZE, 0); 459 alarm(0); 460 if (n < 0) { /* really? */ 461 syslog(LOG_ERR, "tftpd: read: %m\n"); 462 goto abort; 463 } 464 dp->th_opcode = ntohs((u_short)dp->th_opcode); 465 dp->th_block = ntohs((u_short)dp->th_block); 466 if (dp->th_opcode == ERROR) 467 goto abort; 468 if (dp->th_opcode == DATA) { 469 if (dp->th_block == block) { 470 break; /* normal */ 471 } 472 /* Re-synchronize with the other side */ 473 (void) synchnet(peer); 474 if (dp->th_block == (block-1)) 475 goto send_ack; /* rexmit */ 476 } 477 } 478 /* size = write(file, dp->th_data, n - 4); */ 479 size = writeit(file, &dp, n - 4, pf->f_convert); 480 if (size != (n-4)) { /* ahem */ 481 if (size < 0) nak(errno + 100); 482 else nak(ENOSPACE); 483 goto abort; 484 } 485 } while (size == SEGSIZE); 486 write_behind(file, pf->f_convert); 487 (void) fclose(file); /* close data file */ 488 489 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ 490 ap->th_block = htons((u_short)(block)); 491 (void) send(peer, ackbuf, 4, 0); 492 493 signal(SIGALRM, justquit); /* just quit on timeout */ 494 alarm(rexmtval); 495 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ 496 alarm(0); 497 if (n >= 4 && /* if read some data */ 498 dp->th_opcode == DATA && /* and got a data block */ 499 block == dp->th_block) { /* then my last ack was lost */ 500 (void) send(peer, ackbuf, 4, 0); /* resend final ack */ 501 } 502 abort: 503 return; 504 } 505 506 struct errmsg { 507 int e_code; 508 char *e_msg; 509 } errmsgs[] = { 510 { EUNDEF, "Undefined error code" }, 511 { ENOTFOUND, "File not found" }, 512 { EACCESS, "Access violation" }, 513 { ENOSPACE, "Disk full or allocation exceeded" }, 514 { EBADOP, "Illegal TFTP operation" }, 515 { EBADID, "Unknown transfer ID" }, 516 { EEXISTS, "File already exists" }, 517 { ENOUSER, "No such user" }, 518 { -1, 0 } 519 }; 520 521 /* 522 * Send a nak packet (error message). 523 * Error code passed in is one of the 524 * standard TFTP codes, or a UNIX errno 525 * offset by 100. 526 */ 527 nak(error) 528 int error; 529 { 530 register struct tftphdr *tp; 531 int length; 532 register struct errmsg *pe; 533 534 tp = (struct tftphdr *)buf; 535 tp->th_opcode = htons((u_short)ERROR); 536 tp->th_code = htons((u_short)error); 537 for (pe = errmsgs; pe->e_code >= 0; pe++) 538 if (pe->e_code == error) 539 break; 540 if (pe->e_code < 0) { 541 pe->e_msg = strerror(error - 100); 542 tp->th_code = EUNDEF; /* set 'undef' errorcode */ 543 } 544 strcpy(tp->th_msg, pe->e_msg); 545 length = strlen(pe->e_msg); 546 tp->th_msg[length] = '\0'; 547 length += 5; 548 if (send(peer, buf, length, 0) != length) 549 syslog(LOG_ERR, "nak: %m\n"); 550 } 551