File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / tftp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 8 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_76p1, HEAD
dnsmasq 2.76

    1: /* dnsmasq is Copyright (c) 2000-2016 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, char *prefix);
   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: static void sanitise(char *buf);
   28: 
   29: #define OP_RRQ  1
   30: #define OP_WRQ  2
   31: #define OP_DATA 3
   32: #define OP_ACK  4
   33: #define OP_ERR  5
   34: #define OP_OACK 6
   35: 
   36: #define ERR_NOTDEF 0
   37: #define ERR_FNF    1
   38: #define ERR_PERM   2
   39: #define ERR_FULL   3
   40: #define ERR_ILL    4
   41: 
   42: void tftp_request(struct listener *listen, time_t now)
   43: {
   44:   ssize_t len;
   45:   char *packet = daemon->packet;
   46:   char *filename, *mode, *p, *end, *opt;
   47:   union mysockaddr addr, peer;
   48:   struct msghdr msg;
   49:   struct iovec iov;
   50:   struct ifreq ifr;
   51:   int is_err = 1, if_index = 0, mtu = 0;
   52:   struct iname *tmp;
   53:   struct tftp_transfer *transfer;
   54:   int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
   55: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
   56:   int mtuflag = IP_PMTUDISC_DONT;
   57: #endif
   58:   char namebuff[IF_NAMESIZE];
   59:   char *name = NULL;
   60:   char *prefix = daemon->tftp_prefix;
   61:   struct tftp_prefix *pref;
   62:   struct all_addr addra;
   63: #ifdef HAVE_IPV6
   64:   /* Can always get recvd interface for IPv6 */
   65:   int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
   66: #else
   67:   int check_dest = !option_bool(OPT_NOWILD);
   68: #endif
   69:   union {
   70:     struct cmsghdr align; /* this ensures alignment */
   71: #ifdef HAVE_IPV6
   72:     char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
   73: #endif
   74: #if defined(HAVE_LINUX_NETWORK)
   75:     char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
   76: #elif defined(HAVE_SOLARIS_NETWORK)
   77:     char control[CMSG_SPACE(sizeof(unsigned int))];
   78: #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
   79:     char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
   80: #endif
   81:   } control_u; 
   82: 
   83:   msg.msg_controllen = sizeof(control_u);
   84:   msg.msg_control = control_u.control;
   85:   msg.msg_flags = 0;
   86:   msg.msg_name = &peer;
   87:   msg.msg_namelen = sizeof(peer);
   88:   msg.msg_iov = &iov;
   89:   msg.msg_iovlen = 1;
   90: 
   91:   iov.iov_base = packet;
   92:   iov.iov_len = daemon->packet_buff_sz;
   93: 
   94:   /* we overwrote the buffer... */
   95:   daemon->srv_save = NULL;
   96: 
   97:   if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
   98:     return;
   99: 
  100:   /* Can always get recvd interface for IPv6 */
  101:   if (!check_dest)
  102:     {
  103:       if (listen->iface)
  104: 	{
  105: 	  addr = listen->iface->addr;
  106: 	  name = listen->iface->name;
  107: 	  mtu = listen->iface->mtu;
  108: 	  if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
  109: 	    mtu = daemon->tftp_mtu;
  110: 	}
  111:       else
  112: 	{
  113: 	  /* we're listening on an address that doesn't appear on an interface,
  114: 	     ask the kernel what the socket is bound to */
  115: 	  socklen_t tcp_len = sizeof(union mysockaddr);
  116: 	  if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
  117: 	    return;
  118: 	}
  119:     }
  120:   else
  121:     {
  122:       struct cmsghdr *cmptr;
  123: 
  124:       if (msg.msg_controllen < sizeof(struct cmsghdr))
  125:         return;
  126:       
  127:       addr.sa.sa_family = listen->family;
  128:       
  129: #if defined(HAVE_LINUX_NETWORK)
  130:       if (listen->family == AF_INET)
  131: 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
  132: 	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
  133: 	    {
  134: 	      union {
  135: 		unsigned char *c;
  136: 		struct in_pktinfo *p;
  137: 	      } p;
  138: 	      p.c = CMSG_DATA(cmptr);
  139: 	      addr.in.sin_addr = p.p->ipi_spec_dst;
  140: 	      if_index = p.p->ipi_ifindex;
  141: 	    }
  142:       
  143: #elif defined(HAVE_SOLARIS_NETWORK)
  144:       if (listen->family == AF_INET)
  145: 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
  146: 	  {
  147: 	    union {
  148: 	      unsigned char *c;
  149: 	      struct in_addr *a;
  150: 	      unsigned int *i;
  151: 	    } p;
  152: 	    p.c = CMSG_DATA(cmptr);
  153: 	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
  154: 	    addr.in.sin_addr = *(p.a);
  155: 	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
  156: 	    if_index = *(p.i);
  157: 	  }
  158:       
  159: #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
  160:       if (listen->family == AF_INET)
  161: 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
  162: 	  {
  163: 	    union {
  164: 	      unsigned char *c;
  165: 	      struct in_addr *a;
  166: 	      struct sockaddr_dl *s;
  167: 	    } p;
  168: 	    p.c = CMSG_DATA(cmptr);
  169: 	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
  170: 	      addr.in.sin_addr = *(p.a);
  171: 	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
  172: 	      if_index = p.s->sdl_index;
  173: 	  }
  174: 	  
  175: #endif
  176: 
  177: #ifdef HAVE_IPV6
  178:       if (listen->family == AF_INET6)
  179:         {
  180:           for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
  181:             if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
  182:               {
  183:                 union {
  184:                   unsigned char *c;
  185:                   struct in6_pktinfo *p;
  186:                 } p;
  187:                 p.c = CMSG_DATA(cmptr);
  188:                   
  189:                 addr.in6.sin6_addr = p.p->ipi6_addr;
  190:                 if_index = p.p->ipi6_ifindex;
  191:               }
  192:         }
  193: #endif
  194:       
  195:       if (!indextoname(listen->tftpfd, if_index, namebuff))
  196: 	return;
  197: 
  198:       name = namebuff;
  199:       
  200:       addra.addr.addr4 = addr.in.sin_addr;
  201: 
  202: #ifdef HAVE_IPV6
  203:       if (listen->family == AF_INET6)
  204: 	addra.addr.addr6 = addr.in6.sin6_addr;
  205: #endif
  206: 
  207:       if (daemon->tftp_interfaces)
  208: 	{
  209: 	  /* dedicated tftp interface list */
  210: 	  for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
  211: 	    if (tmp->name && wildcard_match(tmp->name, name))
  212: 	      break;
  213: 
  214: 	  if (!tmp)
  215: 	    return;
  216: 	}
  217:       else
  218: 	{
  219: 	  /* Do the same as DHCP */
  220: 	  if (!iface_check(listen->family, &addra, name, NULL))
  221: 	    {
  222: 	      if (!option_bool(OPT_CLEVERBIND))
  223: 		enumerate_interfaces(0); 
  224: 	      if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
  225: 		  !label_exception(if_index, listen->family, &addra) )
  226: 		return;
  227: 	    }
  228: 	  
  229: #ifdef HAVE_DHCP      
  230: 	  /* allowed interfaces are the same as for DHCP */
  231: 	  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
  232: 	    if (tmp->name && wildcard_match(tmp->name, name))
  233: 	      return;
  234: #endif
  235: 	}
  236: 
  237:       strncpy(ifr.ifr_name, name, IF_NAMESIZE);
  238:       if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
  239: 	{
  240: 	  mtu = ifr.ifr_mtu;  
  241: 	  if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
  242: 	    mtu = daemon->tftp_mtu;    
  243: 	}
  244:     }
  245: 
  246:   /* Failed to get interface mtu - can use configured value. */
  247:   if (mtu == 0)
  248:     mtu = daemon->tftp_mtu;
  249: 
  250:   if (name)
  251:     {
  252:       /* check for per-interface prefix */ 
  253:       for (pref = daemon->if_prefix; pref; pref = pref->next)
  254: 	if (strcmp(pref->interface, name) == 0)
  255: 	  prefix = pref->prefix;  
  256:     }
  257: 
  258:   if (listen->family == AF_INET)
  259:     {
  260:       addr.in.sin_port = htons(port);
  261: #ifdef HAVE_SOCKADDR_SA_LEN
  262:       addr.in.sin_len = sizeof(addr.in);
  263: #endif
  264:     }
  265: #ifdef HAVE_IPV6
  266:   else
  267:     {
  268:       addr.in6.sin6_port = htons(port);
  269:       addr.in6.sin6_flowinfo = 0;
  270:       addr.in6.sin6_scope_id = 0;
  271: #ifdef HAVE_SOCKADDR_SA_LEN
  272:       addr.in6.sin6_len = sizeof(addr.in6);
  273: #endif
  274:     }
  275: #endif
  276: 
  277:   if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
  278:     return;
  279:   
  280:   if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
  281:     {
  282:       free(transfer);
  283:       return;
  284:     }
  285:   
  286:   transfer->peer = peer;
  287:   transfer->timeout = now + 2;
  288:   transfer->backoff = 1;
  289:   transfer->block = 1;
  290:   transfer->blocksize = 512;
  291:   transfer->offset = 0;
  292:   transfer->file = NULL;
  293:   transfer->opt_blocksize = transfer->opt_transize = 0;
  294:   transfer->netascii = transfer->carrylf = 0;
  295:  
  296:   prettyprint_addr(&peer, daemon->addrbuff);
  297:   
  298:   /* if we have a nailed-down range, iterate until we find a free one. */
  299:   while (1)
  300:     {
  301:       if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
  302: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
  303: 	  setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
  304: #endif
  305: 	  !fix_fd(transfer->sockfd))
  306: 	{
  307: 	  if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
  308: 	    {
  309: 	      if (++port <= daemon->end_tftp_port)
  310: 		{ 
  311: 		  if (listen->family == AF_INET)
  312: 		    addr.in.sin_port = htons(port);
  313: #ifdef HAVE_IPV6
  314: 		  else
  315: 		     addr.in6.sin6_port = htons(port);
  316: #endif
  317: 		  continue;
  318: 		}
  319: 	      my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
  320: 	    }
  321: 	  free_transfer(transfer);
  322: 	  return;
  323: 	}
  324:       break;
  325:     }
  326:   
  327:   p = packet + 2;
  328:   end = packet + len;
  329: 
  330:   if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
  331:       !(filename = next(&p, end)) ||
  332:       !(mode = next(&p, end)) ||
  333:       (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
  334:     {
  335:       len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
  336:       is_err = 1;
  337:     }
  338:   else
  339:     {
  340:       if (strcasecmp(mode, "netascii") == 0)
  341: 	transfer->netascii = 1;
  342:       
  343:       while ((opt = next(&p, end)))
  344: 	{
  345: 	  if (strcasecmp(opt, "blksize") == 0)
  346: 	    {
  347: 	      if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
  348: 		{
  349: 		  /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
  350: 		  int overhead = (listen->family == AF_INET) ? 32 : 52;
  351: 		  transfer->blocksize = atoi(opt);
  352: 		  if (transfer->blocksize < 1)
  353: 		    transfer->blocksize = 1;
  354: 		  if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
  355: 		    transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
  356: 		  if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
  357: 		    transfer->blocksize = (unsigned)mtu - overhead;
  358: 		  transfer->opt_blocksize = 1;
  359: 		  transfer->block = 0;
  360: 		}
  361: 	    }
  362: 	  else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
  363: 	    {
  364: 	      transfer->opt_transize = 1;
  365: 	      transfer->block = 0;
  366: 	    }
  367: 	}
  368: 
  369:       /* cope with backslashes from windows boxen. */
  370:       for (p = filename; *p; p++)
  371: 	if (*p == '\\')
  372: 	  *p = '/';
  373: 	else if (option_bool(OPT_TFTP_LC))
  374: 	  *p = tolower(*p);
  375: 		
  376:       strcpy(daemon->namebuff, "/");
  377:       if (prefix)
  378: 	{
  379: 	  if (prefix[0] == '/')
  380: 	    daemon->namebuff[0] = 0;
  381: 	  strncat(daemon->namebuff, prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
  382: 	  if (prefix[strlen(prefix)-1] != '/')
  383: 	    strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
  384: 
  385: 	  if (option_bool(OPT_TFTP_APREF))
  386: 	    {
  387: 	      size_t oldlen = strlen(daemon->namebuff);
  388: 	      struct stat statbuf;
  389: 	      
  390: 	      strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
  391: 	      strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
  392: 	      
  393: 	      /* remove unique-directory if it doesn't exist */
  394: 	      if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
  395: 		daemon->namebuff[oldlen] = 0;
  396: 	    }
  397: 		
  398: 	  /* Absolute pathnames OK if they match prefix */
  399: 	  if (filename[0] == '/')
  400: 	    {
  401: 	      if (strstr(filename, daemon->namebuff) == filename)
  402: 		daemon->namebuff[0] = 0;
  403: 	      else
  404: 		filename++;
  405: 	    }
  406: 	}
  407:       else if (filename[0] == '/')
  408: 	daemon->namebuff[0] = 0;
  409:       strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
  410: 
  411:       /* check permissions and open file */
  412:       if ((transfer->file = check_tftp_fileperm(&len, prefix)))
  413: 	{
  414: 	  if ((len = get_block(packet, transfer)) == -1)
  415: 	    len = tftp_err_oops(packet, daemon->namebuff);
  416: 	  else
  417: 	    is_err = 0;
  418: 	}
  419:     }
  420:   
  421:   while (sendto(transfer->sockfd, packet, len, 0, 
  422: 		(struct sockaddr *)&peer, sa_len(&peer)) == -1 && errno == EINTR);
  423:   
  424:   if (is_err)
  425:     free_transfer(transfer);
  426:   else
  427:     {
  428:       transfer->next = daemon->tftp_trans;
  429:       daemon->tftp_trans = transfer;
  430:     }
  431: }
  432:  
  433: static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
  434: {
  435:   char *packet = daemon->packet, *namebuff = daemon->namebuff;
  436:   struct tftp_file *file;
  437:   struct tftp_transfer *t;
  438:   uid_t uid = geteuid();
  439:   struct stat statbuf;
  440:   int fd = -1;
  441: 
  442:   /* trick to ban moving out of the subtree */
  443:   if (prefix && strstr(namebuff, "/../"))
  444:     goto perm;
  445:   
  446:   if ((fd = open(namebuff, O_RDONLY)) == -1)
  447:     {
  448:       if (errno == ENOENT)
  449: 	{
  450: 	  *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
  451: 	  return NULL;
  452: 	}
  453:       else if (errno == EACCES)
  454: 	goto perm;
  455:       else
  456: 	goto oops;
  457:     }
  458:   
  459:   /* stat the file descriptor to avoid stat->open races */
  460:   if (fstat(fd, &statbuf) == -1)
  461:     goto oops;
  462:   
  463:   /* running as root, must be world-readable */
  464:   if (uid == 0)
  465:     {
  466:       if (!(statbuf.st_mode & S_IROTH))
  467: 	goto perm;
  468:     }
  469:   /* in secure mode, must be owned by user running dnsmasq */
  470:   else if (option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
  471:     goto perm;
  472:       
  473:   /* If we're doing many tranfers from the same file, only 
  474:      open it once this saves lots of file descriptors 
  475:      when mass-booting a big cluster, for instance. 
  476:      Be conservative and only share when inode and name match
  477:      this keeps error messages sane. */
  478:   for (t = daemon->tftp_trans; t; t = t->next)
  479:     if (t->file->dev == statbuf.st_dev && 
  480: 	t->file->inode == statbuf.st_ino &&
  481: 	strcmp(t->file->filename, namebuff) == 0)
  482:       {
  483: 	close(fd);
  484: 	t->file->refcount++;
  485: 	return t->file;
  486:       }
  487:   
  488:   if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1)))
  489:     {
  490:       errno = ENOMEM;
  491:       goto oops;
  492:     }
  493: 
  494:   file->fd = fd;
  495:   file->size = statbuf.st_size;
  496:   file->dev = statbuf.st_dev;
  497:   file->inode = statbuf.st_ino;
  498:   file->refcount = 1;
  499:   strcpy(file->filename, namebuff);
  500:   return file;
  501:   
  502:  perm:
  503:   errno = EACCES;
  504:   *len =  tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
  505:   if (fd != -1)
  506:     close(fd);
  507:   return NULL;
  508: 
  509:  oops:
  510:   *len =  tftp_err_oops(packet, namebuff);
  511:   if (fd != -1)
  512:     close(fd);
  513:   return NULL;
  514: }
  515: 
  516: void check_tftp_listeners(time_t now)
  517: {
  518:   struct tftp_transfer *transfer, *tmp, **up;
  519:   ssize_t len;
  520:   
  521:   struct ack {
  522:     unsigned short op, block;
  523:   } *mess = (struct ack *)daemon->packet;
  524:   
  525:   /* Check for activity on any existing transfers */
  526:   for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
  527:     {
  528:       tmp = transfer->next;
  529:       
  530:       prettyprint_addr(&transfer->peer, daemon->addrbuff);
  531:      
  532:       if (poll_check(transfer->sockfd, POLLIN))
  533: 	{
  534: 	  /* we overwrote the buffer... */
  535: 	  daemon->srv_save = NULL;
  536: 	  
  537: 	  if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
  538: 	    {
  539: 	      if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block) 
  540: 		{
  541: 		  /* Got ack, ensure we take the (re)transmit path */
  542: 		  transfer->timeout = now;
  543: 		  transfer->backoff = 0;
  544: 		  if (transfer->block++ != 0)
  545: 		    transfer->offset += transfer->blocksize - transfer->expansion;
  546: 		}
  547: 	      else if (ntohs(mess->op) == OP_ERR)
  548: 		{
  549: 		  char *p = daemon->packet + sizeof(struct ack);
  550: 		  char *end = daemon->packet + len;
  551: 		  char *err = next(&p, end);
  552: 		  
  553: 		  /* Sanitise error message */
  554: 		  if (!err)
  555: 		    err = "";
  556: 		  else
  557: 		    sanitise(err);
  558: 		  
  559: 		  my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
  560: 			    (int)ntohs(mess->block), err, 
  561: 			    daemon->addrbuff);	
  562: 		  
  563: 		  /* Got err, ensure we take abort */
  564: 		  transfer->timeout = now;
  565: 		  transfer->backoff = 100;
  566: 		}
  567: 	    }
  568: 	}
  569:       
  570:       if (difftime(now, transfer->timeout) >= 0.0)
  571: 	{
  572: 	  int endcon = 0;
  573: 
  574: 	  /* timeout, retransmit */
  575: 	  transfer->timeout += 1 + (1<<transfer->backoff);
  576: 	  	  
  577: 	  /* we overwrote the buffer... */
  578: 	  daemon->srv_save = NULL;
  579: 	 
  580: 	  if ((len = get_block(daemon->packet, transfer)) == -1)
  581: 	    {
  582: 	      len = tftp_err_oops(daemon->packet, transfer->file->filename);
  583: 	      endcon = 1;
  584: 	    }
  585: 	  /* don't complain about timeout when we're awaiting the last
  586: 	     ACK, some clients never send it */
  587: 	  else if (++transfer->backoff > 7 && len != 0)
  588: 	    {
  589: 	      endcon = 1;
  590: 	      len = 0;
  591: 	    }
  592: 
  593: 	  if (len != 0)
  594: 	    while(sendto(transfer->sockfd, daemon->packet, len, 0, 
  595: 			 (struct sockaddr *)&transfer->peer, sa_len(&transfer->peer)) == -1 && errno == EINTR);
  596: 	  
  597: 	  if (endcon || len == 0)
  598: 	    {
  599: 	      strcpy(daemon->namebuff, transfer->file->filename);
  600: 	      sanitise(daemon->namebuff);
  601: 	      my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
  602: 	      /* unlink */
  603: 	      *up = tmp;
  604: 	      if (endcon)
  605: 		free_transfer(transfer);
  606: 	      else
  607: 		{
  608: 		  /* put on queue to be sent to script and deleted */
  609: 		  transfer->next = daemon->tftp_done_trans;
  610: 		  daemon->tftp_done_trans = transfer;
  611: 		}
  612: 	      continue;
  613: 	    }
  614: 	}
  615: 
  616:       up = &transfer->next;
  617:     }    
  618: }
  619: 
  620: static void free_transfer(struct tftp_transfer *transfer)
  621: {
  622:   close(transfer->sockfd);
  623:   if (transfer->file && (--transfer->file->refcount) == 0)
  624:     {
  625:       close(transfer->file->fd);
  626:       free(transfer->file);
  627:     }
  628:   free(transfer);
  629: }
  630: 
  631: static char *next(char **p, char *end)
  632: {
  633:   char *ret = *p;
  634:   size_t len;
  635: 
  636:   if (*(end-1) != 0 || 
  637:       *p == end ||
  638:       (len = strlen(ret)) == 0)
  639:     return NULL;
  640: 
  641:   *p += len + 1;
  642:   return ret;
  643: }
  644: 
  645: static void sanitise(char *buf)
  646: {
  647:   unsigned char *q, *r;
  648:   for (q = r = (unsigned char *)buf; *r; r++)
  649:     if (isprint((int)*r))
  650:       *(q++) = *r;
  651:   *q = 0;
  652: 
  653: }
  654: 
  655: static ssize_t tftp_err(int err, char *packet, char *message, char *file)
  656: {
  657:   struct errmess {
  658:     unsigned short op, err;
  659:     char message[];
  660:   } *mess = (struct errmess *)packet;
  661:   ssize_t ret = 4;
  662:   char *errstr = strerror(errno);
  663:   
  664:   sanitise(file);
  665: 
  666:   mess->op = htons(OP_ERR);
  667:   mess->err = htons(err);
  668:   ret += (snprintf(mess->message, 500,  message, file, errstr) + 1);
  669:   my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
  670:   
  671:   return  ret;
  672: }
  673: 
  674: static ssize_t tftp_err_oops(char *packet, char *file)
  675: {
  676:   /* May have >1 refs to file, so potentially mangle a copy of the name */
  677:   strcpy(daemon->namebuff, file);
  678:   return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
  679: }
  680: 
  681: /* return -1 for error, zero for done. */
  682: static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
  683: {
  684:   if (transfer->block == 0)
  685:     {
  686:       /* send OACK */
  687:       char *p;
  688:       struct oackmess {
  689: 	unsigned short op;
  690: 	char data[];
  691:       } *mess = (struct oackmess *)packet;
  692:       
  693:       p = mess->data;
  694:       mess->op = htons(OP_OACK);
  695:       if (transfer->opt_blocksize)
  696: 	{
  697: 	  p += (sprintf(p, "blksize") + 1);
  698: 	  p += (sprintf(p, "%d", transfer->blocksize) + 1);
  699: 	}
  700:       if (transfer->opt_transize)
  701: 	{
  702: 	  p += (sprintf(p,"tsize") + 1);
  703: 	  p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
  704: 	}
  705: 
  706:       return p - packet;
  707:     }
  708:   else
  709:     {
  710:       /* send data packet */
  711:       struct datamess {
  712: 	unsigned short op, block;
  713: 	unsigned char data[];
  714:       } *mess = (struct datamess *)packet;
  715:       
  716:       size_t size = transfer->file->size - transfer->offset; 
  717:       
  718:       if (transfer->offset > transfer->file->size)
  719: 	return 0; /* finished */
  720:       
  721:       if (size > transfer->blocksize)
  722: 	size = transfer->blocksize;
  723:       
  724:       mess->op = htons(OP_DATA);
  725:       mess->block = htons((unsigned short)(transfer->block));
  726:       
  727:       if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
  728: 	  !read_write(transfer->file->fd, mess->data, size, 1))
  729: 	return -1;
  730:       
  731:       transfer->expansion = 0;
  732:       
  733:       /* Map '\n' to CR-LF in netascii mode */
  734:       if (transfer->netascii)
  735: 	{
  736: 	  size_t i;
  737: 	  int newcarrylf;
  738: 
  739: 	  for (i = 0, newcarrylf = 0; i < size; i++)
  740: 	    if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
  741: 	      {
  742: 		transfer->expansion++;
  743: 
  744: 		if (size != transfer->blocksize)
  745: 		  size++; /* room in this block */
  746: 		else  if (i == size - 1)
  747: 		  newcarrylf = 1; /* don't expand LF again if it moves to the next block */
  748: 		  
  749: 		/* make space and insert CR */
  750: 		memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
  751: 		mess->data[i] = '\r';
  752: 		
  753: 		i++;
  754: 	      }
  755: 	  transfer->carrylf = newcarrylf;
  756: 	  
  757: 	}
  758: 
  759:       return size + 4;
  760:     }
  761: }
  762: 
  763: 
  764: int do_tftp_script_run(void)
  765: {
  766:   struct tftp_transfer *transfer;
  767: 
  768:   if ((transfer = daemon->tftp_done_trans))
  769:     {
  770:       daemon->tftp_done_trans = transfer->next;
  771: #ifdef HAVE_SCRIPT
  772:       queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
  773: #endif
  774:       free_transfer(transfer);
  775:       return 1;
  776:     }
  777: 
  778:   return 0;
  779: }
  780: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>