103
static const char *fix_path(const char *path)
109
static int fix_path(struct mail_namespace *ns, const char *path,
110
const char **path_r, const char **error_r)
105
112
size_t len = strlen(path);
107
114
if (len > 1 && path[len-1] == '/')
108
115
path = t_strndup(path, len-1);
109
return home_expand(path);
116
if (path[0] == '~' && path[1] != '/') {
118
if (home_try_expand(&path) < 0) {
119
*error_r = t_strconcat(
120
"No home directory for system user. "
121
"Can't expand ", t_strcut(path, '/'),
126
if (mail_user_try_home_expand(ns->user, &path) < 0) {
127
*error_r = "Home directory not set for user. "
128
"Can't expand ~/ for ";
136
static const char *split_next_arg(const char *const **_args)
138
const char *const *args = *_args;
139
const char *str = args[0];
142
while (*args != NULL && **args == '\0') {
145
/* string ends with ":", just ignore it. */
148
str = t_strconcat(str, ":", *args, NULL);
112
155
int mailbox_list_settings_parse(const char *data,
113
156
struct mailbox_list_settings *set,
157
struct mail_namespace *ns,
114
158
const char **layout, const char **alt_dir_r,
115
159
const char **error_r)
117
const char *const *tmp, *key, *value;
161
const char *const *tmp, *key, *value, **dest, *str, *error;
119
163
i_assert(*data != '\0');
126
170
tmp = t_strsplit(data, ":");
127
set->root_dir = fix_path(*tmp);
171
str = split_next_arg(&tmp);
172
if (fix_path(ns, str, &set->root_dir, &error) < 0) {
173
*error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
130
for (; *tmp != NULL; tmp++) {
131
value = strchr(*tmp, '=');
177
while (*tmp != NULL) {
178
str = split_next_arg(&tmp);
179
value = strchr(str, '=');
132
180
if (value == NULL) {
136
key = t_strdup_until(*tmp, value);
184
key = t_strdup_until(str, value);
140
188
if (strcmp(key, "INBOX") == 0)
141
set->inbox_path = fix_path(value);
189
dest = &set->inbox_path;
142
190
else if (strcmp(key, "INDEX") == 0)
143
set->index_dir = fix_path(value);
191
dest = &set->index_dir;
144
192
else if (strcmp(key, "CONTROL") == 0)
145
set->control_dir = fix_path(value);
193
dest = &set->control_dir;
146
194
else if (strcmp(key, "ALT") == 0 && alt_dir_r != NULL)
147
*alt_dir_r = fix_path(value);
148
196
else if (strcmp(key, "LAYOUT") == 0)
150
198
else if (strcmp(key, "SUBSCRIPTIONS") == 0)
151
set->subscription_fname = fix_path(value);
199
dest = &set->subscription_fname;
152
200
else if (strcmp(key, "DIRNAME") == 0)
153
set->maildir_name = value;
201
dest = &set->maildir_name;
202
else if (strcmp(key, "MAILBOXDIR") == 0)
203
dest = &set->mailbox_dir_name;
155
205
*error_r = t_strdup_printf("Unknown setting: %s", key);
208
if (fix_path(ns, value, dest, &error) < 0) {
209
*error_r = t_strconcat(error, key, " in: ", data, NULL);
160
214
if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
187
242
list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
188
243
list->set.subscription_fname =
189
244
p_strdup(list->pool, set->subscription_fname);
190
list->set.maildir_name = p_strdup(list->pool, set->maildir_name);
245
list->set.maildir_name =
246
(list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
247
p_strdup(list->pool, set->maildir_name);
249
if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
250
list->set.mailbox_dir_name = "";
251
else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
252
list->set.mailbox_dir_name =
253
p_strdup(list->pool, set->mailbox_dir_name);
255
list->set.mailbox_dir_name =
256
p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
192
259
list->set.mail_storage_flags = set->mail_storage_flags;
193
260
list->set.lock_method = set->lock_method;
195
262
if ((flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
196
263
i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
197
list->name, list->set.root_dir,
265
list->set.root_dir == NULL ? "" : list->set.root_dir,
198
266
list->set.index_dir == NULL ? "" : list->set.index_dir,
199
267
list->set.control_dir == NULL ?
200
268
"" : list->set.control_dir,
216
284
list->v.deinit(list);
219
const char *mailbox_list_get_driver_name(struct mailbox_list *list)
287
const char *mailbox_list_get_driver_name(const struct mailbox_list *list)
221
289
return list->name;
224
char mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
292
char mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
226
294
return list->hierarchy_sep;
229
enum mailbox_list_flags mailbox_list_get_flags(struct mailbox_list *list)
297
enum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
231
299
return list->flags;
234
struct mail_namespace *mailbox_list_get_namespace(struct mailbox_list *list)
302
struct mail_namespace *
303
mailbox_list_get_namespace(const struct mailbox_list *list)
239
void mailbox_list_get_permissions(struct mailbox_list *list,
240
mode_t *mode_r, gid_t *gid_r)
308
static mode_t get_dir_mode(mode_t mode)
310
/* add the execute bit if either read or write bit is set */
311
if ((mode & 0600) != 0) mode |= 0100;
312
if ((mode & 0060) != 0) mode |= 0010;
313
if ((mode & 0006) != 0) mode |= 0001;
318
mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
319
mode_t *file_mode_r, mode_t *dir_mode_r,
320
gid_t *gid_r, const char **gid_origin_r)
242
322
const char *path;
245
if (list->file_create_mode != (mode_t)-1) {
246
*mode_r = list->file_create_mode;
247
*gid_r = list->file_create_gid;
251
path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
325
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
252
326
if (stat(path, &st) < 0) {
253
327
if (!ENOTFOUND(errno)) {
254
328
mailbox_list_set_critical(list, "stat(%s) failed: %m",
257
331
i_info("Namespace %s: Permission lookup failed from %s",
258
332
list->ns->prefix, path);
335
/* return defaults */
336
mailbox_list_get_permissions_full(list, NULL,
260
342
/* return safe defaults */
262
345
*gid_r = (gid_t)-1;
266
list->file_create_mode = st.st_mode & 0666;
267
if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
268
/* directory's GID is used automatically for new files */
269
list->file_create_gid = (gid_t)-1;
270
} else if ((st.st_mode & 0060) == 0) {
271
/* group doesn't have any permissions, so don't bother
273
list->file_create_gid = (gid_t)-1;
274
} else if (getegid() == st.st_gid) {
275
/* using our own gid, no need to change it */
276
list->file_create_gid = (gid_t)-1;
346
*gid_origin_r = "defaults";
278
list->file_create_gid = st.st_gid;
281
if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
348
*file_mode_r = st.st_mode & 0666;
349
*dir_mode_r = st.st_mode & 0777;
350
*gid_origin_r = path;
352
if (!S_ISDIR(st.st_mode)) {
353
/* we're getting permissions from a file.
354
apply +x modes as necessary. */
355
*dir_mode_r = get_dir_mode(*dir_mode_r);
358
if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
359
/* directory's GID is used automatically for new
362
} else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
363
/* group has same permissions as world, so don't bother
366
} else if (getegid() == st.st_gid) {
367
/* using our own gid, no need to change it */
375
list->file_create_mode = *file_mode_r;
376
list->dir_create_mode = *dir_mode_r;
377
list->file_create_gid = *gid_r;
378
list->file_create_gid_origin =
379
p_strdup(list->pool, *gid_origin_r);
382
if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0 && name == NULL) {
282
383
i_info("Namespace %s: Using permissions from %s: "
283
384
"mode=0%o gid=%ld", list->ns->prefix, path,
284
(int)list->file_create_mode,
385
(int)list->dir_create_mode,
285
386
list->file_create_gid == (gid_t)-1 ? -1L :
286
387
(long)list->file_create_gid);
289
*mode_r = list->file_create_mode;
290
*gid_r = list->file_create_gid;
391
void mailbox_list_get_permissions(struct mailbox_list *list,
393
mode_t *mode_r, gid_t *gid_r,
394
const char **gid_origin_r)
398
if (list->file_create_mode != (mode_t)-1 && name == NULL) {
399
*mode_r = list->file_create_mode;
400
*gid_r = list->file_create_gid;
401
*gid_origin_r = list->file_create_gid_origin;
405
mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
409
void mailbox_list_get_dir_permissions(struct mailbox_list *list,
411
mode_t *mode_r, gid_t *gid_r,
412
const char **gid_origin_r)
416
if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
417
*mode_r = list->dir_create_mode;
418
*gid_r = list->file_create_gid;
419
*gid_origin_r = list->file_create_gid_origin;
423
mailbox_list_get_permissions_full(list, name, &file_mode,
424
mode_r, gid_r, gid_origin_r);
293
427
bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
299
433
bool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
300
434
const char *name)
436
if (*name == '\0' && *list->ns->prefix != '\0') {
437
/* an ugly way to get to mailbox root (e.g. Maildir/ when
438
it's not the INBOX) */
302
442
return list->v.is_valid_existing_name(list, name);
305
445
bool mailbox_list_is_valid_create_name(struct mailbox_list *list,
306
446
const char *name)
308
return list->v.is_valid_create_name(list, name);
451
/* safer to just disallow all control characters */
452
for (p = name; *p != '\0'; p++) {
458
string_t *str = t_str_new(256);
459
ret = imap_utf7_to_utf8(name, str);
461
return ret < 0 ? FALSE :
462
list->v.is_valid_create_name(list, name);
311
465
const char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
376
529
return list->v.iter_init(list, patterns, flags);
532
static const struct mailbox_info *
533
mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx)
535
struct ns_list_iterate_context *ctx =
536
(struct ns_list_iterate_context *)_ctx;
537
const struct mailbox_info *info;
539
info = mailbox_list_iter_next(ctx->backend_ctx);
540
if (info == NULL && ctx->namespaces != NULL) {
541
/* go to the next namespace */
542
if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
544
ctx->ctx.list->ns = ctx->namespaces;
546
mailbox_list_iter_init_multiple(ctx->namespaces->list,
549
ctx->namespaces = ctx->namespaces->next;
550
return mailbox_list_ns_iter_next(_ctx);
556
mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx)
558
struct ns_list_iterate_context *ctx =
559
(struct ns_list_iterate_context *)_ctx;
562
if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
564
ret = _ctx->failed ? -1 : 0;
565
pool_unref(&ctx->pool);
569
struct mailbox_list_iterate_context *
570
mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
571
const char *const *patterns,
572
enum mailbox_list_iter_flags flags)
574
struct ns_list_iterate_context *ctx;
575
unsigned int i, count;
578
i_assert(namespaces != NULL);
580
pool = pool_alloconly_create("mailbox list namespaces", 512);
581
ctx = p_new(pool, struct ns_list_iterate_context, 1);
583
ctx->ctx.flags = flags;
584
ctx->ctx.list = p_new(pool, struct mailbox_list, 1);
585
ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next;
586
ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit;
588
count = str_array_length(patterns);
589
ctx->patterns = p_new(pool, const char *, count + 1);
590
for (i = 0; i < count; i++)
591
ctx->patterns[i] = p_strdup(pool, patterns[i]);
593
ctx->ctx.list->ns = namespaces;
594
ctx->backend_ctx = mailbox_list_iter_init_multiple(namespaces->list,
596
ctx->namespaces = namespaces->next;
379
600
const struct mailbox_info *
380
601
mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
382
return ctx->list->v.iter_next(ctx);
603
const struct mailbox_info *info;
605
info = ctx->list->v.iter_next(ctx);
607
ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
385
611
int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx)
391
617
return ctx->list->v.iter_deinit(ctx);
620
int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
621
enum mailbox_info_flags *flags_r)
623
struct mailbox_list_iterate_context ctx;
626
memset(&ctx, 0, sizeof(ctx));
630
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
631
return list->v.iter_is_mailbox == NULL ? 0 :
632
list->v.iter_is_mailbox(&ctx, path, "", "",
633
MAILBOX_LIST_FILE_TYPE_UNKNOWN,
394
637
int mailbox_list_set_subscribed(struct mailbox_list *list,
395
638
const char *name, bool set)
850
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
853
if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
861
/* try to expand home directory */
862
if ((*name)[1] == '/') {
863
/* ~/dir - use the configured home directory */
864
if (mail_user_try_home_expand(list->ns->user, name) == 0)
867
/* ~otheruser/dir - assume we're using system users */
868
if (home_try_expand(name) == 0)
871
/* fallback to using ~dir */
875
int mailbox_list_create_parent_dir(struct mailbox_list *list,
876
const char *mailbox, const char *path)
878
const char *p, *dir, *origin;
882
p = strrchr(path, '/');
886
dir = t_strdup_until(path, p);
887
mailbox_list_get_dir_permissions(list, mailbox, &mode, &gid, &origin);
888
if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
890
mailbox_list_set_critical(list, "mkdir_parents(%s) failed: %m",
606
897
const char *mailbox_list_get_last_error(struct mailbox_list *list,
607
898
enum mail_error *error_r)