]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - libexec/tftpd/tftpd.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / libexec / tftpd / tftpd.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)tftpd.c     8.1 (Berkeley) 6/4/93";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47
48 /*
49  * Trivial file transfer protocol server.
50  *
51  * This version includes many modifications by Jim Guyton
52  * <guyton@rand-unix>.
53  */
54
55 #include <sys/param.h>
56 #include <sys/ioctl.h>
57 #include <sys/stat.h>
58 #include <sys/socket.h>
59 #include <sys/types.h>
60 #include <sys/time.h>
61
62 #include <netinet/in.h>
63 #include <arpa/tftp.h>
64 #include <arpa/inet.h>
65
66 #include <ctype.h>
67 #include <errno.h>
68 #include <fcntl.h>
69 #include <libutil.h>
70 #include <netdb.h>
71 #include <pwd.h>
72 #include <setjmp.h>
73 #include <signal.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <syslog.h>
78 #include <unistd.h>
79
80 #include "tftpsubs.h"
81
82 #define TIMEOUT         5
83 #define MAX_TIMEOUTS    5
84
85 int     peer;
86 int     rexmtval = TIMEOUT;
87 int     max_rexmtval = 2*TIMEOUT;
88
89 #define PKTSIZE SEGSIZE+4
90 char    buf[PKTSIZE];
91 char    ackbuf[PKTSIZE];
92 struct  sockaddr_storage from;
93
94 void    tftp(struct tftphdr *, int);
95 static void unmappedaddr(struct sockaddr_in6 *);
96
97 /*
98  * Null-terminated directory prefix list for absolute pathname requests and
99  * search list for relative pathname requests.
100  *
101  * MAXDIRS should be at least as large as the number of arguments that
102  * inetd allows (currently 20).
103  */
104 #define MAXDIRS 20
105 static struct dirlist {
106         const char      *name;
107         int     len;
108 } dirs[MAXDIRS+1];
109 static int      suppress_naks;
110 static int      logging;
111 static int      ipchroot;
112 static int      create_new = 0;
113 static char     *newfile_format = "%Y%m%d";
114 static int      increase_name = 0;
115 static mode_t   mask = S_IWGRP|S_IWOTH;
116
117 static const char *errtomsg(int);
118 static void  nak(int);
119 static void  oack(void);
120
121 static void  timer(int);
122 static void  justquit(int);
123
124 int
125 main(int argc, char *argv[])
126 {
127         struct tftphdr *tp;
128         socklen_t fromlen, len;
129         int n;
130         int ch, on;
131         struct sockaddr_storage me;
132         char *chroot_dir = NULL;
133         struct passwd *nobody;
134         const char *chuser = "nobody";
135
136         tzset();                        /* syslog in localtime */
137
138         openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
139         while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
140                 switch (ch) {
141                 case 'c':
142                         ipchroot = 1;
143                         break;
144                 case 'C':
145                         ipchroot = 2;
146                         break;
147                 case 'F':
148                         newfile_format = optarg;
149                         break;
150                 case 'l':
151                         logging = 1;
152                         break;
153                 case 'n':
154                         suppress_naks = 1;
155                         break;
156                 case 's':
157                         chroot_dir = optarg;
158                         break;
159                 case 'u':
160                         chuser = optarg;
161                         break;
162                 case 'U':
163                         mask = strtol(optarg, NULL, 0);
164                         break;
165                 case 'w':
166                         create_new = 1;
167                         break;
168                 case 'W':
169                         create_new = 1;
170                         increase_name = 1;
171                         break;
172                 default:
173                         syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
174                 }
175         }
176         if (optind < argc) {
177                 struct dirlist *dirp;
178
179                 /* Get list of directory prefixes. Skip relative pathnames. */
180                 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
181                      optind++) {
182                         if (argv[optind][0] == '/') {
183                                 dirp->name = argv[optind];
184                                 dirp->len  = strlen(dirp->name);
185                                 dirp++;
186                         }
187                 }
188         }
189         else if (chroot_dir) {
190                 dirs->name = "/";
191                 dirs->len = 1;
192         }
193         if (ipchroot > 0 && chroot_dir == NULL) {
194                 syslog(LOG_ERR, "-c requires -s");
195                 exit(1);
196         }
197
198         umask(mask);
199
200         on = 1;
201         if (ioctl(0, FIONBIO, &on) < 0) {
202                 syslog(LOG_ERR, "ioctl(FIONBIO): %m");
203                 exit(1);
204         }
205         fromlen = sizeof (from);
206         n = recvfrom(0, buf, sizeof (buf), 0,
207             (struct sockaddr *)&from, &fromlen);
208         if (n < 0) {
209                 syslog(LOG_ERR, "recvfrom: %m");
210                 exit(1);
211         }
212         /*
213          * Now that we have read the message out of the UDP
214          * socket, we fork and exit.  Thus, inetd will go back
215          * to listening to the tftp port, and the next request
216          * to come in will start up a new instance of tftpd.
217          *
218          * We do this so that inetd can run tftpd in "wait" mode.
219          * The problem with tftpd running in "nowait" mode is that
220          * inetd may get one or more successful "selects" on the
221          * tftp port before we do our receive, so more than one
222          * instance of tftpd may be started up.  Worse, if tftpd
223          * break before doing the above "recvfrom", inetd would
224          * spawn endless instances, clogging the system.
225          */
226         {
227                 int i, pid;
228
229                 for (i = 1; i < 20; i++) {
230                     pid = fork();
231                     if (pid < 0) {
232                                 sleep(i);
233                                 /*
234                                  * flush out to most recently sent request.
235                                  *
236                                  * This may drop some request, but those
237                                  * will be resent by the clients when
238                                  * they timeout.  The positive effect of
239                                  * this flush is to (try to) prevent more
240                                  * than one tftpd being started up to service
241                                  * a single request from a single client.
242                                  */
243                                 fromlen = sizeof from;
244                                 i = recvfrom(0, buf, sizeof (buf), 0,
245                                     (struct sockaddr *)&from, &fromlen);
246                                 if (i > 0) {
247                                         n = i;
248                                 }
249                     } else {
250                                 break;
251                     }
252                 }
253                 if (pid < 0) {
254                         syslog(LOG_ERR, "fork: %m");
255                         exit(1);
256                 } else if (pid != 0) {
257                         exit(0);
258                 }
259         }
260
261         /*
262          * Since we exit here, we should do that only after the above
263          * recvfrom to keep inetd from constantly forking should there
264          * be a problem.  See the above comment about system clogging.
265          */
266         if (chroot_dir) {
267                 if (ipchroot > 0) {
268                         char *tempchroot;
269                         struct stat sb;
270                         int statret;
271                         struct sockaddr_storage ss;
272                         char hbuf[NI_MAXHOST];
273
274                         memcpy(&ss, &from, from.ss_len);
275                         unmappedaddr((struct sockaddr_in6 *)&ss);
276                         getnameinfo((struct sockaddr *)&ss, ss.ss_len,
277                                     hbuf, sizeof(hbuf), NULL, 0,
278                                     NI_NUMERICHOST);
279                         asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
280                         if (ipchroot == 2)
281                                 statret = stat(tempchroot, &sb);
282                         if (ipchroot == 1 ||
283                             (statret == 0 && (sb.st_mode & S_IFDIR)))
284                                 chroot_dir = tempchroot;
285                 }
286                 /* Must get this before chroot because /etc might go away */
287                 if ((nobody = getpwnam(chuser)) == NULL) {
288                         syslog(LOG_ERR, "%s: no such user", chuser);
289                         exit(1);
290                 }
291                 if (chroot(chroot_dir)) {
292                         syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
293                         exit(1);
294                 }
295                 chdir("/");
296                 setgroups(1, &nobody->pw_gid);
297                 setuid(nobody->pw_uid);
298         }
299
300         len = sizeof(me);
301         if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
302                 switch (me.ss_family) {
303                 case AF_INET:
304                         ((struct sockaddr_in *)&me)->sin_port = 0;
305                         break;
306                 case AF_INET6:
307                         ((struct sockaddr_in6 *)&me)->sin6_port = 0;
308                         break;
309                 default:
310                         /* unsupported */
311                         break;
312                 }
313         } else {
314                 memset(&me, 0, sizeof(me));
315                 me.ss_family = from.ss_family;
316                 me.ss_len = from.ss_len;
317         }
318         alarm(0);
319         close(0);
320         close(1);
321         peer = socket(from.ss_family, SOCK_DGRAM, 0);
322         if (peer < 0) {
323                 syslog(LOG_ERR, "socket: %m");
324                 exit(1);
325         }
326         if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
327                 syslog(LOG_ERR, "bind: %m");
328                 exit(1);
329         }
330         if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
331                 syslog(LOG_ERR, "connect: %m");
332                 exit(1);
333         }
334         tp = (struct tftphdr *)buf;
335         tp->th_opcode = ntohs(tp->th_opcode);
336         if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
337                 tftp(tp, n);
338         exit(1);
339 }
340
341 static void
342 reduce_path(char *fn)
343 {
344         char *slash, *ptr;
345
346         /* Reduce all "/+./" to "/" (just in case we've got "/./../" later */
347         while ((slash = strstr(fn, "/./")) != NULL) {
348                 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
349                         ;
350                 slash += 2;
351                 while (*slash)
352                         *++ptr = *++slash;
353         }
354
355         /* Now reduce all "/something/+../" to "/" */
356         while ((slash = strstr(fn, "/../")) != NULL) {
357                 if (slash == fn)
358                         break;
359                 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
360                         ;
361                 for (ptr--; ptr >= fn; ptr--)
362                         if (*ptr == '/')
363                                 break;
364                 if (ptr < fn)
365                         break;
366                 slash += 3;
367                 while (*slash)
368                         *++ptr = *++slash;
369         }
370 }
371
372 struct formats;
373 int     validate_access(char **, int);
374 void    xmitfile(struct formats *);
375 void    recvfile(struct formats *);
376
377 struct formats {
378         const char      *f_mode;
379         int     (*f_validate)(char **, int);
380         void    (*f_send)(struct formats *);
381         void    (*f_recv)(struct formats *);
382         int     f_convert;
383 } formats[] = {
384         { "netascii",   validate_access,        xmitfile,       recvfile, 1 },
385         { "octet",      validate_access,        xmitfile,       recvfile, 0 },
386 #ifdef notdef
387         { "mail",       validate_user,          sendmail,       recvmail, 1 },
388 #endif
389         { 0,            NULL,                   NULL,           NULL,     0 }
390 };
391
392 struct options {
393         const char      *o_type;
394         char    *o_request;
395         int     o_reply;        /* turn into union if need be */
396 } options[] = {
397         { "tsize",      NULL, 0 },              /* OPT_TSIZE */
398         { "timeout",    NULL, 0 },              /* OPT_TIMEOUT */
399         { NULL,         NULL, 0 }
400 };
401
402 enum opt_enum {
403         OPT_TSIZE = 0,
404         OPT_TIMEOUT,
405 };
406
407 /*
408  * Handle initial connection protocol.
409  */
410 void
411 tftp(struct tftphdr *tp, int size)
412 {
413         char *cp;
414         int i, first = 1, has_options = 0, ecode;
415         struct formats *pf;
416         char *filename, *mode, *option, *ccp;
417         char fnbuf[PATH_MAX];
418
419         cp = tp->th_stuff;
420 again:
421         while (cp < buf + size) {
422                 if (*cp == '\0')
423                         break;
424                 cp++;
425         }
426         if (*cp != '\0') {
427                 nak(EBADOP);
428                 exit(1);
429         }
430         i = cp - tp->th_stuff;
431         if (i >= sizeof(fnbuf)) {
432                 nak(EBADOP);
433                 exit(1);
434         }
435         memcpy(fnbuf, tp->th_stuff, i);
436         fnbuf[i] = '\0';
437         reduce_path(fnbuf);
438         filename = fnbuf;
439         if (first) {
440                 mode = ++cp;
441                 first = 0;
442                 goto again;
443         }
444         for (cp = mode; *cp; cp++)
445                 if (isupper(*cp))
446                         *cp = tolower(*cp);
447         for (pf = formats; pf->f_mode; pf++)
448                 if (strcmp(pf->f_mode, mode) == 0)
449                         break;
450         if (pf->f_mode == 0) {
451                 nak(EBADOP);
452                 exit(1);
453         }
454         while (++cp < buf + size) {
455                 for (i = 2, ccp = cp; i > 0; ccp++) {
456                         if (ccp >= buf + size) {
457                                 /*
458                                  * Don't reject the request, just stop trying
459                                  * to parse the option and get on with it.
460                                  * Some Apple Open Firmware versions have
461                                  * trailing garbage on the end of otherwise
462                                  * valid requests.
463                                  */
464                                 goto option_fail;
465                         } else if (*ccp == '\0')
466                                 i--;
467                 }
468                 for (option = cp; *cp; cp++)
469                         if (isupper(*cp))
470                                 *cp = tolower(*cp);
471                 for (i = 0; options[i].o_type != NULL; i++)
472                         if (strcmp(option, options[i].o_type) == 0) {
473                                 options[i].o_request = ++cp;
474                                 has_options = 1;
475                         }
476                 cp = ccp-1;
477         }
478
479 option_fail:
480         if (options[OPT_TIMEOUT].o_request) {
481                 int to = atoi(options[OPT_TIMEOUT].o_request);
482                 if (to < 1 || to > 255) {
483                         nak(EBADOP);
484                         exit(1);
485                 }
486                 else if (to <= max_rexmtval)
487                         options[OPT_TIMEOUT].o_reply = rexmtval = to;
488                 else
489                         options[OPT_TIMEOUT].o_request = NULL;
490         }
491
492         ecode = (*pf->f_validate)(&filename, tp->th_opcode);
493         if (has_options && ecode == 0)
494                 oack();
495         if (logging) {
496                 char hbuf[NI_MAXHOST];
497
498                 getnameinfo((struct sockaddr *)&from, from.ss_len,
499                             hbuf, sizeof(hbuf), NULL, 0, 0);
500                 syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
501                         tp->th_opcode == WRQ ? "write" : "read",
502                         filename, errtomsg(ecode));
503         }
504         if (ecode) {
505                 /*
506                  * Avoid storms of naks to a RRQ broadcast for a relative
507                  * bootfile pathname from a diskless Sun.
508                  */
509                 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
510                         exit(0);
511                 nak(ecode);
512                 exit(1);
513         }
514         if (tp->th_opcode == WRQ)
515                 (*pf->f_recv)(pf);
516         else
517                 (*pf->f_send)(pf);
518         exit(0);
519 }
520
521
522 FILE *file;
523
524 /*
525  * Find the next value for YYYYMMDD.nn when the file to be written should
526  * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
527  * Besides, that is four updates per hour on a file, which is kind of
528  * execessive anyway.
529  */
530 static int
531 find_next_name(char *filename, int *fd)
532 {
533         int i;
534         time_t tval;
535         size_t len;
536         struct tm lt;
537         char yyyymmdd[MAXPATHLEN];
538         char newname[MAXPATHLEN];
539         struct stat sb;
540         int ret;
541
542         /* Create the YYYYMMDD part of the filename */
543         time(&tval);
544         lt = *localtime(&tval);
545         len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
546         if (len == 0) {
547                 syslog(LOG_WARNING,
548                         "Filename suffix too long (%d characters maximum)",
549                         MAXPATHLEN);
550                 return (EACCESS);
551         }
552
553         /* Make sure the new filename is not too long */
554         if (strlen(filename) > MAXPATHLEN - len - 5) {
555                 syslog(LOG_WARNING,
556                         "Filename too long (%d characters, %d maximum)",
557                         strlen(filename), MAXPATHLEN - len - 5);
558                 return (EACCESS);
559         }
560
561         /* Find the first file which doesn't exist */
562         for (i = 0; i < 100; i++) {
563                 sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
564                 *fd = open(newname,
565                     O_WRONLY | O_CREAT | O_EXCL, 
566                     S_IRUSR | S_IWUSR | S_IRGRP |
567                     S_IWGRP | S_IROTH | S_IWOTH);
568                 if (*fd > 0)
569                         return 0;
570         }
571
572         return (EEXIST);
573 }
574
575 /*
576  * Validate file access.  Since we
577  * have no uid or gid, for now require
578  * file to exist and be publicly
579  * readable/writable.
580  * If we were invoked with arguments
581  * from inetd then the file must also be
582  * in one of the given directory prefixes.
583  * Note also, full path name must be
584  * given as we have no login directory.
585  */
586 int
587 validate_access(char **filep, int mode)
588 {
589         struct stat stbuf;
590         int     fd;
591         int     error;
592         struct dirlist *dirp;
593         static char pathname[MAXPATHLEN];
594         char *filename = *filep;
595
596         /*
597          * Prevent tricksters from getting around the directory restrictions
598          */
599         if (strstr(filename, "/../"))
600                 return (EACCESS);
601
602         if (*filename == '/') {
603                 /*
604                  * Allow the request if it's in one of the approved locations.
605                  * Special case: check the null prefix ("/") by looking
606                  * for length = 1 and relying on the arg. processing that
607                  * it's a /.
608                  */
609                 for (dirp = dirs; dirp->name != NULL; dirp++) {
610                         if (dirp->len == 1 ||
611                             (!strncmp(filename, dirp->name, dirp->len) &&
612                              filename[dirp->len] == '/'))
613                                     break;
614                 }
615                 /* If directory list is empty, allow access to any file */
616                 if (dirp->name == NULL && dirp != dirs)
617                         return (EACCESS);
618                 if (stat(filename, &stbuf) < 0)
619                         return (errno == ENOENT ? ENOTFOUND : EACCESS);
620                 if ((stbuf.st_mode & S_IFMT) != S_IFREG)
621                         return (ENOTFOUND);
622                 if (mode == RRQ) {
623                         if ((stbuf.st_mode & S_IROTH) == 0)
624                                 return (EACCESS);
625                 } else {
626                         if ((stbuf.st_mode & S_IWOTH) == 0)
627                                 return (EACCESS);
628                 }
629         } else {
630                 int err;
631
632                 /*
633                  * Relative file name: search the approved locations for it.
634                  * Don't allow write requests that avoid directory
635                  * restrictions.
636                  */
637
638                 if (!strncmp(filename, "../", 3))
639                         return (EACCESS);
640
641                 /*
642                  * If the file exists in one of the directories and isn't
643                  * readable, continue looking. However, change the error code
644                  * to give an indication that the file exists.
645                  */
646                 err = ENOTFOUND;
647                 for (dirp = dirs; dirp->name != NULL; dirp++) {
648                         snprintf(pathname, sizeof(pathname), "%s/%s",
649                                 dirp->name, filename);
650                         if (stat(pathname, &stbuf) == 0 &&
651                             (stbuf.st_mode & S_IFMT) == S_IFREG) {
652                                 if ((stbuf.st_mode & S_IROTH) != 0) {
653                                         break;
654                                 }
655                                 err = EACCESS;
656                         }
657                 }
658                 if (dirp->name != NULL)
659                         *filep = filename = pathname;
660                 else if (mode == RRQ)
661                         return (err);
662         }
663         if (options[OPT_TSIZE].o_request) {
664                 if (mode == RRQ) 
665                         options[OPT_TSIZE].o_reply = stbuf.st_size;
666                 else
667                         /* XXX Allows writes of all sizes. */
668                         options[OPT_TSIZE].o_reply =
669                                 atoi(options[OPT_TSIZE].o_request);
670         }
671         if (mode == RRQ)
672                 fd = open(filename, O_RDONLY);
673         else {
674                 if (create_new) {
675                         if (increase_name) {
676                                 error = find_next_name(filename, &fd);
677                                 if (error > 0)
678                                         return (error + 100);
679                         } else
680                                 fd = open(filename,
681                                     O_WRONLY | O_TRUNC | O_CREAT, 
682                                     S_IRUSR | S_IWUSR | S_IRGRP | 
683                                     S_IWGRP | S_IROTH | S_IWOTH );
684                 } else
685                         fd = open(filename, O_WRONLY | O_TRUNC);
686         }
687         if (fd < 0)
688                 return (errno + 100);
689         file = fdopen(fd, (mode == RRQ)? "r":"w");
690         if (file == NULL) {
691                 close(fd);
692                 return (errno + 100);
693         }
694         return (0);
695 }
696
697 int     timeouts;
698 jmp_buf timeoutbuf;
699
700 void
701 timer(int sig __unused)
702 {
703         if (++timeouts > MAX_TIMEOUTS)
704                 exit(1);
705         longjmp(timeoutbuf, 1);
706 }
707
708 /*
709  * Send the requested file.
710  */
711 void
712 xmitfile(struct formats *pf)
713 {
714         struct tftphdr *dp;
715         struct tftphdr *ap;    /* ack packet */
716         int size, n;
717         volatile unsigned short block;
718
719         signal(SIGALRM, timer);
720         dp = r_init();
721         ap = (struct tftphdr *)ackbuf;
722         block = 1;
723         do {
724                 size = readit(file, &dp, pf->f_convert);
725                 if (size < 0) {
726                         nak(errno + 100);
727                         goto abort;
728                 }
729                 dp->th_opcode = htons((u_short)DATA);
730                 dp->th_block = htons((u_short)block);
731                 timeouts = 0;
732                 (void)setjmp(timeoutbuf);
733
734 send_data:
735                 {
736                         int i, t = 1;
737                         for (i = 0; ; i++){
738                                 if (send(peer, dp, size + 4, 0) != size + 4) {
739                                         sleep(t);
740                                         t = (t < 32) ? t<< 1 : t;
741                                         if (i >= 12) {
742                                                 syslog(LOG_ERR, "write: %m");
743                                                 goto abort;
744                                         }
745                                 }
746                                 break;
747                         }
748                 }
749                 read_ahead(file, pf->f_convert);
750                 for ( ; ; ) {
751                         alarm(rexmtval);        /* read the ack */
752                         n = recv(peer, ackbuf, sizeof (ackbuf), 0);
753                         alarm(0);
754                         if (n < 0) {
755                                 syslog(LOG_ERR, "read: %m");
756                                 goto abort;
757                         }
758                         ap->th_opcode = ntohs((u_short)ap->th_opcode);
759                         ap->th_block = ntohs((u_short)ap->th_block);
760
761                         if (ap->th_opcode == ERROR)
762                                 goto abort;
763
764                         if (ap->th_opcode == ACK) {
765                                 if (ap->th_block == block)
766                                         break;
767                                 /* Re-synchronize with the other side */
768                                 (void) synchnet(peer);
769                                 if (ap->th_block == (block -1))
770                                         goto send_data;
771                         }
772
773                 }
774                 block++;
775         } while (size == SEGSIZE);
776 abort:
777         (void) fclose(file);
778 }
779
780 void
781 justquit(int sig __unused)
782 {
783         exit(0);
784 }
785
786
787 /*
788  * Receive a file.
789  */
790 void
791 recvfile(struct formats *pf)
792 {
793         struct tftphdr *dp;
794         struct tftphdr *ap;    /* ack buffer */
795         int n, size;
796         volatile unsigned short block;
797
798         signal(SIGALRM, timer);
799         dp = w_init();
800         ap = (struct tftphdr *)ackbuf;
801         block = 0;
802         do {
803                 timeouts = 0;
804                 ap->th_opcode = htons((u_short)ACK);
805                 ap->th_block = htons((u_short)block);
806                 block++;
807                 (void) setjmp(timeoutbuf);
808 send_ack:
809                 if (send(peer, ackbuf, 4, 0) != 4) {
810                         syslog(LOG_ERR, "write: %m");
811                         goto abort;
812                 }
813                 write_behind(file, pf->f_convert);
814                 for ( ; ; ) {
815                         alarm(rexmtval);
816                         n = recv(peer, dp, PKTSIZE, 0);
817                         alarm(0);
818                         if (n < 0) {            /* really? */
819                                 syslog(LOG_ERR, "read: %m");
820                                 goto abort;
821                         }
822                         dp->th_opcode = ntohs((u_short)dp->th_opcode);
823                         dp->th_block = ntohs((u_short)dp->th_block);
824                         if (dp->th_opcode == ERROR)
825                                 goto abort;
826                         if (dp->th_opcode == DATA) {
827                                 if (dp->th_block == block) {
828                                         break;   /* normal */
829                                 }
830                                 /* Re-synchronize with the other side */
831                                 (void) synchnet(peer);
832                                 if (dp->th_block == (block-1))
833                                         goto send_ack;          /* rexmit */
834                         }
835                 }
836                 /*  size = write(file, dp->th_data, n - 4); */
837                 size = writeit(file, &dp, n - 4, pf->f_convert);
838                 if (size != (n-4)) {                    /* ahem */
839                         if (size < 0) nak(errno + 100);
840                         else nak(ENOSPACE);
841                         goto abort;
842                 }
843         } while (size == SEGSIZE);
844         write_behind(file, pf->f_convert);
845         (void) fclose(file);            /* close data file */
846
847         ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
848         ap->th_block = htons((u_short)(block));
849         (void) send(peer, ackbuf, 4, 0);
850
851         signal(SIGALRM, justquit);      /* just quit on timeout */
852         alarm(rexmtval);
853         n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
854         alarm(0);
855         if (n >= 4 &&                   /* if read some data */
856             dp->th_opcode == DATA &&    /* and got a data block */
857             block == dp->th_block) {    /* then my last ack was lost */
858                 (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
859         }
860 abort:
861         return;
862 }
863
864 struct errmsg {
865         int     e_code;
866         const char      *e_msg;
867 } errmsgs[] = {
868         { EUNDEF,       "Undefined error code" },
869         { ENOTFOUND,    "File not found" },
870         { EACCESS,      "Access violation" },
871         { ENOSPACE,     "Disk full or allocation exceeded" },
872         { EBADOP,       "Illegal TFTP operation" },
873         { EBADID,       "Unknown transfer ID" },
874         { EEXISTS,      "File already exists" },
875         { ENOUSER,      "No such user" },
876         { EOPTNEG,      "Option negotiation" },
877         { -1,           0 }
878 };
879
880 static const char *
881 errtomsg(int error)
882 {
883         static char ebuf[20];
884         struct errmsg *pe;
885         if (error == 0)
886                 return "success";
887         for (pe = errmsgs; pe->e_code >= 0; pe++)
888                 if (pe->e_code == error)
889                         return pe->e_msg;
890         snprintf(ebuf, sizeof(buf), "error %d", error);
891         return ebuf;
892 }
893
894 /*
895  * Send a nak packet (error message).
896  * Error code passed in is one of the
897  * standard TFTP codes, or a UNIX errno
898  * offset by 100.
899  */
900 static void
901 nak(int error)
902 {
903         struct tftphdr *tp;
904         int length;
905         struct errmsg *pe;
906
907         tp = (struct tftphdr *)buf;
908         tp->th_opcode = htons((u_short)ERROR);
909         tp->th_code = htons((u_short)error);
910         for (pe = errmsgs; pe->e_code >= 0; pe++)
911                 if (pe->e_code == error)
912                         break;
913         if (pe->e_code < 0) {
914                 pe->e_msg = strerror(error - 100);
915                 tp->th_code = EUNDEF;   /* set 'undef' errorcode */
916         }
917         strcpy(tp->th_msg, pe->e_msg);
918         length = strlen(pe->e_msg);
919         tp->th_msg[length] = '\0';
920         length += 5;
921         if (send(peer, buf, length, 0) != length)
922                 syslog(LOG_ERR, "nak: %m");
923 }
924
925 /* translate IPv4 mapped IPv6 address to IPv4 address */
926 static void
927 unmappedaddr(struct sockaddr_in6 *sin6)
928 {
929         struct sockaddr_in *sin4;
930         u_int32_t addr;
931         int port;
932
933         if (sin6->sin6_family != AF_INET6 ||
934             !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
935                 return;
936         sin4 = (struct sockaddr_in *)sin6;
937         addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
938         port = sin6->sin6_port;
939         memset(sin4, 0, sizeof(struct sockaddr_in));
940         sin4->sin_addr.s_addr = addr;
941         sin4->sin_port = port;
942         sin4->sin_family = AF_INET;
943         sin4->sin_len = sizeof(struct sockaddr_in);
944 }
945
946 /*
947  * Send an oack packet (option acknowledgement).
948  */
949 static void
950 oack(void)
951 {
952         struct tftphdr *tp, *ap;
953         int size, i, n;
954         char *bp;
955
956         tp = (struct tftphdr *)buf;
957         bp = buf + 2;
958         size = sizeof(buf) - 2;
959         tp->th_opcode = htons((u_short)OACK);
960         for (i = 0; options[i].o_type != NULL; i++) {
961                 if (options[i].o_request) {
962                         n = snprintf(bp, size, "%s%c%d", options[i].o_type,
963                                      0, options[i].o_reply);
964                         bp += n+1;
965                         size -= n+1;
966                         if (size < 0) {
967                                 syslog(LOG_ERR, "oack: buffer overflow");
968                                 exit(1);
969                         }
970                 }
971         }
972         size = bp - buf;
973         ap = (struct tftphdr *)ackbuf;
974         signal(SIGALRM, timer);
975         timeouts = 0;
976
977         (void)setjmp(timeoutbuf);
978         if (send(peer, buf, size, 0) != size) {
979                 syslog(LOG_INFO, "oack: %m");
980                 exit(1);
981         }
982
983         for (;;) {
984                 alarm(rexmtval);
985                 n = recv(peer, ackbuf, sizeof (ackbuf), 0);
986                 alarm(0);
987                 if (n < 0) {
988                         syslog(LOG_ERR, "recv: %m");
989                         exit(1);
990                 }
991                 ap->th_opcode = ntohs((u_short)ap->th_opcode);
992                 ap->th_block = ntohs((u_short)ap->th_block);
993                 if (ap->th_opcode == ERROR)
994                         exit(1);
995                 if (ap->th_opcode == ACK && ap->th_block == 0)
996                         break;
997         }
998 }