1 /* $NetBSD: tftpd.c,v 1.32 2009/03/16 01:56:21 lukem Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
35 The Regents of the University of California. All rights reserved.");
37 static char sccsid
[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
39 __RCSID("$NetBSD: tftpd.c,v 1.32 2009/03/16 01:56:21 lukem Exp $");
44 * Trivial file transfer protocol server.
46 * This version includes many modifications by Jim Guyton
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
53 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <arpa/tftp.h>
57 #include <arpa/inet.h>
76 #define DEFAULTUSER "nobody"
81 static int rexmtval
= TIMEOUT
;
82 static int maxtimeout
= 5*TIMEOUT
;
84 static char buf
[MAXPKTSIZE
];
85 static char ackbuf
[PKTSIZE
];
86 static char oackbuf
[PKTSIZE
];
87 static struct sockaddr_storage from
;
88 static socklen_t fromlen
;
91 static int tftp_opt_tsize
= 0;
92 static int tftp_blksize
= SEGSIZE
;
93 static int tftp_tsize
= 0;
96 * Null-terminated directory prefix list for absolute pathname requests and
97 * search list for relative pathname requests.
99 * MAXDIRS should be at least as large as the number of arguments that
100 * inetd allows (currently 20).
103 static struct dirlist
{
107 static int suppress_naks
;
110 static char pathsep
= '\0';
111 static char *securedir
;
115 static const char *errtomsg(int);
116 static void nak(int);
117 static void tftp(struct tftphdr
*, int);
118 static void usage(void) __attribute__((__noreturn__
));
119 static char *verifyhost(struct sockaddr
*);
120 static void justquit(int);
121 static void recvfile(struct formats
*, int, int);
122 static void sendfile(struct formats
*, int, int);
123 static void timer(int);
124 static const char *opcode(int);
125 static int validate_access(char **, int);
127 static struct formats
{
129 int (*f_validate
)(char **, int);
130 void (*f_send
)(struct formats
*, int, int);
131 void (*f_recv
)(struct formats
*, int, int);
134 { "netascii", validate_access
, sendfile
, recvfile
, 1 },
135 { "octet", validate_access
, sendfile
, recvfile
, 0 },
144 "Usage: %s [-dln] [-u user] [-g group] [-s directory] [-p pathsep] [directory ...]",
150 main(int argc
, char *argv
[])
152 struct sockaddr_storage me
;
153 struct passwd
*pwent
;
156 const char *tgtuser
, *tgtgroup
;
161 uid_t curuid
, tgtuid
;
162 gid_t curgid
, tgtgid
;
168 openlog("tftpd", LOG_PID
| LOG_NDELAY
, LOG_DAEMON
);
169 tgtuser
= DEFAULTUSER
;
174 while ((ch
= getopt(argc
, argv
, "dg:lnp:s:u:w:")) != -1)
193 if (optarg
[0] == '\0' || optarg
[1] != '\0')
213 struct dirlist
*dirp
;
215 /* Get list of directory prefixes. Skip relative pathnames. */
216 for (dirp
= dirs
; optind
< argc
&& dirp
< &dirs
[MAXDIRS
];
218 if (argv
[optind
][0] == '/') {
219 dirp
->name
= argv
[optind
];
220 dirp
->len
= strlen(dirp
->name
);
226 if (*tgtuser
== '\0' || (tgtgroup
!= NULL
&& *tgtgroup
== '\0'))
229 nid
= (strtol(tgtuser
, &ep
, 10));
232 syslog(LOG_ERR
, "uid %ld is too large", nid
);
235 pwent
= getpwuid((uid_t
)nid
);
237 pwent
= getpwnam(tgtuser
);
239 syslog(LOG_ERR
, "unknown user `%s'", tgtuser
);
242 tgtuid
= pwent
->pw_uid
;
243 tgtgid
= pwent
->pw_gid
;
245 if (tgtgroup
!= NULL
) {
246 nid
= (strtol(tgtgroup
, &ep
, 10));
249 syslog(LOG_ERR
, "gid %ld is too large", nid
);
252 grent
= getgrgid((gid_t
)nid
);
254 grent
= getgrnam(tgtgroup
);
256 tgtgid
= grent
->gr_gid
;
258 syslog(LOG_ERR
, "unknown group `%s'", tgtgroup
);
264 if (chdir(securedir
) < 0) {
265 syslog(LOG_ERR
, "chdir %s: %m", securedir
);
269 syslog(LOG_ERR
, "chroot: %m");
275 syslog(LOG_DEBUG
, "running as user `%s' (%d), group `%s' (%d)",
276 tgtuser
, tgtuid
, tgtgroup
? tgtgroup
: "(unspecified)",
278 if (curgid
!= tgtgid
) {
279 if (setgid(tgtgid
)) {
280 syslog(LOG_ERR
, "setgid to %d: %m", (int)tgtgid
);
283 if (setgroups(0, NULL
)) {
284 syslog(LOG_ERR
, "setgroups: %m");
289 if (curuid
!= tgtuid
) {
290 if (setuid(tgtuid
)) {
291 syslog(LOG_ERR
, "setuid to %d: %m", (int)tgtuid
);
297 if (ioctl(fd
, FIONBIO
, &on
) < 0) {
298 syslog(LOG_ERR
, "ioctl(FIONBIO): %m");
301 fromlen
= sizeof (from
);
302 n
= recvfrom(fd
, buf
, sizeof (buf
), 0,
303 (struct sockaddr
*)&from
, &fromlen
);
305 syslog(LOG_ERR
, "recvfrom: %m");
309 * Now that we have read the message out of the UDP
310 * socket, we fork and exit. Thus, inetd will go back
311 * to listening to the tftp port, and the next request
312 * to come in will start up a new instance of tftpd.
314 * We do this so that inetd can run tftpd in "wait" mode.
315 * The problem with tftpd running in "nowait" mode is that
316 * inetd may get one or more successful "selects" on the
317 * tftp port before we do our receive, so more than one
318 * instance of tftpd may be started up. Worse, if tftpd
319 * break before doing the above "recvfrom", inetd would
320 * spawn endless instances, clogging the system.
327 for (i
= 1; i
< 20; i
++) {
332 * flush out to most recently sent request.
334 * This may drop some request, but those
335 * will be resent by the clients when
336 * they timeout. The positive effect of
337 * this flush is to (try to) prevent more
338 * than one tftpd being started up to service
339 * a single request from a single client.
342 i
= recvfrom(fd
, buf
, sizeof (buf
), 0,
343 (struct sockaddr
*)&from
, &j
);
353 syslog(LOG_ERR
, "fork: %m");
355 } else if (pid
!= 0) {
361 * remember what address this was sent to, so we can respond on the
365 if (getsockname(fd
, (struct sockaddr
*)&me
, &len
) == 0) {
366 switch (me
.ss_family
) {
368 ((struct sockaddr_in
*)&me
)->sin_port
= 0;
371 ((struct sockaddr_in6
*)&me
)->sin6_port
= 0;
378 memset(&me
, 0, sizeof(me
));
379 me
.ss_family
= from
.ss_family
;
380 me
.ss_len
= from
.ss_len
;
386 peer
= socket(from
.ss_family
, SOCK_DGRAM
, 0);
388 syslog(LOG_ERR
, "socket: %m");
391 if (bind(peer
, (struct sockaddr
*)&me
, me
.ss_len
) < 0) {
392 syslog(LOG_ERR
, "bind: %m");
395 if (connect(peer
, (struct sockaddr
*)&from
, from
.ss_len
) < 0) {
396 syslog(LOG_ERR
, "connect: %m");
399 soopt
= 65536; /* larger than we'll ever need */
400 if (setsockopt(peer
, SOL_SOCKET
, SO_SNDBUF
, (void *) &soopt
, sizeof(soopt
)) < 0) {
401 syslog(LOG_ERR
, "set SNDBUF: %m");
404 if (setsockopt(peer
, SOL_SOCKET
, SO_RCVBUF
, (void *) &soopt
, sizeof(soopt
)) < 0) {
405 syslog(LOG_ERR
, "set RCVBUF: %m");
409 tp
= (struct tftphdr
*)buf
;
410 tp
->th_opcode
= ntohs(tp
->th_opcode
);
411 if (tp
->th_opcode
== RRQ
|| tp
->th_opcode
== WRQ
)
417 blk_handler(struct tftphdr
*tp
, char *opt
, char *val
, char *ack
,
425 * On these failures, we could just ignore the blocksize option.
426 * Perhaps that should be a command-line option.
429 bsize
= strtoul(val
, &endp
, 10);
430 if ((bsize
== ULONG_MAX
&& errno
== ERANGE
) || *endp
) {
431 syslog(LOG_NOTICE
, "%s: %s request for %s: "
432 "illegal value %s for blksize option",
433 verifyhost((struct sockaddr
*)&from
),
434 tp
->th_opcode
== WRQ
? "write" : "read",
438 if (bsize
< 8 || bsize
> 65464) {
439 syslog(LOG_NOTICE
, "%s: %s request for %s: "
440 "out of range value %s for blksize option",
441 verifyhost((struct sockaddr
*)&from
),
442 tp
->th_opcode
== WRQ
? "write" : "read",
447 tftp_blksize
= bsize
;
448 strcpy(ack
+ *ackl
, "blksize");
450 l
= sprintf(ack
+ *ackl
, "%lu", bsize
);
457 timeout_handler(struct tftphdr
*tp
, char *opt
, char *val
, char *ack
,
465 tout
= strtoul(val
, &endp
, 10);
466 if ((tout
== ULONG_MAX
&& errno
== ERANGE
) || *endp
) {
467 syslog(LOG_NOTICE
, "%s: %s request for %s: "
468 "illegal value %s for timeout option",
469 verifyhost((struct sockaddr
*)&from
),
470 tp
->th_opcode
== WRQ
? "write" : "read",
474 if (tout
< 1 || tout
> 255) {
475 syslog(LOG_NOTICE
, "%s: %s request for %s: "
476 "out of range value %s for timeout option",
477 verifyhost((struct sockaddr
*)&from
),
478 tp
->th_opcode
== WRQ
? "write" : "read",
484 strcpy(ack
+ *ackl
, "timeout");
486 l
= sprintf(ack
+ *ackl
, "%lu", tout
);
490 * Arbitrarily pick a maximum timeout on a request to 3
491 * retransmissions if the interval timeout is more than
492 * one minute. Longest possible timeout is therefore
493 * 3 * 255 - 1, or 764 seconds.
496 maxtimeout
= rexmtval
* 3;
498 maxtimeout
= rexmtval
* 5;
505 tsize_handler(struct tftphdr
*tp
, char *opt
, char *val
, char *ack
,
512 * Maximum file even with extended tftp is 65535 blocks of
513 * length 65464, or 4290183240 octets (4784056 less than 2^32).
514 * unsigned long is at least 32 bits on all NetBSD archs.
518 fsize
= strtoul(val
, &endp
, 10);
519 if ((fsize
== ULONG_MAX
&& errno
== ERANGE
) || *endp
) {
520 syslog(LOG_NOTICE
, "%s: %s request for %s: "
521 "illegal value %s for tsize option",
522 verifyhost((struct sockaddr
*)&from
),
523 tp
->th_opcode
== WRQ
? "write" : "read",
527 if (fsize
> (unsigned long) 65535 * 65464) {
528 syslog(LOG_NOTICE
, "%s: %s request for %s: "
529 "out of range value %s for tsize option",
530 verifyhost((struct sockaddr
*)&from
),
531 tp
->th_opcode
== WRQ
? "write" : "read",
539 * We will report this later -- either replying with the fsize (WRQ)
540 * or replying with the actual filesize (RRQ).
546 static const struct tftp_options
{
548 int (*o_handler
)(struct tftphdr
*, char *, char *, char *,
551 { "blksize", blk_handler
},
552 { "timeout", timeout_handler
},
553 { "tsize", tsize_handler
},
558 * Get options for an extended tftp session. Stuff the ones we
559 * recognize in oackbuf.
562 get_options(struct tftphdr
*tp
, char *cp
, int size
, char *ackb
,
565 const struct tftp_options
*op
;
566 char *option
, *value
, *endp
;
572 while (*cp
&& cp
< endp
) {
573 *cp
= tolower((unsigned char)*cp
);
577 /* if we have garbage at the end, just ignore it */
580 cp
++; /* skip over NUL */
582 while (*cp
&& cp
< endp
) {
586 /* if we have garbage at the end, just ignore it */
590 for (op
= options
; op
->o_name
; op
++) {
591 if (strcmp(op
->o_name
, option
) == 0)
595 r
= op
->o_handler(tp
, option
, value
, ackb
, alen
, &ec
);
601 } /* else ignore unknown options */
611 * Handle initial connection protocol.
614 tftp(struct tftphdr
*tp
, int size
)
618 char *filename
, *mode
;
619 int first
, ecode
, alen
, etftp
= 0, r
;
621 ecode
= 0; /* XXX gcc */
625 filename
= cp
= tp
->th_stuff
;
627 while (cp
< buf
+ size
) {
641 for (cp
= mode
; *cp
; cp
++)
642 *cp
= tolower((unsigned char)*cp
);
643 for (pf
= formats
; pf
->f_mode
; pf
++)
644 if (strcmp(pf
->f_mode
, mode
) == 0)
646 if (pf
->f_mode
== 0) {
651 * cp currently points to the NUL byte following the mode.
653 * If we have some valid options, then let's assume that we're
654 * now dealing with an extended tftp session. Note that if we
655 * don't get any options, then we *must* assume that we do not
656 * have an extended tftp session. If we get options, we fill
657 * in the ack buf to acknowledge them. If we skip that, then
658 * the client *must* assume that we are not using an extended
661 size
-= (++cp
- (char *) tp
);
662 if (size
> 0 && *cp
) {
663 alen
= 2; /* Skip over opcode */
664 r
= get_options(tp
, cp
, size
, oackbuf
, &alen
, &ecode
);
673 * Globally replace the path separator given in the -p option
674 * with / to cope with clients expecting a non-unix path separator.
676 if (pathsep
!= '\0') {
677 for (cp
= filename
; *cp
!= '\0'; ++cp
) {
682 ecode
= (*pf
->f_validate
)(&filename
, tp
->th_opcode
);
684 syslog(LOG_INFO
, "%s: %s request for %s: %s",
685 verifyhost((struct sockaddr
*)&from
),
686 tp
->th_opcode
== WRQ
? "write" : "read",
687 filename
, errtomsg(ecode
));
691 * Avoid storms of naks to a RRQ broadcast for a relative
692 * bootfile pathname from a diskless Sun.
694 if (suppress_naks
&& *filename
!= '/' && ecode
== ENOTFOUND
)
701 struct tftphdr
*oack_h
;
703 if (tftp_opt_tsize
) {
706 strcpy(oackbuf
+ alen
, "tsize");
708 l
= sprintf(oackbuf
+ alen
, "%u", tftp_tsize
);
711 oack_h
= (struct tftphdr
*) oackbuf
;
712 oack_h
->th_opcode
= htons(OACK
);
715 if (tp
->th_opcode
== WRQ
)
716 (*pf
->f_recv
)(pf
, etftp
, alen
);
718 (*pf
->f_send
)(pf
, etftp
, alen
);
726 * Validate file access. Since we
727 * have no uid or gid, for now require
728 * file to exist and be publicly
730 * If we were invoked with arguments
731 * from inetd then the file must also be
732 * in one of the given directory prefixes.
735 validate_access(char **filep
, int mode
)
738 struct dirlist
*dirp
;
739 static char pathname
[MAXPATHLEN
];
746 * Prevent tricksters from getting around the directory restrictions
748 if (strstr(filename
, "/../"))
751 if (*filename
== '/') {
753 * Allow the request if it's in one of the approved locations.
754 * Special case: check the null prefix ("/") by looking
755 * for length = 1 and relying on the arg. processing that
758 for (dirp
= dirs
; dirp
->name
!= NULL
; dirp
++) {
759 if (dirp
->len
== 1 ||
760 (!strncmp(filename
, dirp
->name
, dirp
->len
) &&
761 filename
[dirp
->len
] == '/'))
764 /* If directory list is empty, allow access to any file */
765 if (dirp
->name
== NULL
&& dirp
!= dirs
)
767 if (stat(filename
, &stbuf
) < 0)
768 return (errno
== ENOENT
? ENOTFOUND
: EACCESS
);
769 if (!S_ISREG(stbuf
.st_mode
))
772 if ((stbuf
.st_mode
& S_IROTH
) == 0)
775 if ((stbuf
.st_mode
& S_IWOTH
) == 0)
780 * Relative file name: search the approved locations for it.
783 if (!strncmp(filename
, "../", 3))
787 * Find the first file that exists in any of the directories,
788 * check access on it.
790 if (dirs
[0].name
!= NULL
) {
791 for (dirp
= dirs
; dirp
->name
!= NULL
; dirp
++) {
792 snprintf(pathname
, sizeof pathname
, "%s/%s",
793 dirp
->name
, filename
);
794 if (stat(pathname
, &stbuf
) == 0 &&
795 (stbuf
.st_mode
& S_IFMT
) == S_IFREG
) {
799 if (dirp
->name
== NULL
)
801 if (mode
== RRQ
&& !(stbuf
.st_mode
& S_IROTH
))
803 if (mode
== WRQ
&& !(stbuf
.st_mode
& S_IWOTH
))
805 *filep
= filename
= pathname
;
808 * If there's no directory list, take our cue from the
809 * absolute file request check above (*filename == '/'),
810 * and allow access to anything.
812 if (stat(filename
, &stbuf
) < 0)
813 return (errno
== ENOENT
? ENOTFOUND
: EACCESS
);
814 if (!S_ISREG(stbuf
.st_mode
))
817 if ((stbuf
.st_mode
& S_IROTH
) == 0)
820 if ((stbuf
.st_mode
& S_IWOTH
) == 0)
827 if (tftp_opt_tsize
&& mode
== RRQ
)
828 tftp_tsize
= (unsigned long) stbuf
.st_size
;
830 fd
= open(filename
, mode
== RRQ
? O_RDONLY
: O_WRONLY
| O_TRUNC
);
832 return (errno
+ 100);
833 file
= fdopen(fd
, (mode
== RRQ
)? "r":"w");
836 return (errno
+ 100);
842 static jmp_buf timeoutbuf
;
849 if (timeout
>= maxtimeout
)
851 longjmp(timeoutbuf
, 1);
857 static char obuf
[64];
873 (void)snprintf(obuf
, sizeof(obuf
), "*code 0x%x*", code
);
879 * Send the requested file.
882 sendfile(struct formats
*pf
, volatile int etftp
, int acklength
)
884 volatile unsigned int block
;
886 struct tftphdr
*ap
; /* ack packet */
890 signal(SIGALRM
, timer
);
891 ap
= (struct tftphdr
*)ackbuf
;
893 dp
= (struct tftphdr
*)oackbuf
;
894 size
= acklength
- 4;
904 size
= readit(file
, &dp
, tftp_blksize
, pf
->f_convert
);
909 dp
->th_opcode
= htons((u_short
)DATA
);
910 dp
->th_block
= htons((u_short
)block
);
913 (void)setjmp(timeoutbuf
);
917 syslog(LOG_DEBUG
, "Send DATA %u", block
);
918 if ((n
= send(peer
, dp
, size
+ 4, 0)) != size
+ 4) {
919 syslog(LOG_ERR
, "tftpd: write: %m");
923 read_ahead(file
, tftp_blksize
, pf
->f_convert
);
925 alarm(rexmtval
); /* read the ack */
926 n
= recv(peer
, ackbuf
, tftp_blksize
, 0);
929 syslog(LOG_ERR
, "tftpd: read: %m");
932 ap
->th_opcode
= ntohs((u_short
)ap
->th_opcode
);
933 ap
->th_block
= ntohs((u_short
)ap
->th_block
);
934 switch (ap
->th_opcode
) {
939 if (etftp
&& ap
->th_block
== 0) {
945 if (ap
->th_block
== (u_short
)block
)
948 syslog(LOG_DEBUG
, "Resync ACK %u != %u",
949 (unsigned int)ap
->th_block
, block
);
950 /* Re-synchronize with the other side */
951 (void) synchnet(peer
, tftp_blksize
);
952 if (ap
->th_block
== (u_short
)(block
- 1))
955 syslog(LOG_INFO
, "Received %s in sendfile\n",
956 opcode(dp
->th_opcode
));
962 syslog(LOG_DEBUG
, "Received ACK for block %u", block
);
963 if (block
== UINT16_MAX
&& size
== tftp_blksize
)
965 "Block number wrapped (hint: increase block size)");
967 } while (size
== tftp_blksize
|| block
== 1);
983 recvfile(struct formats
*pf
, volatile int etftp
, volatile int acklength
)
985 volatile unsigned int block
;
987 struct tftphdr
*ap
; /* ack buffer */
991 signal(SIGALRM
, timer
);
993 ap
= (struct tftphdr
*)oackbuf
;
998 ap
= (struct tftphdr
*)ackbuf
;
999 ap
->th_opcode
= htons((u_short
)ACK
);
1000 ap
->th_block
= htons((u_short
)block
);
1004 syslog(LOG_DEBUG
, "Sending ACK for block %u\n", block
);
1005 if (block
== UINT16_MAX
)
1007 "Block number wrapped (hint: increase block size)");
1009 (void) setjmp(timeoutbuf
);
1011 ap
= (struct tftphdr
*) (etftp
? oackbuf
: ackbuf
);
1012 if (send(peer
, ap
, acklength
, 0) != acklength
) {
1013 syslog(LOG_ERR
, "tftpd: write: %m");
1016 write_behind(file
, pf
->f_convert
);
1019 n
= recv(peer
, dp
, tftp_blksize
+ 4, 0);
1021 if (n
< 0) { /* really? */
1022 syslog(LOG_ERR
, "tftpd: read: %m");
1026 dp
->th_opcode
= ntohs((u_short
)dp
->th_opcode
);
1027 dp
->th_block
= ntohs((u_short
)dp
->th_block
);
1029 syslog(LOG_DEBUG
, "Received %s for block %u",
1030 opcode(dp
->th_opcode
),
1031 (unsigned int)dp
->th_block
);
1033 switch (dp
->th_opcode
) {
1037 if (dp
->th_block
== block
)
1038 goto done
; /* normal */
1040 syslog(LOG_DEBUG
, "Resync %u != %u",
1041 (unsigned int)dp
->th_block
, block
);
1042 /* Re-synchronize with the other side */
1043 (void) synchnet(peer
, tftp_blksize
);
1044 if (dp
->th_block
== (block
-1))
1045 goto send_ack
; /* rexmit */
1048 syslog(LOG_INFO
, "Received %s in recvfile\n",
1049 opcode(dp
->th_opcode
));
1055 syslog(LOG_DEBUG
, "Got block %u", block
);
1056 /* size = write(file, dp->th_data, n - 4); */
1057 size
= writeit(file
, &dp
, n
- 4, pf
->f_convert
);
1058 if (size
!= (n
-4)) { /* ahem */
1059 if (size
< 0) nak(errno
+ 100);
1063 } while (size
== tftp_blksize
);
1064 write_behind(file
, pf
->f_convert
);
1065 (void) fclose(file
); /* close data file */
1067 ap
->th_opcode
= htons((u_short
)ACK
); /* send the "final" ack */
1068 ap
->th_block
= htons((u_short
)(block
));
1070 syslog(LOG_DEBUG
, "Send final ACK %u", block
);
1071 (void) send(peer
, ackbuf
, 4, 0);
1073 signal(SIGALRM
, justquit
); /* just quit on timeout */
1075 n
= recv(peer
, buf
, sizeof (buf
), 0); /* normally times out and quits */
1077 if (n
>= 4 && /* if read some data */
1078 dp
->th_opcode
== DATA
&& /* and got a data block */
1079 block
== dp
->th_block
) { /* then my last ack was lost */
1080 (void) send(peer
, ackbuf
, 4, 0); /* resend final ack */
1086 const struct errmsg
{
1090 { EUNDEF
, "Undefined error code" },
1091 { ENOTFOUND
, "File not found" },
1092 { EACCESS
, "Access violation" },
1093 { ENOSPACE
, "Disk full or allocation exceeded" },
1094 { EBADOP
, "Illegal TFTP operation" },
1095 { EBADID
, "Unknown transfer ID" },
1096 { EEXISTS
, "File already exists" },
1097 { ENOUSER
, "No such user" },
1098 { EOPTNEG
, "Option negotiation failed" },
1105 static char ebuf
[20];
1106 const struct errmsg
*pe
;
1110 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
1111 if (pe
->e_code
== error
)
1113 snprintf(ebuf
, sizeof(ebuf
), "error %d", error
);
1118 * Send a nak packet (error message).
1119 * Error code passed in is one of the
1120 * standard TFTP codes, or a UNIX errno
1126 const struct errmsg
*pe
;
1131 tp
= (struct tftphdr
*)buf
;
1132 tp
->th_opcode
= htons((u_short
)ERROR
);
1133 msglen
= sizeof(buf
) - (&tp
->th_msg
[0] - buf
);
1134 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
1135 if (pe
->e_code
== error
)
1137 if (pe
->e_code
< 0) {
1138 tp
->th_code
= EUNDEF
; /* set 'undef' errorcode */
1139 strlcpy(tp
->th_msg
, strerror(error
- 100), msglen
);
1141 tp
->th_code
= htons((u_short
)error
);
1142 strlcpy(tp
->th_msg
, pe
->e_msg
, msglen
);
1145 syslog(LOG_DEBUG
, "Send NACK %s", tp
->th_msg
);
1146 length
= strlen(tp
->th_msg
);
1147 msglen
= &tp
->th_msg
[length
+ 1] - buf
;
1148 if (send(peer
, buf
, msglen
, 0) != msglen
)
1149 syslog(LOG_ERR
, "nak: %m");
1153 verifyhost(struct sockaddr
*fromp
)
1155 static char hbuf
[MAXHOSTNAMELEN
];
1157 if (getnameinfo(fromp
, fromp
->sa_len
, hbuf
, sizeof(hbuf
), NULL
, 0, 0))
1158 strlcpy(hbuf
, "?", sizeof(hbuf
));