]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/tftpd/tftpd.c
This commit was generated by cvs2svn to compensate for changes in r135768,
[FreeBSD/FreeBSD.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 int     fromlen;
94
95 void    tftp(struct tftphdr *, int);
96 static void unmappedaddr(struct sockaddr_in6 *);
97
98 /*
99  * Null-terminated directory prefix list for absolute pathname requests and
100  * search list for relative pathname requests.
101  *
102  * MAXDIRS should be at least as large as the number of arguments that
103  * inetd allows (currently 20).
104  */
105 #define MAXDIRS 20
106 static struct dirlist {
107         const char      *name;
108         int     len;
109 } dirs[MAXDIRS+1];
110 static int      suppress_naks;
111 static int      logging;
112 static int      ipchroot;
113 static int      create_new = 0;
114 static mode_t   mask = S_IWGRP|S_IWOTH;
115
116 static const char *errtomsg(int);
117 static void  nak(int);
118 static void  oack(void);
119
120 static void  timer(int);
121 static void  justquit(int);
122
123 int
124 main(int argc, char *argv[])
125 {
126         struct tftphdr *tp;
127         int n;
128         int ch, on;
129         struct sockaddr_storage me;
130         int len;
131         char *chroot_dir = NULL;
132         struct passwd *nobody;
133         const char *chuser = "nobody";
134
135         tzset();                        /* syslog in localtime */
136
137         openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
138         while ((ch = getopt(argc, argv, "cClns:u:Uw")) != -1) {
139                 switch (ch) {
140                 case 'c':
141                         ipchroot = 1;
142                         break;
143                 case 'C':
144                         ipchroot = 2;
145                         break;
146                 case 'l':
147                         logging = 1;
148                         break;
149                 case 'n':
150                         suppress_naks = 1;
151                         break;
152                 case 's':
153                         chroot_dir = optarg;
154                         break;
155                 case 'u':
156                         chuser = optarg;
157                         break;
158                 case 'U':
159                         mask = strtol(optarg, NULL, 0);
160                         break;
161                 case 'w':
162                         create_new = 1;
163                         break;
164                 default:
165                         syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
166                 }
167         }
168         if (optind < argc) {
169                 struct dirlist *dirp;
170
171                 /* Get list of directory prefixes. Skip relative pathnames. */
172                 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
173                      optind++) {
174                         if (argv[optind][0] == '/') {
175                                 dirp->name = argv[optind];
176                                 dirp->len  = strlen(dirp->name);
177                                 dirp++;
178                         }
179                 }
180         }
181         else if (chroot_dir) {
182                 dirs->name = "/";
183                 dirs->len = 1;
184         }
185         if (ipchroot > 0 && chroot_dir == NULL) {
186                 syslog(LOG_ERR, "-c requires -s");
187                 exit(1);
188         }
189
190         umask(mask);
191
192         on = 1;
193         if (ioctl(0, FIONBIO, &on) < 0) {
194                 syslog(LOG_ERR, "ioctl(FIONBIO): %m");
195                 exit(1);
196         }
197         fromlen = sizeof (from);
198         n = recvfrom(0, buf, sizeof (buf), 0,
199             (struct sockaddr *)&from, &fromlen);
200         if (n < 0) {
201                 syslog(LOG_ERR, "recvfrom: %m");
202                 exit(1);
203         }
204         /*
205          * Now that we have read the message out of the UDP
206          * socket, we fork and exit.  Thus, inetd will go back
207          * to listening to the tftp port, and the next request
208          * to come in will start up a new instance of tftpd.
209          *
210          * We do this so that inetd can run tftpd in "wait" mode.
211          * The problem with tftpd running in "nowait" mode is that
212          * inetd may get one or more successful "selects" on the
213          * tftp port before we do our receive, so more than one
214          * instance of tftpd may be started up.  Worse, if tftpd
215          * break before doing the above "recvfrom", inetd would
216          * spawn endless instances, clogging the system.
217          */
218         {
219                 int pid;
220                 int i, j;
221
222                 for (i = 1; i < 20; i++) {
223                     pid = fork();
224                     if (pid < 0) {
225                                 sleep(i);
226                                 /*
227                                  * flush out to most recently sent request.
228                                  *
229                                  * This may drop some request, but those
230                                  * will be resent by the clients when
231                                  * they timeout.  The positive effect of
232                                  * this flush is to (try to) prevent more
233                                  * than one tftpd being started up to service
234                                  * a single request from a single client.
235                                  */
236                                 j = sizeof from;
237                                 i = recvfrom(0, buf, sizeof (buf), 0,
238                                     (struct sockaddr *)&from, &j);
239                                 if (i > 0) {
240                                         n = i;
241                                         fromlen = j;
242                                 }
243                     } else {
244                                 break;
245                     }
246                 }
247                 if (pid < 0) {
248                         syslog(LOG_ERR, "fork: %m");
249                         exit(1);
250                 } else if (pid != 0) {
251                         exit(0);
252                 }
253         }
254
255         /*
256          * Since we exit here, we should do that only after the above
257          * recvfrom to keep inetd from constantly forking should there
258          * be a problem.  See the above comment about system clogging.
259          */
260         if (chroot_dir) {
261                 if (ipchroot > 0) {
262                         char *tempchroot;
263                         struct stat sb;
264                         int statret;
265                         struct sockaddr_storage ss;
266                         char hbuf[NI_MAXHOST];
267
268                         memcpy(&ss, &from, from.ss_len);
269                         unmappedaddr((struct sockaddr_in6 *)&ss);
270                         getnameinfo((struct sockaddr *)&ss, ss.ss_len,
271                                     hbuf, sizeof(hbuf), NULL, 0,
272                                     NI_NUMERICHOST | NI_WITHSCOPEID);
273                         asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
274                         if (ipchroot == 2)
275                                 statret = stat(tempchroot, &sb);
276                         if (ipchroot == 1 ||
277                             (statret == 0 && (sb.st_mode & S_IFDIR)))
278                                 chroot_dir = tempchroot;
279                 }
280                 /* Must get this before chroot because /etc might go away */
281                 if ((nobody = getpwnam(chuser)) == NULL) {
282                         syslog(LOG_ERR, "%s: no such user", chuser);
283                         exit(1);
284                 }
285                 if (chroot(chroot_dir)) {
286                         syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
287                         exit(1);
288                 }
289                 chdir("/");
290                 setgroups(1, &nobody->pw_gid);
291                 setuid(nobody->pw_uid);
292         }
293
294         len = sizeof(me);
295         if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
296                 switch (me.ss_family) {
297                 case AF_INET:
298                         ((struct sockaddr_in *)&me)->sin_port = 0;
299                         break;
300                 case AF_INET6:
301                         ((struct sockaddr_in6 *)&me)->sin6_port = 0;
302                         break;
303                 default:
304                         /* unsupported */
305                         break;
306                 }
307         } else {
308                 memset(&me, 0, sizeof(me));
309                 me.ss_family = from.ss_family;
310                 me.ss_len = from.ss_len;
311         }
312         alarm(0);
313         close(0);
314         close(1);
315         peer = socket(from.ss_family, SOCK_DGRAM, 0);
316         if (peer < 0) {
317                 syslog(LOG_ERR, "socket: %m");
318                 exit(1);
319         }
320         if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
321                 syslog(LOG_ERR, "bind: %m");
322                 exit(1);
323         }
324         if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
325                 syslog(LOG_ERR, "connect: %m");
326                 exit(1);
327         }
328         tp = (struct tftphdr *)buf;
329         tp->th_opcode = ntohs(tp->th_opcode);
330         if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
331                 tftp(tp, n);
332         exit(1);
333 }
334
335 static void
336 reduce_path(char *fn)
337 {
338         char *slash, *ptr;
339
340         /* Reduce all "/+./" to "/" (just in case we've got "/./../" later */
341         while ((slash = strstr(fn, "/./")) != NULL) {
342                 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
343                         ;
344                 slash += 2;
345                 while (*slash)
346                         *++ptr = *++slash;
347         }
348
349         /* Now reduce all "/something/+../" to "/" */
350         while ((slash = strstr(fn, "/../")) != NULL) {
351                 if (slash == fn)
352                         break;
353                 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
354                         ;
355                 for (ptr--; ptr >= fn; ptr--)
356                         if (*ptr == '/')
357                                 break;
358                 if (ptr < fn)
359                         break;
360                 slash += 3;
361                 while (*slash)
362                         *++ptr = *++slash;
363         }
364 }
365
366 struct formats;
367 int     validate_access(char **, int);
368 void    xmitfile(struct formats *);
369 void    recvfile(struct formats *);
370
371 struct formats {
372         const char      *f_mode;
373         int     (*f_validate)(char **, int);
374         void    (*f_send)(struct formats *);
375         void    (*f_recv)(struct formats *);
376         int     f_convert;
377 } formats[] = {
378         { "netascii",   validate_access,        xmitfile,       recvfile, 1 },
379         { "octet",      validate_access,        xmitfile,       recvfile, 0 },
380 #ifdef notdef
381         { "mail",       validate_user,          sendmail,       recvmail, 1 },
382 #endif
383         { 0,            NULL,                   NULL,           NULL,     0 }
384 };
385
386 struct options {
387         const char      *o_type;
388         char    *o_request;
389         int     o_reply;        /* turn into union if need be */
390 } options[] = {
391         { "tsize",      NULL, 0 },              /* OPT_TSIZE */
392         { "timeout",    NULL, 0 },              /* OPT_TIMEOUT */
393         { NULL,         NULL, 0 }
394 };
395
396 enum opt_enum {
397         OPT_TSIZE = 0,
398         OPT_TIMEOUT,
399 };
400
401 /*
402  * Handle initial connection protocol.
403  */
404 void
405 tftp(struct tftphdr *tp, int size)
406 {
407         char *cp;
408         int i, first = 1, has_options = 0, ecode;
409         struct formats *pf;
410         char *filename, *mode, *option, *ccp;
411         char fnbuf[PATH_MAX], resolved_fnbuf[PATH_MAX];
412
413         cp = tp->th_stuff;
414 again:
415         while (cp < buf + size) {
416                 if (*cp == '\0')
417                         break;
418                 cp++;
419         }
420         if (*cp != '\0') {
421                 nak(EBADOP);
422                 exit(1);
423         }
424         i = cp - tp->th_stuff;
425         if (i >= sizeof(fnbuf)) {
426                 nak(EBADOP);
427                 exit(1);
428         }
429         memcpy(fnbuf, tp->th_stuff, i);
430         fnbuf[i] = '\0';
431         reduce_path(fnbuf);
432         filename = fnbuf;
433         if (first) {
434                 mode = ++cp;
435                 first = 0;
436                 goto again;
437         }
438         for (cp = mode; *cp; cp++)
439                 if (isupper(*cp))
440                         *cp = tolower(*cp);
441         for (pf = formats; pf->f_mode; pf++)
442                 if (strcmp(pf->f_mode, mode) == 0)
443                         break;
444         if (pf->f_mode == 0) {
445                 nak(EBADOP);
446                 exit(1);
447         }
448         while (++cp < buf + size) {
449                 for (i = 2, ccp = cp; i > 0; ccp++) {
450                         if (ccp >= buf + size) {
451                                 /*
452                                  * Don't reject the request, just stop trying
453                                  * to parse the option and get on with it.
454                                  * Some Apple Open Firmware versions have
455                                  * trailing garbage on the end of otherwise
456                                  * valid requests.
457                                  */
458                                 goto option_fail;
459                         } else if (*ccp == '\0')
460                                 i--;
461                 }
462                 for (option = cp; *cp; cp++)
463                         if (isupper(*cp))
464                                 *cp = tolower(*cp);
465                 for (i = 0; options[i].o_type != NULL; i++)
466                         if (strcmp(option, options[i].o_type) == 0) {
467                                 options[i].o_request = ++cp;
468                                 has_options = 1;
469                         }
470                 cp = ccp-1;
471         }
472
473 option_fail:
474         if (options[OPT_TIMEOUT].o_request) {
475                 int to = atoi(options[OPT_TIMEOUT].o_request);
476                 if (to < 1 || to > 255) {
477                         nak(EBADOP);
478                         exit(1);
479                 }
480                 else if (to <= max_rexmtval)
481                         options[OPT_TIMEOUT].o_reply = rexmtval = to;
482                 else
483                         options[OPT_TIMEOUT].o_request = NULL;
484         }
485
486         ecode = (*pf->f_validate)(&filename, tp->th_opcode);
487         if (has_options && ecode == 0)
488                 oack();
489         if (logging) {
490                 char hbuf[NI_MAXHOST];
491
492                 getnameinfo((struct sockaddr *)&from, from.ss_len,
493                             hbuf, sizeof(hbuf), NULL, 0, 
494                             NI_WITHSCOPEID);
495                 syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
496                         tp->th_opcode == WRQ ? "write" : "read",
497                         filename, errtomsg(ecode));
498         }
499         if (ecode) {
500                 /*
501                  * Avoid storms of naks to a RRQ broadcast for a relative
502                  * bootfile pathname from a diskless Sun.
503                  */
504                 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
505                         exit(0);
506                 nak(ecode);
507                 exit(1);
508         }
509         if (tp->th_opcode == WRQ)
510                 (*pf->f_recv)(pf);
511         else
512                 (*pf->f_send)(pf);
513         exit(0);
514 }
515
516
517 FILE *file;
518
519 /*
520  * Validate file access.  Since we
521  * have no uid or gid, for now require
522  * file to exist and be publicly
523  * readable/writable.
524  * If we were invoked with arguments
525  * from inetd then the file must also be
526  * in one of the given directory prefixes.
527  * Note also, full path name must be
528  * given as we have no login directory.
529  */
530 int
531 validate_access(char **filep, int mode)
532 {
533         struct stat stbuf;
534         int     fd;
535         struct dirlist *dirp;
536         static char pathname[MAXPATHLEN];
537         char *filename = *filep;
538
539         /*
540          * Prevent tricksters from getting around the directory restrictions
541          */
542         if (strstr(filename, "/../"))
543                 return (EACCESS);
544
545         if (*filename == '/') {
546                 /*
547                  * Allow the request if it's in one of the approved locations.
548                  * Special case: check the null prefix ("/") by looking
549                  * for length = 1 and relying on the arg. processing that
550                  * it's a /.
551                  */
552                 for (dirp = dirs; dirp->name != NULL; dirp++) {
553                         if (dirp->len == 1 ||
554                             (!strncmp(filename, dirp->name, dirp->len) &&
555                              filename[dirp->len] == '/'))
556                                     break;
557                 }
558                 /* If directory list is empty, allow access to any file */
559                 if (dirp->name == NULL && dirp != dirs)
560                         return (EACCESS);
561                 if (stat(filename, &stbuf) < 0)
562                         return (errno == ENOENT ? ENOTFOUND : EACCESS);
563                 if ((stbuf.st_mode & S_IFMT) != S_IFREG)
564                         return (ENOTFOUND);
565                 if (mode == RRQ) {
566                         if ((stbuf.st_mode & S_IROTH) == 0)
567                                 return (EACCESS);
568                 } else {
569                         if ((stbuf.st_mode & S_IWOTH) == 0)
570                                 return (EACCESS);
571                 }
572         } else {
573                 int err;
574
575                 /*
576                  * Relative file name: search the approved locations for it.
577                  * Don't allow write requests that avoid directory
578                  * restrictions.
579                  */
580
581                 if (!strncmp(filename, "../", 3))
582                         return (EACCESS);
583
584                 /*
585                  * If the file exists in one of the directories and isn't
586                  * readable, continue looking. However, change the error code
587                  * to give an indication that the file exists.
588                  */
589                 err = ENOTFOUND;
590                 for (dirp = dirs; dirp->name != NULL; dirp++) {
591                         snprintf(pathname, sizeof(pathname), "%s/%s",
592                                 dirp->name, filename);
593                         if (stat(pathname, &stbuf) == 0 &&
594                             (stbuf.st_mode & S_IFMT) == S_IFREG) {
595                                 if ((stbuf.st_mode & S_IROTH) != 0) {
596                                         break;
597                                 }
598                                 err = EACCESS;
599                         }
600                 }
601                 if (dirp->name != NULL)
602                         *filep = filename = pathname;
603                 else if (mode == RRQ)
604                         return (err);
605         }
606         if (options[OPT_TSIZE].o_request) {
607                 if (mode == RRQ) 
608                         options[OPT_TSIZE].o_reply = stbuf.st_size;
609                 else
610                         /* XXX Allows writes of all sizes. */
611                         options[OPT_TSIZE].o_reply =
612                                 atoi(options[OPT_TSIZE].o_request);
613         }
614         if (mode == RRQ)
615                 fd = open(filename, O_RDONLY);
616         else {
617                 if (create_new)
618                         fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
619                 else
620                         fd = open(filename, O_WRONLY|O_TRUNC);
621         }
622         if (fd < 0)
623                 return (errno + 100);
624         file = fdopen(fd, (mode == RRQ)? "r":"w");
625         if (file == NULL) {
626                 close(fd);
627                 return (errno + 100);
628         }
629         return (0);
630 }
631
632 int     timeouts;
633 jmp_buf timeoutbuf;
634
635 void
636 timer(int sig __unused)
637 {
638         if (++timeouts > MAX_TIMEOUTS)
639                 exit(1);
640         longjmp(timeoutbuf, 1);
641 }
642
643 /*
644  * Send the requested file.
645  */
646 void
647 xmitfile(struct formats *pf)
648 {
649         struct tftphdr *dp;
650         struct tftphdr *ap;    /* ack packet */
651         int size, n;
652         volatile unsigned short block;
653
654         signal(SIGALRM, timer);
655         dp = r_init();
656         ap = (struct tftphdr *)ackbuf;
657         block = 1;
658         do {
659                 size = readit(file, &dp, pf->f_convert);
660                 if (size < 0) {
661                         nak(errno + 100);
662                         goto abort;
663                 }
664                 dp->th_opcode = htons((u_short)DATA);
665                 dp->th_block = htons((u_short)block);
666                 timeouts = 0;
667                 (void)setjmp(timeoutbuf);
668
669 send_data:
670                 {
671                         int i, t = 1;
672                         for (i = 0; ; i++){
673                                 if (send(peer, dp, size + 4, 0) != size + 4) {
674                                         sleep(t);
675                                         t = (t < 32) ? t<< 1 : t;
676                                         if (i >= 12) {
677                                                 syslog(LOG_ERR, "write: %m");
678                                                 goto abort;
679                                         }
680                                 }
681                                 break;
682                         }
683                 }
684                 read_ahead(file, pf->f_convert);
685                 for ( ; ; ) {
686                         alarm(rexmtval);        /* read the ack */
687                         n = recv(peer, ackbuf, sizeof (ackbuf), 0);
688                         alarm(0);
689                         if (n < 0) {
690                                 syslog(LOG_ERR, "read: %m");
691                                 goto abort;
692                         }
693                         ap->th_opcode = ntohs((u_short)ap->th_opcode);
694                         ap->th_block = ntohs((u_short)ap->th_block);
695
696                         if (ap->th_opcode == ERROR)
697                                 goto abort;
698
699                         if (ap->th_opcode == ACK) {
700                                 if (ap->th_block == block)
701                                         break;
702                                 /* Re-synchronize with the other side */
703                                 (void) synchnet(peer);
704                                 if (ap->th_block == (block -1))
705                                         goto send_data;
706                         }
707
708                 }
709                 block++;
710         } while (size == SEGSIZE);
711 abort:
712         (void) fclose(file);
713 }
714
715 void
716 justquit(int sig __unused)
717 {
718         exit(0);
719 }
720
721
722 /*
723  * Receive a file.
724  */
725 void
726 recvfile(struct formats *pf)
727 {
728         struct tftphdr *dp;
729         struct tftphdr *ap;    /* ack buffer */
730         int n, size;
731         volatile unsigned short block;
732
733         signal(SIGALRM, timer);
734         dp = w_init();
735         ap = (struct tftphdr *)ackbuf;
736         block = 0;
737         do {
738                 timeouts = 0;
739                 ap->th_opcode = htons((u_short)ACK);
740                 ap->th_block = htons((u_short)block);
741                 block++;
742                 (void) setjmp(timeoutbuf);
743 send_ack:
744                 if (send(peer, ackbuf, 4, 0) != 4) {
745                         syslog(LOG_ERR, "write: %m");
746                         goto abort;
747                 }
748                 write_behind(file, pf->f_convert);
749                 for ( ; ; ) {
750                         alarm(rexmtval);
751                         n = recv(peer, dp, PKTSIZE, 0);
752                         alarm(0);
753                         if (n < 0) {            /* really? */
754                                 syslog(LOG_ERR, "read: %m");
755                                 goto abort;
756                         }
757                         dp->th_opcode = ntohs((u_short)dp->th_opcode);
758                         dp->th_block = ntohs((u_short)dp->th_block);
759                         if (dp->th_opcode == ERROR)
760                                 goto abort;
761                         if (dp->th_opcode == DATA) {
762                                 if (dp->th_block == block) {
763                                         break;   /* normal */
764                                 }
765                                 /* Re-synchronize with the other side */
766                                 (void) synchnet(peer);
767                                 if (dp->th_block == (block-1))
768                                         goto send_ack;          /* rexmit */
769                         }
770                 }
771                 /*  size = write(file, dp->th_data, n - 4); */
772                 size = writeit(file, &dp, n - 4, pf->f_convert);
773                 if (size != (n-4)) {                    /* ahem */
774                         if (size < 0) nak(errno + 100);
775                         else nak(ENOSPACE);
776                         goto abort;
777                 }
778         } while (size == SEGSIZE);
779         write_behind(file, pf->f_convert);
780         (void) fclose(file);            /* close data file */
781
782         ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
783         ap->th_block = htons((u_short)(block));
784         (void) send(peer, ackbuf, 4, 0);
785
786         signal(SIGALRM, justquit);      /* just quit on timeout */
787         alarm(rexmtval);
788         n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
789         alarm(0);
790         if (n >= 4 &&                   /* if read some data */
791             dp->th_opcode == DATA &&    /* and got a data block */
792             block == dp->th_block) {    /* then my last ack was lost */
793                 (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
794         }
795 abort:
796         return;
797 }
798
799 struct errmsg {
800         int     e_code;
801         const char      *e_msg;
802 } errmsgs[] = {
803         { EUNDEF,       "Undefined error code" },
804         { ENOTFOUND,    "File not found" },
805         { EACCESS,      "Access violation" },
806         { ENOSPACE,     "Disk full or allocation exceeded" },
807         { EBADOP,       "Illegal TFTP operation" },
808         { EBADID,       "Unknown transfer ID" },
809         { EEXISTS,      "File already exists" },
810         { ENOUSER,      "No such user" },
811         { EOPTNEG,      "Option negotiation" },
812         { -1,           0 }
813 };
814
815 static const char *
816 errtomsg(int error)
817 {
818         static char ebuf[20];
819         struct errmsg *pe;
820         if (error == 0)
821                 return "success";
822         for (pe = errmsgs; pe->e_code >= 0; pe++)
823                 if (pe->e_code == error)
824                         return pe->e_msg;
825         snprintf(ebuf, sizeof(buf), "error %d", error);
826         return ebuf;
827 }
828
829 /*
830  * Send a nak packet (error message).
831  * Error code passed in is one of the
832  * standard TFTP codes, or a UNIX errno
833  * offset by 100.
834  */
835 static void
836 nak(int error)
837 {
838         struct tftphdr *tp;
839         int length;
840         struct errmsg *pe;
841
842         tp = (struct tftphdr *)buf;
843         tp->th_opcode = htons((u_short)ERROR);
844         tp->th_code = htons((u_short)error);
845         for (pe = errmsgs; pe->e_code >= 0; pe++)
846                 if (pe->e_code == error)
847                         break;
848         if (pe->e_code < 0) {
849                 pe->e_msg = strerror(error - 100);
850                 tp->th_code = EUNDEF;   /* set 'undef' errorcode */
851         }
852         strcpy(tp->th_msg, pe->e_msg);
853         length = strlen(pe->e_msg);
854         tp->th_msg[length] = '\0';
855         length += 5;
856         if (send(peer, buf, length, 0) != length)
857                 syslog(LOG_ERR, "nak: %m");
858 }
859
860 /* translate IPv4 mapped IPv6 address to IPv4 address */
861 static void
862 unmappedaddr(struct sockaddr_in6 *sin6)
863 {
864         struct sockaddr_in *sin4;
865         u_int32_t addr;
866         int port;
867
868         if (sin6->sin6_family != AF_INET6 ||
869             !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
870                 return;
871         sin4 = (struct sockaddr_in *)sin6;
872         addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
873         port = sin6->sin6_port;
874         memset(sin4, 0, sizeof(struct sockaddr_in));
875         sin4->sin_addr.s_addr = addr;
876         sin4->sin_port = port;
877         sin4->sin_family = AF_INET;
878         sin4->sin_len = sizeof(struct sockaddr_in);
879 }
880
881 /*
882  * Send an oack packet (option acknowledgement).
883  */
884 static void
885 oack(void)
886 {
887         struct tftphdr *tp, *ap;
888         int size, i, n;
889         char *bp;
890
891         tp = (struct tftphdr *)buf;
892         bp = buf + 2;
893         size = sizeof(buf) - 2;
894         tp->th_opcode = htons((u_short)OACK);
895         for (i = 0; options[i].o_type != NULL; i++) {
896                 if (options[i].o_request) {
897                         n = snprintf(bp, size, "%s%c%d", options[i].o_type,
898                                      0, options[i].o_reply);
899                         bp += n+1;
900                         size -= n+1;
901                         if (size < 0) {
902                                 syslog(LOG_ERR, "oack: buffer overflow");
903                                 exit(1);
904                         }
905                 }
906         }
907         size = bp - buf;
908         ap = (struct tftphdr *)ackbuf;
909         signal(SIGALRM, timer);
910         timeouts = 0;
911
912         (void)setjmp(timeoutbuf);
913         if (send(peer, buf, size, 0) != size) {
914                 syslog(LOG_INFO, "oack: %m");
915                 exit(1);
916         }
917
918         for (;;) {
919                 alarm(rexmtval);
920                 n = recv(peer, ackbuf, sizeof (ackbuf), 0);
921                 alarm(0);
922                 if (n < 0) {
923                         syslog(LOG_ERR, "recv: %m");
924                         exit(1);
925                 }
926                 ap->th_opcode = ntohs((u_short)ap->th_opcode);
927                 ap->th_block = ntohs((u_short)ap->th_block);
928                 if (ap->th_opcode == ERROR)
929                         exit(1);
930                 if (ap->th_opcode == ACK && ap->th_block == 0)
931                         break;
932         }
933 }