File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / tftp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years, 2 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

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

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