1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is free software; you can redistribute it and/or modify
4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   it under the terms of the GNU General Public License as published by
5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   the Free Software Foundation; version 2 dated June, 1991, or
6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   (at your option) version 3 dated 29 June, 2007.
7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is distributed in the hope that it will be useful,
9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   but WITHOUT ANY WARRANTY; without even the implied warranty of
10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   GNU General Public License for more details.
12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   You should have received a copy of the GNU General Public License
14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/
16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h"
18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_TFTP
20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct tftp_file *check_tftp_fileperm(ssize_t *len);
22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_transfer(struct tftp_transfer *transfer);
23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err(int err, char *packet, char *mess, char *file);
24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err_oops(char *packet, char *file);
25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t get_block(char *packet, struct tftp_transfer *transfer);
26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic char *next(char **p, char *end);
27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_RRQ  1
29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_WRQ  2
30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_DATA 3
31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_ACK  4
32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_ERR  5
33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_OACK 6
34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_NOTDEF 0
36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_FNF    1
37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_PERM   2
38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_FULL   3
39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_ILL    4
40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid tftp_request(struct listener *listen, time_t now)
42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ssize_t len;
44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *packet = daemon->packet;
45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *filename, *mode, *p, *end, *opt;
46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct sockaddr_in addr, peer;
47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct msghdr msg;
48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct iovec iov;
49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ifreq ifr;
50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int is_err = 1, if_index = 0, mtu = 0;
51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct iname *tmp;
52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct tftp_transfer *transfer;
53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int mtuflag = IP_PMTUDISC_DONT;
56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  union {
59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    struct cmsghdr align; /* this ensures alignment */
60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK)
63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(unsigned int))];
64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } control_u;
68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_controllen = sizeof(control_u);
70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_control = control_u.control;
71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_flags = 0;
72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_name = &peer;
73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_namelen = sizeof(peer);
74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iov = &iov;
75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iovlen = 1;
76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov.iov_base = packet;
78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov.iov_len = daemon->packet_buff_sz;
79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* we overwrote the buffer... */
81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  daemon->srv_save = NULL;
82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->options & OPT_NOWILD)
87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      addr = listen->iface->addr.in;
89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      mtu = listen->iface->mtu;
90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      char name[IF_NAMESIZE];
94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct cmsghdr *cmptr;
95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      addr.sin_addr.s_addr = 0;
97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  {
102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  }
105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK)
107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if_index = *((unsigned int *)CMSG_DATA(cmptr));
112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!indextoname(listen->tftpfd, if_index, name) ||
124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  addr.sin_addr.s_addr == 0 ||
125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index))
126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return;
127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* allowed interfaces are the same as for DHCP */
129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (tmp->name && (strcmp(tmp->name, name) == 0))
131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return;
132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      strncpy(name, ifr.ifr_name, IF_NAMESIZE);
134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	mtu = ifr.ifr_mtu;
136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  addr.sin_port = htons(port);
139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  addr.sin_family = AF_INET;
140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOCKADDR_SA_LEN
141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  addr.sin_len = sizeof(addr);
142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free(transfer);
150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return;
151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->peer = peer;
154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->timeout = now + 2;
155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->backoff = 1;
156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->block = 1;
157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->blocksize = 512;
158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->offset = 0;
159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->file = NULL;
160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->opt_blocksize = transfer->opt_transize = 0;
161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  transfer->netascii = transfer->carrylf = 0;
162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* if we have a nailed-down range, iterate until we find a free one. */
164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (1)
165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !fix_fd(transfer->sockfd))
171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (++port <= daemon->end_tftp_port)
175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  addr.sin_port = htons(port);
177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  continue;
178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free_transfer(transfer);
182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return;
183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      break;
185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  p = packet + 2;
188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  end = packet + len;
189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      !(filename = next(&p, end)) ||
192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      !(mode = next(&p, end)) ||
193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (strcasecmp(mode, "netascii") == 0)
198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	transfer->netascii = 1;
199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      while ((opt = next(&p, end)))
201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (strcasecmp(opt, "blksize") == 0)
203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if ((opt = next(&p, end)) &&
205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  !(daemon->options & OPT_TFTP_NOBLOCK))
206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->blocksize = atoi(opt);
208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (transfer->blocksize < 1)
209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    transfer->blocksize = 1;
210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* 32 bytes for IP, UDP and TFTP headers */
213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32)
214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    transfer->blocksize = (unsigned)mtu - 32;
215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->opt_blocksize = 1;
216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->block = 0;
217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      transfer->opt_transize = 1;
222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      transfer->block = 0;
223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* cope with backslashes from windows boxen. */
227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      while ((p = strchr(filename, '\\')))
228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	*p = '/';
229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      strcpy(daemon->namebuff, "/");
231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (daemon->tftp_prefix)
232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (daemon->tftp_prefix[0] == '/')
234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    daemon->namebuff[0] = 0;
235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  strncat(daemon->namebuff, daemon->tftp_prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/')
237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (daemon->options & OPT_TFTP_APREF)
240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      size_t oldlen = strlen(daemon->namebuff);
242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      struct stat statbuf;
243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff));
245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      /* remove unique-directory if it doesn't exist */
248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		daemon->namebuff[oldlen] = 0;
250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* Absolute pathnames OK if they match prefix */
253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (filename[0] == '/')
254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (strstr(filename, daemon->namebuff) == filename)
256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		daemon->namebuff[0] = 0;
257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      else
258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		filename++;
259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else if (filename[0] == '/')
262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	daemon->namebuff[0] = 0;
263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* check permissions and open file */
266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if ((transfer->file = check_tftp_fileperm(&len)))
267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if ((len = get_block(packet, transfer)) == -1)
269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    len = tftp_err_oops(packet, daemon->namebuff);
270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else
271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    is_err = 0;
272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (sendto(transfer->sockfd, packet, len, 0,
276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		(struct sockaddr *)&peer, sizeof(peer)) == -1 && errno == EINTR);
277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (is_err)
279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    free_transfer(transfer);
280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      my_syslog(MS_TFTP | LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      transfer->next = daemon->tftp_trans;
284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      daemon->tftp_trans = transfer;
285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct tftp_file *check_tftp_fileperm(ssize_t *len)
289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *packet = daemon->packet, *namebuff = daemon->namebuff;
291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct tftp_file *file;
292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct tftp_transfer *t;
293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  uid_t uid = geteuid();
294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct stat statbuf;
295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int fd = -1;
296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* trick to ban moving out of the subtree */
298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->tftp_prefix && strstr(namebuff, "/../"))
299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    goto perm;
300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((fd = open(namebuff, O_RDONLY)) == -1)
302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (errno == ENOENT)
304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return NULL;
307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else if (errno == EACCES)
309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto perm;
310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto oops;
312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* stat the file descriptor to avoid stat->open races */
315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (fstat(fd, &statbuf) == -1)
316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    goto oops;
317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* running as root, must be world-readable */
319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (uid == 0)
320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!(statbuf.st_mode & S_IROTH))
322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto perm;
323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* in secure mode, must be owned by user running dnsmasq */
325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else if ((daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    goto perm;
327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If we're doing many tranfers from the same file, only
329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     open it once this saves lots of file descriptors
330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     when mass-booting a big cluster, for instance.
331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     Be conservative and only share when inode and name match
332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     this keeps error messages sane. */
333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (t = daemon->tftp_trans; t; t = t->next)
334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (t->file->dev == statbuf.st_dev &&
335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	t->file->inode == statbuf.st_ino &&
336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	strcmp(t->file->filename, namebuff) == 0)
337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	close(fd);
339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	t->file->refcount++;
340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return t->file;
341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1)))
344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      errno = ENOMEM;
346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      goto oops;
347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file->fd = fd;
350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file->size = statbuf.st_size;
351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file->dev = statbuf.st_dev;
352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file->inode = statbuf.st_ino;
353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file->refcount = 1;
354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  strcpy(file->filename, namebuff);
355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return file;
356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perm:
358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  errno = EACCES;
359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  *len =  tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (fd != -1)
361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    close(fd);
362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat oops:
365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  *len =  tftp_err_oops(packet, namebuff);
366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (fd != -1)
367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    close(fd);
368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid check_tftp_listeners(fd_set *rset, time_t now)
372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct tftp_transfer *transfer, *tmp, **up;
374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ssize_t len;
375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct ack {
377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    unsigned short op, block;
378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } *mess = (struct ack *)daemon->packet;
379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Check for activity on any existing transfers */
381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      tmp = transfer->next;
384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (FD_ISSET(transfer->sockfd, rset))
386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* we overwrote the buffer... */
388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->srv_save = NULL;
389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block)
393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* Got ack, ensure we take the (re)transmit path */
395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->timeout = now;
396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->backoff = 0;
397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (transfer->block++ != 0)
398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    transfer->offset += transfer->blocksize - transfer->expansion;
399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      else if (ntohs(mess->op) == OP_ERR)
401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  char *p = daemon->packet + sizeof(struct ack);
403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  char *end = daemon->packet + len;
404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  char *err = next(&p, end);
405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* Sanitise error message */
406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!err)
407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    err = "";
408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  else
409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      char *q, *r;
411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      for (q = r = err; *r; r++)
412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			if (isprint((int)*r))
413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  *(q++) = *r;
414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      *q = 0;
415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  my_syslog(MS_TFTP | LOG_ERR, _("TFTP error %d %s received from %s"),
417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			    (int)ntohs(mess->block), err,
418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			    inet_ntoa(transfer->peer.sin_addr));
419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* Got err, ensure we take abort */
421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->timeout = now;
422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  transfer->backoff = 100;
423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (difftime(now, transfer->timeout) >= 0.0)
428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  int endcon = 0;
430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* timeout, retransmit */
432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  transfer->timeout += 1 + (1<<transfer->backoff);
433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* we overwrote the buffer... */
435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->srv_save = NULL;
436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if ((len = get_block(daemon->packet, transfer)) == -1)
438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      len = tftp_err_oops(daemon->packet, transfer->file->filename);
440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      endcon = 1;
441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else if (++transfer->backoff > 5)
443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      /* don't complain about timeout when we're awaiting the last
445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		 ACK, some clients never send it */
446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (len != 0)
447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		my_syslog(MS_TFTP | LOG_ERR, _("TFTP failed sending %s to %s"),
448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      len = 0;
450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (len != 0)
453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    while(sendto(transfer->sockfd, daemon->packet, len, 0,
454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 (struct sockaddr *)&transfer->peer, sizeof(transfer->peer)) == -1 && errno == EINTR);
455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (endcon || len == 0)
457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      /* unlink */
459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      *up = tmp;
460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      free_transfer(transfer);
461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      continue;
462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      up = &transfer->next;
466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_transfer(struct tftp_transfer *transfer)
470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  close(transfer->sockfd);
472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (transfer->file && (--transfer->file->refcount) == 0)
473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      close(transfer->file->fd);
475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free(transfer->file);
476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  free(transfer);
478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic char *next(char **p, char *end)
481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *ret = *p;
483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t len;
484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (*(end-1) != 0 ||
486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      *p == end ||
487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (len = strlen(ret)) == 0)
488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return NULL;
489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  *p += len + 1;
491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return ret;
492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err(int err, char *packet, char *message, char *file)
495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct errmess {
497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    unsigned short op, err;
498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char message[];
499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } *mess = (struct errmess *)packet;
500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ssize_t ret = 4;
501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *errstr = strerror(errno);
502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  mess->op = htons(OP_ERR);
504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  mess->err = htons(err);
505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ret += (snprintf(mess->message, 500,  message, file, errstr) + 1);
506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  my_syslog(MS_TFTP | LOG_ERR, "TFTP %s", mess->message);
507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return  ret;
509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err_oops(char *packet, char *file)
512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), file);
514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* return -1 for error, zero for done. */
517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t get_block(char *packet, struct tftp_transfer *transfer)
518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (transfer->block == 0)
520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* send OACK */
522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      char *p;
523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct oackmess {
524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	unsigned short op;
525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	char data[];
526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      } *mess = (struct oackmess *)packet;
527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      p = mess->data;
529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      mess->op = htons(OP_OACK);
530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (transfer->opt_blocksize)
531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  p += (sprintf(p, "blksize") + 1);
533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  p += (sprintf(p, "%d", transfer->blocksize) + 1);
534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (transfer->opt_transize)
536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  p += (sprintf(p,"tsize") + 1);
538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return p - packet;
542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* send data packet */
546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct datamess {
547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	unsigned short op, block;
548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	unsigned char data[];
549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      } *mess = (struct datamess *)packet;
550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      size_t size = transfer->file->size - transfer->offset;
552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (transfer->offset > transfer->file->size)
554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return 0; /* finished */
555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (size > transfer->blocksize)
557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	size = transfer->blocksize;
558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      mess->op = htons(OP_DATA);
560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      mess->block = htons((unsigned short)(transfer->block));
561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !read_write(transfer->file->fd, mess->data, size, 1))
564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return -1;
565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      transfer->expansion = 0;
567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* Map '\n' to CR-LF in netascii mode */
569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (transfer->netascii)
570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  size_t i;
572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  int newcarrylf;
573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  for (i = 0, newcarrylf = 0; i < size; i++)
575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      {
577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		if (size == transfer->blocksize)
578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  {
579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    transfer->expansion++;
580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    if (i == size - 1)
581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      newcarrylf = 1; /* don't expand LF again if it moves to the next block */
582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  }
583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		else
584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  size++; /* room in this block */
585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		/* make space and insert CR */
587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		mess->data[i] = '\r';
589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		i++;
591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      }
592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  transfer->carrylf = newcarrylf;
593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return size + 4;
597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
601