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