dovecot-2.2: lib-storage: When mkdir()ing home, copy permissions...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Oct 24 12:47:47 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/40b6534ddae3
changeset: 15254:40b6534ddae3
user: Timo Sirainen <tss at iki.fi>
date: Wed Oct 24 12:47:34 2012 +0300
description:
lib-storage: When mkdir()ing home, copy permissions from parent if it has setgid-bit and we're using %h/~.
When using %d/%n instead of %h in the location directories, use the earlier
methods.
diffstat:
src/lib-storage/mailbox-list.c | 88 ++++++++++++++++++++++++++++++-----------
1 files changed, 63 insertions(+), 25 deletions(-)
diffs (163 lines):
diff -r fa8fa246189a -r 40b6534ddae3 src/lib-storage/mailbox-list.c
--- a/src/lib-storage/mailbox-list.c Wed Oct 24 12:23:36 2012 +0300
+++ b/src/lib-storage/mailbox-list.c Wed Oct 24 12:47:34 2012 +0300
@@ -207,14 +207,16 @@
return 0;
}
-static int fix_path(struct mail_user *user, const char *path,
+static int fix_path(struct mail_user *user, const char *path, bool expand_home,
const char **path_r, const char **error_r)
{
size_t len = strlen(path);
if (len > 1 && path[len-1] == '/')
path = t_strndup(path, len-1);
- if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
+ if (!expand_home) {
+ /* no ~ expansion */
+ } else if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
/* ~otheruser/dir */
if (home_try_expand(&path) < 0) {
*error_r = t_strconcat(
@@ -253,9 +255,11 @@
return str;
}
-int mailbox_list_settings_parse(struct mail_user *user, const char *data,
- struct mailbox_list_settings *set_r,
- const char **error_r)
+static int
+mailbox_list_settings_parse_full(struct mail_user *user, const char *data,
+ bool expand_home,
+ struct mailbox_list_settings *set_r,
+ const char **error_r)
{
const char *const *tmp, *key, *value, **dest, *str, *error;
@@ -271,7 +275,7 @@
/* <root dir> */
tmp = t_strsplit(data, ":");
str = split_next_arg(&tmp);
- if (fix_path(user, str, &set_r->root_dir, &error) < 0) {
+ if (fix_path(user, str, expand_home, &set_r->root_dir, &error) < 0) {
*error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
return -1;
}
@@ -323,7 +327,7 @@
*error_r = t_strdup_printf("Unknown setting: %s", key);
return -1;
}
- if (fix_path(user, value, dest, &error) < 0) {
+ if (fix_path(user, value, expand_home, dest, &error) < 0) {
*error_r = t_strconcat(error, key, " in: ", data, NULL);
return -1;
}
@@ -334,6 +338,14 @@
return 0;
}
+int mailbox_list_settings_parse(struct mail_user *user, const char *data,
+ struct mailbox_list_settings *set_r,
+ const char **error_r)
+{
+ return mailbox_list_settings_parse_full(user, data, TRUE,
+ set_r, error_r);
+}
+
const char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
enum mailbox_list_path_type type)
{
@@ -367,7 +379,8 @@
if (p == NULL)
return "";
- if (mailbox_list_settings_parse(user, p + 1, &set, &error) < 0)
+ if (mailbox_list_settings_parse_full(user, p + 1, FALSE,
+ &set, &error) < 0)
return "";
if (mailbox_list_set_get_root_path(&set, type, &path) <= 0)
return "";
@@ -963,33 +976,50 @@
{
const char *expanded, *unexpanded, *root_dir, *p;
struct stat st;
+ bool home = FALSE;
/* get the directory path up to last %variable. for example
unexpanded path may be "/var/mail/%d/%2n/%n/Maildir", and we want
to get expanded="/var/mail/domain/nn" */
unexpanded = mailbox_list_get_unexpanded_path(list, type);
p = strrchr(unexpanded, '%');
- if (p == NULL)
- expanded = "";
- else {
+ if ((p == unexpanded && p[1] == 'h') ||
+ (p == NULL && unexpanded[0] == '~')) {
+ /* home directory used */
+ if (!mailbox_list_get_root_path(list, type, &expanded))
+ i_unreached();
+ home = TRUE;
+ } else if (p == NULL) {
+ return 0;
+ } else {
while (p != unexpanded && *p != '/') p--;
if (p == unexpanded)
- expanded = "";
- else {
- if (!mailbox_list_get_root_path(list, type, &expanded))
- i_unreached();
- expanded = get_expanded_path(unexpanded, p, expanded);
- }
+ return 0;
+
+ if (!mailbox_list_get_root_path(list, type, &expanded))
+ i_unreached();
+ expanded = get_expanded_path(unexpanded, p, expanded);
+ if (*expanded == '\0')
+ return 0;
}
- if (*expanded != '\0') {
- /* up to this directory get the permissions from the first
- parent directory that exists, if it has setgid bit
- enabled. */
- if (mailbox_list_stat_parent(expanded, &root_dir, &st,
- error_r) < 0)
- return -1;
- if ((st.st_mode & S_ISGID) != 0 && root_dir != expanded) {
+ /* get the first existing parent directory's permissions */
+ if (mailbox_list_stat_parent(expanded, &root_dir, &st, error_r) < 0)
+ return -1;
+
+ /* if the parent directory doesn't have setgid-bit enabled, we don't
+ copy any permissions from it. */
+ if ((st.st_mode & S_ISGID) == 0)
+ return 0;
+
+ if (!home) {
+ /* assuming we have e.g. /var/vmail/%d/%n directory, here we
+ want to create up to /var/vmail/%d with permissions from
+ the parent directory. we never want to create the %n
+ directory itself. */
+ if (root_dir == expanded) {
+ /* this is the %n directory */
+ } else {
if (mkdir_parents_chgrp(expanded, st.st_mode,
(gid_t)-1, root_dir) < 0 &&
errno != EEXIST) {
@@ -1006,6 +1036,14 @@
perm->file_create_gid_origin = "egid";
perm->gid_origin_is_mailbox_path = FALSE;
}
+ } else {
+ /* when using %h and the parent has setgid-bit,
+ copy the permissions from it for the home we're creating */
+ perm->file_create_mode = st.st_mode & 0666;
+ perm->dir_create_mode = st.st_mode;
+ perm->file_create_gid = (gid_t)-1;
+ perm->file_create_gid_origin = "parent";
+ perm->gid_origin_is_mailbox_path = FALSE;
}
return 0;
}
More information about the dovecot-cvs
mailing list