|
|
fb7fda2 |
--- configure.in
|
|
|
fb7fda2 |
+++ configure.in
|
|
|
fb7fda2 |
@@ -1399,7 +1399,7 @@ AC_PROG_GCC_TRADITIONAL
|
|
|
fb7fda2 |
AC_FUNC_SETPGRP
|
|
|
fb7fda2 |
AC_TYPE_SIGNAL
|
|
|
fb7fda2 |
AC_FUNC_VPRINTF
|
|
|
fb7fda2 |
-AC_CHECK_FUNCS(bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp nl_langinfo)
|
|
|
fb7fda2 |
+AC_CHECK_FUNCS(bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp mkdtemp nl_langinfo)
|
|
|
fb7fda2 |
AC_CHECK_FUNC(gai_strerror,
|
|
|
fb7fda2 |
AC_DEFINE(HAVE_GAI_STRERROR, 1,
|
|
|
fb7fda2 |
[Define if you have the gai_strerror() function]),
|
|
|
fb7fda2 |
--- configure
|
|
|
fb7fda2 |
+++ configure
|
|
|
fb7fda2 |
@@ -26526,7 +26526,8 @@ done
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
-for ac_func in bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp nl_langinfo
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+for ac_func in bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp mkdtemp nl_langinfo
|
|
|
fb7fda2 |
do
|
|
|
fb7fda2 |
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
|
|
fb7fda2 |
{ echo "$as_me:$LINENO: checking for $ac_func" >&5
|
|
|
fb7fda2 |
--- config.h.in
|
|
|
fb7fda2 |
+++ config.h.in
|
|
|
fb7fda2 |
@@ -357,6 +357,9 @@
|
|
|
fb7fda2 |
/* Define if you have the mkdir function. */
|
|
|
fb7fda2 |
#undef HAVE_MKDIR
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+/* Define if you have the mkdtemp function. */
|
|
|
fb7fda2 |
+#undef HAVE_MKDTEMP
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
/* Define if you have the mkstemp function. */
|
|
|
fb7fda2 |
#undef HAVE_MKSTEMP
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
--- contrib/mod_sftp/fxp.c
|
|
|
fb7fda2 |
+++ contrib/mod_sftp/fxp.c
|
|
|
fb7fda2 |
@@ -5498,7 +5498,7 @@ static int fxp_handle_mkdir(struct fxp_p
|
|
|
fb7fda2 |
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
|
|
|
fb7fda2 |
"creating directory '%s' with mode 0%o", path, (unsigned int) dir_mode);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
- res = pr_fsio_mkdir(path, dir_mode);
|
|
|
fb7fda2 |
+ res = pr_fsio_smkdir(fxp->pool, path, dir_mode, (uid_t) -1, (gid_t) -1);
|
|
|
fb7fda2 |
if (res < 0) {
|
|
|
fb7fda2 |
const char *reason;
|
|
|
fb7fda2 |
int xerrno = errno;
|
|
|
fb7fda2 |
--- contrib/mod_sftp/scp.c
|
|
|
fb7fda2 |
+++ contrib/mod_sftp/scp.c
|
|
|
fb7fda2 |
@@ -711,7 +711,7 @@ static int recv_finfo(pool *p, uint32_t
|
|
|
fb7fda2 |
if (xerrno == ENOENT) {
|
|
|
fb7fda2 |
pr_trace_msg(trace_channel, 5, "creating directory '%s'", sp->filename);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
- if (pr_fsio_mkdir(sp->filename, 0777) < 0) {
|
|
|
fb7fda2 |
+ if (pr_fsio_smkdir(p, sp->filename, 0777, (uid_t) -1, (gid_t) -1) < 0) {
|
|
|
fb7fda2 |
xerrno = errno;
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
|
|
|
fb7fda2 |
--- include/fsio.h
|
|
|
fb7fda2 |
+++ include/fsio.h
|
|
|
fb7fda2 |
@@ -129,6 +129,7 @@ struct fs_rec {
|
|
|
fb7fda2 |
int (*fchmod)(pr_fh_t *, int, mode_t);
|
|
|
fb7fda2 |
int (*chown)(pr_fs_t *, const char *, uid_t, gid_t);
|
|
|
fb7fda2 |
int (*fchown)(pr_fh_t *, int, uid_t, gid_t);
|
|
|
fb7fda2 |
+ int (*lchown)(pr_fs_t *, const char *, uid_t, gid_t);
|
|
|
fb7fda2 |
int (*access)(pr_fs_t *, const char *, int, uid_t, gid_t, array_header *);
|
|
|
fb7fda2 |
int (*faccess)(pr_fh_t *, int, uid_t, gid_t, array_header *);
|
|
|
fb7fda2 |
int (*utimes)(pr_fs_t *, const char *, struct timeval *);
|
|
|
fb7fda2 |
@@ -249,6 +250,7 @@ int pr_fsio_mkdir(const char *, mode_t);
|
|
|
fb7fda2 |
int pr_fsio_rmdir(const char *);
|
|
|
fb7fda2 |
int pr_fsio_rename(const char *, const char *);
|
|
|
fb7fda2 |
int pr_fsio_rename_canon(const char *, const char *);
|
|
|
fb7fda2 |
+int pr_fsio_smkdir(pool *, const char *, mode_t, uid_t, gid_t);
|
|
|
fb7fda2 |
int pr_fsio_unlink(const char *);
|
|
|
fb7fda2 |
int pr_fsio_unlink_canon(const char *);
|
|
|
fb7fda2 |
pr_fh_t *pr_fsio_open(const char *, int);
|
|
|
fb7fda2 |
@@ -270,6 +272,7 @@ int pr_fsio_fchmod(pr_fh_t *, mode_t);
|
|
|
fb7fda2 |
int pr_fsio_chmod_canon(const char *, mode_t);
|
|
|
fb7fda2 |
int pr_fsio_chown(const char *, uid_t, gid_t);
|
|
|
fb7fda2 |
int pr_fsio_fchown(pr_fh_t *, uid_t, gid_t);
|
|
|
fb7fda2 |
+int pr_fsio_lchown(const char *, uid_t, gid_t);
|
|
|
fb7fda2 |
int pr_fsio_chown_canon(const char *, uid_t, gid_t);
|
|
|
fb7fda2 |
int pr_fsio_chroot(const char *);
|
|
|
fb7fda2 |
int pr_fsio_access(const char *, int, uid_t, gid_t, array_header *);
|
|
|
fb7fda2 |
@@ -278,6 +281,11 @@ int pr_fsio_utimes(const char *, struct
|
|
|
fb7fda2 |
int pr_fsio_futimes(pr_fh_t *, struct timeval *);
|
|
|
fb7fda2 |
off_t pr_fsio_lseek(pr_fh_t *, off_t, int);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+/* Set a flag determining whether to use mkdtemp(3) (if available) or not.
|
|
|
fb7fda2 |
+ * Returns the previously-set value.
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+int pr_fsio_set_use_mkdtemp(int);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
/* FS-related functions */
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
char *pr_fsio_getline(char *, int, pr_fh_t *, unsigned int *);
|
|
|
fb7fda2 |
--- modules/mod_core.c
|
|
|
fb7fda2 |
+++ modules/mod_core.c
|
|
|
fb7fda2 |
@@ -3744,7 +3744,7 @@ int core_chgrp(cmd_rec *cmd, char *dir,
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
cmd->argv[0] = cmd_name;
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
- return pr_fsio_chown(dir, uid, gid);
|
|
|
fb7fda2 |
+ return pr_fsio_lchown(dir, uid, gid);
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
int core_chmod(cmd_rec *cmd, char *dir, mode_t mode) {
|
|
|
fb7fda2 |
@@ -4002,7 +4002,6 @@ MODRET core_rmd(cmd_rec *cmd) {
|
|
|
fb7fda2 |
MODRET core_mkd(cmd_rec *cmd) {
|
|
|
fb7fda2 |
int res;
|
|
|
fb7fda2 |
char *dir;
|
|
|
fb7fda2 |
- struct stat st;
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
CHECK_CMD_MIN_ARGS(cmd, 2);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
@@ -4043,7 +4042,8 @@ MODRET core_mkd(cmd_rec *cmd) {
|
|
|
fb7fda2 |
return PR_ERROR(cmd);
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
- if (pr_fsio_mkdir(dir, 0777) < 0) {
|
|
|
fb7fda2 |
+ if (pr_fsio_smkdir(cmd->tmp_pool, dir, 0777, session.fsuid,
|
|
|
fb7fda2 |
+ session.fsgid) < 0) {
|
|
|
fb7fda2 |
int xerrno = errno;
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
(void) pr_trace_msg("fileperms", 1, "%s, user '%s' (UID %lu, GID %lu): "
|
|
|
fb7fda2 |
@@ -4055,71 +4055,6 @@ MODRET core_mkd(cmd_rec *cmd) {
|
|
|
fb7fda2 |
return PR_ERROR(cmd);
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
- /* Check to see if we need to change the ownership (user and/or group) of
|
|
|
fb7fda2 |
- * the newly created directory.
|
|
|
fb7fda2 |
- */
|
|
|
fb7fda2 |
- if (session.fsuid != (uid_t) -1) {
|
|
|
fb7fda2 |
- int err = 0, iserr = 0;
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- pr_fsio_stat(dir, &st);
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- PRIVS_ROOT
|
|
|
fb7fda2 |
- if (pr_fsio_chown(dir, session.fsuid, session.fsgid) == -1) {
|
|
|
fb7fda2 |
- iserr++;
|
|
|
fb7fda2 |
- err = errno;
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
- PRIVS_RELINQUISH
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- if (iserr) {
|
|
|
fb7fda2 |
- pr_log_pri(PR_LOG_WARNING, "chown() as root failed: %s", strerror(err));
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- } else {
|
|
|
fb7fda2 |
- if (session.fsgid != (gid_t) -1) {
|
|
|
fb7fda2 |
- pr_log_debug(DEBUG2, "root chown(%s) to uid %lu, gid %lu successful",
|
|
|
fb7fda2 |
- dir, (unsigned long) session.fsuid, (unsigned long) session.fsgid);
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- } else {
|
|
|
fb7fda2 |
- pr_log_debug(DEBUG2, "root chown(%s) to uid %lu successful", dir,
|
|
|
fb7fda2 |
- (unsigned long) session.fsuid);
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- } else if (session.fsgid != (gid_t) -1) {
|
|
|
fb7fda2 |
- register unsigned int i;
|
|
|
fb7fda2 |
- int use_root_privs = TRUE;
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- pr_fsio_stat(dir, &st);
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- /* Check if session.fsgid is in session.gids. If not, use root privs. */
|
|
|
fb7fda2 |
- for (i = 0; i < session.gids->nelts; i++) {
|
|
|
fb7fda2 |
- gid_t *group_ids = session.gids->elts;
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- if (group_ids[i] == session.fsgid) {
|
|
|
fb7fda2 |
- use_root_privs = FALSE;
|
|
|
fb7fda2 |
- break;
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- if (use_root_privs) {
|
|
|
fb7fda2 |
- PRIVS_ROOT
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- res = pr_fsio_chown(dir, (uid_t) -1, session.fsgid);
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- if (use_root_privs) {
|
|
|
fb7fda2 |
- PRIVS_RELINQUISH
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- if (res == -1) {
|
|
|
fb7fda2 |
- pr_log_pri(PR_LOG_WARNING, "%schown() failed: %s",
|
|
|
fb7fda2 |
- use_root_privs ? "root " : "", strerror(errno));
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
- } else {
|
|
|
fb7fda2 |
- pr_log_debug(DEBUG2, "%schown(%s) to gid %lu successful",
|
|
|
fb7fda2 |
- use_root_privs ? "root " : "", dir, (unsigned long) session.fsgid);
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
- }
|
|
|
fb7fda2 |
-
|
|
|
fb7fda2 |
pr_response_add(R_257, _("\"%s\" - Directory successfully created"),
|
|
|
fb7fda2 |
quote_dir(cmd, dir));
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
--- src/fsio.c
|
|
|
fb7fda2 |
+++ src/fsio.c
|
|
|
fb7fda2 |
@@ -29,6 +29,7 @@
|
|
|
fb7fda2 |
*/
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
#include "conf.h"
|
|
|
fb7fda2 |
+#include "privs.h"
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
#ifdef HAVE_REGEX_H
|
|
|
fb7fda2 |
# include <regex.h>
|
|
|
fb7fda2 |
@@ -84,6 +85,13 @@ static unsigned char chk_fs_map = FALSE;
|
|
|
fb7fda2 |
static char vwd[PR_TUNABLE_PATH_MAX + 1] = "/";
|
|
|
fb7fda2 |
static char cwd[PR_TUNABLE_PATH_MAX + 1] = "/";
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+/* Runtime enabling/disabling of mkdtemp(3) use. */
|
|
|
fb7fda2 |
+#ifdef HAVE_MKDTEMP
|
|
|
fb7fda2 |
+static int use_mkdtemp = TRUE;
|
|
|
fb7fda2 |
+#else
|
|
|
fb7fda2 |
+static int use_mkdtemp = FALSE;
|
|
|
fb7fda2 |
+#endif /* HAVE_MKDTEMP */
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
/* Runtime enabling/disabling of encoding of paths. */
|
|
|
fb7fda2 |
static int use_encoding = TRUE;
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
@@ -179,6 +187,10 @@ static int sys_fchown(pr_fh_t *fh, int f
|
|
|
fb7fda2 |
return fchown(fd, uid, gid);
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+static int sys_lchown(pr_fs_t *fs, const char *path, uid_t uid, gid_t gid) {
|
|
|
fb7fda2 |
+ return lchown(path, uid, gid);
|
|
|
fb7fda2 |
+}
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
/* We provide our own equivalent of access(2) here, rather than using
|
|
|
fb7fda2 |
* access(2) directly, because access(2) uses the real IDs, rather than
|
|
|
fb7fda2 |
* the effective IDs, of the process.
|
|
|
fb7fda2 |
@@ -2477,6 +2489,213 @@ int pr_fsio_mkdir(const char *path, mode
|
|
|
fb7fda2 |
return res;
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+int pr_fsio_set_use_mkdtemp(int value) {
|
|
|
fb7fda2 |
+ int prev_value;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ prev_value = use_mkdtemp;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+#ifdef HAVE_MKDTEMP
|
|
|
fb7fda2 |
+ use_mkdtemp = value;
|
|
|
fb7fda2 |
+#endif /* HAVE_MKDTEMP */
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ return prev_value;
|
|
|
fb7fda2 |
+}
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+/* "safe mkdir" variant of mkdir(2), uses mkdtemp(3), lchown(2), and
|
|
|
fb7fda2 |
+ * rename(2) to create a directory which cannot be hijacked by a symlink
|
|
|
fb7fda2 |
+ * race (hopefully) before the UserOwner/GroupOwner ownership changes are
|
|
|
fb7fda2 |
+ * applied.
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+int pr_fsio_smkdir(pool *p, const char *path, mode_t mode, uid_t uid,
|
|
|
fb7fda2 |
+ gid_t gid) {
|
|
|
fb7fda2 |
+ int res, use_root_privs = TRUE, xerrno = 0;
|
|
|
fb7fda2 |
+ char *tmpl_path;
|
|
|
fb7fda2 |
+ char *dst_dir, *tmpl;
|
|
|
fb7fda2 |
+ size_t dst_dirlen, tmpl_len;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (path == NULL) {
|
|
|
fb7fda2 |
+ errno = EINVAL;
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+#ifdef HAVE_MKDTEMP
|
|
|
fb7fda2 |
+ if (use_mkdtemp == TRUE) {
|
|
|
fb7fda2 |
+ char *ptr;
|
|
|
fb7fda2 |
+ struct stat st;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ ptr = strrchr(path, '/');
|
|
|
fb7fda2 |
+ if (ptr == NULL) {
|
|
|
fb7fda2 |
+ errno = EINVAL;
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (ptr != path) {
|
|
|
fb7fda2 |
+ dst_dirlen = (ptr - path);
|
|
|
fb7fda2 |
+ dst_dir = pstrndup(p, path, dst_dirlen);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ dst_dirlen = 1;
|
|
|
fb7fda2 |
+ dst_dir = "/";
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ res = lstat(dst_dir, &st);
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (!S_ISDIR(st.st_mode) &&
|
|
|
fb7fda2 |
+ !S_ISLNK(st.st_mode)) {
|
|
|
fb7fda2 |
+ errno = EPERM;
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Allocate enough space for the temporary name: the length of the
|
|
|
fb7fda2 |
+ * destination directory, a slash, 9 X's, 3 for the prefix, and 1 for the
|
|
|
fb7fda2 |
+ * trailing NUL.
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+ tmpl_len = strlen(dst_dir) + 14;
|
|
|
fb7fda2 |
+ tmpl = pcalloc(p, tmpl_len);
|
|
|
fb7fda2 |
+ snprintf(tmpl, tmpl_len-1, "%s/dstXXXXXXXXX",
|
|
|
fb7fda2 |
+ dst_dirlen > 1 ? dst_dir : "");
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Use mkdtemp(3) to create the temporary directory (in the same destination
|
|
|
fb7fda2 |
+ * directory as the target path).
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+ tmpl_path = mkdtemp(tmpl);
|
|
|
fb7fda2 |
+ if (tmpl_path == NULL) {
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ res = pr_fsio_mkdir(path, mode);
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ tmpl_path = pstrdup(p, path);
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+#else
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ res = pr_fsio_mkdir(path, mode);
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ tmpl_path = pstrdup(p, path);
|
|
|
fb7fda2 |
+#endif /* HAVE_MKDTEMP */
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (uid != (uid_t) -1) {
|
|
|
fb7fda2 |
+ PRIVS_ROOT
|
|
|
fb7fda2 |
+ res = pr_fsio_lchown(tmpl_path, uid, gid);
|
|
|
fb7fda2 |
+ xerrno = errno;
|
|
|
fb7fda2 |
+ PRIVS_RELINQUISH
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ pr_log_pri(PR_LOG_WARNING, "lchown(%s) as root failed: %s", tmpl_path,
|
|
|
fb7fda2 |
+ strerror(xerrno));
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ if (gid != (gid_t) -1) {
|
|
|
fb7fda2 |
+ pr_log_debug(DEBUG2, "root lchown(%s) to UID %lu, GID %lu successful",
|
|
|
fb7fda2 |
+ tmpl_path, (unsigned long) uid, (unsigned long) gid);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ pr_log_debug(DEBUG2, "root lchown(%s) to UID %lu successful",
|
|
|
fb7fda2 |
+ tmpl_path, (unsigned long) uid);
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else if (gid != (gid_t) -1) {
|
|
|
fb7fda2 |
+ register unsigned int i;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Check if session.fsgid is in session.gids. If not, use root privs. */
|
|
|
fb7fda2 |
+ for (i = 0; i < session.gids->nelts; i++) {
|
|
|
fb7fda2 |
+ gid_t *group_ids = session.gids->elts;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (group_ids[i] == gid) {
|
|
|
fb7fda2 |
+ use_root_privs = FALSE;
|
|
|
fb7fda2 |
+ break;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (use_root_privs) {
|
|
|
fb7fda2 |
+ PRIVS_ROOT
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ res = pr_fsio_lchown(tmpl_path, (uid_t) -1, gid);
|
|
|
fb7fda2 |
+ xerrno = errno;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (use_root_privs) {
|
|
|
fb7fda2 |
+ PRIVS_RELINQUISH
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ pr_log_pri(PR_LOG_WARNING, "%slchown(%s) failed: %s",
|
|
|
fb7fda2 |
+ use_root_privs ? "root " : "", tmpl_path, strerror(xerrno));
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ pr_log_debug(DEBUG2, "%slchown(%s) to GID %lu successful",
|
|
|
fb7fda2 |
+ use_root_privs ? "root " : "", tmpl_path, (unsigned long) gid);
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (use_mkdtemp == TRUE) {
|
|
|
fb7fda2 |
+ mode_t mask, *dir_umask;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Use chmod(2) to set the permission that we want.
|
|
|
fb7fda2 |
+ *
|
|
|
fb7fda2 |
+ * mkdtemp(3) creates a directory with 0700 perms; we are given the
|
|
|
fb7fda2 |
+ * target mode (modulo the configured Umask).
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+ dir_umask = get_param_ptr(CURRENT_CONF, "DirUmask", FALSE);
|
|
|
fb7fda2 |
+ if (dir_umask) {
|
|
|
fb7fda2 |
+ mask = *dir_umask;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ } else {
|
|
|
fb7fda2 |
+ mask = (mode_t) 0022;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (use_root_privs) {
|
|
|
fb7fda2 |
+ PRIVS_ROOT
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ res = chmod(tmpl_path, mode & ~mask);
|
|
|
fb7fda2 |
+ xerrno = errno;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (use_root_privs) {
|
|
|
fb7fda2 |
+ PRIVS_RELINQUISH
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ pr_log_pri(PR_LOG_WARNING, "%schmod(%s) failed: %s",
|
|
|
fb7fda2 |
+ use_root_privs ? "root " : "", tmpl_path, strerror(xerrno));
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ (void) rmdir(tmpl_path);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ errno = xerrno;
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Use rename(2) to move the temporary directory into place at the
|
|
|
fb7fda2 |
+ * target path.
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+ res = rename(tmpl_path, path);
|
|
|
fb7fda2 |
+ if (res < 0) {
|
|
|
fb7fda2 |
+ xerrno = errno;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ pr_log_pri(PR_LOG_WARNING, "renaming '%s' to '%s' failed: %s", tmpl_path,
|
|
|
fb7fda2 |
+ path, strerror(xerrno));
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ (void) rmdir(tmpl_path);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ errno = xerrno;
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ return 0;
|
|
|
fb7fda2 |
+}
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
int pr_fsio_rmdir(const char *path) {
|
|
|
fb7fda2 |
int res;
|
|
|
fb7fda2 |
pr_fs_t *fs;
|
|
|
fb7fda2 |
@@ -3336,6 +3555,33 @@ int pr_fsio_fchown(pr_fh_t *fh, uid_t ui
|
|
|
fb7fda2 |
return res;
|
|
|
fb7fda2 |
}
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+int pr_fsio_lchown(const char *name, uid_t uid, gid_t gid) {
|
|
|
fb7fda2 |
+ int res;
|
|
|
fb7fda2 |
+ pr_fs_t *fs;
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ fs = lookup_file_fs(name, NULL, FSIO_FILE_CHOWN);
|
|
|
fb7fda2 |
+ if (fs == NULL) {
|
|
|
fb7fda2 |
+ return -1;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ /* Find the first non-NULL custom lchown handler. If there are none,
|
|
|
fb7fda2 |
+ * use the system chown.
|
|
|
fb7fda2 |
+ */
|
|
|
fb7fda2 |
+ while (fs && fs->fs_next && !fs->lchown) {
|
|
|
fb7fda2 |
+ fs = fs->fs_next;
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ pr_trace_msg(trace_channel, 8, "using %s lchown() for path '%s'",
|
|
|
fb7fda2 |
+ fs->fs_name, name);
|
|
|
fb7fda2 |
+ res = (fs->lchown)(fs, name, uid, gid);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (res == 0) {
|
|
|
fb7fda2 |
+ pr_fs_clear_cache();
|
|
|
fb7fda2 |
+ }
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ return res;
|
|
|
fb7fda2 |
+}
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
int pr_fsio_access(const char *path, int mode, uid_t uid, gid_t gid,
|
|
|
fb7fda2 |
array_header *suppl_gids) {
|
|
|
fb7fda2 |
pr_fs_t *fs;
|
|
|
fb7fda2 |
@@ -3955,6 +4201,7 @@ int init_fs(void) {
|
|
|
fb7fda2 |
root_fs->fchmod = sys_fchmod;
|
|
|
fb7fda2 |
root_fs->chown = sys_chown;
|
|
|
fb7fda2 |
root_fs->fchown = sys_fchown;
|
|
|
fb7fda2 |
+ root_fs->lchown = sys_lchown;
|
|
|
fb7fda2 |
root_fs->access = sys_access;
|
|
|
fb7fda2 |
root_fs->faccess = sys_faccess;
|
|
|
fb7fda2 |
root_fs->utimes = sys_utimes;
|
|
|
fb7fda2 |
@@ -4036,6 +4283,12 @@ static const char *get_fs_hooks_str(pool
|
|
|
fb7fda2 |
if (fs->chown)
|
|
|
fb7fda2 |
hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chown(2)", NULL);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
+ if (fs->fchown)
|
|
|
fb7fda2 |
+ hooks = pstrcat(p, hooks, *hooks ? ", " : "", "fchown(2)", NULL);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
+ if (fs->lchown)
|
|
|
fb7fda2 |
+ hooks = pstrcat(p, hooks, *hooks ? ", " : "", "lchown(2)", NULL);
|
|
|
fb7fda2 |
+
|
|
|
fb7fda2 |
if (fs->access)
|
|
|
fb7fda2 |
hooks = pstrcat(p, hooks, *hooks ? ", " : "", "access(2)", NULL);
|
|
|
fb7fda2 |
|
|
|
fb7fda2 |
--- src/Makefile.in
|
|
|
fb7fda2 |
+++ src/Makefile.in
|
|
|
fb7fda2 |
@@ -294,7 +294,7 @@ filter.o: ../include/event.h ../include/
|
|
|
fb7fda2 |
filter.o: ../include/trace.h ../include/encode.h ../include/compat.h
|
|
|
fb7fda2 |
filter.o: ../include/proctitle.h ../include/pidfile.h ../include/env.h
|
|
|
fb7fda2 |
filter.o: ../include/pr-syslog.h
|
|
|
fb7fda2 |
-fsio.o: ../include/conf.h ../include/version.h ../config.h
|
|
|
fb7fda2 |
+fsio.o: ../include/conf.h ../include/privs.h ../include/version.h ../config.h
|
|
|
fb7fda2 |
fsio.o: ../include/default_paths.h ../include/options.h ../include/pool.h
|
|
|
fb7fda2 |
fsio.o: ../include/str.h ../include/regexp.h ../include/table.h
|
|
|
fb7fda2 |
fsio.o: ../include/proftpd.h ../include/class.h ../include/netacl.h
|