File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / tftp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

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

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