Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1263:500ec0ec3b85 HEAD
safe_mkdir(): usage fchmod() and fchown(). chmod() wasn't really safe and
lchown() wasn't portable.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 27 Feb 2003 00:19:51 +0200 |
parents | 7767e5b3e83e |
children | 69642d55545d |
files | src/lib/safe-mkdir.c |
diffstat | 1 files changed, 31 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/safe-mkdir.c Wed Feb 26 23:27:17 2003 +0200 +++ b/src/lib/safe-mkdir.c Thu Feb 27 00:19:51 2003 +0200 @@ -26,11 +26,12 @@ #include <sys/stat.h> #include <unistd.h> +#include <fcntl.h> int safe_mkdir(const char *dir, mode_t mode, uid_t uid, gid_t gid) { struct stat st; - int ret = 1; + int fd, ret = 1; if (lstat(dir, &st) < 0) { if (errno != ENOENT) @@ -38,37 +39,46 @@ if (mkdir(dir, mode) < 0) i_fatal("Can't create directory %s: %m", dir); + } else { + /* already exists. */ + ret = 2; + } - if (lchown(dir, uid, gid) < 0) - i_fatal("lchown() failed for %s: %m", dir); - } else { - /* make sure it's permissions are correct */ - if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) - i_fatal("Not a directory %s", dir); + /* use fchown() and fchmod() just to make sure we aren't following + symbolic links. */ + fd = open(dir, O_RDONLY); + if (fd == -1) + i_fatal("open() failed for %s: %m", dir); + + if (fstat(fd, &st) < 0) + i_fatal("fstat() failed for %s: %m", dir); - if (st.st_uid != uid || st.st_gid != gid) { - if (lchown(dir, uid, gid) < 0) - i_fatal("lchown() failed for %s: %m", dir); - ret = 0; - } + if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) + i_fatal("Not a directory %s", dir); + + if (st.st_uid != uid || st.st_gid != gid) { + if (fchown(fd, uid, gid) < 0) + i_fatal("fchown() failed for %s: %m", dir); + ret = 0; + } - if ((st.st_mode & 07777) != mode) { - if (chmod(dir, mode) < 0) - i_fatal("chmod() failed for %s: %m", dir); - ret = 0; - } + if ((st.st_mode & 07777) != mode) { + if (fchmod(fd, mode) < 0) + i_fatal("chmod() failed for %s: %m", dir); + ret = 0; } + if (close(fd) < 0) + i_fatal("close() failed for %s: %m", dir); + /* make sure we succeeded in everything. chown() and chmod() are racy: user owned 0777 file - change either and the user can still change it back. */ if (lstat(dir, &st) < 0) i_fatal("lstat() check failed for %s: %m", dir); - if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) { - i_fatal("safe_mkdir() failed: %s is still not a directory", - dir); - } + if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) + i_fatal("Not a directory %s", dir); if ((st.st_mode & 07777) != mode) { i_fatal("safe_mkdir() failed: %s (%o) is still not mode %o",