struct mdbox_map * mdbox_map_init(struct mdbox_storage *storage, struct mailbox_list *root_list) { struct mdbox_map *map; const char *root, *index_root; root = mailbox_list_get_root_forced(root_list, MAILBOX_LIST_PATH_TYPE_DIR); index_root = mailbox_list_get_root_forced(root_list, MAILBOX_LIST_PATH_TYPE_INDEX); map = i_new(struct mdbox_map, 1); map->storage = storage; map->set = storage->set; map->path = i_strconcat(root, "/"MDBOX_GLOBAL_DIR_NAME, NULL); map->index_path = i_strconcat(index_root, "/"MDBOX_GLOBAL_DIR_NAME, NULL); map->index = mail_index_alloc(map->index_path, MDBOX_GLOBAL_INDEX_PREFIX); mail_index_set_fsync_mode(map->index, MAP_STORAGE(map)->set->parsed_fsync_mode, 0); mail_index_set_lock_method(map->index, MAP_STORAGE(map)->set->parsed_lock_method, mail_storage_get_lock_timeout(MAP_STORAGE(map), UINT_MAX)); map->root_list = root_list; map->map_ext_id = mail_index_ext_register(map->index, "map", sizeof(struct mdbox_map_mail_index_header), sizeof(struct mdbox_map_mail_index_record), sizeof(uint32_t)); map->ref_ext_id = mail_index_ext_register(map->index, "ref", 0, sizeof(uint16_t), sizeof(uint16_t)); return map; }
static bool acl_list_get_root_dir(struct acl_backend_vfile *backend, const char **root_dir_r, enum mailbox_list_path_type *type_r) { struct mail_storage *storage; const char *rootdir, *maildir; enum mailbox_list_path_type type; storage = mailbox_list_get_namespace(backend->backend.list)->storage; type = (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0 ? MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR; if (!mailbox_list_get_root_path(backend->backend.list, type, &rootdir)) return FALSE; *type_r = type; if (type == MAILBOX_LIST_PATH_TYPE_DIR && mail_storage_is_mailbox_file(storage)) { maildir = mailbox_list_get_root_forced(backend->backend.list, MAILBOX_LIST_PATH_TYPE_MAILBOX); if (strcmp(maildir, rootdir) == 0) { /* dovecot-acl-list would show up as a mailbox if we created it to root dir. since we don't really have any other good alternatives, place it to control dir */ rootdir = mailbox_list_get_root_forced(backend->backend.list, MAILBOX_LIST_PATH_TYPE_CONTROL); *type_r = MAILBOX_LIST_PATH_TYPE_CONTROL; } } *root_dir_r = rootdir; return TRUE; }
int mdbox_storage_create(struct mail_storage *_storage, struct mail_namespace *ns, const char **error_r) { struct mdbox_storage *storage = (struct mdbox_storage *)_storage; const char *dir; storage->set = mail_storage_get_driver_settings(_storage); storage->preallocate_space = storage->set->mdbox_preallocate_space; if (*ns->list->set.mailbox_dir_name == '\0') { *error_r = "mdbox: MAILBOXDIR must not be empty"; return -1; } _storage->unique_root_dir = p_strdup(_storage->pool, ns->list->set.root_dir); dir = mailbox_list_get_root_forced(ns->list, MAILBOX_LIST_PATH_TYPE_DIR); storage->storage_dir = p_strconcat(_storage->pool, dir, "/"MDBOX_GLOBAL_DIR_NAME, NULL); storage->alt_storage_dir = p_strconcat(_storage->pool, ns->list->set.alt_dir, "/"MDBOX_GLOBAL_DIR_NAME, NULL); i_array_init(&storage->open_files, 64); storage->map = mdbox_map_init(storage, ns->list); return dbox_storage_create(_storage, ns, error_r); }
static int mbox_mailbox_open_existing(struct mbox_mailbox *mbox) { struct mailbox *box = &mbox->box; const char *rootdir, *box_path = mailbox_get_path(box); bool move_to_memory; move_to_memory = want_memory_indexes(mbox->storage, box_path); if (box->inbox_any || strcmp(box->name, "INBOX") == 0) { /* if INBOX isn't under the root directory, it's probably in /var/mail and we want to allow privileged dotlocking */ rootdir = mailbox_list_get_root_forced(box->list, MAILBOX_LIST_PATH_TYPE_DIR); if (strncmp(box_path, rootdir, strlen(rootdir)) != 0) mbox->mbox_privileged_locking = TRUE; } if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) { if (mbox_lock(mbox, F_WRLCK, &mbox->mbox_global_lock_id) <= 0) return -1; if (mbox->mbox_dotlock != NULL) { mbox->keep_lock_to = timeout_add(MBOX_LOCK_TOUCH_MSECS, mbox_lock_touch_timeout, mbox); } } return mbox_mailbox_open_finish(mbox, move_to_memory); }
static const char * mailbox_list_maildir_get_trash_dir(struct mailbox_list *_list) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; const char *root_dir; root_dir = mailbox_list_get_root_forced(_list, MAILBOX_LIST_PATH_TYPE_DIR); return t_strdup_printf("%s/%c%c"MAILBOX_LIST_MAILDIR_TRASH_DIR_NAME, root_dir, list->sep, list->sep); }
static int mailbox_list_check_root_delete(struct mailbox_list *list, const char *name, const char *path) { const char *root_dir; root_dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR); if (strcmp(root_dir, path) != 0) return 0; if (strcmp(name, "INBOX") == 0 && (list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) { mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, "INBOX can't be deleted."); return -1; } mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, "Mail storage root can't be deleted."); return -1; }
void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path, enum mailbox_list_path_type type) { const char *root_dir, *p; unsigned int len; root_dir = mailbox_list_get_root_forced(list, type); if (strncmp(path, root_dir, strlen(root_dir)) != 0) { /* mbox workaround: name=child/box, root_dir=mail/.imap/, path=mail/child/.imap/box. we'll want to try to delete the .imap/ part, but no further. */ len = strlen(path); while (len > 0 && path[len-1] != '/') len--; if (len == 0) return; len--; while (len > 0 && path[len-1] != '/') len--; if (len == 0) return; root_dir = t_strndup(path, len-1); } while (strcmp(path, root_dir) != 0) { if (rmdir(path) < 0 && errno != ENOENT) { if (errno == ENOTEMPTY || errno == EEXIST) return; mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path); return; } p = strrchr(path, '/'); if (p == NULL) break; path = t_strdup_until(path, p); } }
static void mbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path) { const char *dir, *errmsg, *name; struct stat st; struct group group; int orig_errno = errno; errmsg = eacces_error_get_creating("file_dotlock_create", path); dir = strrchr(path, '/'); dir = dir == NULL ? "." : t_strdup_until(path, dir); /* allow privileged locking for a) user's own INBOX, b) another user's shared INBOX, and c) anything called INBOX (in inbox=no namespace) */ if (!mbox->box.inbox_any && strcmp(mbox->box.name, "INBOX") != 0) { mailbox_set_critical(&mbox->box, "%s (not INBOX -> no privileged locking)", errmsg); } else if (!mbox->mbox_privileged_locking) { dir = mailbox_list_get_root_forced(mbox->box.list, MAILBOX_LIST_PATH_TYPE_DIR); mailbox_set_critical(&mbox->box, "%s (under root dir %s -> no privileged locking)", errmsg, dir); } else if (stat(dir, &st) == 0 && (st.st_mode & 02) == 0 && /* not world-writable */ (st.st_mode & 020) != 0) { /* group-writable */ if (i_getgrgid(st.st_gid, &group) <= 0) name = dec2str(st.st_gid); else name = group.gr_name; mailbox_set_critical(&mbox->box, "%s (set mail_privileged_group=%s)", errmsg, name); } else { mailbox_set_critical(&mbox->box, "%s (nonstandard permissions in %s)", errmsg, dir); } errno = orig_errno; }
static int cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user, struct dsync_brain *brain, struct dsync_ibc *ibc2, bool *changes_during_sync_r) { struct dsync_brain *brain2; struct mail_user *user2; struct setting_parser_context *set_parser; const char *set_line, *location; bool brain1_running, brain2_running, changed1, changed2; int ret; if (ctx->local_location_from_arg) location = ctx->ctx.args[0]; else { i_assert(ctx->local_location != NULL); location = ctx->local_location; } i_set_failure_prefix("dsync(%s): ", user->username); /* update mail_location and create another user for the second location. */ set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user); set_line = t_strconcat("mail_location=", location, NULL); if (settings_parse_line(set_parser, set_line) < 0) i_unreached(); ret = mail_storage_service_next(ctx->ctx.storage_service, ctx->ctx.cur_service_user, &user2); if (ret < 0) { ctx->ctx.exit_code = ret == -1 ? EX_TEMPFAIL : EX_CONFIG; return -1; } doveadm_user_init_dsync(user2); if (mail_namespaces_get_root_sep(user->namespaces) != mail_namespaces_get_root_sep(user2->namespaces)) { i_error("Mail locations must use the same " "virtual mailbox hierarchy separator " "(specify separator for the default namespace)"); ctx->ctx.exit_code = EX_CONFIG; mail_user_unref(&user2); return -1; } if (paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_MAILBOX) && paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_INDEX)) { i_error("Both source and destination mail_location " "points to same directory: %s", mailbox_list_get_root_forced(user->namespaces->list, MAILBOX_LIST_PATH_TYPE_MAILBOX)); ctx->ctx.exit_code = EX_CONFIG; mail_user_unref(&user2); return -1; } brain2 = dsync_brain_slave_init(user2, ibc2, TRUE); mail_user_unref(&user2); brain1_running = brain2_running = TRUE; changed1 = changed2 = TRUE; while (brain1_running || brain2_running) { if (dsync_brain_has_failed(brain) || dsync_brain_has_failed(brain2)) break; i_assert(changed1 || changed2); brain1_running = dsync_brain_run(brain, &changed1); brain2_running = dsync_brain_run(brain2, &changed2); } *changes_during_sync_r = dsync_brain_has_unexpected_changes(brain2); if (dsync_brain_deinit(&brain2) < 0) { ctx->ctx.exit_code = EX_TEMPFAIL; return -1; } return 0; }
static int maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname, struct mailbox_list *newlist, const char *newname) { const char *oldpath, *newpath, *root_path; int ret; bool found; /* NOTE: it's possible to rename a nonexistent mailbox which has children. In that case we should ignore the rename() error. */ if (mailbox_list_get_path(oldlist, oldname, MAILBOX_LIST_PATH_TYPE_MAILBOX, &oldpath) <= 0 || mailbox_list_get_path(newlist, newname, MAILBOX_LIST_PATH_TYPE_MAILBOX, &newpath) <= 0) i_unreached(); root_path = mailbox_list_get_root_forced(oldlist, MAILBOX_LIST_PATH_TYPE_MAILBOX); if (strcmp(oldpath, root_path) == 0) { /* most likely INBOX */ mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE, t_strdup_printf("Renaming %s isn't supported.", oldname)); return -1; } /* if we're renaming under another mailbox, require its permissions to be same as ours. */ if (strchr(newname, mailbox_list_get_hierarchy_sep(newlist)) != NULL) { struct mailbox_permissions old_perm, new_perm; mailbox_list_get_permissions(oldlist, oldname, &old_perm); mailbox_list_get_permissions(newlist, newname, &new_perm); if ((new_perm.file_create_mode != old_perm.file_create_mode || new_perm.dir_create_mode != old_perm.dir_create_mode || new_perm.file_create_gid != old_perm.file_create_gid)) { mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE, "Renaming not supported across conflicting " "directory permissions"); return -1; } } ret = rename(oldpath, newpath); if (ret == 0 || errno == ENOENT) { (void)rename_dir(oldlist, oldname, newlist, newname, MAILBOX_LIST_PATH_TYPE_CONTROL); (void)rename_dir(oldlist, oldname, newlist, newname, MAILBOX_LIST_PATH_TYPE_INDEX); found = ret == 0; T_BEGIN { ret = maildir_rename_children(oldlist, oldname, newlist, newname); } T_END; if (ret < 0) return -1; if (!found && ret == 0) { mailbox_list_set_error(oldlist, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname)); return -1; } return 0; }