"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib-storage/mail-storage.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

mail-storage.c  (dovecot-2.3.16):mail-storage.c  (dovecot-2.3.17)
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h" #include "lib.h"
#include "ioloop.h" #include "ioloop.h"
#include "array.h" #include "array.h"
#include "llist.h" #include "llist.h"
#include "mail-storage.h"
#include "str.h" #include "str.h"
#include "str-sanitize.h" #include "str-sanitize.h"
#include "sha1.h" #include "sha1.h"
#include "unichar.h" #include "unichar.h"
#include "hex-binary.h" #include "hex-binary.h"
#include "fs-api.h"
#include "iostream-ssl.h"
#include "file-dotlock.h" #include "file-dotlock.h"
#include "file-create-locked.h" #include "file-create-locked.h"
#include "istream.h" #include "istream.h"
#include "eacces-error.h" #include "eacces-error.h"
#include "mkdir-parents.h" #include "mkdir-parents.h"
#include "time-util.h" #include "time-util.h"
#include "var-expand.h" #include "var-expand.h"
#include "dsasl-client.h" #include "dsasl-client.h"
#include "imap-date.h" #include "imap-date.h"
#include "settings-parser.h" #include "settings-parser.h"
skipping to change at line 420 skipping to change at line 423
storage = mail_storage_find(ns->user, storage_class, &list_set); storage = mail_storage_find(ns->user, storage_class, &list_set);
if (storage != NULL) { if (storage != NULL) {
/* using an existing storage */ /* using an existing storage */
storage->refcount++; storage->refcount++;
mail_namespace_add_storage(ns, storage); mail_namespace_add_storage(ns, storage);
*storage_r = storage; *storage_r = storage;
return 0; return 0;
} }
storage = storage_class->v.alloc(); storage = storage_class->v.alloc();
if (storage->lost_mailbox_prefix == NULL)
storage->lost_mailbox_prefix = MAIL_STORAGE_LOST_MAILBOX_PREFIX;
storage->refcount = 1; storage->refcount = 1;
storage->storage_class = storage_class; storage->storage_class = storage_class;
storage->user = ns->user; storage->user = ns->user;
storage->set = ns->mail_set; storage->set = ns->mail_set;
storage->flags = flags; storage->flags = flags;
storage->event = event_create(ns->user->event); storage->event = event_create(ns->user->event);
if (storage_class->event_category != NULL) if (storage_class->event_category != NULL)
event_add_category(storage->event, storage_class->event_category) ; event_add_category(storage->event, storage_class->event_category) ;
p_array_init(&storage->module_contexts, storage->pool, 5); p_array_init(&storage->module_contexts, storage->pool, 5);
if (storage->v.create != NULL && if (storage->v.create != NULL &&
storage->v.create(storage, ns, error_r) < 0) { storage->v.create(storage, ns, error_r) < 0) {
*error_r = t_strdup_printf("%s: %s", storage->name, *error_r); *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
event_unref(&storage->event); event_unref(&storage->event);
pool_unref(&storage->pool); pool_unref(&storage->pool);
return -1; return -1;
} }
/* If storage supports list index rebuild,
provide default mailboxes_fs unless storage
wants to use its own. */
if (storage->v.list_index_rebuild != NULL &&
storage->mailboxes_fs == NULL) {
struct fs_settings fs_set;
struct ssl_iostream_settings ssl_set;
const char *error;
i_zero(&fs_set);
mail_user_init_fs_settings(storage->user, &fs_set, &ssl_set);
if (fs_init("posix", "", &fs_set, &storage->mailboxes_fs,
&error) < 0) {
*error_r = t_strdup_printf("fs_init(posix) failed: %s", e
rror);
storage->v.destroy(storage);
return -1;
}
}
T_BEGIN { T_BEGIN {
hook_mail_storage_created(storage); hook_mail_storage_created(storage);
} T_END; } T_END;
i_assert(storage->unique_root_dir != NULL || i_assert(storage->unique_root_dir != NULL ||
(storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0); (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0);
DLLIST_PREPEND(&ns->user->storages, storage); DLLIST_PREPEND(&ns->user->storages, storage);
mail_namespace_add_storage(ns, storage); mail_namespace_add_storage(ns, storage);
*storage_r = storage; *storage_r = storage;
return 0; return 0;
skipping to change at line 488 skipping to change at line 512
DLLIST_REMOVE(&storage->user->storages, storage); DLLIST_REMOVE(&storage->user->storages, storage);
storage->v.destroy(storage); storage->v.destroy(storage);
i_free(storage->last_internal_error); i_free(storage->last_internal_error);
i_free(storage->error_string); i_free(storage->error_string);
if (array_is_created(&storage->error_stack)) { if (array_is_created(&storage->error_stack)) {
i_assert(array_count(&storage->error_stack) == 0); i_assert(array_count(&storage->error_stack) == 0);
array_free(&storage->error_stack); array_free(&storage->error_stack);
} }
fs_unref(&storage->mailboxes_fs);
event_unref(&storage->event); event_unref(&storage->event);
*_storage = NULL; *_storage = NULL;
pool_unref(&storage->pool); pool_unref(&storage->pool);
mail_index_alloc_cache_destroy_unrefed(); mail_index_alloc_cache_destroy_unrefed();
} }
void mail_storage_obj_ref(struct mail_storage *storage) void mail_storage_obj_ref(struct mail_storage *storage)
{ {
skipping to change at line 923 skipping to change at line 948
static bool static bool
str_contains_special_use(const char *str, const char *special_use) str_contains_special_use(const char *str, const char *special_use)
{ {
const char *const *uses; const char *const *uses;
i_assert(special_use != NULL); i_assert(special_use != NULL);
if (*special_use != '\\') if (*special_use != '\\')
return FALSE; return FALSE;
uses = t_strsplit_spaces(str, " "); bool ret;
return str_array_icase_find(uses, special_use); T_BEGIN {
uses = t_strsplit_spaces(str, " ");
ret = str_array_icase_find(uses, special_use);
} T_END;
return ret;
} }
static int static int
namespace_find_special_use(struct mail_namespace *ns, const char *special_use, namespace_find_special_use(struct mail_namespace *ns, const char *special_use,
const char **vname_r, enum mail_error *error_code_r) const char **vname_r, enum mail_error *error_code_r)
{ {
struct mailbox_list *list = ns->list; struct mailbox_list *list = ns->list;
struct mailbox_list_iterate_context *ctx; struct mailbox_list_iterate_context *ctx;
const struct mailbox_info *info; const struct mailbox_info *info;
int ret = 0; int ret = 0;
skipping to change at line 1207 skipping to change at line 1236
if (vname[0] == '\0') { if (vname[0] == '\0') {
/* "namespace/" isn't a valid mailbox name. */ /* "namespace/" isn't a valid mailbox name. */
*error_r = "Ends with hierarchy separator"; *error_r = "Ends with hierarchy separator";
return FALSE; return FALSE;
} }
} }
*vnamep = vname; *vnamep = vname;
return TRUE; return TRUE;
} }
int mailbox_verify_name(struct mailbox *box) static int mailbox_verify_name_int(struct mailbox *box)
{ {
struct mail_namespace *ns = box->list->ns; struct mail_namespace *ns = box->list->ns;
const char *error, *vname = box->vname; const char *error, *vname = box->vname;
char list_sep, ns_sep; char list_sep, ns_sep;
if (box->inbox_user) { if (box->inbox_user) {
/* this is INBOX - don't bother with further checks */ /* this is INBOX - don't bother with further checks */
return 0; return 0;
} }
skipping to change at line 1263 skipping to change at line 1292
if (!mailbox_name_verify_extra_separators(vname, ns_sep, &error) || if (!mailbox_name_verify_extra_separators(vname, ns_sep, &error) ||
!mailbox_list_is_valid_name(box->list, box->name, &error)) { !mailbox_list_is_valid_name(box->list, box->name, &error)) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
t_strdup_printf("Invalid mailbox name: %s", error)); t_strdup_printf("Invalid mailbox name: %s", error));
return -1; return -1;
} }
return 0; return 0;
} }
static int mailbox_verify_existing_name(struct mailbox *box) int mailbox_verify_name(struct mailbox *box)
{
int ret;
T_BEGIN {
ret = mailbox_verify_name_int(box);
} T_END;
return ret;
}
static int mailbox_verify_existing_name_int(struct mailbox *box)
{ {
const char *path; const char *path;
if (box->opened) if (box->opened)
return 0; return 0;
if (mailbox_verify_name(box) < 0) if (mailbox_verify_name(box) < 0)
return -1; return -1;
/* Make sure box->_path is set, so mailbox_get_path() works from /* Make sure box->_path is set, so mailbox_get_path() works from
skipping to change at line 1291 skipping to change at line 1329
if (mailbox_autocreate(box) < 0) if (mailbox_autocreate(box) < 0)
return -1; return -1;
mailbox_close(box); mailbox_close(box);
if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
&path) < 0) &path) < 0)
return -1; return -1;
} }
return 0; return 0;
} }
static int mailbox_verify_existing_name(struct mailbox *box)
{
int ret;
T_BEGIN {
ret = mailbox_verify_existing_name_int(box);
} T_END;
return ret;
}
static bool mailbox_name_has_control_chars(const char *name) static bool mailbox_name_has_control_chars(const char *name)
{ {
const char *p; const char *p;
for (p = name; *p != '\0'; p++) { for (p = name; *p != '\0'; p++) {
if ((unsigned char)*p < ' ') if ((unsigned char)*p < ' ')
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
skipping to change at line 1709 skipping to change at line 1756
/* Avoid race conditions by keeping mailbox list locked during changes. /* Avoid race conditions by keeping mailbox list locked during changes.
This especially fixes a race during INBOX creation with LAYOUT=index This especially fixes a race during INBOX creation with LAYOUT=index
because it scans for missing mailboxes if INBOX doesn't exist. The because it scans for missing mailboxes if INBOX doesn't exist. The
second process's scan can find a half-created INBOX and add it, second process's scan can find a half-created INBOX and add it,
causing the first process to become confused. */ causing the first process to become confused. */
if (mailbox_list_lock(box->list) < 0) { if (mailbox_list_lock(box->list) < 0) {
mail_storage_copy_list_error(box->storage, box->list); mail_storage_copy_list_error(box->storage, box->list);
return -1; return -1;
} }
box->creating = TRUE; box->creating = TRUE;
ret = box->v.create_box(box, update, directory); T_BEGIN {
ret = box->v.create_box(box, update, directory);
} T_END;
box->creating = FALSE; box->creating = FALSE;
mailbox_list_unlock(box->list); mailbox_list_unlock(box->list);
if (ret == 0) { if (ret == 0) {
box->list->guid_cache_updated = TRUE; box->list->guid_cache_updated = TRUE;
if (!box->inbox_any) if (!box->inbox_any) T_BEGIN {
mailbox_copy_cache_decisions_from_inbox(box); mailbox_copy_cache_decisions_from_inbox(box);
} T_END;
} else if (box->opened) { } else if (box->opened) {
/* Creation failed after (partially) opening the mailbox. /* Creation failed after (partially) opening the mailbox.
It may not be in a valid state, so close it. */ It may not be in a valid state, so close it. */
mail_storage_last_error_push(box->storage); mail_storage_last_error_push(box->storage);
mailbox_close(box); mailbox_close(box);
mail_storage_last_error_pop(box->storage); mail_storage_last_error_pop(box->storage);
} }
return ret; return ret;
} }
skipping to change at line 1750 skipping to change at line 1800
return ret; return ret;
} }
int mailbox_mark_index_deleted(struct mailbox *box, bool del) int mailbox_mark_index_deleted(struct mailbox *box, bool del)
{ {
struct mail_index_transaction *trans; struct mail_index_transaction *trans;
enum mail_index_transaction_flags trans_flags = 0; enum mail_index_transaction_flags trans_flags = 0;
enum mailbox_flags old_flag; enum mailbox_flags old_flag;
int ret; int ret;
e_debug(box->event, "Attempting to %s mailbox", del ?
"delete" : "undelete");
if (box->marked_deleted && del) { if (box->marked_deleted && del) {
/* we already marked it deleted. this allows plugins to /* we already marked it deleted. this allows plugins to
"lock" the deletion earlier. */ "lock" the deletion earlier. */
return 0; return 0;
} }
old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED; old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
box->flags |= MAILBOX_FLAG_OPEN_DELETED; box->flags |= MAILBOX_FLAG_OPEN_DELETED;
ret = mailbox_open(box); ret = mailbox_open(box);
box->flags = (box->flags & ENUM_NEGATE(MAILBOX_FLAG_OPEN_DELETED)) | old_ flag; box->flags = (box->flags & ENUM_NEGATE(MAILBOX_FLAG_OPEN_DELETED)) | old_ flag;
skipping to change at line 1797 skipping to change at line 1850
return 0; return 0;
} }
static void mailbox_close_reset_path(struct mailbox *box) static void mailbox_close_reset_path(struct mailbox *box)
{ {
i_zero(&box->_perm); i_zero(&box->_perm);
box->_path = NULL; box->_path = NULL;
box->_index_path = NULL; box->_index_path = NULL;
} }
int mailbox_delete(struct mailbox *box) static int mailbox_delete_real(struct mailbox *box)
{ {
bool list_locked; bool list_locked;
int ret; int ret;
if (*box->name == '\0') { if (*box->name == '\0') {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Storage root can't be deleted"); "Storage root can't be deleted");
return -1; return -1;
} }
skipping to change at line 1842 skipping to change at line 1895
box->deleting = FALSE; box->deleting = FALSE;
mailbox_close(box); mailbox_close(box);
/* if mailbox is reopened, its path may be different with /* if mailbox is reopened, its path may be different with
LAYOUT=index */ LAYOUT=index */
mailbox_close_reset_path(box); mailbox_close_reset_path(box);
return ret; return ret;
} }
int mailbox_delete(struct mailbox *box)
{
int ret;
T_BEGIN {
ret = mailbox_delete_real(box);
} T_END;
return ret;
}
int mailbox_delete_empty(struct mailbox *box) int mailbox_delete_empty(struct mailbox *box)
{ {
int ret; int ret;
/* FIXME: should be a parameter to delete(), but since it changes API /* FIXME: should be a parameter to delete(), but since it changes API
don't do it for now */ don't do it for now */
box->deleting_must_be_empty = TRUE; box->deleting_must_be_empty = TRUE;
ret = mailbox_delete(box); ret = mailbox_delete(box);
box->deleting_must_be_empty = FALSE; box->deleting_must_be_empty = FALSE;
return ret; return ret;
skipping to change at line 1946 skipping to change at line 2008
} }
/* something went bad */ /* something went bad */
if (mailbox_list_iter_deinit(&iter) < 0) { if (mailbox_list_iter_deinit(&iter) < 0) {
mail_storage_copy_list_error(src->storage, src->list); mail_storage_copy_list_error(src->storage, src->list);
ret = -1; ret = -1;
} }
return ret; return ret;
} }
int mailbox_rename(struct mailbox *src, struct mailbox *dest) static int mailbox_rename_real(struct mailbox *src, struct mailbox *dest)
{ {
const char *error = NULL; const char *error = NULL;
/* Check only name validity, \Noselect don't necessarily exist. */ /* Check only name validity, \Noselect don't necessarily exist. */
if (mailbox_verify_name(src) < 0) if (mailbox_verify_name(src) < 0)
return -1; return -1;
if (*src->name == '\0') { if (*src->name == '\0') {
mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS, mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS,
"Can't rename mailbox root"); "Can't rename mailbox root");
return -1; return -1;
skipping to change at line 2006 skipping to change at line 2068
} }
int ret = src->v.rename_box(src, dest); int ret = src->v.rename_box(src, dest);
mailbox_list_unlock(dest->list); mailbox_list_unlock(dest->list);
if (ret < 0) if (ret < 0)
return -1; return -1;
src->list->guid_cache_invalidated = TRUE; src->list->guid_cache_invalidated = TRUE;
dest->list->guid_cache_invalidated = TRUE; dest->list->guid_cache_invalidated = TRUE;
return 0; return 0;
} }
int mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
int ret;
T_BEGIN {
ret = mailbox_rename_real(src, dest);
} T_END;
return ret;
}
int mailbox_set_subscribed(struct mailbox *box, bool set) int mailbox_set_subscribed(struct mailbox *box, bool set)
{ {
if (mailbox_verify_name(box) < 0) if (mailbox_verify_name(box) < 0)
return -1; return -1;
if (mailbox_list_iter_subscriptions_refresh(box->list) < 0) { if (mailbox_list_iter_subscriptions_refresh(box->list) < 0) {
mail_storage_copy_list_error(box->storage, box->list); mail_storage_copy_list_error(box->storage, box->list);
return -1; return -1;
} }
if (mailbox_is_subscribed(box) == set) if (mailbox_is_subscribed(box) == set)
return 0; return 0;
skipping to change at line 2753 skipping to change at line 2824
return ret; return ret;
} }
int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail) int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail)
{ {
struct mail_save_context *ctx = *_ctx; struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving); i_assert(!ctx->saving);
i_assert(!ctx->moving); i_assert(!ctx->moving);
return mailbox_copy_int(_ctx, mail); int ret;
T_BEGIN {
ret = mailbox_copy_int(_ctx, mail);
} T_END;
return ret;
} }
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail) int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
{ {
struct mail_save_context *ctx = *_ctx; struct mail_save_context *ctx = *_ctx;
int ret; int ret;
i_assert(!ctx->saving); i_assert(!ctx->saving);
i_assert(!ctx->moving); i_assert(!ctx->moving);
ctx->moving = TRUE; ctx->moving = TRUE;
if ((ret = mailbox_copy_int(_ctx, mail)) == 0) T_BEGIN {
mail_expunge(mail); if ((ret = mailbox_copy_int(_ctx, mail)) == 0)
mail_expunge(mail);
} T_END;
ctx->moving = FALSE; ctx->moving = FALSE;
return ret; return ret;
} }
int mailbox_save_using_mail(struct mail_save_context **_ctx, struct mail *mail) int mailbox_save_using_mail(struct mail_save_context **_ctx, struct mail *mail)
{ {
struct mail_save_context *ctx = *_ctx; struct mail_save_context *ctx = *_ctx;
i_assert(!ctx->saving); i_assert(!ctx->saving);
i_assert(!ctx->moving); i_assert(!ctx->moving);
skipping to change at line 3120 skipping to change at line 3198
} }
*lock_r = file_lock_from_dotlock(&dotlock); *lock_r = file_lock_from_dotlock(&dotlock);
return 1; return 1;
} }
int mail_storage_lock_create(const char *lock_path, int mail_storage_lock_create(const char *lock_path,
const struct file_create_settings *lock_set, const struct file_create_settings *lock_set,
const struct mail_storage_settings *mail_set, const struct mail_storage_settings *mail_set,
struct file_lock **lock_r, const char **error_r) struct file_lock **lock_r, const char **error_r)
{ {
struct file_create_settings lock_set_new = *lock_set;
bool created; bool created;
if (lock_set->lock_method == FILE_LOCK_METHOD_DOTLOCK) if (lock_set->lock_settings.lock_method == FILE_LOCK_METHOD_DOTLOCK)
return mail_storage_dotlock_create(lock_path, lock_set, mail_set, lock_r, error_r); return mail_storage_dotlock_create(lock_path, lock_set, mail_set, lock_r, error_r);
if (file_create_locked(lock_path, lock_set, lock_r, lock_set_new.lock_settings.close_on_free = TRUE;
lock_set_new.lock_settings.unlink_on_free = TRUE;
if (file_create_locked(lock_path, &lock_set_new, lock_r,
&created, error_r) == -1) { &created, error_r) == -1) {
*error_r = t_strdup_printf("file_create_locked(%s) failed: %s", *error_r = t_strdup_printf("file_create_locked(%s) failed: %s",
lock_path, *error_r); lock_path, *error_r);
return errno == EAGAIN ? 0 : -1; return errno == EAGAIN ? 0 : -1;
} }
file_lock_set_close_on_free(*lock_r, TRUE);
file_lock_set_unlink_on_free(*lock_r, TRUE);
return 1; return 1;
} }
int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname, int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname,
unsigned int lock_secs, struct file_lock **lock_r, unsigned int lock_secs, struct file_lock **lock_r,
const char **error_r) const char **error_r)
{ {
const struct mailbox_permissions *perm; const struct mailbox_permissions *perm;
struct file_create_settings set; struct file_create_settings set;
const char *lock_path; const char *lock_path;
perm = mailbox_get_permissions(box); perm = mailbox_get_permissions(box);
i_zero(&set); i_zero(&set);
set.lock_timeout_secs = set.lock_timeout_secs =
mail_storage_get_lock_timeout(box->storage, lock_secs); mail_storage_get_lock_timeout(box->storage, lock_secs);
set.lock_method = box->storage->set->parsed_lock_method; set.lock_settings.lock_method = box->storage->set->parsed_lock_method;
set.mode = perm->file_create_mode; set.mode = perm->file_create_mode;
set.gid = perm->file_create_gid; set.gid = perm->file_create_gid;
set.gid_origin = perm->file_create_gid_origin; set.gid_origin = perm->file_create_gid_origin;
if (box->list->set.volatile_dir == NULL) if (box->list->set.volatile_dir == NULL)
lock_path = t_strdup_printf("%s/%s", box->index->dir, lock_fname) ; lock_path = t_strdup_printf("%s/%s", box->index->dir, lock_fname) ;
else { else {
unsigned char box_name_sha1[SHA1_RESULTLEN]; unsigned char box_name_sha1[SHA1_RESULTLEN];
string_t *str = t_str_new(128); string_t *str = t_str_new(128);
 End of changes. 24 change blocks. 
16 lines changed or deleted 96 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)