bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "lib.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "ioloop-private.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "str.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "sha2.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "module-dir.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "var-expand.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "hex-binary.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-namespace.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-storage-hooks.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-storage-service.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "acl-plugin.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "acl-api-private.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-common.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-key.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "mail-crypt-plugin.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#define MAIL_CRYPT_ACL_LIST_CONTEXT(obj) \
5b8e42f398e33019ed65672ba5d0ab79d1c2310bAki Tuomi MODULE_CONTEXT_REQUIRE(obj, mail_crypt_acl_mailbox_list_module)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistruct mail_crypt_acl_mailbox_list {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi union mailbox_list_module_context module_ctx;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_backend_vfuncs acl_vprev;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic MODULE_CONTEXT_DEFINE_INIT(mail_crypt_acl_mailbox_list_module,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &mailbox_list_module_register);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_acl_plugin_init(struct module *module);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_acl_plugin_deinit(void);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_has_user_read_right(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_object_list_iter *iter;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_rights rights;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi iter = acl_object_list_init(aclobj);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while (acl_object_list_next(iter, &rights)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (rights.id_type == ACL_ID_USER &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strcmp(rights.identifier, username) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = str_array_find(rights.rights, MAIL_ACL_READ) ? 1 : 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (acl_object_list_deinit(&iter) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = "Failed to iterate ACL objects";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mail_crypt_acl_has_nonuser_read_right(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_object_list_iter *iter;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_rights rights;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi iter = acl_object_list_init(aclobj);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi while (acl_object_list_next(iter, &rights)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (rights.id_type != ACL_ID_USER &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi rights.id_type != ACL_ID_OWNER &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi rights.rights != NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_array_find(rights.rights, MAIL_ACL_READ)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (acl_object_list_deinit(&iter) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = "Failed to iterate ACL objects";
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_unset_private_keys(struct mailbox *src_box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum mail_attribute_type type,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ARRAY_TYPE(const_string) digests;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *error;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_open(src_box) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(src_box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(src_box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi t_array_init(&digests, 4);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_get_pvt_digests(src_box, pool_datastack_create(),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi type, &digests, &error) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Failed to lookup public key digests: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&src_box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t;
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(src_box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *const *hash;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi array_foreach(&digests, hash) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *ptr;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* if the id contains username part, skip to key public id */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ptr = strchr(*hash, '/')) != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ptr++;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi else
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ptr = *hash;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_box_unset_shared_key(t, ptr, dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_transaction_rollback(&t);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (mailbox_transaction_commit(&t) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_transaction_commit(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(src_box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(src_box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_user_create(struct mail_user *user, const char *dest_username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user **dest_user_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_user **dest_service_user_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const struct mail_storage_service_input *old_input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_input input;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_ctx *service_ctx;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ioloop_context *cur_ioloop_ctx;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(user->_service_user != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi service_ctx = mail_storage_service_user_get_service_ctx(user->_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi old_input = mail_storage_service_user_get_input(user->_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((cur_ioloop_ctx = io_loop_get_current_context(current_ioloop)) != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi io_loop_context_deactivate(cur_ioloop_ctx);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&input);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.module = old_input->module;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.service = old_input->service;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.username = dest_username;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.session_id_prefix = user->session_id;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.flags_override_add = MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS |
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
83d6ad2c8c1a8fca67ee3998f6142a9d6978b449Timo Sirainen input.flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_storage_service_lookup_next(service_ctx, &input,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_service_user_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user_r, error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_update_private_key(struct mailbox *src_box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *dest_user, bool set,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool disallow_insecure,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_public_key *key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct dcrypt_private_key **keyp;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!set) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return mail_crypt_acl_unset_private_keys(src_box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user->username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_ATTRIBUTE_TYPE_SHARED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error_r);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (dest_user != NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* get public key from target user */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_user_get_public_key(dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &key, error_r)) <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret == 0 && disallow_insecure) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("User %s has no active public key",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user->username);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* perform insecure sharing */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi key = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ARRAY_TYPE(dcrypt_private_key) keys;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi t_array_init(&keys, 8);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_transaction_context *t =
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi mailbox_transaction_begin(src_box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* get private keys from box */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_get_private_keys(src_box, &keys, error_r) < 0 ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_box_share_private_keys(t, key,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user == NULL ? NULL :
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dest_user->username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &keys, error_r) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret >= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi array_foreach_modifiable(&keys, keyp) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dcrypt_key_unref_private(keyp);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mailbox_transaction_commit(&t) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi *error_r = mailbox_get_last_internal_error(src_box, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mail_crypt_acl_object_update(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const struct acl_rights_update *update)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *error;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_acl_mailbox_list *mlist =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_ACL_LIST_CONTEXT(aclobj->backend->list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *username;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_user *dest_user;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_user *dest_service_user;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ioloop_context *cur_ioloop_ctx;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool have_rights;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi int ret = 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mlist->acl_vprev.object_update(aclobj, update) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi bool disallow_insecure =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_acl_secure_sharing_enabled(aclobj->backend->list->ns->user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *box_name = mailbox_list_get_vname(aclobj->backend->list,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi aclobj->name);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(aclobj->backend->list, box_name, 0);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi switch (update->rights.id_type) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_USER:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* setting rights for specific user: we can encrypt the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox key for the user. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi username = update->rights.identifier;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_acl_has_user_read_right(aclobj, username, &error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mail_crypt_acl_has_user_read_right(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi have_rights = ret > 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_acl_user_create(aclobj->backend->list->ns->user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi username, &dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &dest_service_user, &error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* to make sure we get correct logging context */
c1ab825edf003f5cfc6c31730442f36a17209101Timo Sirainen if (ret > 0)
c1ab825edf003f5cfc6c31730442f36a17209101Timo Sirainen mail_storage_service_io_deactivate_user(dest_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_io_activate_user(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi aclobj->backend->list->ns->user->_service_user
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi );
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Cannot initialize destination user %s: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi username, error);
c1ab825edf003f5cfc6c31730442f36a17209101Timo Sirainen break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(dest_user != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mailbox_open(box)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mail_crypt_acl_update_private_key(box, dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi have_rights,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi disallow_insecure,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &error)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "acl_update_private_key(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* logging context swap again */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_io_deactivate_user(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi aclobj->backend->list->ns->user->_service_user
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi );
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_io_activate_user(dest_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
c1ab825edf003f5cfc6c31730442f36a17209101Timo Sirainen mail_user_unref(&dest_user);
eb318ea05532d2e54ed3bfc89bc15dcf1adae838Timo Sirainen mail_storage_service_user_unref(&dest_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((cur_ioloop_ctx = io_loop_get_current_context(current_ioloop)) != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi io_loop_context_deactivate(cur_ioloop_ctx);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_io_activate_user(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi aclobj->backend->list->ns->user->_service_user
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi );
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_OWNER:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we should be the one doing this? ignore */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_ANYONE:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_AUTHENTICATED:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_GROUP:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_GROUP_OVERRIDE:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (disallow_insecure) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Secure key sharing is enabled -"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Remove or set plugin { %s = no }",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_ACL_SECURE_SHARE_SETTING);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* the mailbox key needs to be stored unencrypted. for groups
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi we could in theory use per-group encrypted keys, which the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi users belonging to the group would able to decrypt with
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi their private key, but that becomes quite complicated. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_acl_has_nonuser_read_right(aclobj, &error)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: %s", error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mailbox_open(box)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mail_crypt_acl_update_private_key(box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi NULL,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi TRUE,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi disallow_insecure,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi &error)) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_error("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "acl_update_private_key(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_get_vname(box),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi break;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi case ACL_ID_TYPE_COUNT:
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_unreached();
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox_free(&box);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return ret;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_mail_namespace_storage_added(struct mail_namespace *ns)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ns->list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_acl_mailbox_list *mlist =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_ACL_LIST_CONTEXT(ns->list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_backend *backend;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (alist == NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* FIXME: this method works only if there's a single plugin doing it.
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if there are ever multiple plugins hooking into ACL commands the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ACL core code would need some changing to make it work correctly. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi backend = alist->rights.backend;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mlist->acl_vprev = backend->v;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi backend->v.object_update = mail_crypt_acl_object_update;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void mail_crypt_acl_mailbox_list_deinit(struct mailbox_list *list)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_acl_mailbox_list *mlist =
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_ACL_LIST_CONTEXT(list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mlist->module_ctx.super.deinit(list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void mail_crypt_acl_mailbox_list_created(struct mailbox_list *list)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox_list_vfuncs *v = list->vlast;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_crypt_acl_mailbox_list *mlist;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mlist = p_new(list->pool, struct mail_crypt_acl_mailbox_list, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mlist->module_ctx.super = *v;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi list->vlast = &mlist->module_ctx.super;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi v->deinit = mail_crypt_acl_mailbox_list_deinit;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MODULE_CONTEXT_SET(list, mail_crypt_acl_mailbox_list_module, mlist);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct mail_storage_hooks mail_crypt_acl_mail_storage_hooks = {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .mailbox_list_created = mail_crypt_acl_mailbox_list_created,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi .mail_namespace_storage_added = mail_crypt_acl_mail_namespace_storage_added
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi};
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_acl_plugin_init(struct module *module)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_hooks_add(module, &mail_crypt_acl_mail_storage_hooks);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_acl_plugin_deinit(void)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_hooks_remove(&mail_crypt_acl_mail_storage_hooks);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiconst char *mail_crypt_acl_plugin_dependencies[] = { "acl", NULL };