コード例 #1
0
ファイル: mod_copy.c プロジェクト: laoflch/proftpd
static int copy_dir(pool *p, const char *src_dir, const char *dst_dir) {
  DIR *dh = NULL;
  struct dirent *dent = NULL;
  int res = 0;
  pool *iter_pool = NULL;

  dh = opendir(src_dir);
  if (dh == NULL) {
    pr_log_pri(PR_LOG_WARNING, MOD_COPY_VERSION
      ": error reading directory '%s': %s", src_dir, strerror(errno));
    return -1;
  }

  while ((dent = readdir(dh)) != NULL) {
    struct stat st;
    char *src_path, *dst_path;

    pr_signals_handle();

    /* Skip "." and ".." */
    if (strncmp(dent->d_name, ".", 2) == 0 ||
        strncmp(dent->d_name, "..", 3) == 0) {
      continue;
    }

    if (iter_pool != NULL) {
      destroy_pool(iter_pool);
    }

    iter_pool = pr_pool_create_sz(p, 128);
    src_path = pdircat(iter_pool, src_dir, dent->d_name, NULL);
    dst_path = pdircat(iter_pool, dst_dir, dent->d_name, NULL);

    if (pr_fsio_lstat(src_path, &st) < 0) {
      pr_log_debug(DEBUG3, MOD_COPY_VERSION
        ": unable to stat '%s' (%s), skipping", src_path, strerror(errno));
      continue;
    }

    /* Is this path to a directory? */
    if (S_ISDIR(st.st_mode)) {
      if (create_path(iter_pool, dst_path) < 0) {
        res = -1;
        break;
      }

      if (copy_dir(iter_pool, src_path, dst_path) < 0) {
        res = -1;
        break;
      }
      continue;

    /* Is this path to a regular file? */
    } else if (S_ISREG(st.st_mode)) {
      cmd_rec *cmd;

      /* Dispatch fake COPY command, e.g. for mod_quotatab */
      cmd = pr_cmd_alloc(iter_pool, 4, pstrdup(iter_pool, "SITE"),
        pstrdup(iter_pool, "COPY"), pstrdup(iter_pool, src_path),
        pstrdup(iter_pool, dst_path));
      cmd->arg = pstrcat(iter_pool, "COPY ", src_path, " ", dst_path, NULL);
      cmd->cmd_class = CL_WRITE;

      pr_response_clear(&resp_list);
      pr_response_clear(&resp_err_list);

      if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
        int xerrno = errno;

        pr_log_debug(DEBUG3, MOD_COPY_VERSION
          ": COPY of '%s' to '%s' blocked by COPY handler: %s", src_path,
          dst_path, strerror(xerrno));

        pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
        pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
        pr_response_clear(&resp_err_list);

        errno = xerrno;
        res = -1;
        break;

      } else {
        if (pr_fs_copy_file(src_path, dst_path) < 0) {
          pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
          pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
          pr_response_clear(&resp_err_list);

          res = -1;
          break;

        } else {
          char *abs_path;
          
          pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
          pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
          pr_response_clear(&resp_list);

          /* Write a TransferLog entry as well. */

          pr_fs_clear_cache2(dst_path);
          pr_fsio_stat(dst_path, &st);

          abs_path = dir_abs_path(p, dst_path, TRUE);

          if (session.sf_flags & SF_ANON) {
            xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
               (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'a',
               session.anon_user, 'c', "_");

          } else {
            xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
              (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'r',
              session.user, 'c', "_");
          }
        }
      }

      continue;

    /* Is this path a symlink? */
    } else if (S_ISLNK(st.st_mode)) {
      if (copy_symlink(iter_pool, src_path, dst_path) < 0) {
        res = -1;
        break;
      }
      continue;

    /* All other file types are skipped */
    } else {
      pr_log_debug(DEBUG3, MOD_COPY_VERSION ": skipping supported file '%s'",
        src_path);
      continue;
    }
  }

  if (iter_pool != NULL) {
    destroy_pool(iter_pool);
  }

  closedir(dh);
  return res;
}
コード例 #2
0
ファイル: mod_copy.c プロジェクト: laoflch/proftpd
static int copy_paths(pool *p, const char *from, const char *to) {
  struct stat st;
  int res;
  xaset_t *set;

  set = get_dir_ctxt(p, (char *) to);
  res = pr_filter_allow_path(set, to);
  switch (res) {
    case 0:
      break;

    case PR_FILTER_ERR_FAILS_ALLOW_FILTER:
      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": path '%s' denied by PathAllowFilter", to);
      errno = EPERM;
      return -1;

    case PR_FILTER_ERR_FAILS_DENY_FILTER:
      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": path '%s' denied by PathDenyFilter", to);
      errno = EPERM;
      return -1;
  }

  /* Check whether from is a file, a directory, a symlink, or something
   * unsupported.
   */
  res = pr_fsio_lstat(from, &st);
  if (res < 0) {
    int xerrno = errno;

    pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error checking '%s': %s", from,
      strerror(xerrno));

    errno = xerrno;
    return -1;
  }
   
  if (S_ISREG(st.st_mode)) { 
    char *abs_path;

    pr_fs_clear_cache2(to);
    res = pr_fsio_stat(to, &st);
    if (res == 0) {
      unsigned char *allow_overwrite;

      allow_overwrite = get_param_ptr(CURRENT_CONF, "AllowOverwrite", FALSE);
      if (allow_overwrite == NULL ||
          *allow_overwrite == FALSE) {
        pr_log_debug(DEBUG6,
          MOD_COPY_VERSION ": AllowOverwrite permission denied for '%s'", to);
        errno = EACCES;
        return -1;
      }
    }

    res = pr_fs_copy_file(from, to);
    if (res < 0) {
      int xerrno = errno;

      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": error copying file '%s' to '%s': %s", from, to, strerror(xerrno));

      errno = xerrno;
      return -1;
    }

    pr_fs_clear_cache2(to);
    if (pr_fsio_stat(to, &st) < 0) {
      pr_trace_msg(trace_channel, 3,
        "error stat'ing '%s': %s", to, strerror(errno));
    }

    /* Write a TransferLog entry as well. */
    abs_path = dir_abs_path(p, to, TRUE);

    if (session.sf_flags & SF_ANON) {
      xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
        (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'a',
        session.anon_user, 'c', "_");

    } else {
      xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
        (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'r',
        session.user, 'c', "_");
    }

  } else if (S_ISDIR(st.st_mode)) {
    res = create_path(p, to);
    if (res < 0) {
      int xerrno = errno;

      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": error creating path '%s': %s", to, strerror(xerrno));

      errno = xerrno;
      return -1;
    }

    res = copy_dir(p, from, to);
    if (res < 0) {
      int xerrno = errno;

      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": error copying directory '%s' to '%s': %s", from, to,
        strerror(xerrno));

      errno = xerrno;
      return -1;
    }

  } else if (S_ISLNK(st.st_mode)) {
    pr_fs_clear_cache2(to);
    res = pr_fsio_stat(to, &st);
    if (res == 0) {
      unsigned char *allow_overwrite;

      allow_overwrite = get_param_ptr(CURRENT_CONF, "AllowOverwrite", FALSE);
      if (allow_overwrite == NULL ||
          *allow_overwrite == FALSE) {
        pr_log_debug(DEBUG6, MOD_COPY_VERSION
          ": AllowOverwrite permission denied for '%s'", to);
        errno = EACCES;
        return -1;
      }
    }

    res = copy_symlink(p, from, to);
    if (res < 0) {
      int xerrno = errno;

      pr_log_debug(DEBUG7, MOD_COPY_VERSION
        ": error copying symlink '%s' to '%s': %s", from, to, strerror(xerrno));

      errno = xerrno;
      return -1;
    }

  } else {
    pr_log_debug(DEBUG7, MOD_COPY_VERSION
      ": unsupported file type for '%s'", from);
    errno = EINVAL;
    return -1;
  }

  return 0;
}
コード例 #3
0
ファイル: mkhome.c プロジェクト: Distrotech/proftpd
/* srcdir is to be considered a "skeleton" directory, in the manner of
 * /etc/skel, and destdir is a user's newly created home directory that needs
 * to be populated with the files in srcdir.
 */
static int copy_dir(pool *p, const char *src_dir, const char *dst_dir,
    uid_t uid, gid_t gid) {
  DIR *dh = NULL;
  struct dirent *dent = NULL;

  dh = opendir(src_dir);
  if (dh == NULL) {
    pr_log_pri(PR_LOG_WARNING, "CreateHome: error copying '%s' skel files: %s",
      src_dir, strerror(errno));
    return -1;
  }

  while ((dent = readdir(dh)) != NULL) {
    struct stat st;
    char *src_path, *dst_path;

    pr_signals_handle();

    /* Skip "." and ".." */
    if (strncmp(dent->d_name, ".", 2) == 0 ||
        strncmp(dent->d_name, "..", 3) == 0) {
      continue;
    }

    src_path = pdircat(p, src_dir, dent->d_name, NULL);
    dst_path = pdircat(p, dst_dir, dent->d_name, NULL);

    if (pr_fsio_lstat(src_path, &st) < 0) {
      pr_log_debug(DEBUG3, "CreateHome: unable to stat '%s' (%s), skipping",
        src_path, strerror(errno));
      continue;
    }

    /* Is this path to a directory? */
    if (S_ISDIR(st.st_mode)) {
      create_dir(dst_path, uid, gid, st.st_mode);
      copy_dir(p, src_path, dst_path, uid, gid);
      continue;

    /* Is this path to a regular file? */
    } else if (S_ISREG(st.st_mode)) {
      mode_t dst_mode = st.st_mode;

      /* Make sure to prevent S{U,G}ID permissions on target files. */

      if (dst_mode & S_ISUID)
        dst_mode &= ~S_ISUID;

      if (dst_mode & S_ISGID)
        dst_mode &= ~S_ISGID;

      (void) pr_fs_copy_file(src_path, dst_path);

      /* Make sure the destination file has the proper ownership and mode. */
      if (pr_fsio_chown(dst_path, uid, gid) < 0) {
        pr_log_pri(PR_LOG_WARNING, "CreateHome: error chown'ing '%s' "
          "to %u/%u: %s", dst_path, (unsigned int) uid, (unsigned int) gid,
          strerror(errno));
      }

      if (pr_fsio_chmod(dst_path, dst_mode) < 0) {
        pr_log_pri(PR_LOG_WARNING, "CreateHome: error chmod'ing '%s' to "
          "%04o: %s", dst_path, (unsigned int) dst_mode, strerror(errno));
      }

      continue;

    /* Is this path a symlink? */
    } else if (S_ISLNK(st.st_mode)) {

      copy_symlink(p, src_dir, src_path, dst_dir, dst_path, uid, gid);
      continue;

    /* All other file types are skipped */
    } else {
      pr_log_debug(DEBUG3, "CreateHome: skipping skel file '%s'", src_path);
      continue;
    }
  }

  closedir(dh);
  return 0;
}