tftpd.c (71926) | tftpd.c (84047) |
---|---|
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. 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 --- 28 unchanged lines hidden (view full) --- 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; 43#endif 44static const char rcsid[] = | 1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. 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 --- 28 unchanged lines hidden (view full) --- 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; 43#endif 44static const char rcsid[] = |
45 "$FreeBSD: head/libexec/tftpd/tftpd.c 71926 2001-02-02 10:53:02Z asmodai $"; | 45 "$FreeBSD: head/libexec/tftpd/tftpd.c 84047 2001-09-27 20:50:14Z obrien $"; |
46#endif /* not lint */ 47 48/* 49 * Trivial file transfer protocol server. 50 * 51 * This version includes many modifications by Jim Guyton 52 * <guyton@rand-unix>. 53 */ --- 20 unchanged lines hidden (view full) --- 74#include <stdlib.h> 75#include <string.h> 76#include <syslog.h> 77#include <unistd.h> 78 79#include "tftpsubs.h" 80 81#define TIMEOUT 5 | 46#endif /* not lint */ 47 48/* 49 * Trivial file transfer protocol server. 50 * 51 * This version includes many modifications by Jim Guyton 52 * <guyton@rand-unix>. 53 */ --- 20 unchanged lines hidden (view full) --- 74#include <stdlib.h> 75#include <string.h> 76#include <syslog.h> 77#include <unistd.h> 78 79#include "tftpsubs.h" 80 81#define TIMEOUT 5 |
82#define MAX_TIMEOUTS 5 |
|
82 83int peer; 84int rexmtval = TIMEOUT; | 83 84int peer; 85int rexmtval = TIMEOUT; |
85int maxtimeout = 5*TIMEOUT; | 86int max_rexmtval = 2*TIMEOUT; |
86 87#define PKTSIZE SEGSIZE+4 88char buf[PKTSIZE]; 89char ackbuf[PKTSIZE]; 90struct sockaddr_in from; 91int fromlen; 92 93void tftp __P((struct tftphdr *, int)); --- 11 unchanged lines hidden (view full) --- 105 int len; 106} dirs[MAXDIRS+1]; 107static int suppress_naks; 108static int logging; 109static int ipchroot; 110 111static char *errtomsg __P((int)); 112static void nak __P((int)); | 87 88#define PKTSIZE SEGSIZE+4 89char buf[PKTSIZE]; 90char ackbuf[PKTSIZE]; 91struct sockaddr_in from; 92int fromlen; 93 94void tftp __P((struct tftphdr *, int)); --- 11 unchanged lines hidden (view full) --- 106 int len; 107} dirs[MAXDIRS+1]; 108static int suppress_naks; 109static int logging; 110static int ipchroot; 111 112static char *errtomsg __P((int)); 113static void nak __P((int)); |
114static void oack __P(()); |
|
113 114int 115main(argc, argv) 116 int argc; 117 char *argv[]; 118{ 119 register struct tftphdr *tp; 120 register int n; --- 185 unchanged lines hidden (view full) --- 306 { "netascii", validate_access, xmitfile, recvfile, 1 }, 307 { "octet", validate_access, xmitfile, recvfile, 0 }, 308#ifdef notdef 309 { "mail", validate_user, sendmail, recvmail, 1 }, 310#endif 311 { 0 } 312}; 313 | 115 116int 117main(argc, argv) 118 int argc; 119 char *argv[]; 120{ 121 register struct tftphdr *tp; 122 register int n; --- 185 unchanged lines hidden (view full) --- 308 { "netascii", validate_access, xmitfile, recvfile, 1 }, 309 { "octet", validate_access, xmitfile, recvfile, 0 }, 310#ifdef notdef 311 { "mail", validate_user, sendmail, recvmail, 1 }, 312#endif 313 { 0 } 314}; 315 |
316struct options { 317 char *o_type; 318 char *o_request; 319 int o_reply; /* turn into union if need be */ 320} options[] = { 321 { "tsize" }, /* OPT_TSIZE */ 322 { "timeout" }, /* OPT_TIMEOUT */ 323 { NULL } 324}; 325 326enum opt_enum { 327 OPT_TSIZE = 0, 328 OPT_TIMEOUT, 329}; 330 |
|
314/* 315 * Handle initial connection protocol. 316 */ 317void 318tftp(tp, size) 319 struct tftphdr *tp; 320 int size; 321{ 322 register char *cp; | 331/* 332 * Handle initial connection protocol. 333 */ 334void 335tftp(tp, size) 336 struct tftphdr *tp; 337 int size; 338{ 339 register char *cp; |
323 int first = 1, ecode; | 340 int i, first = 1, has_options = 0, ecode; |
324 register struct formats *pf; | 341 register struct formats *pf; |
325 char *filename, *mode; | 342 char *filename, *mode, *option, *ccp; |
326 327 filename = cp = tp->th_stuff; 328again: 329 while (cp < buf + size) { 330 if (*cp == '\0') 331 break; 332 cp++; 333 } --- 11 unchanged lines hidden (view full) --- 345 *cp = tolower(*cp); 346 for (pf = formats; pf->f_mode; pf++) 347 if (strcmp(pf->f_mode, mode) == 0) 348 break; 349 if (pf->f_mode == 0) { 350 nak(EBADOP); 351 exit(1); 352 } | 343 344 filename = cp = tp->th_stuff; 345again: 346 while (cp < buf + size) { 347 if (*cp == '\0') 348 break; 349 cp++; 350 } --- 11 unchanged lines hidden (view full) --- 362 *cp = tolower(*cp); 363 for (pf = formats; pf->f_mode; pf++) 364 if (strcmp(pf->f_mode, mode) == 0) 365 break; 366 if (pf->f_mode == 0) { 367 nak(EBADOP); 368 exit(1); 369 } |
370 while (++cp < buf + size) { 371 for (i = 2, ccp = cp; i > 0; ccp++) { 372 if (ccp >= buf + size) { 373 nak(EBADOP); 374 exit(1); 375 } else if (*ccp == '\0') 376 i--; 377 } 378 for (option = cp; *cp; cp++) 379 if (isupper(*cp)) 380 *cp = tolower(*cp); 381 for (i = 0; options[i].o_type != NULL; i++) 382 if (strcmp(option, options[i].o_type) == 0) { 383 options[i].o_request = ++cp; 384 has_options = 1; 385 } 386 cp = ccp-1; 387 } 388 389 if (options[OPT_TIMEOUT].o_request) { 390 int to = atoi(options[OPT_TIMEOUT].o_request); 391 if (to < 1 || to > 255) { 392 nak(EBADOP); 393 exit(1); 394 } 395 else if (to <= max_rexmtval) 396 options[OPT_TIMEOUT].o_reply = rexmtval = to; 397 else 398 options[OPT_TIMEOUT].o_request = NULL; 399 } 400 |
|
353 ecode = (*pf->f_validate)(&filename, tp->th_opcode); | 401 ecode = (*pf->f_validate)(&filename, tp->th_opcode); |
402 if (has_options) 403 oack(); |
|
354 if (logging) { 355 char host[MAXHOSTNAMELEN]; 356 357 realhostname(host, sizeof(host) - 1, &from.sin_addr); 358 host[sizeof(host) - 1] = '\0'; 359 syslog(LOG_INFO, "%s: %s request for %s: %s", host, 360 tp->th_opcode == WRQ ? "write" : "read", 361 filename, errtomsg(ecode)); --- 101 unchanged lines hidden (view full) --- 463 } 464 err = EACCESS; 465 } 466 } 467 if (dirp->name == NULL) 468 return (err); 469 *filep = filename = pathname; 470 } | 404 if (logging) { 405 char host[MAXHOSTNAMELEN]; 406 407 realhostname(host, sizeof(host) - 1, &from.sin_addr); 408 host[sizeof(host) - 1] = '\0'; 409 syslog(LOG_INFO, "%s: %s request for %s: %s", host, 410 tp->th_opcode == WRQ ? "write" : "read", 411 filename, errtomsg(ecode)); --- 101 unchanged lines hidden (view full) --- 513 } 514 err = EACCESS; 515 } 516 } 517 if (dirp->name == NULL) 518 return (err); 519 *filep = filename = pathname; 520 } |
521 if (options[OPT_TSIZE].o_request) { 522 if (mode == RRQ) 523 options[OPT_TSIZE].o_reply = stbuf.st_size; 524 else 525 /* XXX Allows writes of all sizes. */ 526 options[OPT_TSIZE].o_reply = 527 atoi(options[OPT_TSIZE].o_request); 528 } |
|
471 fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC); 472 if (fd < 0) 473 return (errno + 100); 474 file = fdopen(fd, (mode == RRQ)? "r":"w"); 475 if (file == NULL) { 476 return errno+100; 477 } 478 return (0); 479} 480 | 529 fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC); 530 if (fd < 0) 531 return (errno + 100); 532 file = fdopen(fd, (mode == RRQ)? "r":"w"); 533 if (file == NULL) { 534 return errno+100; 535 } 536 return (0); 537} 538 |
481int timeout; | 539int timeouts; |
482jmp_buf timeoutbuf; 483 484void 485timer() 486{ | 540jmp_buf timeoutbuf; 541 542void 543timer() 544{ |
487 488 timeout += rexmtval; 489 if (timeout >= maxtimeout) | 545 if (++timeouts > MAX_TIMEOUTS) |
490 exit(1); 491 longjmp(timeoutbuf, 1); 492} 493 494/* 495 * Send the requested file. 496 */ 497void --- 12 unchanged lines hidden (view full) --- 510 do { 511 size = readit(file, &dp, pf->f_convert); 512 if (size < 0) { 513 nak(errno + 100); 514 goto abort; 515 } 516 dp->th_opcode = htons((u_short)DATA); 517 dp->th_block = htons((u_short)block); | 546 exit(1); 547 longjmp(timeoutbuf, 1); 548} 549 550/* 551 * Send the requested file. 552 */ 553void --- 12 unchanged lines hidden (view full) --- 566 do { 567 size = readit(file, &dp, pf->f_convert); 568 if (size < 0) { 569 nak(errno + 100); 570 goto abort; 571 } 572 dp->th_opcode = htons((u_short)DATA); 573 dp->th_block = htons((u_short)block); |
518 timeout = 0; | 574 timeouts = 0; |
519 (void)setjmp(timeoutbuf); 520 521send_data: 522 if (send(peer, dp, size + 4, 0) != size + 4) { 523 syslog(LOG_ERR, "write: %m"); 524 goto abort; 525 } 526 read_ahead(file, pf->f_convert); --- 46 unchanged lines hidden (view full) --- 573 register int n, size; 574 volatile unsigned short block; 575 576 signal(SIGALRM, timer); 577 dp = w_init(); 578 ap = (struct tftphdr *)ackbuf; 579 block = 0; 580 do { | 575 (void)setjmp(timeoutbuf); 576 577send_data: 578 if (send(peer, dp, size + 4, 0) != size + 4) { 579 syslog(LOG_ERR, "write: %m"); 580 goto abort; 581 } 582 read_ahead(file, pf->f_convert); --- 46 unchanged lines hidden (view full) --- 629 register int n, size; 630 volatile unsigned short block; 631 632 signal(SIGALRM, timer); 633 dp = w_init(); 634 ap = (struct tftphdr *)ackbuf; 635 block = 0; 636 do { |
581 timeout = 0; | 637 timeouts = 0; |
582 ap->th_opcode = htons((u_short)ACK); 583 ap->th_block = htons((u_short)block); 584 block++; 585 (void) setjmp(timeoutbuf); 586send_ack: 587 if (send(peer, ackbuf, 4, 0) != 4) { 588 syslog(LOG_ERR, "write: %m"); 589 goto abort; --- 56 unchanged lines hidden (view full) --- 646 { EUNDEF, "Undefined error code" }, 647 { ENOTFOUND, "File not found" }, 648 { EACCESS, "Access violation" }, 649 { ENOSPACE, "Disk full or allocation exceeded" }, 650 { EBADOP, "Illegal TFTP operation" }, 651 { EBADID, "Unknown transfer ID" }, 652 { EEXISTS, "File already exists" }, 653 { ENOUSER, "No such user" }, | 638 ap->th_opcode = htons((u_short)ACK); 639 ap->th_block = htons((u_short)block); 640 block++; 641 (void) setjmp(timeoutbuf); 642send_ack: 643 if (send(peer, ackbuf, 4, 0) != 4) { 644 syslog(LOG_ERR, "write: %m"); 645 goto abort; --- 56 unchanged lines hidden (view full) --- 702 { EUNDEF, "Undefined error code" }, 703 { ENOTFOUND, "File not found" }, 704 { EACCESS, "Access violation" }, 705 { ENOSPACE, "Disk full or allocation exceeded" }, 706 { EBADOP, "Illegal TFTP operation" }, 707 { EBADID, "Unknown transfer ID" }, 708 { EEXISTS, "File already exists" }, 709 { ENOUSER, "No such user" }, |
710 { EOPTNEG, "Option negotiation" }, |
|
654 { -1, 0 } 655}; 656 657static char * 658errtomsg(error) 659 int error; 660{ 661 static char buf[20]; --- 33 unchanged lines hidden (view full) --- 695 } 696 strcpy(tp->th_msg, pe->e_msg); 697 length = strlen(pe->e_msg); 698 tp->th_msg[length] = '\0'; 699 length += 5; 700 if (send(peer, buf, length, 0) != length) 701 syslog(LOG_ERR, "nak: %m"); 702} | 711 { -1, 0 } 712}; 713 714static char * 715errtomsg(error) 716 int error; 717{ 718 static char buf[20]; --- 33 unchanged lines hidden (view full) --- 752 } 753 strcpy(tp->th_msg, pe->e_msg); 754 length = strlen(pe->e_msg); 755 tp->th_msg[length] = '\0'; 756 length += 5; 757 if (send(peer, buf, length, 0) != length) 758 syslog(LOG_ERR, "nak: %m"); 759} |
760 761/* 762 * Send an oack packet (option acknowledgement). 763 */ 764static void 765oack() 766{ 767 struct tftphdr *tp, *ap; 768 int size, i, n; 769 char *bp; 770 771 tp = (struct tftphdr *)buf; 772 bp = buf + 2; 773 size = sizeof(buf) - 2; 774 tp->th_opcode = htons((u_short)OACK); 775 for (i = 0; options[i].o_type != NULL; i++) { 776 if (options[i].o_request) { 777 n = snprintf(bp, size, "%s%c%d", options[i].o_type, 778 0, options[i].o_reply); 779 bp += n+1; 780 size -= n+1; 781 if (size < 0) { 782 syslog(LOG_ERR, "oack: buffer overflow"); 783 exit(1); 784 } 785 } 786 } 787 size = bp - buf; 788 ap = (struct tftphdr *)ackbuf; 789 signal(SIGALRM, timer); 790 timeouts = 0; 791 792 (void)setjmp(timeoutbuf); 793 if (send(peer, buf, size, 0) != size) { 794 syslog(LOG_INFO, "oack: %m"); 795 exit(1); 796 } 797 798 for (;;) { 799 alarm(rexmtval); 800 n = recv(peer, ackbuf, sizeof (ackbuf), 0); 801 alarm(0); 802 if (n < 0) { 803 syslog(LOG_ERR, "recv: %m"); 804 exit(1); 805 } 806 ap->th_opcode = ntohs((u_short)ap->th_opcode); 807 ap->th_block = ntohs((u_short)ap->th_block); 808 if (ap->th_opcode == ERROR) 809 exit(1); 810 if (ap->th_opcode == ACK && ap->th_block == 0) 811 break; 812 } 813} |
|