mail-crypt-acl-plugin.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi/* Copyright (c) 2015-2016 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi MODULE_CONTEXT(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 const char *error;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi *error_r = t_strdup_printf("mail-crypt-acl-plugin: "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "mailbox_open(%s) failed: %s",
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",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *const *hash;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *ptr;
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",
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 |
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 */
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) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mail_crypt_acl_object_update(struct acl_object *aclobj,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *error;
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 */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi 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",
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);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_service_user_free(&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",
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 };