2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21 All rights reserved.\n";
25 static char sccsid
[] = "@(#)tftpd.c 5.8 (Berkeley) 6/18/88";
29 * Trivial file transfer protocol server.
31 * This version includes many modifications by Jim Guyton <guyton@rand-unix>
33 * Further modifications by Markus Gutschke <gutschk@math.uni-muenster.de>
34 * - RFC1782 option parsing
35 * - RFC1783 extended blocksize
36 * - "-c" option for changing the root directory
37 * - "-d" option for debugging output
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
46 #include <netinet/in.h>
48 #include <arpa/tftp.h>
71 struct sockaddr_in sin
= { AF_INET
};
73 int rexmtval
= TIMEOUT
;
74 int maxtimeout
= 5*TIMEOUT
;
76 #define PKTSIZE (1432+4) /* SEGSIZE+4 */
77 int segsize
= SEGSIZE
;
80 struct sockaddr_in from
;
95 register struct tftphdr
*tp
;
101 openlog(argv
[0], LOG_PID
, LOG_DAEMON
);
103 while ((n
= getopt(argc
, argv
, "c:dr:")) >= 0) {
114 struct filters
*fp
= (void *)
115 malloc(sizeof(struct filters
) +
118 fp
->fname
= (char *)(fp
+ 1);
119 strcpy(fp
->fname
, optarg
);
124 syslog(LOG_ERR
, "Usage: %s [-c chroot] "
125 "[-r readfilter] [-d]\n",
130 if (argc
-optind
!= 0)
133 ioctl(0, FIONBIO
, &on
);
134 /* if (ioctl(0, FIONBIO, &on) < 0) {
135 syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
139 fromlen
= sizeof (from
);
140 n
= recvfrom(0, buf
, segsize
+4, 0,
141 (struct sockaddr
*)&from
, &fromlen
);
143 syslog(LOG_ERR
, "recvfrom: %m\n");
147 * Now that we have read the message out of the UDP
148 * socket, we fork and exit. Thus, inetd will go back
149 * to listening to the tftp port, and the next request
150 * to come in will start up a new instance of tftpd.
152 * We do this so that inetd can run tftpd in "wait" mode.
153 * The problem with tftpd running in "nowait" mode is that
154 * inetd may get one or more successful "selects" on the
155 * tftp port before we do our receive, so more than one
156 * instance of tftpd may be started up. Worse, if tftpd
157 * break before doing the above "recvfrom", inetd would
158 * spawn endless instances, clogging the system.
164 for (i
= 1; i
< 20; i
++) {
169 * flush out to most recently sent request.
171 * This may drop some request, but those
172 * will be resent by the clients when
173 * they timeout. The positive effect of
174 * this flush is to (try to) prevent more
175 * than one tftpd being started up to service
176 * a single request from a single client.
179 i
= recvfrom(0, buf
, segsize
+4, 0,
180 (struct sockaddr
*)&from
, &j
);
190 syslog(LOG_ERR
, "fork: %m\n");
192 } else if (pid
!= 0) {
196 from
.sin_family
= AF_INET
;
200 peer
= socket(AF_INET
, SOCK_DGRAM
, 0);
202 syslog(LOG_ERR
, "socket: %m\n");
205 if (bind(peer
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
206 syslog(LOG_ERR
, "bind: %m\n");
209 if (connect(peer
, (struct sockaddr
*)&from
, sizeof(from
)) < 0) {
210 syslog(LOG_ERR
, "connect: %m\n");
213 tp
= (struct tftphdr
*)buf
;
214 tp
->th_opcode
= ntohs(tp
->th_opcode
);
215 if (tp
->th_opcode
== RRQ
|| tp
->th_opcode
== WRQ
)
220 int validate_access();
221 int sendfile(), recvfile();
230 { "netascii", validate_access
, sendfile
, recvfile
, 1 },
231 { "octet", validate_access
, sendfile
, recvfile
, 0 },
233 { "mail", validate_user
, sendmail
, recvmail
, 1 },
244 { "blksize", set_blksize
},
249 * Set a non-standard block size (c.f. RFC1783)
252 set_blksize(val
, ret
)
256 static char b_ret
[5];
261 syslog(LOG_ERR
, "Requested packetsize %d < 8\n", sz
);
263 } else if (sz
> PKTSIZE
-4) {
265 syslog(LOG_INFO
, "Requested packetsize %d > %d\n",
269 syslog(LOG_INFO
, "Adjusted packetsize to %d octets\n", sz
);
272 sprintf(*ret
= b_ret
, "%d", sz
);
277 * Parse RFC1782 style options
288 for (po
= options
; po
->o_opt
; po
++)
289 if (strcasecmp(po
->o_opt
, opt
) == 0) {
290 if (po
->o_fnc(val
, &ret
)) {
291 if (*ap
+ strlen(opt
) + strlen(ret
) + 2 >=
292 ackbuf
+ sizeof(ackbuf
)) {
295 "Ackbuf overflow\n");
299 *ap
= strrchr(strcpy(strrchr(strcpy(*ap
, opt
),
308 if (debug
&& !po
->o_opt
)
309 syslog(LOG_WARNING
, "Unhandled option: %d = %d\n", opt
, val
);
314 * Handle initial connection protocol.
322 register struct formats
*pf
;
323 char *filename
, *mode
;
328 ((struct tftphdr
*)ackbuf
)->th_opcode
= ntohs(OACK
);
329 filename
= cp
= tp
->th_stuff
;
331 while (cp
< buf
+ size
) {
338 syslog(LOG_WARNING
, "Received illegal request\n");
346 if (debug
&& argn
== 3)
347 syslog(LOG_INFO
, "Found RFC1782 style options\n");
348 *(argn
& 1 ? &val
: &opt
) = ++cp
;
350 do_opt(opt
, val
, &ap
);
351 if (cp
< buf
+ size
&& *cp
!= '\000')
355 for (cp
= mode
; *cp
; cp
++)
358 for (pf
= formats
; pf
->f_mode
; pf
++)
359 if (strcmp(pf
->f_mode
, mode
) == 0)
361 if (pf
->f_mode
== 0) {
363 syslog(LOG_WARNING
, "Unknown data format: %s\n", mode
);
369 cp
= alloca(strlen(rootdir
) + strlen(filename
) + 1);
374 if (*filename
!= '/') {
377 "Filename has to be absolute: %s\n",
382 filename
= strcat(strcpy(cp
, rootdir
), filename
);
385 ecode
= (*pf
->f_validate
)(filename
, tp
->th_opcode
);
390 isopts
= ap
!= (ackbuf
+2);
391 (tp
->th_opcode
== WRQ
? *pf
->f_recv
: *pf
->f_send
)
392 (pf
, isopts
? ackbuf
: NULL
, isopts
? ap
-ackbuf
: 0);
400 * Validate file access. Since we
401 * have no uid or gid, for now require
402 * file to exist and be publicly
404 * Note also, full path name must be
405 * given as we have no login directory.
407 validate_access(filename
, mode
)
417 struct filters
*fp
= filters
;
418 for (; fp
; fp
= fp
->next
) {
419 if (!strcmp(fp
->fname
,
421 (rootdir
? strlen(rootdir
) : 0))) {
423 syslog(LOG_INFO
, "Opening input "
424 "filter: %s\n", filename
);
425 if ((file
= popen(filename
, "r")) == NULL
) {
426 syslog(LOG_ERR
, "Failed to open input "
436 if (*filename
!= '/') {
438 syslog(LOG_ERR
, "Filename has to be absolute: %s\n",
442 for (cp
= filename
; *cp
; cp
++)
443 if (*cp
== '~' || *cp
== '$' ||
444 (*cp
== '/' && cp
[1] == '.' && cp
[2] == '.')) {
446 syslog(LOG_ERR
, "Illegal filename: %s\n",
451 syslog(LOG_INFO
, "Validating \"%s\" for %sing\n",
452 filename
, mode
== RRQ
? "read" : "writ");
453 if (stat(filename
, &stbuf
) < 0)
454 return (errno
== ENOENT
? ENOTFOUND
: EACCESS
);
456 if ((stbuf
.st_mode
&(S_IREAD
>> 6)) == 0)
459 if ((stbuf
.st_mode
&(S_IWRITE
>> 6)) == 0)
462 fd
= open(filename
, mode
== RRQ
? 0 : 1);
464 return (errno
+ 100);
465 file
= fdopen(fd
, (mode
== RRQ
)? "r":"w");
479 if (timeout
>= maxtimeout
) {
481 syslog(LOG_WARNING
, "Timeout!\n");
484 longjmp(timeoutbuf
, 1);
488 * Send the requested file.
490 sendfile(pf
, oap
, oacklen
)
495 struct tftphdr
*dp
, *r_init();
496 register struct tftphdr
*ap
; /* ack packet */
497 register int size
, n
;
500 signal(SIGALRM
, timer
);
502 ap
= (struct tftphdr
*)ackbuf
;
506 (void) setjmp(timeoutbuf
);
508 if (send(peer
, oap
, oacklen
, 0) != oacklen
) {
509 syslog(LOG_ERR
, "tftpd: write: %m\n");
514 n
= recv(peer
, ackbuf
, sizeof (ackbuf
), 0);
517 syslog(LOG_ERR
, "tftpd: read: %m\n");
520 ap
->th_opcode
= ntohs((u_short
)ap
->th_opcode
);
521 ap
->th_block
= ntohs(ap
->th_block
);
523 if (ap
->th_opcode
== ERROR
) {
525 syslog(LOG_ERR
, "Client does not "
529 if (ap
->th_opcode
== ACK
) {
530 if (ap
->th_block
== 0) {
538 /* Re-synchronize with the other side */
539 (void) synchnet(peer
);
547 size
= readit(file
, &dp
, pf
->f_convert
);
552 dp
->th_opcode
= htons((u_short
)DATA
);
553 dp
->th_block
= htons(block
);
555 (void) setjmp(timeoutbuf
);
558 if (send(peer
, dp
, size
+ 4, 0) != size
+ 4) {
559 syslog(LOG_ERR
, "tftpd: write: %m\n");
562 read_ahead(file
, pf
->f_convert
);
564 alarm(rexmtval
); /* read the ack */
565 n
= recv(peer
, ackbuf
, sizeof (ackbuf
), 0);
568 syslog(LOG_ERR
, "tftpd: read: %m\n");
571 ap
->th_opcode
= ntohs((u_short
)ap
->th_opcode
);
572 ap
->th_block
= ntohs(ap
->th_block
);
574 if (ap
->th_opcode
== ERROR
)
577 if (ap
->th_opcode
== ACK
) {
578 if (ap
->th_block
== block
) {
581 /* Re-synchronize with the other side */
582 (void) synchnet(peer
);
583 if (ap
->th_block
== (block
-1)) {
590 } while (size
== segsize
);
599 void justquit(int sig
)
608 recvfile(pf
, oap
, oacklen
)
613 struct tftphdr
*dp
, *w_init();
614 register struct tftphdr
*ap
; /* ack buffer */
615 register int acksize
, n
, size
;
618 signal(SIGALRM
, timer
);
623 if (!block
++ && oap
) {
624 ap
= (struct tftphdr
*)oap
;
627 ap
= (struct tftphdr
*)ackbuf
;
628 ap
->th_opcode
= htons((u_short
)ACK
);
629 ap
->th_block
= htons(block
-1);
632 (void) setjmp(timeoutbuf
);
634 if (send(peer
, (char *)ap
, acksize
, 0) != acksize
) {
635 syslog(LOG_ERR
, "tftpd: write: %m\n");
638 write_behind(file
, pf
->f_convert
);
641 n
= recv(peer
, dp
, segsize
+4, 0);
643 if (n
< 0) { /* really? */
644 syslog(LOG_ERR
, "tftpd: read: %m\n");
647 dp
->th_opcode
= ntohs((u_short
)dp
->th_opcode
);
648 dp
->th_block
= ntohs(dp
->th_block
);
649 if (dp
->th_opcode
== ERROR
)
651 if (dp
->th_opcode
== DATA
) {
652 if (dp
->th_block
== block
) {
655 /* Re-synchronize with the other side */
656 (void) synchnet(peer
);
657 if (dp
->th_block
== (block
-1))
658 goto send_ack
; /* rexmit */
661 /* size = write(file, dp->th_data, n - 4); */
662 size
= writeit(file
, &dp
, n
- 4, pf
->f_convert
);
663 if (size
!= (n
-4)) { /* ahem */
664 if (size
< 0) nak(errno
+ 100);
668 } while (size
== segsize
);
669 write_behind(file
, pf
->f_convert
);
673 (void) fclose(file
); /* close data file */
676 ap
= (struct tftphdr
*)ackbuf
;
677 ap
->th_opcode
= htons((u_short
)ACK
); /* send the "final" ack */
678 ap
->th_block
= htons(block
);
679 (void) send(peer
, ackbuf
, 4, 0);
681 signal(SIGALRM
, justquit
); /* just quit on timeout */
683 n
= recv(peer
, buf
, segsize
, 0); /* normally times out and quits */
685 if (n
>= 4 && /* if read some data */
686 dp
->th_opcode
== DATA
&& /* and got a data block */
687 block
== dp
->th_block
) { /* then my last ack was lost */
688 (void) send(peer
, ackbuf
, 4, 0); /* resend final ack */
698 { EUNDEF
, "Undefined error code" },
699 { ENOTFOUND
, "File not found" },
700 { EACCESS
, "Access violation" },
701 { ENOSPACE
, "Disk full or allocation exceeded" },
702 { EBADOP
, "Illegal TFTP operation" },
703 { EBADID
, "Unknown transfer ID" },
704 { EEXISTS
, "File already exists" },
705 { ENOUSER
, "No such user" },
706 { EOPTNEG
, "Failure to negotiate RFC1782 options" },
711 * Send a nak packet (error message).
712 * Error code passed in is one of the
713 * standard TFTP codes, or a UNIX errno
719 register struct tftphdr
*tp
;
721 register struct errmsg
*pe
;
722 /* extern char *sys_errlist[]; */
724 tp
= (struct tftphdr
*)buf
;
725 tp
->th_opcode
= htons((u_short
)ERROR
);
726 tp
->th_code
= htons((u_short
)error
);
727 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
728 if (pe
->e_code
== error
)
730 if (pe
->e_code
< 0) {
731 pe
->e_msg
= sys_errlist
[error
-100];
732 tp
->th_code
= EUNDEF
; /* set 'undef' errorcode */
734 strcpy(tp
->th_msg
, pe
->e_msg
);
735 length
= strlen(pe
->e_msg
);
736 tp
->th_msg
[length
] = '\0';
739 syslog(LOG_ERR
, "Negative acknowledge: %s\n", tp
->th_msg
);
740 if (send(peer
, buf
, length
, 0) != length
)
741 syslog(LOG_ERR
, "nak: %m\n");