tftpd.c revision 1.27 1 /* $NetBSD: tftpd.c,v 1.27 2004/01/06 14:30:10 briggs Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #if 0
37 static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
38 #else
39 __RCSID("$NetBSD: tftpd.c,v 1.27 2004/01/06 14:30:10 briggs Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * Trivial file transfer protocol server.
45 *
46 * This version includes many modifications by Jim Guyton
47 * <guyton@rand-unix>.
48 */
49
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/stat.h>
53 #include <sys/socket.h>
54
55 #include <netinet/in.h>
56 #include <arpa/tftp.h>
57 #include <arpa/inet.h>
58
59 #include <ctype.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <grp.h>
63 #include <netdb.h>
64 #include <pwd.h>
65 #include <setjmp.h>
66 #include <signal.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <syslog.h>
71 #include <unistd.h>
72
73 #include "tftpsubs.h"
74
75 #define DEFAULTUSER "nobody"
76
77 #define TIMEOUT 5
78
79 int peer;
80 int rexmtval = TIMEOUT;
81 int maxtimeout = 5*TIMEOUT;
82
83 char buf[MAXPKTSIZE];
84 char ackbuf[PKTSIZE];
85 char oackbuf[PKTSIZE];
86 struct sockaddr_storage from;
87 int fromlen;
88 int debug;
89
90 int tftp_opt_tsize = 0;
91 int tftp_blksize = SEGSIZE;
92 int tftp_tsize = 0;
93
94 /*
95 * Null-terminated directory prefix list for absolute pathname requests and
96 * search list for relative pathname requests.
97 *
98 * MAXDIRS should be at least as large as the number of arguments that
99 * inetd allows (currently 20).
100 */
101 #define MAXDIRS 20
102 static struct dirlist {
103 char *name;
104 int len;
105 } dirs[MAXDIRS+1];
106 static int suppress_naks;
107 static int logging;
108 static int secure;
109 static char *securedir;
110
111 struct formats;
112
113 static const char *errtomsg(int);
114 static void nak(int);
115 static void tftp(struct tftphdr *, int);
116 static void usage(void);
117 static char *verifyhost(struct sockaddr *);
118 void justquit(int);
119 int main(int, char **);
120 void recvfile(struct formats *, int, int);
121 void sendfile(struct formats *, int, int);
122 void timer(int);
123 static const char *opcode(int);
124 int validate_access(char **, int);
125
126 struct formats {
127 const char *f_mode;
128 int (*f_validate)(char **, int);
129 void (*f_send)(struct formats *, int, int);
130 void (*f_recv)(struct formats *, int, int);
131 int f_convert;
132 } formats[] = {
133 { "netascii", validate_access, sendfile, recvfile, 1 },
134 { "octet", validate_access, sendfile, recvfile, 0 },
135 { 0 }
136 };
137
138 static void
139 usage(void)
140 {
141
142 syslog(LOG_ERR,
143 "Usage: %s [-dln] [-u user] [-g group] [-s directory] [directory ...]",
144 getprogname());
145 exit(1);
146 }
147
148 int
149 main(int argc, char *argv[])
150 {
151 struct sockaddr_storage me;
152 struct passwd *pwent;
153 struct group *grent;
154 struct tftphdr *tp;
155 char *tgtuser, *tgtgroup, *ep;
156 int n, ch, on, fd;
157 int len, soopt;
158 uid_t curuid, tgtuid;
159 gid_t curgid, tgtgid;
160 long nid;
161
162 n = 0;
163 fd = 0;
164 openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
165 tgtuser = DEFAULTUSER;
166 tgtgroup = NULL;
167 curuid = getuid();
168 curgid = getgid();
169
170 while ((ch = getopt(argc, argv, "dg:lns:u:")) != -1)
171 switch (ch) {
172 case 'd':
173 debug++;
174 break;
175
176 case 'g':
177 tgtgroup = optarg;
178 break;
179
180 case 'l':
181 logging = 1;
182 break;
183
184 case 'n':
185 suppress_naks = 1;
186 break;
187
188 case 's':
189 secure = 1;
190 securedir = optarg;
191 break;
192
193 case 'u':
194 tgtuser = optarg;
195 break;
196
197 default:
198 usage();
199 break;
200 }
201
202 if (optind < argc) {
203 struct dirlist *dirp;
204
205 /* Get list of directory prefixes. Skip relative pathnames. */
206 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
207 optind++) {
208 if (argv[optind][0] == '/') {
209 dirp->name = argv[optind];
210 dirp->len = strlen(dirp->name);
211 dirp++;
212 }
213 }
214 }
215
216 if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0'))
217 usage();
218
219 nid = (strtol(tgtuser, &ep, 10));
220 if (*ep == '\0') {
221 if (nid > UID_MAX) {
222 syslog(LOG_ERR, "uid %ld is too large", nid);
223 exit(1);
224 }
225 pwent = getpwuid((uid_t)nid);
226 } else
227 pwent = getpwnam(tgtuser);
228 if (pwent == NULL) {
229 syslog(LOG_ERR, "unknown user `%s'", tgtuser);
230 exit(1);
231 }
232 tgtuid = pwent->pw_uid;
233 tgtgid = pwent->pw_gid;
234
235 if (tgtgroup != NULL) {
236 nid = (strtol(tgtgroup, &ep, 10));
237 if (*ep == '\0') {
238 if (nid > GID_MAX) {
239 syslog(LOG_ERR, "gid %ld is too large", nid);
240 exit(1);
241 }
242 grent = getgrgid((gid_t)nid);
243 } else
244 grent = getgrnam(tgtgroup);
245 if (grent != NULL)
246 tgtgid = grent->gr_gid;
247 else {
248 syslog(LOG_ERR, "unknown group `%s'", tgtgroup);
249 exit(1);
250 }
251 }
252
253 if (secure) {
254 if (chdir(securedir) < 0) {
255 syslog(LOG_ERR, "chdir %s: %m", securedir);
256 exit(1);
257 }
258 if (chroot(".")) {
259 syslog(LOG_ERR, "chroot: %m");
260 exit(1);
261 }
262 }
263
264 if (logging)
265 syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)",
266 tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)",
267 tgtgid);
268 if (curgid != tgtgid) {
269 if (setgid(tgtgid)) {
270 syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid);
271 exit(1);
272 }
273 if (setgroups(0, NULL)) {
274 syslog(LOG_ERR, "setgroups: %m");
275 exit(1);
276 }
277 }
278
279 if (curuid != tgtuid) {
280 if (setuid(tgtuid)) {
281 syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid);
282 exit(1);
283 }
284 }
285
286 on = 1;
287 if (ioctl(fd, FIONBIO, &on) < 0) {
288 syslog(LOG_ERR, "ioctl(FIONBIO): %m");
289 exit(1);
290 }
291 fromlen = sizeof (from);
292 n = recvfrom(fd, buf, sizeof (buf), 0,
293 (struct sockaddr *)&from, &fromlen);
294 if (n < 0) {
295 syslog(LOG_ERR, "recvfrom: %m");
296 exit(1);
297 }
298 /*
299 * Now that we have read the message out of the UDP
300 * socket, we fork and exit. Thus, inetd will go back
301 * to listening to the tftp port, and the next request
302 * to come in will start up a new instance of tftpd.
303 *
304 * We do this so that inetd can run tftpd in "wait" mode.
305 * The problem with tftpd running in "nowait" mode is that
306 * inetd may get one or more successful "selects" on the
307 * tftp port before we do our receive, so more than one
308 * instance of tftpd may be started up. Worse, if tftpd
309 * break before doing the above "recvfrom", inetd would
310 * spawn endless instances, clogging the system.
311 */
312 {
313 int pid;
314 int i, j;
315
316 for (i = 1; i < 20; i++) {
317 pid = fork();
318 if (pid < 0) {
319 sleep(i);
320 /*
321 * flush out to most recently sent request.
322 *
323 * This may drop some request, but those
324 * will be resent by the clients when
325 * they timeout. The positive effect of
326 * this flush is to (try to) prevent more
327 * than one tftpd being started up to service
328 * a single request from a single client.
329 */
330 j = sizeof from;
331 i = recvfrom(fd, buf, sizeof (buf), 0,
332 (struct sockaddr *)&from, &j);
333 if (i > 0) {
334 n = i;
335 fromlen = j;
336 }
337 } else {
338 break;
339 }
340 }
341 if (pid < 0) {
342 syslog(LOG_ERR, "fork: %m");
343 exit(1);
344 } else if (pid != 0) {
345 exit(0);
346 }
347 }
348
349 /*
350 * remember what address this was sent to, so we can respond on the
351 * same interface
352 */
353 len = sizeof(me);
354 if (getsockname(fd, (struct sockaddr *)&me, &len) == 0) {
355 switch (me.ss_family) {
356 case AF_INET:
357 ((struct sockaddr_in *)&me)->sin_port = 0;
358 break;
359 case AF_INET6:
360 ((struct sockaddr_in6 *)&me)->sin6_port = 0;
361 break;
362 default:
363 /* unsupported */
364 break;
365 }
366 } else {
367 memset(&me, 0, sizeof(me));
368 me.ss_family = from.ss_family;
369 me.ss_len = from.ss_len;
370 }
371
372 alarm(0);
373 close(fd);
374 close(1);
375 peer = socket(from.ss_family, SOCK_DGRAM, 0);
376 if (peer < 0) {
377 syslog(LOG_ERR, "socket: %m");
378 exit(1);
379 }
380 if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
381 syslog(LOG_ERR, "bind: %m");
382 exit(1);
383 }
384 if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
385 syslog(LOG_ERR, "connect: %m");
386 exit(1);
387 }
388 soopt = 65536; /* larger than we'll ever need */
389 if (setsockopt(peer, SOL_SOCKET, SO_SNDBUF, (void *) &soopt, sizeof(soopt)) < 0) {
390 syslog(LOG_ERR, "set SNDBUF: %m");
391 exit(1);
392 }
393 if (setsockopt(peer, SOL_SOCKET, SO_RCVBUF, (void *) &soopt, sizeof(soopt)) < 0) {
394 syslog(LOG_ERR, "set RCVBUF: %m");
395 exit(1);
396 }
397
398 tp = (struct tftphdr *)buf;
399 tp->th_opcode = ntohs(tp->th_opcode);
400 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
401 tftp(tp, n);
402 exit(1);
403 }
404
405 static int
406 blk_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
407 int *ackl, int *ec)
408 {
409 unsigned long bsize;
410 char *endp;
411 int l;
412
413 /*
414 * On these failures, we could just ignore the blocksize option.
415 * Perhaps that should be a command-line option.
416 */
417 errno = 0;
418 bsize = strtoul(val, &endp, 10);
419 if ((bsize == ULONG_MAX && errno == ERANGE) || *endp) {
420 syslog(LOG_NOTICE, "%s: %s request for %s: "
421 "illegal value %s for blksize option",
422 verifyhost((struct sockaddr *)&from),
423 tp->th_opcode == WRQ ? "write" : "read",
424 tp->th_stuff, val);
425 return 0;
426 }
427 if (bsize < 8 || bsize > 65464) {
428 syslog(LOG_NOTICE, "%s: %s request for %s: "
429 "out of range value %s for blksize option",
430 verifyhost((struct sockaddr *)&from),
431 tp->th_opcode == WRQ ? "write" : "read",
432 tp->th_stuff, val);
433 return 0;
434 }
435
436 tftp_blksize = bsize;
437 strcpy(ack + *ackl, "blksize");
438 *ackl += 8;
439 l = sprintf(ack + *ackl, "%lu", bsize);
440 *ackl += l + 1;
441
442 return 0;
443 }
444
445 static int
446 timeout_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
447 int *ackl, int *ec)
448 {
449 unsigned long tout;
450 char *endp;
451 int l;
452
453 errno = 0;
454 tout = strtoul(val, &endp, 10);
455 if ((tout == ULONG_MAX && errno == ERANGE) || *endp) {
456 syslog(LOG_NOTICE, "%s: %s request for %s: "
457 "illegal value %s for timeout option",
458 verifyhost((struct sockaddr *)&from),
459 tp->th_opcode == WRQ ? "write" : "read",
460 tp->th_stuff, val);
461 return 0;
462 }
463 if (tout < 1 || tout > 255) {
464 syslog(LOG_NOTICE, "%s: %s request for %s: "
465 "out of range value %s for timeout option",
466 verifyhost((struct sockaddr *)&from),
467 tp->th_opcode == WRQ ? "write" : "read",
468 tp->th_stuff, val);
469 return 0;
470 }
471
472 rexmtval = tout;
473 strcpy(ack + *ackl, "timeout");
474 *ackl += 8;
475 l = sprintf(ack + *ackl, "%lu", tout);
476 *ackl += l + 1;
477
478 /*
479 * Arbitrarily pick a maximum timeout on a request to 3
480 * retransmissions if the interval timeout is more than
481 * one minute. Longest possible timeout is therefore
482 * 3 * 255 - 1, or 764 seconds.
483 */
484 if (rexmtval > 60) {
485 maxtimeout = rexmtval * 3;
486 } else {
487 maxtimeout = rexmtval * 5;
488 }
489
490 return 0;
491 }
492
493 static int
494 tsize_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
495 int *ackl, int *ec)
496 {
497 unsigned long fsize;
498 char *endp;
499
500 /*
501 * Maximum file even with extended tftp is 65535 blocks of
502 * length 65464, or 4290183240 octets (4784056 less than 2^32).
503 * unsigned long is at least 32 bits on all NetBSD archs.
504 */
505
506 errno = 0;
507 fsize = strtoul(val, &endp, 10);
508 if ((fsize == ULONG_MAX && errno == ERANGE) || *endp) {
509 syslog(LOG_NOTICE, "%s: %s request for %s: "
510 "illegal value %s for tsize option",
511 verifyhost((struct sockaddr *)&from),
512 tp->th_opcode == WRQ ? "write" : "read",
513 tp->th_stuff, val);
514 return 0;
515 }
516 if (fsize > (unsigned long) 65535 * 65464) {
517 syslog(LOG_NOTICE, "%s: %s request for %s: "
518 "out of range value %s for tsize option",
519 verifyhost((struct sockaddr *)&from),
520 tp->th_opcode == WRQ ? "write" : "read",
521 tp->th_stuff, val);
522 return 0;
523 }
524
525 tftp_opt_tsize = 1;
526 tftp_tsize = fsize;
527 /*
528 * We will report this later -- either replying with the fsize (WRQ)
529 * or replying with the actual filesize (RRQ).
530 */
531
532 return 0;
533 }
534
535 struct tftp_options {
536 char *o_name;
537 int (*o_handler)(struct tftphdr *, char *, char *, char *,
538 int *, int *);
539 } options[] = {
540 { "blksize", blk_handler },
541 { "timeout", timeout_handler },
542 { "tsize", tsize_handler },
543 { NULL, NULL }
544 };
545
546 /*
547 * Get options for an extended tftp session. Stuff the ones we
548 * recognize in oackbuf.
549 */
550 static int
551 get_options(struct tftphdr *tp, char *cp, int size, char *ackb,
552 int *alen, int *err)
553 {
554 struct tftp_options *op;
555 char *option, *value, *endp;
556 int r, rv=0, ec=0;
557
558 endp = cp + size;
559 while (cp < endp) {
560 option = cp;
561 while (*cp && cp < endp) {
562 *cp = tolower(*cp);
563 cp++;
564 }
565 if (*cp) {
566 /* if we have garbage at the end, just ignore it */
567 break;
568 }
569 cp++; /* skip over NUL */
570 value = cp;
571 while (*cp && cp < endp) {
572 cp++;
573 }
574 if (*cp) {
575 /* if we have garbage at the end, just ignore it */
576 break;
577 }
578 cp++;
579 for (op = options; op->o_name; op++) {
580 if (strcmp(op->o_name, option) == 0)
581 break;
582 }
583 if (op->o_name) {
584 r = op->o_handler(tp, option, value, ackb, alen, &ec);
585 if (r < 0) {
586 rv = -1;
587 break;
588 }
589 rv++;
590 } /* else ignore unknown options */
591 }
592
593 if (rv < 0)
594 *err = ec;
595
596 return rv;
597 }
598
599 /*
600 * Handle initial connection protocol.
601 */
602 static void
603 tftp(struct tftphdr *tp, int size)
604 {
605 struct formats *pf;
606 char *cp;
607 char *filename, *mode;
608 int first, ecode, alen, etftp=0, r;
609
610 first = 1;
611 mode = NULL;
612
613 filename = cp = tp->th_stuff;
614 again:
615 while (cp < buf + size) {
616 if (*cp == '\0')
617 break;
618 cp++;
619 }
620 if (*cp != '\0') {
621 nak(EBADOP);
622 exit(1);
623 }
624 if (first) {
625 mode = ++cp;
626 first = 0;
627 goto again;
628 }
629 for (cp = mode; *cp; cp++)
630 if (isupper(*cp))
631 *cp = tolower(*cp);
632 for (pf = formats; pf->f_mode; pf++)
633 if (strcmp(pf->f_mode, mode) == 0)
634 break;
635 if (pf->f_mode == 0) {
636 nak(EBADOP);
637 exit(1);
638 }
639 /*
640 * cp currently points to the NUL byte following the mode.
641 *
642 * If we have some valid options, then let's assume that we're
643 * now dealing with an extended tftp session. Note that if we
644 * don't get any options, then we *must* assume that we do not
645 * have an extended tftp session. If we get options, we fill
646 * in the ack buf to acknowledge them. If we skip that, then
647 * the client *must* assume that we are not using an extended
648 * session.
649 */
650 size -= (++cp - (char *) tp);
651 if (size > 0 && *cp) {
652 alen = 2; /* Skip over opcode */
653 r = get_options(tp, cp, size, oackbuf, &alen, &ecode);
654 if (r > 0) {
655 etftp = 1;
656 } else if (r < 0) {
657 nak(ecode);
658 exit(1);
659 }
660 }
661 ecode = (*pf->f_validate)(&filename, tp->th_opcode);
662 if (logging) {
663 syslog(LOG_INFO, "%s: %s request for %s: %s",
664 verifyhost((struct sockaddr *)&from),
665 tp->th_opcode == WRQ ? "write" : "read",
666 filename, errtomsg(ecode));
667 }
668 if (ecode) {
669 /*
670 * Avoid storms of naks to a RRQ broadcast for a relative
671 * bootfile pathname from a diskless Sun.
672 */
673 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
674 exit(0);
675 nak(ecode);
676 exit(1);
677 }
678
679 if (etftp) {
680 struct tftphdr *oack_h;
681
682 if (tftp_opt_tsize) {
683 int l;
684
685 strcpy(oackbuf + alen, "tsize");
686 alen += 6;
687 l = sprintf(oackbuf + alen, "%u", tftp_tsize);
688 alen += l + 1;
689 }
690 oack_h = (struct tftphdr *) oackbuf;
691 oack_h->th_opcode = htons(OACK);
692 }
693
694 if (tp->th_opcode == WRQ)
695 (*pf->f_recv)(pf, etftp, alen);
696 else
697 (*pf->f_send)(pf, etftp, alen);
698 exit(0);
699 }
700
701
702 FILE *file;
703
704 /*
705 * Validate file access. Since we
706 * have no uid or gid, for now require
707 * file to exist and be publicly
708 * readable/writable.
709 * If we were invoked with arguments
710 * from inetd then the file must also be
711 * in one of the given directory prefixes.
712 */
713 int
714 validate_access(char **filep, int mode)
715 {
716 struct stat stbuf;
717 struct dirlist *dirp;
718 static char pathname[MAXPATHLEN];
719 char *filename;
720 int fd;
721
722 filename = *filep;
723
724 /*
725 * Prevent tricksters from getting around the directory restrictions
726 */
727 if (strstr(filename, "/../"))
728 return (EACCESS);
729
730 if (*filename == '/') {
731 /*
732 * Allow the request if it's in one of the approved locations.
733 * Special case: check the null prefix ("/") by looking
734 * for length = 1 and relying on the arg. processing that
735 * it's a /.
736 */
737 for (dirp = dirs; dirp->name != NULL; dirp++) {
738 if (dirp->len == 1 ||
739 (!strncmp(filename, dirp->name, dirp->len) &&
740 filename[dirp->len] == '/'))
741 break;
742 }
743 /* If directory list is empty, allow access to any file */
744 if (dirp->name == NULL && dirp != dirs)
745 return (EACCESS);
746 if (stat(filename, &stbuf) < 0)
747 return (errno == ENOENT ? ENOTFOUND : EACCESS);
748 if (!S_ISREG(stbuf.st_mode))
749 return (ENOTFOUND);
750 if (mode == RRQ) {
751 if ((stbuf.st_mode & S_IROTH) == 0)
752 return (EACCESS);
753 } else {
754 if ((stbuf.st_mode & S_IWOTH) == 0)
755 return (EACCESS);
756 }
757 } else {
758 /*
759 * Relative file name: search the approved locations for it.
760 */
761
762 if (!strncmp(filename, "../", 3))
763 return (EACCESS);
764
765 /*
766 * Find the first file that exists in any of the directories,
767 * check access on it.
768 */
769 if (dirs[0].name != NULL) {
770 for (dirp = dirs; dirp->name != NULL; dirp++) {
771 snprintf(pathname, sizeof pathname, "%s/%s",
772 dirp->name, filename);
773 if (stat(pathname, &stbuf) == 0 &&
774 (stbuf.st_mode & S_IFMT) == S_IFREG) {
775 break;
776 }
777 }
778 if (dirp->name == NULL)
779 return (ENOTFOUND);
780 if (mode == RRQ && !(stbuf.st_mode & S_IROTH))
781 return (EACCESS);
782 if (mode == WRQ && !(stbuf.st_mode & S_IWOTH))
783 return (EACCESS);
784 *filep = filename = pathname;
785 } else {
786 /*
787 * If there's no directory list, take our cue from the
788 * absolute file request check above (*filename == '/'),
789 * and allow access to anything.
790 */
791 if (stat(filename, &stbuf) < 0)
792 return (errno == ENOENT ? ENOTFOUND : EACCESS);
793 if (!S_ISREG(stbuf.st_mode))
794 return (ENOTFOUND);
795 if (mode == RRQ) {
796 if ((stbuf.st_mode & S_IROTH) == 0)
797 return (EACCESS);
798 } else {
799 if ((stbuf.st_mode & S_IWOTH) == 0)
800 return (EACCESS);
801 }
802 *filep = filename;
803 }
804 }
805
806 if (tftp_opt_tsize && mode == RRQ)
807 tftp_tsize = (unsigned long) stbuf.st_size;
808
809 fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC);
810 if (fd < 0)
811 return (errno + 100);
812 file = fdopen(fd, (mode == RRQ)? "r":"w");
813 if (file == NULL) {
814 close(fd);
815 return (errno + 100);
816 }
817 return (0);
818 }
819
820 int timeout;
821 jmp_buf timeoutbuf;
822
823 void
824 timer(int dummy)
825 {
826
827 timeout += rexmtval;
828 if (timeout >= maxtimeout)
829 exit(1);
830 longjmp(timeoutbuf, 1);
831 }
832
833 static const char *
834 opcode(int code)
835 {
836 static char buf[64];
837
838 switch (code) {
839 case RRQ:
840 return "RRQ";
841 case WRQ:
842 return "WRQ";
843 case DATA:
844 return "DATA";
845 case ACK:
846 return "ACK";
847 case ERROR:
848 return "ERROR";
849 case OACK:
850 return "OACK";
851 default:
852 (void)snprintf(buf, sizeof(buf), "*code %d*", code);
853 return buf;
854 }
855 }
856
857 /*
858 * Send the requested file.
859 */
860 void
861 sendfile(struct formats *pf, int etftp, int acklength)
862 {
863 volatile unsigned int block;
864 struct tftphdr *dp;
865 struct tftphdr *ap; /* ack packet */
866 int size, n;
867
868 signal(SIGALRM, timer);
869 ap = (struct tftphdr *)ackbuf;
870 if (etftp) {
871 dp = (struct tftphdr *)oackbuf;
872 size = acklength - 4;
873 block = 0;
874 } else {
875 dp = r_init();
876 size = 0;
877 block = 1;
878 }
879
880 do {
881 if (block > 0) {
882 size = readit(file, &dp, tftp_blksize, pf->f_convert);
883 if (size < 0) {
884 nak(errno + 100);
885 goto abort;
886 }
887 dp->th_opcode = htons((u_short)DATA);
888 dp->th_block = htons((u_short)block);
889 }
890 timeout = 0;
891 (void)setjmp(timeoutbuf);
892
893 send_data:
894 if (!etftp && debug)
895 syslog(LOG_DEBUG, "Send DATA %u", block);
896 if ((n = send(peer, dp, size + 4, 0)) != size + 4) {
897 syslog(LOG_ERR, "tftpd: write: %m");
898 goto abort;
899 }
900 if (block)
901 read_ahead(file, tftp_blksize, pf->f_convert);
902 for ( ; ; ) {
903 alarm(rexmtval); /* read the ack */
904 n = recv(peer, ackbuf, tftp_blksize, 0);
905 alarm(0);
906 if (n < 0) {
907 syslog(LOG_ERR, "tftpd: read: %m");
908 goto abort;
909 }
910 ap->th_opcode = ntohs((u_short)ap->th_opcode);
911 ap->th_block = ntohs((u_short)ap->th_block);
912 switch (ap->th_opcode) {
913 case ERROR:
914 goto abort;
915
916 case ACK:
917 if (ap->th_block == 0) {
918 etftp = 0;
919 acklength = 0;
920 dp = r_init();
921 goto done;
922 }
923 if (ap->th_block == block)
924 goto done;
925 if (debug)
926 syslog(LOG_DEBUG, "Resync ACK %u != %u",
927 (unsigned int)ap->th_block, block);
928 /* Re-synchronize with the other side */
929 (void) synchnet(peer, tftp_blksize);
930 if (ap->th_block == (block -1))
931 goto send_data;
932 default:
933 syslog(LOG_INFO, "Received %s in sendfile\n",
934 opcode(dp->th_opcode));
935 }
936
937 }
938 done:
939 if (debug)
940 syslog(LOG_DEBUG, "Received ACK for block %u", block);
941 block++;
942 } while (size == tftp_blksize || block == 1);
943 abort:
944 (void) fclose(file);
945 }
946
947 void
948 justquit(int dummy)
949 {
950
951 exit(0);
952 }
953
954 /*
955 * Receive a file.
956 */
957 void
958 recvfile(struct formats *pf, int etftp, int acklength)
959 {
960 volatile unsigned int block;
961 struct tftphdr *dp;
962 struct tftphdr *ap; /* ack buffer */
963 int n, size;
964
965 signal(SIGALRM, timer);
966 dp = w_init();
967 ap = (struct tftphdr *)oackbuf;
968 block = 0;
969 do {
970 timeout = 0;
971 if (etftp == 0) {
972 ap = (struct tftphdr *)ackbuf;
973 ap->th_opcode = htons((u_short)ACK);
974 ap->th_block = htons((u_short)block);
975 acklength = 4;
976 }
977 if (debug)
978 syslog(LOG_DEBUG, "Sending ACK for block %u\n", block);
979 block++;
980 (void) setjmp(timeoutbuf);
981 send_ack:
982 if (send(peer, ap, acklength, 0) != acklength) {
983 syslog(LOG_ERR, "tftpd: write: %m");
984 goto abort;
985 }
986 write_behind(file, pf->f_convert);
987 for ( ; ; ) {
988 alarm(rexmtval);
989 n = recv(peer, dp, tftp_blksize + 4, 0);
990 alarm(0);
991 if (n < 0) { /* really? */
992 syslog(LOG_ERR, "tftpd: read: %m");
993 goto abort;
994 }
995 etftp = 0;
996 dp->th_opcode = ntohs((u_short)dp->th_opcode);
997 dp->th_block = ntohs((u_short)dp->th_block);
998 if (debug)
999 syslog(LOG_DEBUG, "Received %s for block %u",
1000 opcode(dp->th_opcode),
1001 (unsigned int)dp->th_block);
1002
1003 switch (dp->th_opcode) {
1004 case ERROR:
1005 goto abort;
1006 case DATA:
1007 if (dp->th_block == block)
1008 goto done; /* normal */
1009 if (debug)
1010 syslog(LOG_DEBUG, "Resync %u != %u",
1011 (unsigned int)dp->th_block, block);
1012 /* Re-synchronize with the other side */
1013 (void) synchnet(peer, tftp_blksize);
1014 if (dp->th_block == (block-1))
1015 goto send_ack; /* rexmit */
1016 break;
1017 default:
1018 syslog(LOG_INFO, "Received %s in recvfile\n",
1019 opcode(dp->th_opcode));
1020 break;
1021 }
1022 }
1023 done:
1024 if (debug)
1025 syslog(LOG_DEBUG, "Got block %u", block);
1026 /* size = write(file, dp->th_data, n - 4); */
1027 size = writeit(file, &dp, n - 4, pf->f_convert);
1028 if (size != (n-4)) { /* ahem */
1029 if (size < 0) nak(errno + 100);
1030 else nak(ENOSPACE);
1031 goto abort;
1032 }
1033 } while (size == tftp_blksize);
1034 write_behind(file, pf->f_convert);
1035 (void) fclose(file); /* close data file */
1036
1037 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
1038 ap->th_block = htons((u_short)(block));
1039 if (debug)
1040 syslog(LOG_DEBUG, "Send final ACK %u", block);
1041 (void) send(peer, ackbuf, 4, 0);
1042
1043 signal(SIGALRM, justquit); /* just quit on timeout */
1044 alarm(rexmtval);
1045 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
1046 alarm(0);
1047 if (n >= 4 && /* if read some data */
1048 dp->th_opcode == DATA && /* and got a data block */
1049 block == dp->th_block) { /* then my last ack was lost */
1050 (void) send(peer, ackbuf, 4, 0); /* resend final ack */
1051 }
1052 abort:
1053 return;
1054 }
1055
1056 const struct errmsg {
1057 int e_code;
1058 const char *e_msg;
1059 } errmsgs[] = {
1060 { EUNDEF, "Undefined error code" },
1061 { ENOTFOUND, "File not found" },
1062 { EACCESS, "Access violation" },
1063 { ENOSPACE, "Disk full or allocation exceeded" },
1064 { EBADOP, "Illegal TFTP operation" },
1065 { EBADID, "Unknown transfer ID" },
1066 { EEXISTS, "File already exists" },
1067 { ENOUSER, "No such user" },
1068 { EOPTNEG, "Option negotiation failed" },
1069 { -1, 0 }
1070 };
1071
1072 static const char *
1073 errtomsg(int error)
1074 {
1075 static char ebuf[20];
1076 const struct errmsg *pe;
1077
1078 if (error == 0)
1079 return ("success");
1080 for (pe = errmsgs; pe->e_code >= 0; pe++)
1081 if (pe->e_code == error)
1082 return (pe->e_msg);
1083 snprintf(ebuf, sizeof(ebuf), "error %d", error);
1084 return (ebuf);
1085 }
1086
1087 /*
1088 * Send a nak packet (error message).
1089 * Error code passed in is one of the
1090 * standard TFTP codes, or a UNIX errno
1091 * offset by 100.
1092 */
1093 static void
1094 nak(int error)
1095 {
1096 const struct errmsg *pe;
1097 struct tftphdr *tp;
1098 int length;
1099 size_t msglen;
1100
1101 tp = (struct tftphdr *)buf;
1102 tp->th_opcode = htons((u_short)ERROR);
1103 msglen = sizeof(buf) - (&tp->th_msg[0] - buf);
1104 for (pe = errmsgs; pe->e_code >= 0; pe++)
1105 if (pe->e_code == error)
1106 break;
1107 if (pe->e_code < 0) {
1108 tp->th_code = EUNDEF; /* set 'undef' errorcode */
1109 strlcpy(tp->th_msg, strerror(error - 100), msglen);
1110 } else {
1111 tp->th_code = htons((u_short)error);
1112 strlcpy(tp->th_msg, pe->e_msg, msglen);
1113 }
1114 if (debug)
1115 syslog(LOG_DEBUG, "Send NACK %s", tp->th_msg);
1116 length = strlen(tp->th_msg);
1117 msglen = &tp->th_msg[length + 1] - buf;
1118 if (send(peer, buf, msglen, 0) != msglen)
1119 syslog(LOG_ERR, "nak: %m");
1120 }
1121
1122 static char *
1123 verifyhost(struct sockaddr *fromp)
1124 {
1125 static char hbuf[MAXHOSTNAMELEN];
1126
1127 if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0))
1128 strlcpy(hbuf, "?", sizeof(hbuf));
1129 return (hbuf);
1130 }
1131