Diff for /embedaddon/dnsmasq/src/tftp.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2021/03/17 00:56:46 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 19 Line 19
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
   
 static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);  static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client);
 static void free_transfer(struct tftp_transfer *transfer);  static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *message, char *file);static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2);
static ssize_t tftp_err_oops(char *packet, char *file);static ssize_t tftp_err_oops(char *packet, const char *file);
 static ssize_t get_block(char *packet, struct tftp_transfer *transfer);  static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
 static char *next(char **p, char *end);  static char *next(char **p, char *end);
 static void sanitise(char *buf);  static void sanitise(char *buf);
Line 39  static void sanitise(char *buf); Line 39  static void sanitise(char *buf);
 #define ERR_PERM   2  #define ERR_PERM   2
 #define ERR_FULL   3  #define ERR_FULL   3
 #define ERR_ILL    4  #define ERR_ILL    4
   #define ERR_TID    5
   
 void tftp_request(struct listener *listen, time_t now)  void tftp_request(struct listener *listen, time_t now)
 {  {
Line 95  void tftp_request(struct listener *listen, time_t now) Line 96  void tftp_request(struct listener *listen, time_t now)
   if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)    if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
     return;      return;
   
   #ifdef HAVE_DUMPFILE
     dump_packet_udp(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, listen->tftpfd);
   #endif
     
   /* Can always get recvd interface for IPv6 */    /* Can always get recvd interface for IPv6 */
   if (!check_dest)    if (!check_dest)
     {      {
Line 361  void tftp_request(struct listener *listen, time_t now) Line 366  void tftp_request(struct listener *listen, time_t now)
       !(mode = next(&p, end)) ||        !(mode = next(&p, end)) ||
       (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))        (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
     {      {
      len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);      len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff, NULL);
       is_err = 1;        is_err = 1;
     }      }
   else    else
Line 400  void tftp_request(struct listener *listen, time_t now) Line 405  void tftp_request(struct listener *listen, time_t now)
         if (*p == '\\')          if (*p == '\\')
           *p = '/';            *p = '/';
         else if (option_bool(OPT_TFTP_LC))          else if (option_bool(OPT_TFTP_LC))
          *p = tolower(*p);          *p = tolower((unsigned char)*p);
                                   
       strcpy(daemon->namebuff, "/");        strcpy(daemon->namebuff, "/");
       if (prefix)        if (prefix)
Line 471  void tftp_request(struct listener *listen, time_t now) Line 476  void tftp_request(struct listener *listen, time_t now)
       strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));        strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
               
       /* check permissions and open file */        /* check permissions and open file */
      if ((transfer->file = check_tftp_fileperm(&len, prefix)))      if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
         {          {
           if ((len = get_block(packet, transfer)) == -1)            if ((len = get_block(packet, transfer)) == -1)
             len = tftp_err_oops(packet, daemon->namebuff);              len = tftp_err_oops(packet, daemon->namebuff);
Line 481  void tftp_request(struct listener *listen, time_t now) Line 486  void tftp_request(struct listener *listen, time_t now)
     }      }
   
   send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);    send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);
   
   #ifdef HAVE_DUMPFILE
     dump_packet_udp(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
   #endif
       
   if (is_err)    if (is_err)
     free_transfer(transfer);      free_transfer(transfer);
Line 491  void tftp_request(struct listener *listen, time_t now) Line 500  void tftp_request(struct listener *listen, time_t now)
     }      }
 }  }
     
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client)
 {  {
   char *packet = daemon->packet, *namebuff = daemon->namebuff;    char *packet = daemon->packet, *namebuff = daemon->namebuff;
   struct tftp_file *file;    struct tftp_file *file;
Line 508  static struct tftp_file *check_tftp_fileperm(ssize_t * Line 517  static struct tftp_file *check_tftp_fileperm(ssize_t *
     {      {
       if (errno == ENOENT)        if (errno == ENOENT)
         {          {
          *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);          *len = tftp_err(ERR_FNF, packet, _("file %s not found for %s"), namebuff, client);
           return NULL;            return NULL;
         }          }
       else if (errno == EACCES)        else if (errno == EACCES)
Line 561  static struct tftp_file *check_tftp_fileperm(ssize_t * Line 570  static struct tftp_file *check_tftp_fileperm(ssize_t *
   return file;    return file;
       
  perm:   perm:
  errno = EACCES;  *len =  tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff, strerror(EACCES));
  *len =  tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff); 
   if (fd != -1)    if (fd != -1)
     close(fd);      close(fd);
   return NULL;    return NULL;
Line 583  void check_tftp_listeners(time_t now) Line 591  void check_tftp_listeners(time_t now)
     for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)      for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
       if (poll_check(transfer->sockfd, POLLIN))        if (poll_check(transfer->sockfd, POLLIN))
         {          {
             union mysockaddr peer;
             socklen_t addr_len = sizeof(union mysockaddr);
             ssize_t len;
             
           /* we overwrote the buffer... */            /* we overwrote the buffer... */
           daemon->srv_save = NULL;            daemon->srv_save = NULL;
           handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));  
         }  
   
             if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
               {
                 if (sockaddr_isequal(&peer, &transfer->peer)) 
                   handle_tftp(now, transfer, len);
                 else
                   {
                     /* Wrong source address. See rfc1350 para 4. */
                     prettyprint_addr(&peer, daemon->addrbuff);
                     len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
                     while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
   
   #ifdef HAVE_DUMPFILE
                     dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
   #endif
                   }
               }
           }
             
   for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)    for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
     {      {
       tmp = transfer->next;        tmp = transfer->next;
Line 602  void check_tftp_listeners(time_t now) Line 630  void check_tftp_listeners(time_t now)
                                       
           /* we overwrote the buffer... */            /* we overwrote the buffer... */
           daemon->srv_save = NULL;            daemon->srv_save = NULL;
         
           if ((len = get_block(daemon->packet, transfer)) == -1)            if ((len = get_block(daemon->packet, transfer)) == -1)
             {              {
               len = tftp_err_oops(daemon->packet, transfer->file->filename);                len = tftp_err_oops(daemon->packet, transfer->file->filename);
Line 618  void check_tftp_listeners(time_t now) Line 646  void check_tftp_listeners(time_t now)
             }              }
   
           if (len != 0)            if (len != 0)
            send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,            {
                      &transfer->peer, &transfer->source, transfer->if_index);              send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
                                          &transfer->peer, &transfer->source, transfer->if_index);
 #ifdef HAVE_DUMPFILE
               dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd);
 #endif
             }
           
           if (endcon || len == 0)            if (endcon || len == 0)
             {              {
               strcpy(daemon->namebuff, transfer->file->filename);                strcpy(daemon->namebuff, transfer->file->filename);
Line 726  static void sanitise(char *buf) Line 759  static void sanitise(char *buf)
 }  }
   
 #define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */   #define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */ 
static ssize_t tftp_err(int err, char *packet, char *message, char *file)static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2)
 {  {
   struct errmess {    struct errmess {
     unsigned short op, err;      unsigned short op, err;
     char message[];      char message[];
   } *mess = (struct errmess *)packet;    } *mess = (struct errmess *)packet;
   ssize_t len, ret = 4;    ssize_t len, ret = 4;
  char *errstr = strerror(errno);    
   
   memset(packet, 0, daemon->packet_buff_sz);    memset(packet, 0, daemon->packet_buff_sz);
  sanitise(file);  if (file)
     sanitise(file);
       
   mess->op = htons(OP_ERR);    mess->op = htons(OP_ERR);
   mess->err = htons(err);    mess->err = htons(err);
  len = snprintf(mess->message, MAXMESSAGE,  message, file, errstr);  len = snprintf(mess->message, MAXMESSAGE,  message, file, arg2);
   ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */    ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
       
  my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);  if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
     my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
       
   return  ret;    return  ret;
 }  }
   
static ssize_t tftp_err_oops(char *packet, char *file)static ssize_t tftp_err_oops(char *packet, const char *file)
 {  {
   /* May have >1 refs to file, so potentially mangle a copy of the name */    /* May have >1 refs to file, so potentially mangle a copy of the name */
  strcpy(daemon->namebuff, file);  if (file != daemon->namebuff)
  return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);    strcpy(daemon->namebuff, file);
   return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff, strerror(errno));
 }  }
   
 /* return -1 for error, zero for done. */  /* return -1 for error, zero for done. */

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


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