bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
5b8e42f398e33019ed65672ba5d0ab79d1c2310bAki Tuomi MODULE_CONTEXT_REQUIRE(obj, mail_crypt_acl_mailbox_list_module)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic MODULE_CONTEXT_DEFINE_INIT(mail_crypt_acl_mailbox_list_module,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid mail_crypt_acl_plugin_init(struct module *module);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_has_user_read_right(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = str_array_find(rights.rights, MAIL_ACL_READ) ? 1 : 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mail_crypt_acl_has_nonuser_read_right(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_unset_private_keys(struct mailbox *src_box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(src_box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_get_pvt_digests(src_box, pool_datastack_create(),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Failed to lookup public key digests: %s",
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi t = mailbox_transaction_begin(src_box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* if the id contains username part, skip to key public id */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_box_unset_shared_key(t, ptr, dest_user,
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",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(src_box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_user_create(struct mail_user *user, const char *dest_username,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_user **dest_service_user_r,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const struct mail_storage_service_input *old_input;
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 if ((cur_ioloop_ctx = io_loop_get_current_context(current_ioloop)) != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi input.flags_override_add = MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS |
83d6ad2c8c1a8fca67ee3998f6142a9d6978b449Timo Sirainen input.flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_storage_service_lookup_next(service_ctx, &input,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_update_private_key(struct mailbox *src_box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char **error_r)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* get public key from target user */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ret = mail_crypt_user_get_public_key(dest_user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("User %s has no active public key",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (ret == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* perform insecure sharing */
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi mailbox_transaction_begin(src_box, 0, __func__);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* get private keys from box */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mail_crypt_box_get_private_keys(src_box, &keys, error_r) < 0 ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret >= 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi *error_r = mailbox_get_last_internal_error(src_box, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mail_crypt_acl_object_update(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MAIL_CRYPT_ACL_LIST_CONTEXT(aclobj->backend->list);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mail_storage_service_user *dest_service_user;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mlist->acl_vprev.object_update(aclobj, update) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_crypt_acl_secure_sharing_enabled(aclobj->backend->list->ns->user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *box_name = mailbox_list_get_vname(aclobj->backend->list,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct mailbox *box = mailbox_alloc(aclobj->backend->list, box_name, 0);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* setting rights for specific user: we can encrypt the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mailbox key for the user. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_acl_has_user_read_right(aclobj, username, &error);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mail_crypt_acl_has_user_read_right(%s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ret = mail_crypt_acl_user_create(aclobj->backend->list->ns->user,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* to make sure we get correct logging context */
c1ab825edf003f5cfc6c31730442f36a17209101Timo Sirainen mail_storage_service_io_deactivate_user(dest_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (ret <= 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Cannot initialize destination user %s: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
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 "acl_update_private_key(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* logging context swap again */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_io_activate_user(dest_service_user);
eb318ea05532d2e54ed3bfc89bc15dcf1adae838Timo Sirainen mail_storage_service_user_unref(&dest_service_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((cur_ioloop_ctx = io_loop_get_current_context(current_ioloop)) != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we should be the one doing this? ignore */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Secure key sharing is enabled -"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Remove or set plugin { %s = no }",
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 "mailbox_open(%s) failed: %s",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if ((ret = mail_crypt_acl_update_private_key(box,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "acl_update_private_key(%s, %s) failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimail_crypt_acl_mail_namespace_storage_added(struct mail_namespace *ns)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ns->list);
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->v.object_update = mail_crypt_acl_object_update;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void mail_crypt_acl_mailbox_list_deinit(struct mailbox_list *list)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void mail_crypt_acl_mailbox_list_created(struct mailbox_list *list)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mlist = p_new(list->pool, struct mail_crypt_acl_mailbox_list, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MODULE_CONTEXT_SET(list, mail_crypt_acl_mailbox_list_module, mlist);
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 Tuomivoid mail_crypt_acl_plugin_init(struct module *module)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_hooks_add(module, &mail_crypt_acl_mail_storage_hooks);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_hooks_remove(&mail_crypt_acl_mail_storage_hooks);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiconst char *mail_crypt_acl_plugin_dependencies[] = { "acl", NULL };