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

1.1       misho       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>