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