示例#1
0
static bool copy_entry(const char *source,
                       const char *destination,
                       uid_t uid,
                       gid_t gid) {
  struct stat sb;
  if (lstat(source, &sb) != 0)
    return false;

  struct timeval tv[2];
  tv[0].tv_sec = sb.st_atime;
  tv[0].tv_usec = 0;
  tv[1].tv_sec = sb.st_mtime;
  tv[1].tv_usec = 0;

  if (S_ISDIR(sb.st_mode)) {
    if (!copy_dir(source, destination, uid, gid, &sb))
      return false;
  } else if (S_ISLNK(sb.st_mode)) {
    if (!copy_symlink(source, destination, uid, gid, &sb))
      return false;
  } else if (S_ISREG(sb.st_mode)) {
    if (!copy_file(source, destination, uid, gid, &sb))
      return false;
  } else {
    if (!copy_special(source, destination, uid, gid, &sb))
      return false;
  }

  if (lutimes(destination, tv) != 0)
    return false;

  return true;
}
示例#2
0
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
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;
}
示例#4
0
文件: copydir.c 项目: bfeeny/shadow
/*
 * copy_entry - copy the entry of a directory
 *
 *	Copy the entry src to dst.
 *	Depending on the type of entry, this function will forward the
 *	request to copy_dir(), copy_symlink(), copy_hardlink(),
 *	copy_special(), or copy_file().
 *
 *	The access and modification time will not be modified.
 *
 *	The permissions will be set to new_uid/new_gid.
 *
 *	If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
 *	not be modified.
 *
 *	Only the files owned (resp. group-owned) by old_uid (resp.
 *	old_gid) will be modified, unless old_uid (resp. old_gid) is set
 *	to -1.
 */
static int copy_entry (const char *src, const char *dst,
                       bool reset_selinux,
                       uid_t old_uid, uid_t new_uid,
                       gid_t old_gid, gid_t new_gid)
{
    int err = 0;
    struct stat sb;
    struct link_name *lp;
    struct timeval mt[2];

    if (LSTAT (src, &sb) == -1) {
        /* If we cannot stat the file, do not care. */
    } else {
#ifdef HAVE_STRUCT_STAT_ST_ATIM
        mt[0].tv_sec  = sb.st_atim.tv_sec;
        mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
#else				/* !HAVE_STRUCT_STAT_ST_ATIM */
        mt[0].tv_sec  = sb.st_atime;
# ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
        mt[0].tv_usec = sb.st_atimensec / 1000;
# else				/* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
        mt[0].tv_usec = 0;
# endif				/* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
#endif				/* !HAVE_STRUCT_STAT_ST_ATIM */

#ifdef HAVE_STRUCT_STAT_ST_MTIM
        mt[1].tv_sec  = sb.st_mtim.tv_sec;
        mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
#else				/* !HAVE_STRUCT_STAT_ST_MTIM */
        mt[1].tv_sec  = sb.st_mtime;
# ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
        mt[1].tv_usec = sb.st_mtimensec / 1000;
# else				/* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
        mt[1].tv_usec = 0;
# endif				/* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
#endif				/* !HAVE_STRUCT_STAT_ST_MTIM */

        if (S_ISDIR (sb.st_mode)) {
            err = copy_dir (src, dst, reset_selinux, &sb, mt,
                            old_uid, new_uid, old_gid, new_gid);
        }

#ifdef	S_IFLNK
        /*
         * Copy any symbolic links
         */

        else if (S_ISLNK (sb.st_mode)) {
            err = copy_symlink (src, dst, reset_selinux, &sb, mt,
                                old_uid, new_uid, old_gid, new_gid);
        }
#endif				/* S_IFLNK */

        /*
         * See if this is a previously copied link
         */

        else if ((lp = check_link (src, &sb)) != NULL) {
            err = copy_hardlink (dst, reset_selinux, lp);
        }

        /*
         * Deal with FIFOs and special files.  The user really
         * shouldn't have any of these, but it seems like it
         * would be nice to copy everything ...
         */

        else if (!S_ISREG (sb.st_mode)) {
            err = copy_special (src, dst, reset_selinux, &sb, mt,
                                old_uid, new_uid, old_gid, new_gid);
        }

        /*
         * Create the new file and copy the contents.  The new
         * file will be owned by the provided UID and GID values.
         */

        else {
            err = copy_file (src, dst, reset_selinux, &sb, mt,
                             old_uid, new_uid, old_gid, new_gid);
        }
    }

    return err;
}
示例#5
0
/* 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;
}
示例#6
0
int transfer_begin(struct job *j)
{
    int res;
    char *pread = NULL, *pwrite = NULL;
    size_t p_len;

    pthread_mutex_lock(&m_transfer);

    if (t_state.active)
    {
        DEBUG("called transfer_begin while a transfer is active!");
        pthread_mutex_unlock(&m_transfer);
        return TRANSFER_FAIL;
    }
    pthread_mutex_unlock(&m_transfer);

    p_len = strlen(j->path);

    if (j->op == JOB_PUSH)
    {
        pread = cache_path2(j->path, p_len);
        pwrite = remote_path2(j->path, p_len);
    }
    else if (j->op == JOB_PULL)
    {
        pread = remote_path2(j->path, p_len);
        pwrite = cache_path2(j->path, p_len);
    }

    if (!pread || !pwrite)
    {
        free(pread);
        free(pwrite);
        errno = ENOMEM;
        return -1;
    }

    if (is_reg(pread))
    {
        if (!is_reg(pwrite) && !is_nonexist(pwrite))
        {
            DEBUG("write target is non-regular file: %s", pwrite);
            free(pread);
            free(pwrite);
            return TRANSFER_FAIL;
        }

        pthread_mutex_lock(&m_transfer);
        t_state.active = true;
        t_state.job = j;
        t_state.offset = 0;
        pthread_mutex_unlock(&m_transfer);

        res = transfer(pread, pwrite);
        free(pread);
        free(pwrite);
        return res;
    }
    /* if symlink, copy instantly */
    else if (is_lnk(pread))
    {
        DEBUG("push/pull on symlink");
        copy_symlink(pread, pwrite);
        copy_attrs(pread, pwrite);
        free(pread);
        free(pwrite);
        return TRANSFER_FINISH;
    }
    else if (is_dir(pread))
    {
        DEBUG("push/pull on DIR");
        clone_dir(pread, pwrite);
        copy_attrs(pread, pwrite);
        free(pread);
        free(pwrite);
        return TRANSFER_FINISH;
    }
    else
    {
        ERROR("cannot read file %s", pread);
        free(pread);
        free(pwrite);
        return TRANSFER_FAIL;
    }

    DEBUG("wtf");
    return TRANSFER_FAIL;
}