1 /* 2 * Copyright (c) 1983, 1993 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1983, 1993 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)tftpd.c 5.16 (Berkeley) 06/04/93"; 16 #endif /* not lint */ 17 18 /* 19 * Trivial file transfer protocol server. 20 * 21 * This version includes many modifications by Jim Guyton 22 * <guyton@rand-unix>. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/ioctl.h> 27 #include <sys/stat.h> 28 #include <sys/socket.h> 29 30 #include <netinet/in.h> 31 #include <arpa/tftp.h> 32 #include <arpa/inet.h> 33 34 #include <ctype.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <netdb.h> 38 #include <setjmp.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <unistd.h> 45 46 #include "tftpsubs.h" 47 48 #define TIMEOUT 5 49 50 int peer; 51 int rexmtval = TIMEOUT; 52 int maxtimeout = 5*TIMEOUT; 53 54 #define PKTSIZE SEGSIZE+4 55 char buf[PKTSIZE]; 56 char ackbuf[PKTSIZE]; 57 struct sockaddr_in from; 58 int fromlen; 59 60 void tftp __P((struct tftphdr *, int)); 61 62 /* 63 * Null-terminated directory prefix list for absolute pathname requests and 64 * search list for relative pathname requests. 65 * 66 * MAXDIRS should be at least as large as the number of arguments that 67 * inetd allows (currently 20). 68 */ 69 #define MAXDIRS 20 70 static struct dirlist { 71 char *name; 72 int len; 73 } dirs[MAXDIRS+1]; 74 static int suppress_naks; 75 static int logging; 76 77 static char *errtomsg __P((int)); 78 static void nak __P((int)); 79 static char *verifyhost __P((struct sockaddr_in *)); 80 81 int 82 main(argc, argv) 83 int argc; 84 char *argv[]; 85 { 86 register struct tftphdr *tp; 87 register int n; 88 int ch, on; 89 struct sockaddr_in sin; 90 91 openlog("tftpd", LOG_PID, LOG_FTP); 92 while ((ch = getopt(argc, argv, "ln")) != EOF) { 93 switch (ch) { 94 case 'l': 95 logging = 1; 96 break; 97 case 'n': 98 suppress_naks = 1; 99 break; 100 default: 101 syslog(LOG_WARNING, "ignoring unknown option -%c", ch); 102 } 103 } 104 if (optind < argc) { 105 struct dirlist *dirp; 106 107 /* Get list of directory prefixes. Skip relative pathnames. */ 108 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS]; 109 optind++) { 110 if (argv[optind][0] == '/') { 111 dirp->name = argv[optind]; 112 dirp->len = strlen(dirp->name); 113 dirp++; 114 } 115 } 116 } 117 118 on = 1; 119 if (ioctl(0, FIONBIO, &on) < 0) { 120 syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); 121 exit(1); 122 } 123 fromlen = sizeof (from); 124 n = recvfrom(0, buf, sizeof (buf), 0, 125 (struct sockaddr *)&from, &fromlen); 126 if (n < 0) { 127 syslog(LOG_ERR, "recvfrom: %m\n"); 128 exit(1); 129 } 130 /* 131 * Now that we have read the message out of the UDP 132 * socket, we fork and exit. Thus, inetd will go back 133 * to listening to the tftp port, and the next request 134 * to come in will start up a new instance of tftpd. 135 * 136 * We do this so that inetd can run tftpd in "wait" mode. 137 * The problem with tftpd running in "nowait" mode is that 138 * inetd may get one or more successful "selects" on the 139 * tftp port before we do our receive, so more than one 140 * instance of tftpd may be started up. Worse, if tftpd 141 * break before doing the above "recvfrom", inetd would 142 * spawn endless instances, clogging the system. 143 */ 144 { 145 int pid; 146 int i, j; 147 148 for (i = 1; i < 20; i++) { 149 pid = fork(); 150 if (pid < 0) { 151 sleep(i); 152 /* 153 * flush out to most recently sent request. 154 * 155 * This may drop some request, but those 156 * will be resent by the clients when 157 * they timeout. The positive effect of 158 * this flush is to (try to) prevent more 159 * than one tftpd being started up to service 160 * a single request from a single client. 161 */ 162 j = sizeof from; 163 i = recvfrom(0, buf, sizeof (buf), 0, 164 (struct sockaddr *)&from, &j); 165 if (i > 0) { 166 n = i; 167 fromlen = j; 168 } 169 } else { 170 break; 171 } 172 } 173 if (pid < 0) { 174 syslog(LOG_ERR, "fork: %m\n"); 175 exit(1); 176 } else if (pid != 0) { 177 exit(0); 178 } 179 } 180 from.sin_family = AF_INET; 181 alarm(0); 182 close(0); 183 close(1); 184 peer = socket(AF_INET, SOCK_DGRAM, 0); 185 if (peer < 0) { 186 syslog(LOG_ERR, "socket: %m\n"); 187 exit(1); 188 } 189 memset(&sin, 0, sizeof(sin)); 190 sin.sin_family = AF_INET; 191 if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 192 syslog(LOG_ERR, "bind: %m\n"); 193 exit(1); 194 } 195 if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { 196 syslog(LOG_ERR, "connect: %m\n"); 197 exit(1); 198 } 199 tp = (struct tftphdr *)buf; 200 tp->th_opcode = ntohs(tp->th_opcode); 201 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 202 tftp(tp, n); 203 exit(1); 204 } 205 206 struct formats; 207 int validate_access __P((char **, int)); 208 void sendfile __P((struct formats *)); 209 void recvfile __P((struct formats *)); 210 211 struct formats { 212 char *f_mode; 213 int (*f_validate) __P((char **, int)); 214 void (*f_send) __P((struct formats *)); 215 void (*f_recv) __P((struct formats *)); 216 int f_convert; 217 } formats[] = { 218 { "netascii", validate_access, sendfile, recvfile, 1 }, 219 { "octet", validate_access, sendfile, recvfile, 0 }, 220 #ifdef notdef 221 { "mail", validate_user, sendmail, recvmail, 1 }, 222 #endif 223 { 0 } 224 }; 225 226 /* 227 * Handle initial connection protocol. 228 */ 229 void 230 tftp(tp, size) 231 struct tftphdr *tp; 232 int size; 233 { 234 register char *cp; 235 int first = 1, ecode; 236 register struct formats *pf; 237 char *filename, *mode; 238 239 filename = cp = tp->th_stuff; 240 again: 241 while (cp < buf + size) { 242 if (*cp == '\0') 243 break; 244 cp++; 245 } 246 if (*cp != '\0') { 247 nak(EBADOP); 248 exit(1); 249 } 250 if (first) { 251 mode = ++cp; 252 first = 0; 253 goto again; 254 } 255 for (cp = mode; *cp; cp++) 256 if (isupper(*cp)) 257 *cp = tolower(*cp); 258 for (pf = formats; pf->f_mode; pf++) 259 if (strcmp(pf->f_mode, mode) == 0) 260 break; 261 if (pf->f_mode == 0) { 262 nak(EBADOP); 263 exit(1); 264 } 265 ecode = (*pf->f_validate)(&filename, tp->th_opcode); 266 if (logging) { 267 syslog(LOG_INFO, "%s: %s request for %s: %s", 268 verifyhost(&from), 269 tp->th_opcode == WRQ ? "write" : "read", 270 filename, errtomsg(ecode)); 271 } 272 if (ecode) { 273 /* 274 * Avoid storms of naks to a RRQ broadcast for a relative 275 * bootfile pathname from a diskless Sun. 276 */ 277 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) 278 exit(0); 279 nak(ecode); 280 exit(1); 281 } 282 if (tp->th_opcode == WRQ) 283 (*pf->f_recv)(pf); 284 else 285 (*pf->f_send)(pf); 286 exit(0); 287 } 288 289 290 FILE *file; 291 292 /* 293 * Validate file access. Since we 294 * have no uid or gid, for now require 295 * file to exist and be publicly 296 * readable/writable. 297 * If we were invoked with arguments 298 * from inetd then the file must also be 299 * in one of the given directory prefixes. 300 * Note also, full path name must be 301 * given as we have no login directory. 302 */ 303 int 304 validate_access(filep, mode) 305 char **filep; 306 int mode; 307 { 308 struct stat stbuf; 309 int fd; 310 struct dirlist *dirp; 311 static char pathname[MAXPATHLEN]; 312 char *filename = *filep; 313 314 /* 315 * Prevent tricksters from getting around the directory restrictions 316 */ 317 if (strstr(filename, "/../")) 318 return (EACCESS); 319 320 if (*filename == '/') { 321 /* 322 * Allow the request if it's in one of the approved locations. 323 * Special case: check the null prefix ("/") by looking 324 * for length = 1 and relying on the arg. processing that 325 * it's a /. 326 */ 327 for (dirp = dirs; dirp->name != NULL; dirp++) { 328 if (dirp->len == 1 || 329 (!strncmp(filename, dirp->name, dirp->len) && 330 filename[dirp->len] == '/')) 331 break; 332 } 333 /* If directory list is empty, allow access to any file */ 334 if (dirp->name == NULL && dirp != dirs) 335 return (EACCESS); 336 if (stat(filename, &stbuf) < 0) 337 return (errno == ENOENT ? ENOTFOUND : EACCESS); 338 if ((stbuf.st_mode & S_IFMT) != S_IFREG) 339 return (ENOTFOUND); 340 if (mode == RRQ) { 341 if ((stbuf.st_mode & S_IROTH) == 0) 342 return (EACCESS); 343 } else { 344 if ((stbuf.st_mode & S_IWOTH) == 0) 345 return (EACCESS); 346 } 347 } else { 348 int err; 349 350 /* 351 * Relative file name: search the approved locations for it. 352 * Don't allow write requests or ones that avoid directory 353 * restrictions. 354 */ 355 356 if (mode != RRQ || !strncmp(filename, "../", 3)) 357 return (EACCESS); 358 359 /* 360 * If the file exists in one of the directories and isn't 361 * readable, continue looking. However, change the error code 362 * to give an indication that the file exists. 363 */ 364 err = ENOTFOUND; 365 for (dirp = dirs; dirp->name != NULL; dirp++) { 366 sprintf(pathname, "%s/%s", dirp->name, filename); 367 if (stat(pathname, &stbuf) == 0 && 368 (stbuf.st_mode & S_IFMT) == S_IFREG) { 369 if ((stbuf.st_mode & S_IROTH) != 0) { 370 break; 371 } 372 err = EACCESS; 373 } 374 } 375 if (dirp->name == NULL) 376 return (err); 377 *filep = filename = pathname; 378 } 379 fd = open(filename, mode == RRQ ? 0 : 1); 380 if (fd < 0) 381 return (errno + 100); 382 file = fdopen(fd, (mode == RRQ)? "r":"w"); 383 if (file == NULL) { 384 return errno+100; 385 } 386 return (0); 387 } 388 389 int timeout; 390 jmp_buf timeoutbuf; 391 392 void 393 timer() 394 { 395 396 timeout += rexmtval; 397 if (timeout >= maxtimeout) 398 exit(1); 399 longjmp(timeoutbuf, 1); 400 } 401 402 /* 403 * Send the requested file. 404 */ 405 void 406 sendfile(pf) 407 struct formats *pf; 408 { 409 struct tftphdr *dp, *r_init(); 410 register struct tftphdr *ap; /* ack packet */ 411 register int size, n; 412 volatile int block; 413 414 signal(SIGALRM, timer); 415 dp = r_init(); 416 ap = (struct tftphdr *)ackbuf; 417 block = 1; 418 do { 419 size = readit(file, &dp, pf->f_convert); 420 if (size < 0) { 421 nak(errno + 100); 422 goto abort; 423 } 424 dp->th_opcode = htons((u_short)DATA); 425 dp->th_block = htons((u_short)block); 426 timeout = 0; 427 (void)setjmp(timeoutbuf); 428 429 send_data: 430 if (send(peer, dp, size + 4, 0) != size + 4) { 431 syslog(LOG_ERR, "tftpd: write: %m\n"); 432 goto abort; 433 } 434 read_ahead(file, pf->f_convert); 435 for ( ; ; ) { 436 alarm(rexmtval); /* read the ack */ 437 n = recv(peer, ackbuf, sizeof (ackbuf), 0); 438 alarm(0); 439 if (n < 0) { 440 syslog(LOG_ERR, "tftpd: read: %m\n"); 441 goto abort; 442 } 443 ap->th_opcode = ntohs((u_short)ap->th_opcode); 444 ap->th_block = ntohs((u_short)ap->th_block); 445 446 if (ap->th_opcode == ERROR) 447 goto abort; 448 449 if (ap->th_opcode == ACK) { 450 if (ap->th_block == block) 451 break; 452 /* Re-synchronize with the other side */ 453 (void) synchnet(peer); 454 if (ap->th_block == (block -1)) 455 goto send_data; 456 } 457 458 } 459 block++; 460 } while (size == SEGSIZE); 461 abort: 462 (void) fclose(file); 463 } 464 465 void 466 justquit() 467 { 468 exit(0); 469 } 470 471 472 /* 473 * Receive a file. 474 */ 475 void 476 recvfile(pf) 477 struct formats *pf; 478 { 479 struct tftphdr *dp, *w_init(); 480 register struct tftphdr *ap; /* ack buffer */ 481 register int n, size; 482 volatile int block; 483 484 signal(SIGALRM, timer); 485 dp = w_init(); 486 ap = (struct tftphdr *)ackbuf; 487 block = 0; 488 do { 489 timeout = 0; 490 ap->th_opcode = htons((u_short)ACK); 491 ap->th_block = htons((u_short)block); 492 block++; 493 (void) setjmp(timeoutbuf); 494 send_ack: 495 if (send(peer, ackbuf, 4, 0) != 4) { 496 syslog(LOG_ERR, "tftpd: write: %m\n"); 497 goto abort; 498 } 499 write_behind(file, pf->f_convert); 500 for ( ; ; ) { 501 alarm(rexmtval); 502 n = recv(peer, dp, PKTSIZE, 0); 503 alarm(0); 504 if (n < 0) { /* really? */ 505 syslog(LOG_ERR, "tftpd: read: %m\n"); 506 goto abort; 507 } 508 dp->th_opcode = ntohs((u_short)dp->th_opcode); 509 dp->th_block = ntohs((u_short)dp->th_block); 510 if (dp->th_opcode == ERROR) 511 goto abort; 512 if (dp->th_opcode == DATA) { 513 if (dp->th_block == block) { 514 break; /* normal */ 515 } 516 /* Re-synchronize with the other side */ 517 (void) synchnet(peer); 518 if (dp->th_block == (block-1)) 519 goto send_ack; /* rexmit */ 520 } 521 } 522 /* size = write(file, dp->th_data, n - 4); */ 523 size = writeit(file, &dp, n - 4, pf->f_convert); 524 if (size != (n-4)) { /* ahem */ 525 if (size < 0) nak(errno + 100); 526 else nak(ENOSPACE); 527 goto abort; 528 } 529 } while (size == SEGSIZE); 530 write_behind(file, pf->f_convert); 531 (void) fclose(file); /* close data file */ 532 533 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ 534 ap->th_block = htons((u_short)(block)); 535 (void) send(peer, ackbuf, 4, 0); 536 537 signal(SIGALRM, justquit); /* just quit on timeout */ 538 alarm(rexmtval); 539 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ 540 alarm(0); 541 if (n >= 4 && /* if read some data */ 542 dp->th_opcode == DATA && /* and got a data block */ 543 block == dp->th_block) { /* then my last ack was lost */ 544 (void) send(peer, ackbuf, 4, 0); /* resend final ack */ 545 } 546 abort: 547 return; 548 } 549 550 struct errmsg { 551 int e_code; 552 char *e_msg; 553 } errmsgs[] = { 554 { EUNDEF, "Undefined error code" }, 555 { ENOTFOUND, "File not found" }, 556 { EACCESS, "Access violation" }, 557 { ENOSPACE, "Disk full or allocation exceeded" }, 558 { EBADOP, "Illegal TFTP operation" }, 559 { EBADID, "Unknown transfer ID" }, 560 { EEXISTS, "File already exists" }, 561 { ENOUSER, "No such user" }, 562 { -1, 0 } 563 }; 564 565 static char * 566 errtomsg(error) 567 int error; 568 { 569 static char buf[20]; 570 register struct errmsg *pe; 571 if (error == 0) 572 return "success"; 573 for (pe = errmsgs; pe->e_code >= 0; pe++) 574 if (pe->e_code == error) 575 return pe->e_msg; 576 sprintf(buf, "error %d", error); 577 return buf; 578 } 579 580 /* 581 * Send a nak packet (error message). 582 * Error code passed in is one of the 583 * standard TFTP codes, or a UNIX errno 584 * offset by 100. 585 */ 586 static void 587 nak(error) 588 int error; 589 { 590 register struct tftphdr *tp; 591 int length; 592 register struct errmsg *pe; 593 594 tp = (struct tftphdr *)buf; 595 tp->th_opcode = htons((u_short)ERROR); 596 tp->th_code = htons((u_short)error); 597 for (pe = errmsgs; pe->e_code >= 0; pe++) 598 if (pe->e_code == error) 599 break; 600 if (pe->e_code < 0) { 601 pe->e_msg = strerror(error - 100); 602 tp->th_code = EUNDEF; /* set 'undef' errorcode */ 603 } 604 strcpy(tp->th_msg, pe->e_msg); 605 length = strlen(pe->e_msg); 606 tp->th_msg[length] = '\0'; 607 length += 5; 608 if (send(peer, buf, length, 0) != length) 609 syslog(LOG_ERR, "nak: %m\n"); 610 } 611 612 static char * 613 verifyhost(fromp) 614 struct sockaddr_in *fromp; 615 { 616 struct hostent *hp; 617 618 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr), 619 fromp->sin_family); 620 if (hp) 621 return hp->h_name; 622 else 623 return inet_ntoa(fromp->sin_addr); 624 } 625