diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-imap-urlauth/imap-urlauth-backend.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/lib-imap-urlauth/imap-urlauth-backend.c b/src/lib-imap-urlauth/imap-urlauth-backend.c new file mode 100644 index 0000000..de2b9c9 --- /dev/null +++ b/src/lib-imap-urlauth/imap-urlauth-backend.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "hex-binary.h" +#include "randgen.h" +#include "mail-user.h" +#include "mail-storage.h" +#include "mailbox-list-iter.h" +#include "imap-urlauth-private.h" +#include "imap-urlauth-backend.h" + +#define IMAP_URLAUTH_KEY MAILBOX_ATTRIBUTE_PREFIX_DOVECOT"imap-urlauth" + +static int +imap_urlauth_backend_trans_set_mailbox_key(struct mailbox *box, + unsigned char mailbox_key_r[IMAP_URLAUTH_KEY_LEN], + const char **client_error_r, + enum mail_error *error_code_r) +{ + struct mail_attribute_value urlauth_key; + const char *mailbox_key_hex = NULL; + int ret; + + if (mailbox_open(box) < 0) { + *client_error_r = mailbox_get_last_error(box, error_code_r); + return -1; + } + + struct mailbox_transaction_context *t = + mailbox_transaction_begin(box, + MAILBOX_TRANSACTION_FLAG_EXTERNAL, + __func__); + + /* create new key */ + random_fill(mailbox_key_r, IMAP_URLAUTH_KEY_LEN); + mailbox_key_hex = binary_to_hex(mailbox_key_r, + IMAP_URLAUTH_KEY_LEN); + i_zero(&urlauth_key); + urlauth_key.value = mailbox_key_hex; + ret = mailbox_attribute_set(t, MAIL_ATTRIBUTE_TYPE_PRIVATE, + IMAP_URLAUTH_KEY, &urlauth_key); + + if (mailbox_transaction_commit(&t) < 0) { + *client_error_r = mailbox_get_last_error(box, error_code_r); + ret = -1; + } + + return ret; +} + +static int +imap_urlauth_backend_trans_get_mailbox_key(struct mailbox *box, + bool create, + unsigned char mailbox_key_r[IMAP_URLAUTH_KEY_LEN], + const char **client_error_r, + enum mail_error *error_code_r) +{ + struct mail_user *user = mail_storage_get_user(mailbox_get_storage(box)); + struct mail_attribute_value urlauth_key; + const char *mailbox_key_hex = NULL; + buffer_t key_buf; + int ret; + + *client_error_r = "Internal server error"; + *error_code_r = MAIL_ERROR_TEMP; + + ret = mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_PRIVATE, + IMAP_URLAUTH_KEY, &urlauth_key); + if (ret < 0) + return -1; + + e_debug(user->event, "imap-urlauth: %skey found for mailbox %s", + (ret > 0 ? "" : "no "), mailbox_get_vname(box)); + + if (ret == 0) { + if (!create) + return 0; + + ret = imap_urlauth_backend_trans_set_mailbox_key(box, + mailbox_key_r, + client_error_r, + error_code_r); + + if (ret < 0) + return -1; + e_debug(user->event, "imap-urlauth: created key for mailbox %s", + mailbox_get_vname(box)); + } else { + /* read existing key */ + buffer_create_from_data(&key_buf, mailbox_key_r, + IMAP_URLAUTH_KEY_LEN); + mailbox_key_hex = urlauth_key.value; + if (strlen(mailbox_key_hex) != 2*IMAP_URLAUTH_KEY_LEN || + hex_to_binary(mailbox_key_hex, &key_buf) < 0 || + key_buf.used != IMAP_URLAUTH_KEY_LEN) { + i_error("imap-urlauth: key found for mailbox %s is invalid", + mailbox_get_vname(box)); + return -1; + } + } + return 1; +} + +int imap_urlauth_backend_get_mailbox_key(struct mailbox *box, bool create, + unsigned char mailbox_key_r[IMAP_URLAUTH_KEY_LEN], + const char **client_error_r, + enum mail_error *error_code_r) +{ + int ret; + + ret = imap_urlauth_backend_trans_get_mailbox_key(box, create, + mailbox_key_r, + client_error_r, + error_code_r); + return ret; +} + +int imap_urlauth_backend_reset_mailbox_key(struct mailbox *box) +{ + struct mailbox_transaction_context *t; + int ret; + + t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL, + __func__); + ret = mailbox_attribute_unset(t, MAIL_ATTRIBUTE_TYPE_PRIVATE, + IMAP_URLAUTH_KEY); + if (mailbox_transaction_commit(&t) < 0) + ret = -1; + return ret; +} + +static int imap_urlauth_backend_mailbox_reset_key(struct mailbox *box) +{ + const char *errstr; + enum mail_error error; + + if (mailbox_open(box) < 0) { + errstr = mailbox_get_last_internal_error(box, &error); + if (error == MAIL_ERROR_NOTFOUND || error == MAIL_ERROR_PERM) + return 0; + i_error("urlauth key reset: Couldn't open mailbox %s: %s", + mailbox_get_vname(box), errstr); + return -1; + } + return imap_urlauth_backend_reset_mailbox_key(box); +} + +int imap_urlauth_backend_reset_all_keys(struct mail_user *user) +{ + const char *const patterns[] = { "*", NULL }; + struct mailbox_list_iterate_context *iter; + const struct mailbox_info *info; + struct mailbox *box; + int ret = 0; + + iter = mailbox_list_iter_init_namespaces(user->namespaces, patterns, + MAIL_NAMESPACE_TYPE_MASK_ALL, + MAILBOX_LIST_ITER_NO_AUTO_BOXES | + MAILBOX_LIST_ITER_SKIP_ALIASES | + MAILBOX_LIST_ITER_RETURN_NO_FLAGS); + while ((info = mailbox_list_iter_next(iter)) != NULL) { + box = mailbox_alloc(info->ns->list, info->vname, 0); + if (imap_urlauth_backend_mailbox_reset_key(box) < 0) + ret = -1; + mailbox_free(&box); + } + if (mailbox_list_iter_deinit(&iter) < 0) { + i_error("urlauth key reset: Couldn't iterate mailboxes: %s", + mailbox_list_get_last_internal_error(user->namespaces->list, NULL)); + ret = -1; + } + return ret; +} |