tftpd源代码修改支持写请求

/*
 * Validate file access.  Since we
 * have no uid or gid, for now require
 * file to exist and be publicly
 * readable/writable.
 * If we were invoked with arguments
 * from inetd then the file must also be
 * in one of the given directory prefixes.
 * Note also, full path name must be
 * given as we have no login directory.
 */
int
validate_access (char **filep, int mode)
{
  struct stat stbuf;
  int fd;
  struct dirlist *dirp;
  static char *pathname = 0;
  char *filename = *filep;

  /*
   * Prevent tricksters from getting around the directory restrictions
   */
  if (strstr (filename, "/../"))
    return (EACCESS);

  if (*filename == '/')
    {
      /*
       * Allow the request if it's in one of the approved locations.
       * Special case: check the null prefix ("/") by looking
       * for length = 1 and relying on the arg. processing that
       * it's a /.
       */
      for (dirp = dirs; dirp->name != NULL; dirp++)
    {
      if (dirp->len == 1 ||
          (!strncmp (filename, dirp->name, dirp->len) &&
           filename[dirp->len] == '/'))
        break;
    }
      /* If directory list is empty, allow access to any file */
      if (dirp->name == NULL && dirp != dirs)
    return (EACCESS);
      if (stat (filename, &stbuf) < 0)
    return (errno == ENOENT ? ENOTFOUND : EACCESS);
      if ((stbuf.st_mode & S_IFMT) != S_IFREG)
    return (ENOTFOUND);
      if (mode == RRQ)
    {
      if ((stbuf.st_mode & S_IROTH) == 0)
        return (EACCESS);
    }
      else
    {
      if ((stbuf.st_mode & S_IWOTH) == 0)
        return (EACCESS);
    }
    }
  else
    {
      int err;

      /*
       * Relative file name: search the approved locations for it.
       * Don't allow write requests or ones that avoid directory
       * restrictions.        这里不支持写请求,去掉即可
       */

 //     if (mode != RRQ || !strncmp (filename, "../", 3))
      if ( !strncmp (filename, "../", 3))

    return (EACCESS);

      /*
       * If the file exists in one of the directories and isn't
       * readable, continue looking. However, change the error code
       * to give an indication that the file exists.
       */
      err = ENOTFOUND;
      for (dirp = dirs; dirp->name != NULL; dirp++)
    {
      free (pathname);
      pathname = malloc (strlen (dirp->name) + 1 + strlen (filename) + 1);
      if (!pathname)
        return ENOMEM;
      sprintf (pathname, "%s/%s", dirp->name, filename);
      if (stat (pathname, &stbuf) == 0 &&
          (stbuf.st_mode & S_IFMT) == S_IFREG)
        {
          if ((stbuf.st_mode & S_IROTH) != 0)
        {
          break;
        }
          err = EACCESS;
        }
    }


     /*
       * 这里要加上读请求才返回错误,如果是写请求直接创建文件
            */


      if (mode == RRQ)
    {
              if (dirp->name == NULL)
        return (err);
    }

//      if (dirp->name == NULL)
//    return (err);

      *filep = filename = pathname;
    }


     /*
       * 这里加上创建文件标志
            */

  fd = open (filename, mode == RRQ ? O_RDONLY : ( O_CREAT |O_WRONLY | O_TRUNC),0777);

//  fd = open (filename, mode == RRQ ? O_RDONLY : (O_WRONLY | O_TRUNC));
  if (fd < 0)
    return (errno + 100);
  file = fdopen (fd, (mode == RRQ) ? "r" : "w");
  if (file == NULL)
    {
      return errno + 100;
    }
  return (0);

}




/*
 * Send a nak packet (error message).
 * Error code passed in is one of the
 * standard TFTP codes, or a UNIX errno
 * offset by 100.
 */
static void
nak (int error)
{
  register struct tftphdr *tp;
  int length;
  register struct errmsg *pe;


  tp = (struct tftphdr *) buf;
  tp->th_opcode = htons ((unsigned short) ERROR);
  tp->th_code = htons ((unsigned short) error);
  for (pe = errmsgs; pe->e_code >= 0; pe++)
    if (pe->e_code == error)
      break;
  if (pe->e_code < 0)
    {
      pe->e_msg = strerror (error - 100);
      tp->th_code = EUNDEF;    /* set 'undef' errorcode */
    }

     /*
       * 这里要改strcpy为memcpy,不然会溢出。
            */

  length = strlen (pe->e_msg);
  memcpy (tp->th_msg, pe->e_msg,length);
//  strcpy (tp->th_msg, pe->e_msg);
//  length = strlen (pe->e_msg);
  tp->th_msg[length] = '\0';

  length += 5;
  if (sendto (peer, buf, length, 0, (struct sockaddr *) &from, fromlen) != length)
    syslog (LOG_ERR, "nak: %m\n");
}


root@ch-HP:~# tftp 127.0.0.1
tftp> put test
Sent 7 bytes in 0.0 seconds
tftp> put test5
Sent 13 bytes in 0.0 seconds
tftp> q
root@ch-HP:~#



猜你喜欢

转载自blog.csdn.net/sitelist/article/details/78753447
今日推荐