• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  *
9  * Trivial file transfer protocol server.
10  *
11  * This code includes many modifications by Jim Guyton <guyton@rand-unix>
12  *
13  * This source file was started based on netkit-tftpd 0.17
14  * Heavily modified for curl's test suite
15  */
16 
17 /*
18  * Copyright (C) 2005 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
19  * Copyright (c) 1983, Regents of the University of California.
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the above copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *      This product includes software developed by the University of
33  *      California, Berkeley and its contributors.
34  * 4. Neither the name of the University nor the names of its contributors
35  *    may be used to endorse or promote products derived from this software
36  *    without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  */
50 
51 #include "server_setup.h"
52 
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
55 #endif
56 #ifdef HAVE_SIGNAL_H
57 #include <signal.h>
58 #endif
59 #ifdef HAVE_FCNTL_H
60 #include <fcntl.h>
61 #endif
62 #ifdef HAVE_NETINET_IN_H
63 #include <netinet/in.h>
64 #endif
65 #ifdef HAVE_ARPA_INET_H
66 #include <arpa/inet.h>
67 #endif
68 #ifdef HAVE_ARPA_TFTP_H
69 #include <arpa/tftp.h>
70 #else
71 #include "tftp.h"
72 #endif
73 #ifdef HAVE_NETDB_H
74 #include <netdb.h>
75 #endif
76 #ifdef HAVE_SYS_FILIO_H
77 /* FIONREAD on Solaris 7 */
78 #include <sys/filio.h>
79 #endif
80 
81 #ifdef HAVE_SETJMP_H
82 #include <setjmp.h>
83 #endif
84 
85 #ifdef HAVE_PWD_H
86 #include <pwd.h>
87 #endif
88 
89 #define ENABLE_CURLX_PRINTF
90 /* make the curlx header define all printf() functions to use the curlx_*
91    versions instead */
92 #include "curlx.h" /* from the private lib dir */
93 #include "getpart.h"
94 #include "util.h"
95 #include "server_sockaddr.h"
96 
97 /* include memdebug.h last */
98 #include "memdebug.h"
99 
100 /*****************************************************************************
101 *                      STRUCT DECLARATIONS AND DEFINES                       *
102 *****************************************************************************/
103 
104 #ifndef PKTSIZE
105 #define PKTSIZE (SEGSIZE + 4)  /* SEGSIZE defined in arpa/tftp.h */
106 #endif
107 
108 struct testcase {
109   char *buffer;   /* holds the file data to send to the client */
110   size_t bufsize; /* size of the data in buffer */
111   char *rptr;     /* read pointer into the buffer */
112   size_t rcount;  /* amount of data left to read of the file */
113   long testno;    /* test case number */
114   int ofile;      /* file descriptor for output file when uploading to us */
115 
116   int writedelay; /* number of seconds between each packet */
117 };
118 
119 struct formats {
120   const char *f_mode;
121   int f_convert;
122 };
123 
124 struct errmsg {
125   int e_code;
126   const char *e_msg;
127 };
128 
129 typedef union {
130   struct tftphdr hdr;
131   char storage[PKTSIZE];
132 } tftphdr_storage_t;
133 
134 /*
135  * bf.counter values in range [-1 .. SEGSIZE] represents size of data in the
136  * bf.buf buffer. Additionally it can also hold flags BF_ALLOC or BF_FREE.
137  */
138 
139 struct bf {
140   int counter;            /* size of data in buffer, or flag */
141   tftphdr_storage_t buf;  /* room for data packet */
142 };
143 
144 #define BF_ALLOC -3       /* alloc'd but not yet filled */
145 #define BF_FREE  -2       /* free */
146 
147 #define opcode_RRQ   1
148 #define opcode_WRQ   2
149 #define opcode_DATA  3
150 #define opcode_ACK   4
151 #define opcode_ERROR 5
152 
153 #define TIMEOUT      5
154 
155 #undef MIN
156 #define MIN(x,y) ((x)<(y)?(x):(y))
157 
158 #ifndef DEFAULT_LOGFILE
159 #define DEFAULT_LOGFILE "log/tftpd.log"
160 #endif
161 
162 #define REQUEST_DUMP  "log/server.input"
163 
164 #define DEFAULT_PORT 8999 /* UDP */
165 
166 /*****************************************************************************
167 *                              GLOBAL VARIABLES                              *
168 *****************************************************************************/
169 
170 static struct errmsg errmsgs[] = {
171   { EUNDEF,       "Undefined error code" },
172   { ENOTFOUND,    "File not found" },
173   { EACCESS,      "Access violation" },
174   { ENOSPACE,     "Disk full or allocation exceeded" },
175   { EBADOP,       "Illegal TFTP operation" },
176   { EBADID,       "Unknown transfer ID" },
177   { EEXISTS,      "File already exists" },
178   { ENOUSER,      "No such user" },
179   { -1,           0 }
180 };
181 
182 static const struct formats formata[] = {
183   { "netascii",   1 },
184   { "octet",      0 },
185   { NULL,         0 }
186 };
187 
188 static struct bf bfs[2];
189 
190 static int nextone;     /* index of next buffer to use */
191 static int current;     /* index of buffer in use */
192 
193                            /* control flags for crlf conversions */
194 static int newline = 0;    /* fillbuf: in middle of newline expansion */
195 static int prevchar = -1;  /* putbuf: previous char (cr check) */
196 
197 static tftphdr_storage_t buf;
198 static tftphdr_storage_t ackbuf;
199 
200 static srvr_sockaddr_union_t from;
201 static curl_socklen_t fromlen;
202 
203 static curl_socket_t peer = CURL_SOCKET_BAD;
204 
205 static unsigned int timeout;
206 static unsigned int maxtimeout = 5 * TIMEOUT;
207 
208 #ifdef ENABLE_IPV6
209 static bool use_ipv6 = FALSE;
210 #endif
211 static const char *ipv_inuse = "IPv4";
212 
213 const  char *serverlogfile = DEFAULT_LOGFILE;
214 static const char *pidname = ".tftpd.pid";
215 static const char *portname = NULL; /* none by default */
216 static int serverlogslocked = 0;
217 static int wrotepidfile = 0;
218 static int wroteportfile = 0;
219 
220 #ifdef HAVE_SIGSETJMP
221 static sigjmp_buf timeoutbuf;
222 #endif
223 
224 #if defined(HAVE_ALARM) && defined(SIGALRM)
225 static const unsigned int rexmtval = TIMEOUT;
226 #endif
227 
228 /*****************************************************************************
229 *                            FUNCTION PROTOTYPES                             *
230 *****************************************************************************/
231 
232 static struct tftphdr *rw_init(int);
233 
234 static struct tftphdr *w_init(void);
235 
236 static struct tftphdr *r_init(void);
237 
238 static void read_ahead(struct testcase *test, int convert);
239 
240 static ssize_t write_behind(struct testcase *test, int convert);
241 
242 static int synchnet(curl_socket_t);
243 
244 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size);
245 
246 static int validate_access(struct testcase *test, const char *fname, int mode);
247 
248 static void sendtftp(struct testcase *test, const struct formats *pf);
249 
250 static void recvtftp(struct testcase *test, const struct formats *pf);
251 
252 static void nak(int error);
253 
254 #if defined(HAVE_ALARM) && defined(SIGALRM)
255 
256 static void mysignal(int sig, void (*handler)(int));
257 
258 static void timer(int signum);
259 
260 static void justtimeout(int signum);
261 
262 #endif /* HAVE_ALARM && SIGALRM */
263 
264 /*****************************************************************************
265 *                          FUNCTION IMPLEMENTATIONS                          *
266 *****************************************************************************/
267 
268 #if defined(HAVE_ALARM) && defined(SIGALRM)
269 
270 /*
271  * Like signal(), but with well-defined semantics.
272  */
mysignal(int sig,void (* handler)(int))273 static void mysignal(int sig, void (*handler)(int))
274 {
275   struct sigaction sa;
276   memset(&sa, 0, sizeof(sa));
277   sa.sa_handler = handler;
278   sigaction(sig, &sa, NULL);
279 }
280 
timer(int signum)281 static void timer(int signum)
282 {
283   (void)signum;
284 
285   logmsg("alarm!");
286 
287   timeout += rexmtval;
288   if(timeout >= maxtimeout) {
289     if(wrotepidfile) {
290       wrotepidfile = 0;
291       unlink(pidname);
292     }
293     if(wroteportfile) {
294       wroteportfile = 0;
295       unlink(portname);
296     }
297     if(serverlogslocked) {
298       serverlogslocked = 0;
299       clear_advisor_read_lock(SERVERLOGS_LOCK);
300     }
301     exit(1);
302   }
303 #ifdef HAVE_SIGSETJMP
304   siglongjmp(timeoutbuf, 1);
305 #endif
306 }
307 
justtimeout(int signum)308 static void justtimeout(int signum)
309 {
310   (void)signum;
311 }
312 
313 #endif /* HAVE_ALARM && SIGALRM */
314 
315 /*
316  * init for either read-ahead or write-behind.
317  * zero for write-behind, one for read-head.
318  */
rw_init(int x)319 static struct tftphdr *rw_init(int x)
320 {
321   newline = 0;                    /* init crlf flag */
322   prevchar = -1;
323   bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
324   current = 0;
325   bfs[1].counter = BF_FREE;
326   nextone = x;                    /* ahead or behind? */
327   return &bfs[0].buf.hdr;
328 }
329 
w_init(void)330 static struct tftphdr *w_init(void)
331 {
332   return rw_init(0); /* write-behind */
333 }
334 
r_init(void)335 static struct tftphdr *r_init(void)
336 {
337   return rw_init(1); /* read-ahead */
338 }
339 
340 /* Have emptied current buffer by sending to net and getting ack.
341    Free it and return next buffer filled with data.
342  */
readit(struct testcase * test,struct tftphdr ** dpp,int convert)343 static int readit(struct testcase *test, struct tftphdr **dpp,
344                   int convert /* if true, convert to ascii */)
345 {
346   struct bf *b;
347 
348   bfs[current].counter = BF_FREE; /* free old one */
349   current = !current;             /* "incr" current */
350 
351   b = &bfs[current];              /* look at new buffer */
352   if(b->counter == BF_FREE)      /* if it's empty */
353     read_ahead(test, convert);    /* fill it */
354 
355   *dpp = &b->buf.hdr;             /* set caller's ptr */
356   return b->counter;
357 }
358 
359 /*
360  * fill the input buffer, doing ascii conversions if requested
361  * conversions are  lf -> cr, lf  and cr -> cr, nul
362  */
read_ahead(struct testcase * test,int convert)363 static void read_ahead(struct testcase *test,
364                        int convert /* if true, convert to ascii */)
365 {
366   int i;
367   char *p;
368   int c;
369   struct bf *b;
370   struct tftphdr *dp;
371 
372   b = &bfs[nextone];              /* look at "next" buffer */
373   if(b->counter != BF_FREE)      /* nop if not free */
374     return;
375   nextone = !nextone;             /* "incr" next buffer ptr */
376 
377   dp = &b->buf.hdr;
378 
379   if(convert == 0) {
380     /* The former file reading code did this:
381        b->counter = read(fileno(file), dp->th_data, SEGSIZE); */
382     size_t copy_n = MIN(SEGSIZE, test->rcount);
383     memcpy(dp->th_data, test->rptr, copy_n);
384 
385     /* decrease amount, advance pointer */
386     test->rcount -= copy_n;
387     test->rptr += copy_n;
388     b->counter = (int)copy_n;
389     return;
390   }
391 
392   p = dp->th_data;
393   for(i = 0 ; i < SEGSIZE; i++) {
394     if(newline) {
395       if(prevchar == '\n')
396         c = '\n';       /* lf to cr,lf */
397       else
398         c = '\0';       /* cr to cr,nul */
399       newline = 0;
400     }
401     else {
402       if(test->rcount) {
403         c = test->rptr[0];
404         test->rptr++;
405         test->rcount--;
406       }
407       else
408         break;
409       if(c == '\n' || c == '\r') {
410         prevchar = c;
411         c = '\r';
412         newline = 1;
413       }
414     }
415     *p++ = (char)c;
416   }
417   b->counter = (int)(p - dp->th_data);
418 }
419 
420 /* Update count associated with the buffer, get new buffer from the queue.
421    Calls write_behind only if next buffer not available.
422  */
writeit(struct testcase * test,struct tftphdr * volatile * dpp,int ct,int convert)423 static int writeit(struct testcase *test, struct tftphdr * volatile *dpp,
424                    int ct, int convert)
425 {
426   bfs[current].counter = ct;      /* set size of data to write */
427   current = !current;             /* switch to other buffer */
428   if(bfs[current].counter != BF_FREE)     /* if not free */
429     write_behind(test, convert);     /* flush it */
430   bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
431   *dpp =  &bfs[current].buf.hdr;
432   return ct;                      /* this is a lie of course */
433 }
434 
435 /*
436  * Output a buffer to a file, converting from netascii if requested.
437  * CR, NUL -> CR  and CR, LF => LF.
438  * Note spec is undefined if we get CR as last byte of file or a
439  * CR followed by anything else.  In this case we leave it alone.
440  */
write_behind(struct testcase * test,int convert)441 static ssize_t write_behind(struct testcase *test, int convert)
442 {
443   char *writebuf;
444   int count;
445   int ct;
446   char *p;
447   int c;                          /* current character */
448   struct bf *b;
449   struct tftphdr *dp;
450 
451   b = &bfs[nextone];
452   if(b->counter < -1)            /* anything to flush? */
453     return 0;                     /* just nop if nothing to do */
454 
455   if(!test->ofile) {
456     char outfile[256];
457     msnprintf(outfile, sizeof(outfile), "log/upload.%ld", test->testno);
458 #ifdef WIN32
459     test->ofile = open(outfile, O_CREAT|O_RDWR|O_BINARY, 0777);
460 #else
461     test->ofile = open(outfile, O_CREAT|O_RDWR, 0777);
462 #endif
463     if(test->ofile == -1) {
464       logmsg("Couldn't create and/or open file %s for upload!", outfile);
465       return -1; /* failure! */
466     }
467   }
468 
469   count = b->counter;             /* remember byte count */
470   b->counter = BF_FREE;           /* reset flag */
471   dp = &b->buf.hdr;
472   nextone = !nextone;             /* incr for next time */
473   writebuf = dp->th_data;
474 
475   if(count <= 0)
476     return -1;                    /* nak logic? */
477 
478   if(convert == 0)
479     return write(test->ofile, writebuf, count);
480 
481   p = writebuf;
482   ct = count;
483   while(ct--) {                   /* loop over the buffer */
484     c = *p++;                     /* pick up a character */
485     if(prevchar == '\r') {        /* if prev char was cr */
486       if(c == '\n')               /* if have cr,lf then just */
487         lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */
488       else
489         if(c == '\0')             /* if have cr,nul then */
490           goto skipit;            /* just skip over the putc */
491       /* else just fall through and allow it */
492     }
493     /* formerly
494        putc(c, file); */
495     if(1 != write(test->ofile, &c, 1))
496       break;
497     skipit:
498     prevchar = c;
499   }
500   return count;
501 }
502 
503 /* When an error has occurred, it is possible that the two sides are out of
504  * synch.  Ie: that what I think is the other side's response to packet N is
505  * really their response to packet N-1.
506  *
507  * So, to try to prevent that, we flush all the input queued up for us on the
508  * network connection on our host.
509  *
510  * We return the number of packets we flushed (mostly for reporting when trace
511  * is active).
512  */
513 
synchnet(curl_socket_t f)514 static int synchnet(curl_socket_t f /* socket to flush */)
515 {
516 
517 #if defined(HAVE_IOCTLSOCKET)
518   unsigned long i;
519 #else
520   int i;
521 #endif
522   int j = 0;
523   char rbuf[PKTSIZE];
524   srvr_sockaddr_union_t fromaddr;
525   curl_socklen_t fromaddrlen;
526 
527   for(;;) {
528 #if defined(HAVE_IOCTLSOCKET)
529     (void) ioctlsocket(f, FIONREAD, &i);
530 #else
531     (void) ioctl(f, FIONREAD, &i);
532 #endif
533     if(i) {
534       j++;
535 #ifdef ENABLE_IPV6
536       if(!use_ipv6)
537 #endif
538         fromaddrlen = sizeof(fromaddr.sa4);
539 #ifdef ENABLE_IPV6
540       else
541         fromaddrlen = sizeof(fromaddr.sa6);
542 #endif
543       (void) recvfrom(f, rbuf, sizeof(rbuf), 0,
544                       &fromaddr.sa, &fromaddrlen);
545     }
546     else
547       break;
548   }
549   return j;
550 }
551 
main(int argc,char ** argv)552 int main(int argc, char **argv)
553 {
554   srvr_sockaddr_union_t me;
555   struct tftphdr *tp;
556   ssize_t n = 0;
557   int arg = 1;
558   unsigned short port = DEFAULT_PORT;
559   curl_socket_t sock = CURL_SOCKET_BAD;
560   int flag;
561   int rc;
562   int error;
563   struct testcase test;
564   int result = 0;
565 
566   memset(&test, 0, sizeof(test));
567 
568   while(argc>arg) {
569     if(!strcmp("--version", argv[arg])) {
570       printf("tftpd IPv4%s\n",
571 #ifdef ENABLE_IPV6
572              "/IPv6"
573 #else
574              ""
575 #endif
576              );
577       return 0;
578     }
579     else if(!strcmp("--pidfile", argv[arg])) {
580       arg++;
581       if(argc>arg)
582         pidname = argv[arg++];
583     }
584     else if(!strcmp("--portfile", argv[arg])) {
585       arg++;
586       if(argc>arg)
587         portname = argv[arg++];
588     }
589     else if(!strcmp("--logfile", argv[arg])) {
590       arg++;
591       if(argc>arg)
592         serverlogfile = argv[arg++];
593     }
594     else if(!strcmp("--ipv4", argv[arg])) {
595 #ifdef ENABLE_IPV6
596       ipv_inuse = "IPv4";
597       use_ipv6 = FALSE;
598 #endif
599       arg++;
600     }
601     else if(!strcmp("--ipv6", argv[arg])) {
602 #ifdef ENABLE_IPV6
603       ipv_inuse = "IPv6";
604       use_ipv6 = TRUE;
605 #endif
606       arg++;
607     }
608     else if(!strcmp("--port", argv[arg])) {
609       arg++;
610       if(argc>arg) {
611         char *endptr;
612         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
613         port = curlx_ultous(ulnum);
614         arg++;
615       }
616     }
617     else if(!strcmp("--srcdir", argv[arg])) {
618       arg++;
619       if(argc>arg) {
620         path = argv[arg];
621         arg++;
622       }
623     }
624     else {
625       puts("Usage: tftpd [option]\n"
626            " --version\n"
627            " --logfile [file]\n"
628            " --pidfile [file]\n"
629            " --portfile [file]\n"
630            " --ipv4\n"
631            " --ipv6\n"
632            " --port [port]\n"
633            " --srcdir [path]");
634       return 0;
635     }
636   }
637 
638 #ifdef WIN32
639   win32_init();
640   atexit(win32_cleanup);
641 #endif
642 
643   install_signal_handlers(true);
644 
645 #ifdef ENABLE_IPV6
646   if(!use_ipv6)
647 #endif
648     sock = socket(AF_INET, SOCK_DGRAM, 0);
649 #ifdef ENABLE_IPV6
650   else
651     sock = socket(AF_INET6, SOCK_DGRAM, 0);
652 #endif
653 
654   if(CURL_SOCKET_BAD == sock) {
655     error = SOCKERRNO;
656     logmsg("Error creating socket: (%d) %s",
657            error, strerror(error));
658     result = 1;
659     goto tftpd_cleanup;
660   }
661 
662   flag = 1;
663   if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
664             (void *)&flag, sizeof(flag))) {
665     error = SOCKERRNO;
666     logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
667            error, strerror(error));
668     result = 1;
669     goto tftpd_cleanup;
670   }
671 
672 #ifdef ENABLE_IPV6
673   if(!use_ipv6) {
674 #endif
675     memset(&me.sa4, 0, sizeof(me.sa4));
676     me.sa4.sin_family = AF_INET;
677     me.sa4.sin_addr.s_addr = INADDR_ANY;
678     me.sa4.sin_port = htons(port);
679     rc = bind(sock, &me.sa, sizeof(me.sa4));
680 #ifdef ENABLE_IPV6
681   }
682   else {
683     memset(&me.sa6, 0, sizeof(me.sa6));
684     me.sa6.sin6_family = AF_INET6;
685     me.sa6.sin6_addr = in6addr_any;
686     me.sa6.sin6_port = htons(port);
687     rc = bind(sock, &me.sa, sizeof(me.sa6));
688   }
689 #endif /* ENABLE_IPV6 */
690   if(0 != rc) {
691     error = SOCKERRNO;
692     logmsg("Error binding socket on port %hu: (%d) %s",
693            port, error, strerror(error));
694     result = 1;
695     goto tftpd_cleanup;
696   }
697 
698   if(!port) {
699     /* The system was supposed to choose a port number, figure out which
700        port we actually got and update the listener port value with it. */
701     curl_socklen_t la_size;
702     srvr_sockaddr_union_t localaddr;
703 #ifdef ENABLE_IPV6
704     if(!use_ipv6)
705 #endif
706       la_size = sizeof(localaddr.sa4);
707 #ifdef ENABLE_IPV6
708     else
709       la_size = sizeof(localaddr.sa6);
710 #endif
711     memset(&localaddr.sa, 0, (size_t)la_size);
712     if(getsockname(sock, &localaddr.sa, &la_size) < 0) {
713       error = SOCKERRNO;
714       logmsg("getsockname() failed with error: (%d) %s",
715              error, strerror(error));
716       sclose(sock);
717       goto tftpd_cleanup;
718     }
719     switch(localaddr.sa.sa_family) {
720     case AF_INET:
721       port = ntohs(localaddr.sa4.sin_port);
722       break;
723 #ifdef ENABLE_IPV6
724     case AF_INET6:
725       port = ntohs(localaddr.sa6.sin6_port);
726       break;
727 #endif
728     default:
729       break;
730     }
731     if(!port) {
732       /* Real failure, listener port shall not be zero beyond this point. */
733       logmsg("Apparently getsockname() succeeded, with listener port zero.");
734       logmsg("A valid reason for this failure is a binary built without");
735       logmsg("proper network library linkage. This might not be the only");
736       logmsg("reason, but double check it before anything else.");
737       result = 2;
738       goto tftpd_cleanup;
739     }
740   }
741 
742   wrotepidfile = write_pidfile(pidname);
743   if(!wrotepidfile) {
744     result = 1;
745     goto tftpd_cleanup;
746   }
747 
748   if(portname) {
749     wroteportfile = write_portfile(portname, port);
750     if(!wroteportfile) {
751       result = 1;
752       goto tftpd_cleanup;
753     }
754   }
755 
756   logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port);
757 
758   for(;;) {
759     fromlen = sizeof(from);
760 #ifdef ENABLE_IPV6
761     if(!use_ipv6)
762 #endif
763       fromlen = sizeof(from.sa4);
764 #ifdef ENABLE_IPV6
765     else
766       fromlen = sizeof(from.sa6);
767 #endif
768     n = (ssize_t)recvfrom(sock, &buf.storage[0], sizeof(buf.storage), 0,
769                           &from.sa, &fromlen);
770     if(got_exit_signal)
771       break;
772     if(n < 0) {
773       logmsg("recvfrom");
774       result = 3;
775       break;
776     }
777 
778     set_advisor_read_lock(SERVERLOGS_LOCK);
779     serverlogslocked = 1;
780 
781 #ifdef ENABLE_IPV6
782     if(!use_ipv6) {
783 #endif
784       from.sa4.sin_family = AF_INET;
785       peer = socket(AF_INET, SOCK_DGRAM, 0);
786       if(CURL_SOCKET_BAD == peer) {
787         logmsg("socket");
788         result = 2;
789         break;
790       }
791       if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) {
792         logmsg("connect: fail");
793         result = 1;
794         break;
795       }
796 #ifdef ENABLE_IPV6
797     }
798     else {
799       from.sa6.sin6_family = AF_INET6;
800       peer = socket(AF_INET6, SOCK_DGRAM, 0);
801       if(CURL_SOCKET_BAD == peer) {
802         logmsg("socket");
803         result = 2;
804         break;
805       }
806       if(connect(peer, &from.sa, sizeof(from.sa6)) < 0) {
807         logmsg("connect: fail");
808         result = 1;
809         break;
810       }
811     }
812 #endif
813 
814     maxtimeout = 5*TIMEOUT;
815 
816     tp = &buf.hdr;
817     tp->th_opcode = ntohs(tp->th_opcode);
818     if(tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) {
819       memset(&test, 0, sizeof(test));
820       if(do_tftp(&test, tp, n) < 0)
821         break;
822       free(test.buffer);
823     }
824     sclose(peer);
825     peer = CURL_SOCKET_BAD;
826 
827     if(got_exit_signal)
828       break;
829 
830     if(serverlogslocked) {
831       serverlogslocked = 0;
832       clear_advisor_read_lock(SERVERLOGS_LOCK);
833     }
834 
835     logmsg("end of one transfer");
836 
837   }
838 
839 tftpd_cleanup:
840 
841   if(test.ofile > 0)
842     close(test.ofile);
843 
844   if((peer != sock) && (peer != CURL_SOCKET_BAD))
845     sclose(peer);
846 
847   if(sock != CURL_SOCKET_BAD)
848     sclose(sock);
849 
850   if(got_exit_signal)
851     logmsg("signalled to die");
852 
853   if(wrotepidfile)
854     unlink(pidname);
855   if(wroteportfile)
856     unlink(portname);
857 
858   if(serverlogslocked) {
859     serverlogslocked = 0;
860     clear_advisor_read_lock(SERVERLOGS_LOCK);
861   }
862 
863   restore_signal_handlers(true);
864 
865   if(got_exit_signal) {
866     logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)",
867            ipv_inuse, (int)port, (long)getpid(), exit_signal);
868     /*
869      * To properly set the return status of the process we
870      * must raise the same signal SIGINT or SIGTERM that we
871      * caught and let the old handler take care of it.
872      */
873     raise(exit_signal);
874   }
875 
876   logmsg("========> tftpd quits");
877   return result;
878 }
879 
880 /*
881  * Handle initial connection protocol.
882  */
do_tftp(struct testcase * test,struct tftphdr * tp,ssize_t size)883 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size)
884 {
885   char *cp;
886   int first = 1, ecode;
887   const struct formats *pf;
888   char *filename, *mode = NULL;
889 #ifdef USE_WINSOCK
890   DWORD recvtimeout, recvtimeoutbak;
891 #endif
892   const char *option = "mode"; /* mode is implicit */
893   int toggle = 1;
894 
895   /* Open request dump file. */
896   FILE *server = fopen(REQUEST_DUMP, "ab");
897   if(!server) {
898     int error = errno;
899     logmsg("fopen() failed with error: %d %s", error, strerror(error));
900     logmsg("Error opening file: %s", REQUEST_DUMP);
901     return -1;
902   }
903 
904   /* store input protocol */
905   fprintf(server, "opcode = %x\n", tp->th_opcode);
906 
907   cp = (char *)&tp->th_stuff;
908   filename = cp;
909   do {
910     bool endofit = true;
911     while(cp < &buf.storage[size]) {
912       if(*cp == '\0') {
913         endofit = false;
914         break;
915       }
916       cp++;
917     }
918     if(endofit)
919       /* no more options */
920       break;
921 
922     /* before increasing pointer, make sure it is still within the legal
923        space */
924     if((cp + 1) < &buf.storage[size]) {
925       ++cp;
926       if(first) {
927         /* store the mode since we need it later */
928         mode = cp;
929         first = 0;
930       }
931       if(toggle)
932         /* name/value pair: */
933         fprintf(server, "%s = %s\n", option, cp);
934       else {
935         /* store the name pointer */
936         option = cp;
937       }
938       toggle ^= 1;
939     }
940     else
941       /* No more options */
942       break;
943   } while(1);
944 
945   if(*cp) {
946     nak(EBADOP);
947     fclose(server);
948     return 3;
949   }
950 
951   /* store input protocol */
952   fprintf(server, "filename = %s\n", filename);
953 
954   for(cp = mode; cp && *cp; cp++)
955     if(ISUPPER(*cp))
956       *cp = (char)tolower((int)*cp);
957 
958   /* store input protocol */
959   fclose(server);
960 
961   for(pf = formata; pf->f_mode; pf++)
962     if(strcmp(pf->f_mode, mode) == 0)
963       break;
964   if(!pf->f_mode) {
965     nak(EBADOP);
966     return 2;
967   }
968   ecode = validate_access(test, filename, tp->th_opcode);
969   if(ecode) {
970     nak(ecode);
971     return 1;
972   }
973 
974 #ifdef USE_WINSOCK
975   recvtimeout = sizeof(recvtimeoutbak);
976   getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
977              (char *)&recvtimeoutbak, (int *)&recvtimeout);
978   recvtimeout = TIMEOUT*1000;
979   setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
980              (const char *)&recvtimeout, sizeof(recvtimeout));
981 #endif
982 
983   if(tp->th_opcode == opcode_WRQ)
984     recvtftp(test, pf);
985   else
986     sendtftp(test, pf);
987 
988 #ifdef USE_WINSOCK
989   recvtimeout = recvtimeoutbak;
990   setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
991              (const char *)&recvtimeout, sizeof(recvtimeout));
992 #endif
993 
994   return 0;
995 }
996 
997 /* Based on the testno, parse the correct server commands. */
parse_servercmd(struct testcase * req)998 static int parse_servercmd(struct testcase *req)
999 {
1000   FILE *stream;
1001   int error;
1002 
1003   stream = test2fopen(req->testno);
1004   if(!stream) {
1005     error = errno;
1006     logmsg("fopen() failed with error: %d %s", error, strerror(error));
1007     logmsg("  Couldn't open test file %ld", req->testno);
1008     return 1; /* done */
1009   }
1010   else {
1011     char *orgcmd = NULL;
1012     char *cmd = NULL;
1013     size_t cmdsize = 0;
1014     int num = 0;
1015 
1016     /* get the custom server control "commands" */
1017     error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
1018     fclose(stream);
1019     if(error) {
1020       logmsg("getpart() failed with error: %d", error);
1021       return 1; /* done */
1022     }
1023 
1024     cmd = orgcmd;
1025     while(cmd && cmdsize) {
1026       char *check;
1027       if(1 == sscanf(cmd, "writedelay: %d", &num)) {
1028         logmsg("instructed to delay %d secs between packets", num);
1029         req->writedelay = num;
1030       }
1031       else {
1032         logmsg("Unknown <servercmd> instruction found: %s", cmd);
1033       }
1034       /* try to deal with CRLF or just LF */
1035       check = strchr(cmd, '\r');
1036       if(!check)
1037         check = strchr(cmd, '\n');
1038 
1039       if(check) {
1040         /* get to the letter following the newline */
1041         while((*check == '\r') || (*check == '\n'))
1042           check++;
1043 
1044         if(!*check)
1045           /* if we reached a zero, get out */
1046           break;
1047         cmd = check;
1048       }
1049       else
1050         break;
1051     }
1052     free(orgcmd);
1053   }
1054 
1055   return 0; /* OK! */
1056 }
1057 
1058 
1059 /*
1060  * Validate file access.
1061  */
validate_access(struct testcase * test,const char * filename,int mode)1062 static int validate_access(struct testcase *test,
1063                            const char *filename, int mode)
1064 {
1065   char *ptr;
1066 
1067   logmsg("trying to get file: %s mode %x", filename, mode);
1068 
1069   if(!strncmp("verifiedserver", filename, 14)) {
1070     char weare[128];
1071     size_t count = msnprintf(weare, sizeof(weare), "WE ROOLZ: %"
1072                              CURL_FORMAT_CURL_OFF_T "\r\n", our_getpid());
1073 
1074     logmsg("Are-we-friendly question received");
1075     test->buffer = strdup(weare);
1076     test->rptr = test->buffer; /* set read pointer */
1077     test->bufsize = count;    /* set total count */
1078     test->rcount = count;     /* set data left to read */
1079     return 0; /* fine */
1080   }
1081 
1082   /* find the last slash */
1083   ptr = strrchr(filename, '/');
1084 
1085   if(ptr) {
1086     char partbuf[80]="data";
1087     long partno;
1088     long testno;
1089     FILE *stream;
1090 
1091     ptr++; /* skip the slash */
1092 
1093     /* skip all non-numericals following the slash */
1094     while(*ptr && !ISDIGIT(*ptr))
1095       ptr++;
1096 
1097     /* get the number */
1098     testno = strtol(ptr, &ptr, 10);
1099 
1100     if(testno > 10000) {
1101       partno = testno % 10000;
1102       testno /= 10000;
1103     }
1104     else
1105       partno = 0;
1106 
1107 
1108     logmsg("requested test number %ld part %ld", testno, partno);
1109 
1110     test->testno = testno;
1111 
1112     (void)parse_servercmd(test);
1113 
1114     stream = test2fopen(testno);
1115 
1116     if(0 != partno)
1117       msnprintf(partbuf, sizeof(partbuf), "data%ld", partno);
1118 
1119     if(!stream) {
1120       int error = errno;
1121       logmsg("fopen() failed with error: %d %s", error, strerror(error));
1122       logmsg("Couldn't open test file for test : %d", testno);
1123       return EACCESS;
1124     }
1125     else {
1126       size_t count;
1127       int error = getpart(&test->buffer, &count, "reply", partbuf, stream);
1128       fclose(stream);
1129       if(error) {
1130         logmsg("getpart() failed with error: %d", error);
1131         return EACCESS;
1132       }
1133       if(test->buffer) {
1134         test->rptr = test->buffer; /* set read pointer */
1135         test->bufsize = count;    /* set total count */
1136         test->rcount = count;     /* set data left to read */
1137       }
1138       else
1139         return EACCESS;
1140     }
1141   }
1142   else {
1143     logmsg("no slash found in path");
1144     return EACCESS; /* failure */
1145   }
1146 
1147   logmsg("file opened and all is good");
1148   return 0;
1149 }
1150 
1151 /*
1152  * Send the requested file.
1153  */
sendtftp(struct testcase * test,const struct formats * pf)1154 static void sendtftp(struct testcase *test, const struct formats *pf)
1155 {
1156   int size;
1157   ssize_t n;
1158   /* These are volatile to live through a siglongjmp */
1159   volatile unsigned short sendblock; /* block count */
1160   struct tftphdr * volatile sdp = r_init(); /* data buffer */
1161   struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */
1162 
1163   sendblock = 1;
1164 #if defined(HAVE_ALARM) && defined(SIGALRM)
1165   mysignal(SIGALRM, timer);
1166 #endif
1167   do {
1168     size = readit(test, (struct tftphdr **)&sdp, pf->f_convert);
1169     if(size < 0) {
1170       nak(errno + 100);
1171       return;
1172     }
1173     sdp->th_opcode = htons((unsigned short)opcode_DATA);
1174     sdp->th_block = htons(sendblock);
1175     timeout = 0;
1176 #ifdef HAVE_SIGSETJMP
1177     (void) sigsetjmp(timeoutbuf, 1);
1178 #endif
1179     if(test->writedelay) {
1180       logmsg("Pausing %d seconds before %d bytes", test->writedelay,
1181              size);
1182       wait_ms(1000*test->writedelay);
1183     }
1184 
1185     send_data:
1186     logmsg("write");
1187     if(swrite(peer, sdp, size + 4) != size + 4) {
1188       logmsg("write: fail");
1189       return;
1190     }
1191     read_ahead(test, pf->f_convert);
1192     for(;;) {
1193 #ifdef HAVE_ALARM
1194       alarm(rexmtval);        /* read the ack */
1195 #endif
1196       logmsg("read");
1197       n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage));
1198       logmsg("read: %zd", n);
1199 #ifdef HAVE_ALARM
1200       alarm(0);
1201 #endif
1202       if(got_exit_signal)
1203         return;
1204       if(n < 0) {
1205         logmsg("read: fail");
1206         return;
1207       }
1208       sap->th_opcode = ntohs((unsigned short)sap->th_opcode);
1209       sap->th_block = ntohs(sap->th_block);
1210 
1211       if(sap->th_opcode == opcode_ERROR) {
1212         logmsg("got ERROR");
1213         return;
1214       }
1215 
1216       if(sap->th_opcode == opcode_ACK) {
1217         if(sap->th_block == sendblock) {
1218           break;
1219         }
1220         /* Re-synchronize with the other side */
1221         (void) synchnet(peer);
1222         if(sap->th_block == (sendblock-1)) {
1223           goto send_data;
1224         }
1225       }
1226 
1227     }
1228     sendblock++;
1229   } while(size == SEGSIZE);
1230 }
1231 
1232 /*
1233  * Receive a file.
1234  */
recvtftp(struct testcase * test,const struct formats * pf)1235 static void recvtftp(struct testcase *test, const struct formats *pf)
1236 {
1237   ssize_t n, size;
1238   /* These are volatile to live through a siglongjmp */
1239   volatile unsigned short recvblock; /* block count */
1240   struct tftphdr * volatile rdp;     /* data buffer */
1241   struct tftphdr *rap;      /* ack buffer */
1242 
1243   recvblock = 0;
1244   rdp = w_init();
1245 #if defined(HAVE_ALARM) && defined(SIGALRM)
1246   mysignal(SIGALRM, timer);
1247 #endif
1248   rap = &ackbuf.hdr;
1249   do {
1250     timeout = 0;
1251     rap->th_opcode = htons((unsigned short)opcode_ACK);
1252     rap->th_block = htons(recvblock);
1253     recvblock++;
1254 #ifdef HAVE_SIGSETJMP
1255     (void) sigsetjmp(timeoutbuf, 1);
1256 #endif
1257 send_ack:
1258     logmsg("write");
1259     if(swrite(peer, &ackbuf.storage[0], 4) != 4) {
1260       logmsg("write: fail");
1261       goto abort;
1262     }
1263     write_behind(test, pf->f_convert);
1264     for(;;) {
1265 #ifdef HAVE_ALARM
1266       alarm(rexmtval);
1267 #endif
1268       logmsg("read");
1269       n = sread(peer, rdp, PKTSIZE);
1270       logmsg("read: %zd", n);
1271 #ifdef HAVE_ALARM
1272       alarm(0);
1273 #endif
1274       if(got_exit_signal)
1275         goto abort;
1276       if(n < 0) {                       /* really? */
1277         logmsg("read: fail");
1278         goto abort;
1279       }
1280       rdp->th_opcode = ntohs((unsigned short)rdp->th_opcode);
1281       rdp->th_block = ntohs(rdp->th_block);
1282       if(rdp->th_opcode == opcode_ERROR)
1283         goto abort;
1284       if(rdp->th_opcode == opcode_DATA) {
1285         if(rdp->th_block == recvblock) {
1286           break;                         /* normal */
1287         }
1288         /* Re-synchronize with the other side */
1289         (void) synchnet(peer);
1290         if(rdp->th_block == (recvblock-1))
1291           goto send_ack;                 /* rexmit */
1292       }
1293     }
1294 
1295     size = writeit(test, &rdp, (int)(n - 4), pf->f_convert);
1296     if(size != (n-4)) {                 /* ahem */
1297       if(size < 0)
1298         nak(errno + 100);
1299       else
1300         nak(ENOSPACE);
1301       goto abort;
1302     }
1303   } while(size == SEGSIZE);
1304   write_behind(test, pf->f_convert);
1305   /* close the output file as early as possible after upload completion */
1306   if(test->ofile > 0) {
1307     close(test->ofile);
1308     test->ofile = 0;
1309   }
1310 
1311   rap->th_opcode = htons((unsigned short)opcode_ACK);  /* send the "final"
1312                                                           ack */
1313   rap->th_block = htons(recvblock);
1314   (void) swrite(peer, &ackbuf.storage[0], 4);
1315 #if defined(HAVE_ALARM) && defined(SIGALRM)
1316   mysignal(SIGALRM, justtimeout);        /* just abort read on timeout */
1317   alarm(rexmtval);
1318 #endif
1319   /* normally times out and quits */
1320   n = sread(peer, &buf.storage[0], sizeof(buf.storage));
1321 #ifdef HAVE_ALARM
1322   alarm(0);
1323 #endif
1324   if(got_exit_signal)
1325     goto abort;
1326   if(n >= 4 &&                               /* if read some data */
1327      rdp->th_opcode == opcode_DATA &&        /* and got a data block */
1328      recvblock == rdp->th_block) {           /* then my last ack was lost */
1329     (void) swrite(peer, &ackbuf.storage[0], 4);  /* resend final ack */
1330   }
1331 abort:
1332   /* make sure the output file is closed in case of abort */
1333   if(test->ofile > 0) {
1334     close(test->ofile);
1335     test->ofile = 0;
1336   }
1337   return;
1338 }
1339 
1340 /*
1341  * Send a nak packet (error message).  Error code passed in is one of the
1342  * standard TFTP codes, or a Unix errno offset by 100.
1343  */
nak(int error)1344 static void nak(int error)
1345 {
1346   struct tftphdr *tp;
1347   int length;
1348   struct errmsg *pe;
1349 
1350   tp = &buf.hdr;
1351   tp->th_opcode = htons((unsigned short)opcode_ERROR);
1352   tp->th_code = htons((unsigned short)error);
1353   for(pe = errmsgs; pe->e_code >= 0; pe++)
1354     if(pe->e_code == error)
1355       break;
1356   if(pe->e_code < 0) {
1357     pe->e_msg = strerror(error - 100);
1358     tp->th_code = EUNDEF;   /* set 'undef' errorcode */
1359   }
1360   length = (int)strlen(pe->e_msg);
1361 
1362   /* we use memcpy() instead of strcpy() in order to avoid buffer overflow
1363    * report from glibc with FORTIFY_SOURCE */
1364   memcpy(tp->th_msg, pe->e_msg, length + 1);
1365   length += 5;
1366   if(swrite(peer, &buf.storage[0], length) != length)
1367     logmsg("nak: fail\n");
1368 }
1369