1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * $Id: tftpd.c,v 1.39 2008-07-30 06:20:43 yangtse Exp $
10 * Trivial file transfer protocol server.
12 * This code includes many modifications by Jim Guyton <guyton@rand-unix>
14 * This source file was started based on netkit-tftpd 0.17
15 * Heavily modified for curl's test suite
19 * Copyright (c) 1983 Regents of the University of California.
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
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.
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
51 #include "setup.h" /* portability help from the lib directory */
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
62 #ifdef HAVE_SYS_SOCKET_H
63 #include <sys/socket.h>
65 #ifdef HAVE_NETINET_IN_H
66 #include <netinet/in.h>
68 #ifdef HAVE_ARPA_TFTP_H
69 #include <arpa/tftp.h>
76 #ifdef HAVE_SYS_FILIO_H
77 /* FIONREAD on Solaris 7 */
78 #include <sys/filio.h>
89 #define ENABLE_CURLX_PRINTF
90 /* make the curlx header define all printf() functions to use the curlx_*
92 #include "curlx.h" /* from the private lib dir */
96 /* include memdebug.h last */
100 char *buffer
; /* holds the file data to send to the client */
101 size_t bufsize
; /* size of the data in buffer */
102 char *rptr
; /* read pointer into the buffer */
103 size_t rcount
; /* amount of data left to read of the file */
104 long num
; /* test case number */
105 int ofile
; /* file descriptor for output file when uploading to us */
108 static int synchnet(curl_socket_t
);
109 static struct tftphdr
*r_init(void);
110 static struct tftphdr
*w_init(void);
111 static int readit(struct testcase
*test
, struct tftphdr
**dpp
, int convert
);
112 static int writeit(struct testcase
*test
, struct tftphdr
**dpp
, int ct
,
114 static void mysignal(int, void (*func
)(int));
119 #define PKTSIZE SEGSIZE+4
122 static int tftp(struct testcase
*test
, struct tftphdr
*tp
, ssize_t size
);
123 static void nak(int error
);
124 static void sendtftp(struct testcase
*test
, struct formats
*pf
);
125 static void recvtftp(struct testcase
*test
, struct formats
*pf
);
126 static int validate_access(struct testcase
*test
, const char *, int);
128 static curl_socket_t peer
;
129 static int rexmtval
= TIMEOUT
;
130 static int maxtimeout
= 5*TIMEOUT
;
132 static char buf
[PKTSIZE
];
133 static char ackbuf
[PKTSIZE
];
134 static struct sockaddr_in from
;
135 static socklen_t fromlen
;
138 int counter
; /* size of data in buffer, or flag */
139 char buf
[PKTSIZE
]; /* room for data packet */
142 /* Values for bf.counter */
143 #define BF_ALLOC -3 /* alloc'd but not yet filled */
144 #define BF_FREE -2 /* free */
145 /* [-1 .. SEGSIZE] = size of data in the data buffer */
147 static int nextone
; /* index of next buffer to use */
148 static int current
; /* index of buffer in use */
150 /* control flags for crlf conversions */
151 int newline
= 0; /* fillbuf: in middle of newline expansion */
152 int prevchar
= -1; /* putbuf: previous char (cr check) */
154 static void read_ahead(struct testcase
*test
,
155 int convert
/* if true, convert to ascii */);
156 static ssize_t
write_behind(struct testcase
*test
, int convert
);
157 static struct tftphdr
*rw_init(int);
158 static struct tftphdr
*w_init(void) { return rw_init(0); } /* write-behind */
159 static struct tftphdr
*r_init(void) { return rw_init(1); } /* read-ahead */
161 static struct tftphdr
*
162 rw_init(int x
) /* init for either read-ahead or write-behind */
163 { /* zero for write-behind, one for read-head */
164 newline
= 0; /* init crlf flag */
166 bfs
[0].counter
= BF_ALLOC
; /* pass out the first buffer */
168 bfs
[1].counter
= BF_FREE
;
169 nextone
= x
; /* ahead or behind? */
170 return (struct tftphdr
*)bfs
[0].buf
;
174 /* Have emptied current buffer by sending to net and getting ack.
175 Free it and return next buffer filled with data.
177 static int readit(struct testcase
*test
, struct tftphdr
**dpp
,
178 int convert
/* if true, convert to ascii */)
182 bfs
[current
].counter
= BF_FREE
; /* free old one */
183 current
= !current
; /* "incr" current */
185 b
= &bfs
[current
]; /* look at new buffer */
186 if (b
->counter
== BF_FREE
) /* if it's empty */
187 read_ahead(test
, convert
); /* fill it */
189 *dpp
= (struct tftphdr
*)b
->buf
; /* set caller's ptr */
193 #undef MIN /* some systems have this defined already, some don't */
194 #define MIN(x,y) ((x)<(y)?(x):(y));
197 * fill the input buffer, doing ascii conversions if requested
198 * conversions are lf -> cr,lf and cr -> cr, nul
200 static void read_ahead(struct testcase
*test
,
201 int convert
/* if true, convert to ascii */)
209 b
= &bfs
[nextone
]; /* look at "next" buffer */
210 if (b
->counter
!= BF_FREE
) /* nop if not free */
212 nextone
= !nextone
; /* "incr" next buffer ptr */
214 dp
= (struct tftphdr
*)b
->buf
;
217 /* The former file reading code did this:
218 b->counter = read(fileno(file), dp->th_data, SEGSIZE); */
219 size_t copy_n
= MIN(SEGSIZE
, test
->rcount
);
220 memcpy(dp
->th_data
, test
->rptr
, copy_n
);
222 /* decrease amount, advance pointer */
223 test
->rcount
-= copy_n
;
224 test
->rptr
+= copy_n
;
225 b
->counter
= (int)copy_n
;
230 for (i
= 0 ; i
< SEGSIZE
; i
++) {
232 if (prevchar
== '\n')
233 c
= '\n'; /* lf to cr,lf */
235 c
= '\0'; /* cr to cr,nul */
246 if (c
== '\n' || c
== '\r') {
254 b
->counter
= (int)(p
- dp
->th_data
);
257 /* Update count associated with the buffer, get new buffer from the queue.
258 Calls write_behind only if next buffer not available.
260 static int writeit(struct testcase
*test
, struct tftphdr
**dpp
,
263 bfs
[current
].counter
= ct
; /* set size of data to write */
264 current
= !current
; /* switch to other buffer */
265 if (bfs
[current
].counter
!= BF_FREE
) /* if not free */
266 write_behind(test
, convert
); /* flush it */
267 bfs
[current
].counter
= BF_ALLOC
; /* mark as alloc'd */
268 *dpp
= (struct tftphdr
*)bfs
[current
].buf
;
269 return ct
; /* this is a lie of course */
273 * Output a buffer to a file, converting from netascii if requested.
274 * CR,NUL -> CR and CR,LF => LF.
275 * Note spec is undefined if we get CR as last byte of file or a
276 * CR followed by anything else. In this case we leave it alone.
278 static ssize_t
write_behind(struct testcase
*test
, int convert
)
284 int c
; /* current character */
289 if (b
->counter
< -1) /* anything to flush? */
290 return 0; /* just nop if nothing to do */
294 snprintf(outfile
, sizeof(outfile
), "log/upload.%ld", test
->num
);
295 test
->ofile
=open(outfile
, O_CREAT
|O_RDWR
, 0777);
296 if(test
->ofile
== -1) {
297 logmsg("Couldn't create and/or open file %s for upload!", outfile
);
298 return -1; /* failure! */
302 count
= b
->counter
; /* remember byte count */
303 b
->counter
= BF_FREE
; /* reset flag */
304 dp
= (struct tftphdr
*)b
->buf
;
305 nextone
= !nextone
; /* incr for next time */
306 writebuf
= dp
->th_data
;
309 return -1; /* nak logic? */
312 return write(test
->ofile
, writebuf
, count
);
316 while (ct
--) { /* loop over the buffer */
317 c
= *p
++; /* pick up a character */
318 if (prevchar
== '\r') { /* if prev char was cr */
319 if (c
== '\n') /* if have cr,lf then just */
320 lseek(test
->ofile
, -1, SEEK_CUR
); /* smash lf on top of the cr */
322 if (c
== '\0') /* if have cr,nul then */
323 goto skipit
; /* just skip over the putc */
324 /* else just fall through and allow it */
328 write(test
->ofile
, &c
, 1);
336 /* When an error has occurred, it is possible that the two sides are out of
337 * synch. Ie: that what I think is the other side's response to packet N is
338 * really their response to packet N-1.
340 * So, to try to prevent that, we flush all the input queued up for us on the
341 * network connection on our host.
343 * We return the number of packets we flushed (mostly for reporting when trace
347 static int synchnet(curl_socket_t f
/* socket to flush */)
350 #if defined(HAVE_IOCTLSOCKET)
357 struct sockaddr_in fromaddr
;
358 socklen_t fromaddrlen
;
361 #if defined(HAVE_IOCTLSOCKET)
362 (void) ioctlsocket(f
, FIONREAD
, &i
);
364 (void) ioctl(f
, FIONREAD
, &i
);
368 fromaddrlen
= sizeof(fromaddr
);
369 (void)recvfrom(f
, rbuf
, sizeof(rbuf
), 0,
370 (struct sockaddr
*)&fromaddr
, &fromaddrlen
);
378 #if defined(HAVE_ALARM) && defined(SIGALRM)
380 * Like signal(), but with well-defined semantics.
382 static void mysignal(int sig
, void (*handler
)(int))
385 memset(&sa
, 0, sizeof(sa
));
386 sa
.sa_handler
= handler
;
387 sigaction(sig
, &sa
, NULL
);
391 #ifndef DEFAULT_LOGFILE
392 #define DEFAULT_LOGFILE "log/tftpd.log"
395 #define DEFAULT_PORT 8999 /* UDP */
396 const char *serverlogfile
= DEFAULT_LOGFILE
;
398 #define REQUEST_DUMP "log/server.input"
402 int main(int argc
, char **argv
)
404 struct sockaddr_in me
;
406 struct sockaddr_in6 me6
;
407 #endif /* ENABLE_IPV6 */
412 char *pidname
= (char *)".tftpd.pid";
413 unsigned short port
= DEFAULT_PORT
;
417 struct testcase test
;
421 if(!strcmp("--version", argv
[arg
])) {
422 printf("tftpd IPv4%s\n",
431 else if(!strcmp("--pidfile", argv
[arg
])) {
434 pidname
= argv
[arg
++];
436 else if(!strcmp("--ipv6", argv
[arg
])) {
445 port
= (unsigned short)atoi(argv
[arg
++]);
454 atexit(win32_cleanup
);
460 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
463 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
467 perror("opening stream socket");
468 logmsg("Error opening socket");
474 (sock
, SOL_SOCKET
, SO_REUSEADDR
, (const void *) &flag
,
476 perror("setsockopt(SO_REUSEADDR)");
482 me
.sin_family
= AF_INET
;
483 me
.sin_addr
.s_addr
= INADDR_ANY
;
484 me
.sin_port
= htons(port
);
485 rc
= bind(sock
, (struct sockaddr
*) &me
, sizeof(me
));
489 memset(&me6
, 0, sizeof(struct sockaddr_in6
));
490 me6
.sin6_family
= AF_INET6
;
491 me6
.sin6_addr
= in6addr_any
;
492 me6
.sin6_port
= htons(port
);
493 rc
= bind(sock
, (struct sockaddr
*) &me6
, sizeof(me6
));
495 #endif /* ENABLE_IPV6 */
497 perror("binding stream socket");
498 logmsg("Error binding socket");
503 if(!write_pidfile(pidname
)) {
508 logmsg("Running IPv%d version on port UDP/%d",
517 fromlen
= sizeof(from
);
518 n
= (ssize_t
)recvfrom(sock
, buf
, sizeof(buf
), 0,
519 (struct sockaddr
*)&from
, &fromlen
);
521 logmsg("recvfrom:\n");
526 set_advisor_read_lock(SERVERLOGS_LOCK
);
528 from
.sin_family
= AF_INET
;
530 peer
= socket(AF_INET
, SOCK_DGRAM
, 0);
537 if (connect(peer
, (struct sockaddr
*)&from
, sizeof(from
)) < 0) {
538 logmsg("connect: fail\n");
542 maxtimeout
= 5*TIMEOUT
;
544 tp
= (struct tftphdr
*)buf
;
545 tp
->th_opcode
= ntohs(tp
->th_opcode
);
546 if (tp
->th_opcode
== RRQ
|| tp
->th_opcode
== WRQ
) {
547 memset(&test
, 0, sizeof(test
));
548 if (tftp(&test
, tp
, n
) < 0)
555 clear_advisor_read_lock(SERVERLOGS_LOCK
);
559 clear_advisor_read_lock(SERVERLOGS_LOCK
);
574 * Handle initial connection protocol.
576 static int tftp(struct testcase
*test
, struct tftphdr
*tp
, ssize_t size
)
579 int first
= 1, ecode
;
581 char *filename
, *mode
= NULL
;
585 /* Open request dump file. */
586 server
= fopen(REQUEST_DUMP
, "ab");
589 logmsg("fopen() failed with error: %d %s", error
, strerror(error
));
590 logmsg("Error opening file: %s", REQUEST_DUMP
);
594 /* store input protocol */
595 fprintf(server
, "opcode: %x\n", tp
->th_opcode
);
597 cp
= (char *)&tp
->th_stuff
;
600 while (cp
< buf
+ size
) {
615 /* store input protocol */
616 fprintf(server
, "filename: %s\n", filename
);
618 for (cp
= mode
; *cp
; cp
++)
620 *cp
= (char)tolower((int)*cp
);
622 /* store input protocol */
623 fprintf(server
, "mode: %s\n", mode
);
626 for (pf
= formats
; pf
->f_mode
; pf
++)
627 if (strcmp(pf
->f_mode
, mode
) == 0)
633 ecode
= validate_access(test
, filename
, tp
->th_opcode
);
638 if (tp
->th_opcode
== WRQ
)
647 * Validate file access.
649 static int validate_access(struct testcase
*test
,
650 const char *filename
, int mode
)
655 char partbuf
[80]="data";
657 logmsg("trying to get file: %s mode %x", filename
, mode
);
659 if(!strncmp("verifiedserver", filename
, 14)) {
661 size_t count
= sprintf(weare
, "WE ROOLZ: %ld\r\n", (long)getpid());
663 logmsg("Are-we-friendly question received");
664 test
->buffer
= strdup(weare
);
665 test
->rptr
= test
->buffer
; /* set read pointer */
666 test
->bufsize
= count
; /* set total count */
667 test
->rcount
= count
; /* set data left to read */
671 /* find the last slash */
672 ptr
= strrchr(filename
, '/');
677 ptr
++; /* skip the slash */
679 /* skip all non-numericals following the slash */
680 while(*ptr
&& !ISDIGIT(*ptr
))
684 testno
= strtol(ptr
, &ptr
, 10);
687 partno
= testno
% 10000;
694 logmsg("requested test number %ld part %ld", testno
, partno
);
698 file
= test2file(testno
);
701 sprintf(partbuf
, "data%ld", partno
);
704 FILE *stream
=fopen(file
, "rb");
707 logmsg("fopen() failed with error: %d %s", error
, strerror(error
));
708 logmsg("Error opening file: %s", file
);
709 logmsg("Couldn't open test file: %s", file
);
714 test
->buffer
= (char *)spitout(stream
, "reply", partbuf
, &count
);
717 test
->rptr
= test
->buffer
; /* set read pointer */
718 test
->bufsize
= count
; /* set total count */
719 test
->rcount
= count
; /* set data left to read */
730 logmsg("no slash found in path");
731 return EACCESS
; /* failure */
738 #ifdef HAVE_SIGSETJMP
739 sigjmp_buf timeoutbuf
;
742 static void timer(int signum
)
749 if(timeout
>= maxtimeout
) {
750 clear_advisor_read_lock(SERVERLOGS_LOCK
);
753 #ifdef HAVE_SIGSETJMP
754 siglongjmp(timeoutbuf
, 1);
759 * Send the requested file.
761 static void sendtftp(struct testcase
*test
, struct formats
*pf
)
764 struct tftphdr
*ap
; /* ack packet */
765 unsigned short block
= 1;
768 #if defined(HAVE_ALARM) && defined(SIGALRM)
769 mysignal(SIGALRM
, timer
);
772 ap
= (struct tftphdr
*)ackbuf
;
774 size
= readit(test
, &dp
, pf
->f_convert
);
779 dp
->th_opcode
= htons((u_short
)DATA
);
780 dp
->th_block
= htons((u_short
)block
);
782 #ifdef HAVE_SIGSETJMP
783 (void) sigsetjmp(timeoutbuf
, 1);
786 if (swrite(peer
, dp
, size
+ 4) != size
+ 4) {
790 read_ahead(test
, pf
->f_convert
);
793 alarm(rexmtval
); /* read the ack */
795 n
= sread(peer
, ackbuf
, sizeof (ackbuf
));
800 logmsg("read: fail\n");
803 ap
->th_opcode
= ntohs((u_short
)ap
->th_opcode
);
804 ap
->th_block
= ntohs((u_short
)ap
->th_block
);
806 if (ap
->th_opcode
== ERROR
) {
811 if (ap
->th_opcode
== ACK
) {
812 if (ap
->th_block
== block
) {
815 /* Re-synchronize with the other side */
816 (void) synchnet(peer
);
817 if (ap
->th_block
== (block
-1)) {
824 } while (size
== SEGSIZE
);
827 static void justtimeout(int signum
)
836 static void recvtftp(struct testcase
*test
, struct formats
*pf
)
839 struct tftphdr
*ap
; /* ack buffer */
840 unsigned short block
= 0;
842 #if defined(HAVE_ALARM) && defined(SIGALRM)
843 mysignal(SIGALRM
, timer
);
846 ap
= (struct tftphdr
*)ackbuf
;
849 ap
->th_opcode
= htons((u_short
)ACK
);
850 ap
->th_block
= htons((u_short
)block
);
852 #ifdef HAVE_SIGSETJMP
853 (void) sigsetjmp(timeoutbuf
, 1);
856 if (swrite(peer
, ackbuf
, 4) != 4) {
857 logmsg("write: fail\n");
860 write_behind(test
, pf
->f_convert
);
865 n
= sread(peer
, dp
, PKTSIZE
);
869 if (n
< 0) { /* really? */
870 logmsg("read: fail\n");
873 dp
->th_opcode
= ntohs((u_short
)dp
->th_opcode
);
874 dp
->th_block
= ntohs((u_short
)dp
->th_block
);
875 if (dp
->th_opcode
== ERROR
)
877 if (dp
->th_opcode
== DATA
) {
878 if (dp
->th_block
== block
) {
881 /* Re-synchronize with the other side */
882 (void) synchnet(peer
);
883 if (dp
->th_block
== (block
-1))
884 goto send_ack
; /* rexmit */
888 size
= writeit(test
, &dp
, (int)(n
- 4), pf
->f_convert
);
889 if (size
!= (n
-4)) { /* ahem */
896 } while (size
== SEGSIZE
);
897 write_behind(test
, pf
->f_convert
);
899 ap
->th_opcode
= htons((u_short
)ACK
); /* send the "final" ack */
900 ap
->th_block
= htons((u_short
)(block
));
901 (void) swrite(peer
, ackbuf
, 4);
902 #if defined(HAVE_ALARM) && defined(SIGALRM)
903 mysignal(SIGALRM
, justtimeout
); /* just abort read on timeout */
906 n
= sread(peer
, buf
, sizeof(buf
)); /* normally times out and quits */
910 if (n
>= 4 && /* if read some data */
911 dp
->th_opcode
== DATA
&& /* and got a data block */
912 block
== dp
->th_block
) { /* then my last ack was lost */
913 (void) swrite(peer
, ackbuf
, 4); /* resend final ack */
923 { EUNDEF
, "Undefined error code" },
924 { ENOTFOUND
, "File not found" },
925 { EACCESS
, "Access violation" },
926 { ENOSPACE
, "Disk full or allocation exceeded" },
927 { EBADOP
, "Illegal TFTP operation" },
928 { EBADID
, "Unknown transfer ID" },
929 { EEXISTS
, "File already exists" },
930 { ENOUSER
, "No such user" },
935 * Send a nak packet (error message). Error code passed in is one of the
936 * standard TFTP codes, or a UNIX errno offset by 100.
938 static void nak(int error
)
944 tp
= (struct tftphdr
*)buf
;
945 tp
->th_opcode
= htons((u_short
)ERROR
);
946 tp
->th_code
= htons((u_short
)error
);
947 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
948 if (pe
->e_code
== error
)
950 if (pe
->e_code
< 0) {
951 pe
->e_msg
= strerror(error
- 100);
952 tp
->th_code
= EUNDEF
; /* set 'undef' errorcode */
954 strcpy(tp
->th_msg
, pe
->e_msg
);
955 length
= (int)strlen(pe
->e_msg
);
956 tp
->th_msg
[length
] = '\0';
958 if (swrite(peer
, buf
, length
) != length
)
959 logmsg("nak: fail\n");