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