Annotation of embedaddon/dnsmasq/src/tftp.c, revision 1.1.1.3

1.1.1.3 ! misho       1: /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
1.1       misho       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;
1.1.1.2   misho      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
1.1       misho      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;
1.1.1.2   misho      99: 
                    100:   /* Can always get recvd interface for IPv6 */
                    101:   if (!check_dest)
1.1       misho     102:     {
                    103:       if (listen->iface)
                    104:        {
                    105:          addr = listen->iface->addr;
                    106:          name = listen->iface->name;
1.1.1.3 ! misho     107:          mtu = listen->iface->mtu;
        !           108:          if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
        !           109:            mtu = daemon->tftp_mtu;
1.1       misho     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: 
1.1.1.2   misho     207:       if (daemon->tftp_interfaces)
1.1       misho     208:        {
1.1.1.2   misho     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)
1.1       misho     215:            return;
                    216:        }
1.1.1.2   misho     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:          
1.1       misho     229: #ifdef HAVE_DHCP      
1.1.1.2   misho     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;
1.1       misho     234: #endif
1.1.1.2   misho     235:        }
                    236: 
1.1       misho     237:       strncpy(ifr.ifr_name, name, IF_NAMESIZE);
                    238:       if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
1.1.1.3 ! misho     239:        {
        !           240:          mtu = ifr.ifr_mtu;  
        !           241:          if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
        !           242:            mtu = daemon->tftp_mtu;    
        !           243:        }
1.1       misho     244:     }
1.1.1.3 ! misho     245: 
        !           246:   /* Failed to get interface mtu - can use configured value. */
        !           247:   if (mtu == 0)
        !           248:     mtu = daemon->tftp_mtu;
        !           249: 
1.1       misho     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:                {
1.1.1.3 ! misho     349:                  /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
        !           350:                  int overhead = (listen->family == AF_INET) ? 32 : 52;
1.1       misho     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;
1.1.1.3 ! misho     356:                  if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
        !           357:                    transfer->blocksize = (unsigned)mtu - overhead;
1.1       misho     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: 
1.1.1.3 ! misho     516: void check_tftp_listeners(time_t now)
1.1       misho     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:      
1.1.1.3 ! misho     532:       if (poll_check(transfer->sockfd, POLLIN))
1.1       misho     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 */
1.1.1.2   misho     587:          else if (++transfer->backoff > 7 && len != 0)
1.1       misho     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>