00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include "server_setup.h"
00051
00052 #ifdef HAVE_SYS_IOCTL_H
00053 #include <sys/ioctl.h>
00054 #endif
00055 #ifdef HAVE_SIGNAL_H
00056 #include <signal.h>
00057 #endif
00058 #ifdef HAVE_FCNTL_H
00059 #include <fcntl.h>
00060 #endif
00061 #ifdef HAVE_NETINET_IN_H
00062 #include <netinet/in.h>
00063 #endif
00064 #ifdef HAVE_ARPA_INET_H
00065 #include <arpa/inet.h>
00066 #endif
00067 #ifdef HAVE_ARPA_TFTP_H
00068 #include <arpa/tftp.h>
00069 #else
00070 #include "tftp.h"
00071 #endif
00072 #ifdef HAVE_NETDB_H
00073 #include <netdb.h>
00074 #endif
00075 #ifdef HAVE_SYS_FILIO_H
00076
00077 #include <sys/filio.h>
00078 #endif
00079
00080 #include <setjmp.h>
00081
00082 #ifdef HAVE_PWD_H
00083 #include <pwd.h>
00084 #endif
00085
00086 #define ENABLE_CURLX_PRINTF
00087
00088
00089 #include "curlx.h"
00090 #include "getpart.h"
00091 #include "util.h"
00092 #include "server_sockaddr.h"
00093
00094
00095 #include "memdebug.h"
00096
00097
00098
00099
00100
00101 #ifndef PKTSIZE
00102 #define PKTSIZE (SEGSIZE + 4)
00103 #endif
00104
00105 struct testcase {
00106 char *buffer;
00107 size_t bufsize;
00108 char *rptr;
00109 size_t rcount;
00110 long testno;
00111 int ofile;
00112
00113 int writedelay;
00114 };
00115
00116 struct formats {
00117 const char *f_mode;
00118 int f_convert;
00119 };
00120
00121 struct errmsg {
00122 int e_code;
00123 const char *e_msg;
00124 };
00125
00126 typedef union {
00127 struct tftphdr hdr;
00128 char storage[PKTSIZE];
00129 } tftphdr_storage_t;
00130
00131
00132
00133
00134
00135
00136 struct bf {
00137 int counter;
00138 tftphdr_storage_t buf;
00139 };
00140
00141 #define BF_ALLOC -3
00142 #define BF_FREE -2
00143
00144 #define opcode_RRQ 1
00145 #define opcode_WRQ 2
00146 #define opcode_DATA 3
00147 #define opcode_ACK 4
00148 #define opcode_ERROR 5
00149
00150 #define TIMEOUT 5
00151
00152 #undef MIN
00153 #define MIN(x,y) ((x)<(y)?(x):(y))
00154
00155 #ifndef DEFAULT_LOGFILE
00156 #define DEFAULT_LOGFILE "log/tftpd.log"
00157 #endif
00158
00159 #define REQUEST_DUMP "log/server.input"
00160
00161 #define DEFAULT_PORT 8999
00162
00163
00164
00165
00166
00167 static struct errmsg errmsgs[] = {
00168 { EUNDEF, "Undefined error code" },
00169 { ENOTFOUND, "File not found" },
00170 { EACCESS, "Access violation" },
00171 { ENOSPACE, "Disk full or allocation exceeded" },
00172 { EBADOP, "Illegal TFTP operation" },
00173 { EBADID, "Unknown transfer ID" },
00174 { EEXISTS, "File already exists" },
00175 { ENOUSER, "No such user" },
00176 { -1, 0 }
00177 };
00178
00179 static struct formats formata[] = {
00180 { "netascii", 1 },
00181 { "octet", 0 },
00182 { NULL, 0 }
00183 };
00184
00185 static struct bf bfs[2];
00186
00187 static int nextone;
00188 static int current;
00189
00190
00191 static int newline = 0;
00192 static int prevchar = -1;
00193
00194 static tftphdr_storage_t buf;
00195 static tftphdr_storage_t ackbuf;
00196
00197 static srvr_sockaddr_union_t from;
00198 static curl_socklen_t fromlen;
00199
00200 static curl_socket_t peer = CURL_SOCKET_BAD;
00201
00202 static int timeout;
00203 static int maxtimeout = 5 * TIMEOUT;
00204
00205 #ifdef ENABLE_IPV6
00206 static bool use_ipv6 = FALSE;
00207 #endif
00208 static const char *ipv_inuse = "IPv4";
00209
00210 const char *serverlogfile = DEFAULT_LOGFILE;
00211 static char *pidname= (char *)".tftpd.pid";
00212 static int serverlogslocked = 0;
00213 static int wrotepidfile = 0;
00214
00215 #ifdef HAVE_SIGSETJMP
00216 static sigjmp_buf timeoutbuf;
00217 #endif
00218
00219 #if defined(HAVE_ALARM) && defined(SIGALRM)
00220 static int rexmtval = TIMEOUT;
00221 #endif
00222
00223
00224
00225 #ifndef HAVE_SIGINTERRUPT
00226 #define siginterrupt(x,y) do {} while(0)
00227 #endif
00228
00229
00230
00231 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
00232
00233 #ifdef SIGHUP
00234 static SIGHANDLER_T old_sighup_handler = SIG_ERR;
00235 #endif
00236
00237 #ifdef SIGPIPE
00238 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
00239 #endif
00240
00241 #ifdef SIGINT
00242 static SIGHANDLER_T old_sigint_handler = SIG_ERR;
00243 #endif
00244
00245 #ifdef SIGTERM
00246 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
00247 #endif
00248
00249 #if defined(SIGBREAK) && defined(WIN32)
00250 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
00251 #endif
00252
00253
00254
00255 SIG_ATOMIC_T got_exit_signal = 0;
00256
00257
00258
00259 static volatile int exit_signal = 0;
00260
00261
00262
00263
00264
00265 static struct tftphdr *rw_init(int);
00266
00267 static struct tftphdr *w_init(void);
00268
00269 static struct tftphdr *r_init(void);
00270
00271 static void read_ahead(struct testcase *test, int convert);
00272
00273 static ssize_t write_behind(struct testcase *test, int convert);
00274
00275 static int synchnet(curl_socket_t);
00276
00277 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size);
00278
00279 static int validate_access(struct testcase *test, const char *fname, int mode);
00280
00281 static void sendtftp(struct testcase *test, struct formats *pf);
00282
00283 static void recvtftp(struct testcase *test, struct formats *pf);
00284
00285 static void nak(int error);
00286
00287 #if defined(HAVE_ALARM) && defined(SIGALRM)
00288
00289 static void mysignal(int sig, void (*handler)(int));
00290
00291 static void timer(int signum);
00292
00293 static void justtimeout(int signum);
00294
00295 #endif
00296
00297 static RETSIGTYPE exit_signal_handler(int signum);
00298
00299 static void install_signal_handlers(void);
00300
00301 static void restore_signal_handlers(void);
00302
00303
00304
00305
00306
00307 #if defined(HAVE_ALARM) && defined(SIGALRM)
00308
00309
00310
00311
00312 static void mysignal(int sig, void (*handler)(int))
00313 {
00314 struct sigaction sa;
00315 memset(&sa, 0, sizeof(sa));
00316 sa.sa_handler = handler;
00317 sigaction(sig, &sa, NULL);
00318 }
00319
00320 static void timer(int signum)
00321 {
00322 (void)signum;
00323
00324 logmsg("alarm!");
00325
00326 timeout += rexmtval;
00327 if(timeout >= maxtimeout) {
00328 if(wrotepidfile) {
00329 wrotepidfile = 0;
00330 unlink(pidname);
00331 }
00332 if(serverlogslocked) {
00333 serverlogslocked = 0;
00334 clear_advisor_read_lock(SERVERLOGS_LOCK);
00335 }
00336 exit(1);
00337 }
00338 #ifdef HAVE_SIGSETJMP
00339 siglongjmp(timeoutbuf, 1);
00340 #endif
00341 }
00342
00343 static void justtimeout(int signum)
00344 {
00345 (void)signum;
00346 }
00347
00348 #endif
00349
00350
00351
00352
00353
00354
00355 static RETSIGTYPE exit_signal_handler(int signum)
00356 {
00357 int old_errno = errno;
00358 if(got_exit_signal == 0) {
00359 got_exit_signal = 1;
00360 exit_signal = signum;
00361 }
00362 (void)signal(signum, exit_signal_handler);
00363 errno = old_errno;
00364 }
00365
00366 static void install_signal_handlers(void)
00367 {
00368 #ifdef SIGHUP
00369
00370 old_sighup_handler = signal(SIGHUP, SIG_IGN);
00371 if(old_sighup_handler == SIG_ERR)
00372 logmsg("cannot install SIGHUP handler: %s", strerror(errno));
00373 #endif
00374 #ifdef SIGPIPE
00375
00376 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
00377 if(old_sigpipe_handler == SIG_ERR)
00378 logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
00379 #endif
00380 #ifdef SIGINT
00381
00382 old_sigint_handler = signal(SIGINT, exit_signal_handler);
00383 if(old_sigint_handler == SIG_ERR)
00384 logmsg("cannot install SIGINT handler: %s", strerror(errno));
00385 else
00386 siginterrupt(SIGINT, 1);
00387 #endif
00388 #ifdef SIGTERM
00389
00390 old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
00391 if(old_sigterm_handler == SIG_ERR)
00392 logmsg("cannot install SIGTERM handler: %s", strerror(errno));
00393 else
00394 siginterrupt(SIGTERM, 1);
00395 #endif
00396 #if defined(SIGBREAK) && defined(WIN32)
00397
00398 old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
00399 if(old_sigbreak_handler == SIG_ERR)
00400 logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
00401 else
00402 siginterrupt(SIGBREAK, 1);
00403 #endif
00404 }
00405
00406 static void restore_signal_handlers(void)
00407 {
00408 #ifdef SIGHUP
00409 if(SIG_ERR != old_sighup_handler)
00410 (void)signal(SIGHUP, old_sighup_handler);
00411 #endif
00412 #ifdef SIGPIPE
00413 if(SIG_ERR != old_sigpipe_handler)
00414 (void)signal(SIGPIPE, old_sigpipe_handler);
00415 #endif
00416 #ifdef SIGINT
00417 if(SIG_ERR != old_sigint_handler)
00418 (void)signal(SIGINT, old_sigint_handler);
00419 #endif
00420 #ifdef SIGTERM
00421 if(SIG_ERR != old_sigterm_handler)
00422 (void)signal(SIGTERM, old_sigterm_handler);
00423 #endif
00424 #if defined(SIGBREAK) && defined(WIN32)
00425 if(SIG_ERR != old_sigbreak_handler)
00426 (void)signal(SIGBREAK, old_sigbreak_handler);
00427 #endif
00428 }
00429
00430
00431
00432
00433
00434 static struct tftphdr *rw_init(int x)
00435 {
00436 newline = 0;
00437 prevchar = -1;
00438 bfs[0].counter = BF_ALLOC;
00439 current = 0;
00440 bfs[1].counter = BF_FREE;
00441 nextone = x;
00442 return &bfs[0].buf.hdr;
00443 }
00444
00445 static struct tftphdr *w_init(void)
00446 {
00447 return rw_init(0);
00448 }
00449
00450 static struct tftphdr *r_init(void)
00451 {
00452 return rw_init(1);
00453 }
00454
00455
00456
00457
00458 static int readit(struct testcase *test, struct tftphdr **dpp,
00459 int convert )
00460 {
00461 struct bf *b;
00462
00463 bfs[current].counter = BF_FREE;
00464 current = !current;
00465
00466 b = &bfs[current];
00467 if(b->counter == BF_FREE)
00468 read_ahead(test, convert);
00469
00470 *dpp = &b->buf.hdr;
00471 return b->counter;
00472 }
00473
00474
00475
00476
00477
00478 static void read_ahead(struct testcase *test,
00479 int convert )
00480 {
00481 int i;
00482 char *p;
00483 int c;
00484 struct bf *b;
00485 struct tftphdr *dp;
00486
00487 b = &bfs[nextone];
00488 if(b->counter != BF_FREE)
00489 return;
00490 nextone = !nextone;
00491
00492 dp = &b->buf.hdr;
00493
00494 if(convert == 0) {
00495
00496
00497 size_t copy_n = MIN(SEGSIZE, test->rcount);
00498 memcpy(dp->th_data, test->rptr, copy_n);
00499
00500
00501 test->rcount -= copy_n;
00502 test->rptr += copy_n;
00503 b->counter = (int)copy_n;
00504 return;
00505 }
00506
00507 p = dp->th_data;
00508 for(i = 0 ; i < SEGSIZE; i++) {
00509 if(newline) {
00510 if(prevchar == '\n')
00511 c = '\n';
00512 else
00513 c = '\0';
00514 newline = 0;
00515 }
00516 else {
00517 if(test->rcount) {
00518 c=test->rptr[0];
00519 test->rptr++;
00520 test->rcount--;
00521 }
00522 else
00523 break;
00524 if(c == '\n' || c == '\r') {
00525 prevchar = c;
00526 c = '\r';
00527 newline = 1;
00528 }
00529 }
00530 *p++ = (char)c;
00531 }
00532 b->counter = (int)(p - dp->th_data);
00533 }
00534
00535
00536
00537
00538 static int writeit(struct testcase *test, struct tftphdr * volatile *dpp,
00539 int ct, int convert)
00540 {
00541 bfs[current].counter = ct;
00542 current = !current;
00543 if(bfs[current].counter != BF_FREE)
00544 write_behind(test, convert);
00545 bfs[current].counter = BF_ALLOC;
00546 *dpp = &bfs[current].buf.hdr;
00547 return ct;
00548 }
00549
00550
00551
00552
00553
00554
00555
00556 static ssize_t write_behind(struct testcase *test, int convert)
00557 {
00558 char *writebuf;
00559 int count;
00560 int ct;
00561 char *p;
00562 int c;
00563 struct bf *b;
00564 struct tftphdr *dp;
00565
00566 b = &bfs[nextone];
00567 if(b->counter < -1)
00568 return 0;
00569
00570 if(!test->ofile) {
00571 char outfile[256];
00572 snprintf(outfile, sizeof(outfile), "log/upload.%ld", test->testno);
00573 #ifdef WIN32
00574 test->ofile=open(outfile, O_CREAT|O_RDWR|O_BINARY, 0777);
00575 #else
00576 test->ofile=open(outfile, O_CREAT|O_RDWR, 0777);
00577 #endif
00578 if(test->ofile == -1) {
00579 logmsg("Couldn't create and/or open file %s for upload!", outfile);
00580 return -1;
00581 }
00582 }
00583
00584 count = b->counter;
00585 b->counter = BF_FREE;
00586 dp = &b->buf.hdr;
00587 nextone = !nextone;
00588 writebuf = dp->th_data;
00589
00590 if(count <= 0)
00591 return -1;
00592
00593 if(convert == 0)
00594 return write(test->ofile, writebuf, count);
00595
00596 p = writebuf;
00597 ct = count;
00598 while(ct--) {
00599 c = *p++;
00600 if(prevchar == '\r') {
00601 if(c == '\n')
00602 lseek(test->ofile, -1, SEEK_CUR);
00603 else
00604 if(c == '\0')
00605 goto skipit;
00606
00607 }
00608
00609
00610 if(1 != write(test->ofile, &c, 1))
00611 break;
00612 skipit:
00613 prevchar = c;
00614 }
00615 return count;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629 static int synchnet(curl_socket_t f )
00630 {
00631
00632 #if defined(HAVE_IOCTLSOCKET)
00633 unsigned long i;
00634 #else
00635 int i;
00636 #endif
00637 int j = 0;
00638 char rbuf[PKTSIZE];
00639 srvr_sockaddr_union_t fromaddr;
00640 curl_socklen_t fromaddrlen;
00641
00642 for(;;) {
00643 #if defined(HAVE_IOCTLSOCKET)
00644 (void) ioctlsocket(f, FIONREAD, &i);
00645 #else
00646 (void) ioctl(f, FIONREAD, &i);
00647 #endif
00648 if(i) {
00649 j++;
00650 #ifdef ENABLE_IPV6
00651 if(!use_ipv6)
00652 #endif
00653 fromaddrlen = sizeof(fromaddr.sa4);
00654 #ifdef ENABLE_IPV6
00655 else
00656 fromaddrlen = sizeof(fromaddr.sa6);
00657 #endif
00658 (void) recvfrom(f, rbuf, sizeof(rbuf), 0,
00659 &fromaddr.sa, &fromaddrlen);
00660 }
00661 else
00662 break;
00663 }
00664 return j;
00665 }
00666
00667 int main(int argc, char **argv)
00668 {
00669 srvr_sockaddr_union_t me;
00670 struct tftphdr *tp;
00671 ssize_t n = 0;
00672 int arg = 1;
00673 unsigned short port = DEFAULT_PORT;
00674 curl_socket_t sock = CURL_SOCKET_BAD;
00675 int flag;
00676 int rc;
00677 int error;
00678 long pid;
00679 struct testcase test;
00680 int result = 0;
00681
00682 memset(&test, 0, sizeof(test));
00683
00684 while(argc>arg) {
00685 if(!strcmp("--version", argv[arg])) {
00686 printf("tftpd IPv4%s\n",
00687 #ifdef ENABLE_IPV6
00688 "/IPv6"
00689 #else
00690 ""
00691 #endif
00692 );
00693 return 0;
00694 }
00695 else if(!strcmp("--pidfile", argv[arg])) {
00696 arg++;
00697 if(argc>arg)
00698 pidname = argv[arg++];
00699 }
00700 else if(!strcmp("--logfile", argv[arg])) {
00701 arg++;
00702 if(argc>arg)
00703 serverlogfile = argv[arg++];
00704 }
00705 else if(!strcmp("--ipv4", argv[arg])) {
00706 #ifdef ENABLE_IPV6
00707 ipv_inuse = "IPv4";
00708 use_ipv6 = FALSE;
00709 #endif
00710 arg++;
00711 }
00712 else if(!strcmp("--ipv6", argv[arg])) {
00713 #ifdef ENABLE_IPV6
00714 ipv_inuse = "IPv6";
00715 use_ipv6 = TRUE;
00716 #endif
00717 arg++;
00718 }
00719 else if(!strcmp("--port", argv[arg])) {
00720 arg++;
00721 if(argc>arg) {
00722 char *endptr;
00723 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
00724 if((endptr != argv[arg] + strlen(argv[arg])) ||
00725 (ulnum < 1025UL) || (ulnum > 65535UL)) {
00726 fprintf(stderr, "tftpd: invalid --port argument (%s)\n",
00727 argv[arg]);
00728 return 0;
00729 }
00730 port = curlx_ultous(ulnum);
00731 arg++;
00732 }
00733 }
00734 else if(!strcmp("--srcdir", argv[arg])) {
00735 arg++;
00736 if(argc>arg) {
00737 path = argv[arg];
00738 arg++;
00739 }
00740 }
00741 else {
00742 puts("Usage: tftpd [option]\n"
00743 " --version\n"
00744 " --logfile [file]\n"
00745 " --pidfile [file]\n"
00746 " --ipv4\n"
00747 " --ipv6\n"
00748 " --port [port]\n"
00749 " --srcdir [path]");
00750 return 0;
00751 }
00752 }
00753
00754 #ifdef WIN32
00755 win32_init();
00756 atexit(win32_cleanup);
00757 #endif
00758
00759 install_signal_handlers();
00760
00761 pid = (long)getpid();
00762
00763 #ifdef ENABLE_IPV6
00764 if(!use_ipv6)
00765 #endif
00766 sock = socket(AF_INET, SOCK_DGRAM, 0);
00767 #ifdef ENABLE_IPV6
00768 else
00769 sock = socket(AF_INET6, SOCK_DGRAM, 0);
00770 #endif
00771
00772 if(CURL_SOCKET_BAD == sock) {
00773 error = SOCKERRNO;
00774 logmsg("Error creating socket: (%d) %s",
00775 error, strerror(error));
00776 result = 1;
00777 goto tftpd_cleanup;
00778 }
00779
00780 flag = 1;
00781 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
00782 (void *)&flag, sizeof(flag))) {
00783 error = SOCKERRNO;
00784 logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
00785 error, strerror(error));
00786 result = 1;
00787 goto tftpd_cleanup;
00788 }
00789
00790 #ifdef ENABLE_IPV6
00791 if(!use_ipv6) {
00792 #endif
00793 memset(&me.sa4, 0, sizeof(me.sa4));
00794 me.sa4.sin_family = AF_INET;
00795 me.sa4.sin_addr.s_addr = INADDR_ANY;
00796 me.sa4.sin_port = htons(port);
00797 rc = bind(sock, &me.sa, sizeof(me.sa4));
00798 #ifdef ENABLE_IPV6
00799 }
00800 else {
00801 memset(&me.sa6, 0, sizeof(me.sa6));
00802 me.sa6.sin6_family = AF_INET6;
00803 me.sa6.sin6_addr = in6addr_any;
00804 me.sa6.sin6_port = htons(port);
00805 rc = bind(sock, &me.sa, sizeof(me.sa6));
00806 }
00807 #endif
00808 if(0 != rc) {
00809 error = SOCKERRNO;
00810 logmsg("Error binding socket on port %hu: (%d) %s",
00811 port, error, strerror(error));
00812 result = 1;
00813 goto tftpd_cleanup;
00814 }
00815
00816 wrotepidfile = write_pidfile(pidname);
00817 if(!wrotepidfile) {
00818 result = 1;
00819 goto tftpd_cleanup;
00820 }
00821
00822 logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port);
00823
00824 for(;;) {
00825 fromlen = sizeof(from);
00826 #ifdef ENABLE_IPV6
00827 if(!use_ipv6)
00828 #endif
00829 fromlen = sizeof(from.sa4);
00830 #ifdef ENABLE_IPV6
00831 else
00832 fromlen = sizeof(from.sa6);
00833 #endif
00834 n = (ssize_t)recvfrom(sock, &buf.storage[0], sizeof(buf.storage), 0,
00835 &from.sa, &fromlen);
00836 if(got_exit_signal)
00837 break;
00838 if(n < 0) {
00839 logmsg("recvfrom");
00840 result = 3;
00841 break;
00842 }
00843
00844 set_advisor_read_lock(SERVERLOGS_LOCK);
00845 serverlogslocked = 1;
00846
00847 #ifdef ENABLE_IPV6
00848 if(!use_ipv6) {
00849 #endif
00850 from.sa4.sin_family = AF_INET;
00851 peer = socket(AF_INET, SOCK_DGRAM, 0);
00852 if(CURL_SOCKET_BAD == peer) {
00853 logmsg("socket");
00854 result = 2;
00855 break;
00856 }
00857 if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) {
00858 logmsg("connect: fail");
00859 result = 1;
00860 break;
00861 }
00862 #ifdef ENABLE_IPV6
00863 }
00864 else {
00865 from.sa6.sin6_family = AF_INET6;
00866 peer = socket(AF_INET6, SOCK_DGRAM, 0);
00867 if(CURL_SOCKET_BAD == peer) {
00868 logmsg("socket");
00869 result = 2;
00870 break;
00871 }
00872 if(connect(peer, &from.sa, sizeof(from.sa6)) < 0) {
00873 logmsg("connect: fail");
00874 result = 1;
00875 break;
00876 }
00877 }
00878 #endif
00879
00880 maxtimeout = 5*TIMEOUT;
00881
00882 tp = &buf.hdr;
00883 tp->th_opcode = ntohs(tp->th_opcode);
00884 if(tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) {
00885 memset(&test, 0, sizeof(test));
00886 if(do_tftp(&test, tp, n) < 0)
00887 break;
00888 free(test.buffer);
00889 }
00890 sclose(peer);
00891 peer = CURL_SOCKET_BAD;
00892
00893 if(test.ofile > 0) {
00894 close(test.ofile);
00895 test.ofile = 0;
00896 }
00897
00898 if(got_exit_signal)
00899 break;
00900
00901 if(serverlogslocked) {
00902 serverlogslocked = 0;
00903 clear_advisor_read_lock(SERVERLOGS_LOCK);
00904 }
00905
00906 logmsg("end of one transfer");
00907
00908 }
00909
00910 tftpd_cleanup:
00911
00912 if(test.ofile > 0)
00913 close(test.ofile);
00914
00915 if((peer != sock) && (peer != CURL_SOCKET_BAD))
00916 sclose(peer);
00917
00918 if(sock != CURL_SOCKET_BAD)
00919 sclose(sock);
00920
00921 if(got_exit_signal)
00922 logmsg("signalled to die");
00923
00924 if(wrotepidfile)
00925 unlink(pidname);
00926
00927 if(serverlogslocked) {
00928 serverlogslocked = 0;
00929 clear_advisor_read_lock(SERVERLOGS_LOCK);
00930 }
00931
00932 restore_signal_handlers();
00933
00934 if(got_exit_signal) {
00935 logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)",
00936 ipv_inuse, (int)port, pid, exit_signal);
00937
00938
00939
00940
00941
00942 raise(exit_signal);
00943 }
00944
00945 logmsg("========> tftpd quits");
00946 return result;
00947 }
00948
00949
00950
00951
00952 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size)
00953 {
00954 char *cp;
00955 int first = 1, ecode;
00956 struct formats *pf;
00957 char *filename, *mode = NULL;
00958 int error;
00959 FILE *server;
00960 #ifdef USE_WINSOCK
00961 DWORD recvtimeout, recvtimeoutbak;
00962 #endif
00963 char *option = (char *)"mode";
00964 int toggle = 1;
00965
00966
00967 server = fopen(REQUEST_DUMP, "ab");
00968 if(!server) {
00969 error = errno;
00970 logmsg("fopen() failed with error: %d %s", error, strerror(error));
00971 logmsg("Error opening file: %s", REQUEST_DUMP);
00972 return -1;
00973 }
00974
00975
00976 fprintf(server, "opcode: %x\n", tp->th_opcode);
00977
00978 cp = (char *)&tp->th_stuff;
00979 filename = cp;
00980 do {
00981 bool endofit = true;
00982 while(cp < &buf.storage[size]) {
00983 if(*cp == '\0') {
00984 endofit = false;
00985 break;
00986 }
00987 cp++;
00988 }
00989 if(endofit)
00990
00991 break;
00992
00993
00994
00995 if((cp+1) < &buf.storage[size]) {
00996 ++cp;
00997 if(first) {
00998
00999 mode = cp;
01000 first = 0;
01001 }
01002 if(toggle)
01003
01004 fprintf(server, "%s: %s\n", option, cp);
01005 else {
01006
01007 option = cp;
01008 }
01009 toggle ^= 1;
01010 }
01011 else
01012
01013 break;
01014 } while(1);
01015
01016 if(*cp) {
01017 nak(EBADOP);
01018 fclose(server);
01019 return 3;
01020 }
01021
01022
01023 fprintf(server, "filename: %s\n", filename);
01024
01025 for(cp = mode; cp && *cp; cp++)
01026 if(ISUPPER(*cp))
01027 *cp = (char)tolower((int)*cp);
01028
01029
01030 fclose(server);
01031
01032 for(pf = formata; pf->f_mode; pf++)
01033 if(strcmp(pf->f_mode, mode) == 0)
01034 break;
01035 if(!pf->f_mode) {
01036 nak(EBADOP);
01037 return 2;
01038 }
01039 ecode = validate_access(test, filename, tp->th_opcode);
01040 if(ecode) {
01041 nak(ecode);
01042 return 1;
01043 }
01044
01045 #ifdef USE_WINSOCK
01046 recvtimeout = sizeof(recvtimeoutbak);
01047 getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
01048 (char *)&recvtimeoutbak, (int *)&recvtimeout);
01049 recvtimeout = TIMEOUT*1000;
01050 setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
01051 (const char *)&recvtimeout, sizeof(recvtimeout));
01052 #endif
01053
01054 if(tp->th_opcode == opcode_WRQ)
01055 recvtftp(test, pf);
01056 else
01057 sendtftp(test, pf);
01058
01059 #ifdef USE_WINSOCK
01060 recvtimeout = recvtimeoutbak;
01061 setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
01062 (const char *)&recvtimeout, sizeof(recvtimeout));
01063 #endif
01064
01065 return 0;
01066 }
01067
01068
01069 static int parse_servercmd(struct testcase *req)
01070 {
01071 FILE *stream;
01072 char *filename;
01073 int error;
01074
01075 filename = test2file(req->testno);
01076
01077 stream=fopen(filename, "rb");
01078 if(!stream) {
01079 error = errno;
01080 logmsg("fopen() failed with error: %d %s", error, strerror(error));
01081 logmsg(" [1] Error opening file: %s", filename);
01082 logmsg(" Couldn't open test file %ld", req->testno);
01083 return 1;
01084 }
01085 else {
01086 char *orgcmd = NULL;
01087 char *cmd = NULL;
01088 size_t cmdsize = 0;
01089 int num=0;
01090
01091
01092 error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
01093 fclose(stream);
01094 if(error) {
01095 logmsg("getpart() failed with error: %d", error);
01096 return 1;
01097 }
01098
01099 cmd = orgcmd;
01100 while(cmd && cmdsize) {
01101 char *check;
01102 if(1 == sscanf(cmd, "writedelay: %d", &num)) {
01103 logmsg("instructed to delay %d secs between packets", num);
01104 req->writedelay = num;
01105 }
01106 else {
01107 logmsg("Unknown <servercmd> instruction found: %s", cmd);
01108 }
01109
01110 check = strchr(cmd, '\r');
01111 if(!check)
01112 check = strchr(cmd, '\n');
01113
01114 if(check) {
01115
01116 while((*check == '\r') || (*check == '\n'))
01117 check++;
01118
01119 if(!*check)
01120
01121 break;
01122 cmd = check;
01123 }
01124 else
01125 break;
01126 }
01127 free(orgcmd);
01128 }
01129
01130 return 0;
01131 }
01132
01133
01134
01135
01136
01137 static int validate_access(struct testcase *test,
01138 const char *filename, int mode)
01139 {
01140 char *ptr;
01141 long testno, partno;
01142 int error;
01143 char partbuf[80]="data";
01144
01145 logmsg("trying to get file: %s mode %x", filename, mode);
01146
01147 if(!strncmp("verifiedserver", filename, 14)) {
01148 char weare[128];
01149 size_t count = snprintf(weare, sizeof(weare),
01150 "WE ROOLZ: %ld\r\n", (long)getpid());
01151
01152 logmsg("Are-we-friendly question received");
01153 test->buffer = strdup(weare);
01154 test->rptr = test->buffer;
01155 test->bufsize = count;
01156 test->rcount = count;
01157 return 0;
01158 }
01159
01160
01161 ptr = strrchr(filename, '/');
01162
01163 if(ptr) {
01164 char *file;
01165
01166 ptr++;
01167
01168
01169 while(*ptr && !ISDIGIT(*ptr))
01170 ptr++;
01171
01172
01173 testno = strtol(ptr, &ptr, 10);
01174
01175 if(testno > 10000) {
01176 partno = testno % 10000;
01177 testno /= 10000;
01178 }
01179 else
01180 partno = 0;
01181
01182
01183 logmsg("requested test number %ld part %ld", testno, partno);
01184
01185 test->testno = testno;
01186
01187 (void)parse_servercmd(test);
01188
01189 file = test2file(testno);
01190
01191 if(0 != partno)
01192 snprintf(partbuf, sizeof(partbuf), "data%ld", partno);
01193
01194 if(file) {
01195 FILE *stream=fopen(file, "rb");
01196 if(!stream) {
01197 error = errno;
01198 logmsg("fopen() failed with error: %d %s", error, strerror(error));
01199 logmsg("Error opening file: %s", file);
01200 logmsg("Couldn't open test file: %s", file);
01201 return EACCESS;
01202 }
01203 else {
01204 size_t count;
01205 error = getpart(&test->buffer, &count, "reply", partbuf, stream);
01206 fclose(stream);
01207 if(error) {
01208 logmsg("getpart() failed with error: %d", error);
01209 return EACCESS;
01210 }
01211 if(test->buffer) {
01212 test->rptr = test->buffer;
01213 test->bufsize = count;
01214 test->rcount = count;
01215 }
01216 else
01217 return EACCESS;
01218 }
01219
01220 }
01221 else
01222 return EACCESS;
01223 }
01224 else {
01225 logmsg("no slash found in path");
01226 return EACCESS;
01227 }
01228
01229 logmsg("file opened and all is good");
01230 return 0;
01231 }
01232
01233
01234
01235
01236 static void sendtftp(struct testcase *test, struct formats *pf)
01237 {
01238 int size;
01239 ssize_t n;
01240
01241 volatile unsigned short sendblock;
01242 struct tftphdr * volatile sdp = r_init();
01243 struct tftphdr * const sap = &ackbuf.hdr;
01244
01245 sendblock = 1;
01246 #if defined(HAVE_ALARM) && defined(SIGALRM)
01247 mysignal(SIGALRM, timer);
01248 #endif
01249 do {
01250 size = readit(test, (struct tftphdr **)&sdp, pf->f_convert);
01251 if(size < 0) {
01252 nak(errno + 100);
01253 return;
01254 }
01255 sdp->th_opcode = htons((unsigned short)opcode_DATA);
01256 sdp->th_block = htons(sendblock);
01257 timeout = 0;
01258 #ifdef HAVE_SIGSETJMP
01259 (void) sigsetjmp(timeoutbuf, 1);
01260 #endif
01261 if(test->writedelay) {
01262 logmsg("Pausing %d seconds before %d bytes", test->writedelay,
01263 size);
01264 wait_ms(1000*test->writedelay);
01265 }
01266
01267 send_data:
01268 if(swrite(peer, sdp, size + 4) != size + 4) {
01269 logmsg("write");
01270 return;
01271 }
01272 read_ahead(test, pf->f_convert);
01273 for(;;) {
01274 #ifdef HAVE_ALARM
01275 alarm(rexmtval);
01276 #endif
01277 n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage));
01278 #ifdef HAVE_ALARM
01279 alarm(0);
01280 #endif
01281 if(got_exit_signal)
01282 return;
01283 if(n < 0) {
01284 logmsg("read: fail");
01285 return;
01286 }
01287 sap->th_opcode = ntohs((unsigned short)sap->th_opcode);
01288 sap->th_block = ntohs(sap->th_block);
01289
01290 if(sap->th_opcode == opcode_ERROR) {
01291 logmsg("got ERROR");
01292 return;
01293 }
01294
01295 if(sap->th_opcode == opcode_ACK) {
01296 if(sap->th_block == sendblock) {
01297 break;
01298 }
01299
01300 (void) synchnet(peer);
01301 if(sap->th_block == (sendblock-1)) {
01302 goto send_data;
01303 }
01304 }
01305
01306 }
01307 sendblock++;
01308 } while(size == SEGSIZE);
01309 }
01310
01311
01312
01313
01314 static void recvtftp(struct testcase *test, struct formats *pf)
01315 {
01316 ssize_t n, size;
01317
01318 volatile unsigned short recvblock;
01319 struct tftphdr * volatile rdp;
01320 struct tftphdr *rap;
01321
01322 recvblock = 0;
01323 rdp = w_init();
01324 #if defined(HAVE_ALARM) && defined(SIGALRM)
01325 mysignal(SIGALRM, timer);
01326 #endif
01327 rap = &ackbuf.hdr;
01328 do {
01329 timeout = 0;
01330 rap->th_opcode = htons((unsigned short)opcode_ACK);
01331 rap->th_block = htons(recvblock);
01332 recvblock++;
01333 #ifdef HAVE_SIGSETJMP
01334 (void) sigsetjmp(timeoutbuf, 1);
01335 #endif
01336 send_ack:
01337 if(swrite(peer, &ackbuf.storage[0], 4) != 4) {
01338 logmsg("write: fail\n");
01339 goto abort;
01340 }
01341 write_behind(test, pf->f_convert);
01342 for(;;) {
01343 #ifdef HAVE_ALARM
01344 alarm(rexmtval);
01345 #endif
01346 n = sread(peer, rdp, PKTSIZE);
01347 #ifdef HAVE_ALARM
01348 alarm(0);
01349 #endif
01350 if(got_exit_signal)
01351 goto abort;
01352 if(n < 0) {
01353 logmsg("read: fail\n");
01354 goto abort;
01355 }
01356 rdp->th_opcode = ntohs((unsigned short)rdp->th_opcode);
01357 rdp->th_block = ntohs(rdp->th_block);
01358 if(rdp->th_opcode == opcode_ERROR)
01359 goto abort;
01360 if(rdp->th_opcode == opcode_DATA) {
01361 if(rdp->th_block == recvblock) {
01362 break;
01363 }
01364
01365 (void) synchnet(peer);
01366 if(rdp->th_block == (recvblock-1))
01367 goto send_ack;
01368 }
01369 }
01370
01371 size = writeit(test, &rdp, (int)(n - 4), pf->f_convert);
01372 if(size != (n-4)) {
01373 if(size < 0)
01374 nak(errno + 100);
01375 else
01376 nak(ENOSPACE);
01377 goto abort;
01378 }
01379 } while(size == SEGSIZE);
01380 write_behind(test, pf->f_convert);
01381
01382 rap->th_opcode = htons((unsigned short)opcode_ACK);
01383
01384 rap->th_block = htons(recvblock);
01385 (void) swrite(peer, &ackbuf.storage[0], 4);
01386 #if defined(HAVE_ALARM) && defined(SIGALRM)
01387 mysignal(SIGALRM, justtimeout);
01388 alarm(rexmtval);
01389 #endif
01390
01391 n = sread(peer, &buf.storage[0], sizeof(buf.storage));
01392 #ifdef HAVE_ALARM
01393 alarm(0);
01394 #endif
01395 if(got_exit_signal)
01396 goto abort;
01397 if(n >= 4 &&
01398 rdp->th_opcode == opcode_DATA &&
01399 recvblock == rdp->th_block) {
01400 (void) swrite(peer, &ackbuf.storage[0], 4);
01401 }
01402 abort:
01403 return;
01404 }
01405
01406
01407
01408
01409
01410 static void nak(int error)
01411 {
01412 struct tftphdr *tp;
01413 int length;
01414 struct errmsg *pe;
01415
01416 tp = &buf.hdr;
01417 tp->th_opcode = htons((unsigned short)opcode_ERROR);
01418 tp->th_code = htons((unsigned short)error);
01419 for(pe = errmsgs; pe->e_code >= 0; pe++)
01420 if(pe->e_code == error)
01421 break;
01422 if(pe->e_code < 0) {
01423 pe->e_msg = strerror(error - 100);
01424 tp->th_code = EUNDEF;
01425 }
01426 length = (int)strlen(pe->e_msg);
01427
01428
01429
01430 memcpy(tp->th_msg, pe->e_msg, length + 1);
01431 length += 5;
01432 if(swrite(peer, &buf.storage[0], length) != length)
01433 logmsg("nak: fail\n");
01434 }