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

1.1.1.2 ! misho       1: /* dnsmasq is Copyright (c) 2000-2014 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:          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: 
1.1.1.2 ! misho     205:       if (daemon->tftp_interfaces)
1.1       misho     206:        {
1.1.1.2 ! misho     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)
1.1       misho     213:            return;
                    214:        }
1.1.1.2 ! misho     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:          
1.1       misho     227: #ifdef HAVE_DHCP      
1.1.1.2 ! misho     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;
1.1       misho     232: #endif
1.1.1.2 ! misho     233:        }
        !           234: 
1.1       misho     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 */
1.1.1.2 ! misho     576:          else if (++transfer->backoff > 7 && len != 0)
1.1       misho     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>