acl-lookup-dict.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2008-2016 Dovecot authors, see the included COPYING file */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "lib.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "array.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "str.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dict.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-user.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-namespace.h"
a85473f7c11c8734bdee9c2cbe4b767f144a18aaTimo Sirainen#include "acl-api-private.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "acl-storage.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "acl-plugin.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "acl-lookup-dict.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#define DICT_SHARED_BOXES_PATH "shared-boxes/"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainenstruct acl_lookup_dict {
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen struct mail_user *user;
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen struct dict *dict;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct acl_lookup_dict_iter {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_t pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct acl_lookup_dict *dict;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen pool_t iter_value_pool;
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen ARRAY_TYPE(const_string) iter_ids;
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen ARRAY_TYPE(const_string) iter_values;
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen unsigned int iter_idx, iter_value_idx;
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen bool failed:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainenstruct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct acl_lookup_dict *dict;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *uri, *error;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dict = i_new(struct acl_lookup_dict, 1);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen dict->user = user;
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen uri = mail_user_plugin_getenv(user, "acl_shared_dict");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (uri != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dict_settings dict_set;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_zero(&dict_set);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dict_set.username = "";
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dict_set.base_dir = user->set->base_dir;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dict_init(uri, &dict_set, &dict->dict, &error) < 0)
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen i_error("acl: dict_init(%s) failed: %s", uri, error);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen } else if (user->mail_debug) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_debug("acl: No acl_shared_dict setting - "
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "shared mailbox listing is disabled");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dict;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid acl_lookup_dict_deinit(struct acl_lookup_dict **_dict)
3c73d884362b72c86753939551c94f8baa5702f8Timo Sirainen{
3c73d884362b72c86753939551c94f8baa5702f8Timo Sirainen struct acl_lookup_dict *dict = *_dict;
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen *_dict = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dict->dict != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dict_deinit(&dict->dict);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_free(dict);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenbool acl_lookup_dict_is_enabled(struct acl_lookup_dict *dict)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen{
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen return dict->dict != NULL;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen}
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenstatic void
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenacl_lookup_dict_write_rights_id(string_t *dest, const struct acl_rights *right)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen{
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen switch (right->id_type) {
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen case ACL_ID_ANYONE:
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen case ACL_ID_AUTHENTICATED:
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen /* don't bother separating these */
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen str_append(dest, "anyone");
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen break;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen case ACL_ID_USER:
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen str_append(dest, "user/");
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen str_append(dest, right->identifier);
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case ACL_ID_GROUP:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case ACL_ID_GROUP_OVERRIDE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_append(dest, "group/");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_append(dest, right->identifier);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case ACL_ID_OWNER:
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen case ACL_ID_TYPE_COUNT:
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen i_unreached();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenacl_rights_is_same_user(const struct acl_rights *right, struct mail_user *user)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen return right->id_type == ACL_ID_USER &&
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen strcmp(right->identifier, user->username) == 0;
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen}
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainenstatic int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) *ids)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen struct acl_backend *backend;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen struct acl_mailbox_list_context *ctx;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen struct acl_object *aclobj;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen struct acl_object_list_iter *iter;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen struct acl_rights rights;
887a9fbbb2ca6afd53365ba2ccae0ef8728d6948Timo Sirainen const char *name, *id_dup;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen string_t *id;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen int ret = 0;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen if ((ns->flags & NAMESPACE_FLAG_NOACL) != 0 || ns->owner == NULL ||
887a9fbbb2ca6afd53365ba2ccae0ef8728d6948Timo Sirainen ACL_LIST_CONTEXT(ns->list) == NULL)
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen return 0;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen id = t_str_new(128);
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen backend = acl_mailbox_list_get_backend(ns->list);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen ctx = acl_backend_nonowner_lookups_iter_init(backend);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen while (acl_backend_nonowner_lookups_iter_next(ctx, &name)) {
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen aclobj = acl_object_init_from_name(backend, name);
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen iter = acl_object_list_init(aclobj);
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen while (acl_object_list_next(iter, &rights)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* avoid pointless user -> user entries,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen which some clients do */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (acl_rights_has_nonowner_lookup_changes(&rights) &&
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen !acl_rights_is_same_user(&rights, ns->owner)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_truncate(id, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen acl_lookup_dict_write_rights_id(id, &rights);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_append_c(id, '/');
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_append(id, ns->owner->username);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen id_dup = t_strdup(str_c(id));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(ids, &id_dup, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (acl_object_list_deinit(&iter) < 0) ret = -1;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen acl_object_deinit(&aclobj);
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen }
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen if (acl_backend_nonowner_lookups_iter_deinit(&ctx) < 0) ret = -1;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen return ret;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen}
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenacl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen const ARRAY_TYPE(const_string) *new_ids_arr,
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen bool no_removes)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen{
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen const char *username = dict->user->username;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen struct dict_iterate_context *iter;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen struct dict_transaction_context *dt;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen const char *prefix, *key, *value, *const *old_ids, *const *new_ids, *p;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen const char *error;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) old_ids_arr;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int newi, oldi, old_count, new_count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen string_t *path;
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen size_t prefix_len;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get all existing identifiers for the user. we might be able to
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sync identifiers also for other users whose shared namespaces we
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen have, but it's possible that the other users have other namespaces
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen that aren't visible to us, so we don't want to remove anything
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen that could break them. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&old_ids_arr, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen prefix_len = strlen(prefix);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = dict_iterate_init(dict->dict, prefix, DICT_ITERATE_FLAG_RECURSE);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen while (dict_iterate(iter, &key, &value)) {
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen /* prefix/$type/$dest/$source */
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen key += prefix_len;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p = strrchr(key, '/');
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (p != NULL && strcmp(p + 1, username) == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen key = t_strdup_until(key, p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&old_ids_arr, &key, 1);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dict_iterate_deinit(&iter, &error) < 0) {
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen i_error("acl: dict iteration failed: %s - can't update dict", error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* sort the existing identifiers */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_sort(&old_ids_arr, i_strcmp_p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen /* sync the identifiers */
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen path = t_str_new(256);
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen str_append(path, prefix);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dt = dict_transaction_begin(dict->dict);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen old_ids = array_get(&old_ids_arr, &old_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen new_ids = array_get(new_ids_arr, &new_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (newi = oldi = 0; newi < new_count || oldi < old_count; ) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen ret = newi == new_count ? 1 :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen oldi == old_count ? -1 :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen strcmp(new_ids[newi], old_ids[oldi]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret == 0) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen newi++; oldi++;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (ret < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* new identifier, add it */
887a9fbbb2ca6afd53365ba2ccae0ef8728d6948Timo Sirainen str_truncate(path, prefix_len);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_append(path, new_ids[newi]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dict_set(dt, str_c(path), "1");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newi++;
36723cf206a7b64b9d972ab0719bbfaacc9316faTimo Sirainen } else if (!no_removes) {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen /* old identifier removed */
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen str_truncate(path, prefix_len);
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen str_append(path, old_ids[oldi]);
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen str_append_c(path, '/');
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen str_append(path, username);
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen dict_unset(dt, str_c(path));
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen oldi++;
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen }
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen }
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen if (dict_transaction_commit(&dt, &error) < 0) {
14b1d2a2634e75b988078baee1e8ad678de28a04Timo Sirainen i_error("acl: dict commit failed: %s", error);
14b1d2a2634e75b988078baee1e8ad678de28a04Timo Sirainen return -1;
45af47783693b3ba2768c5ad34eeff68132382d0Timo Sirainen }
45af47783693b3ba2768c5ad34eeff68132382d0Timo Sirainen return 0;
afd6d387ea65843b59fb6051fb567719d2a5279cAki Tuomi}
afd6d387ea65843b59fb6051fb567719d2a5279cAki Tuomi
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen{
70df8f39fb3db7c49b18c855178f8172176a037aTimo Sirainen struct mail_namespace *ns;
70df8f39fb3db7c49b18c855178f8172176a037aTimo Sirainen ARRAY_TYPE(const_string) ids_arr;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char **ids;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen unsigned int i, dest, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dict->dict == NULL)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen return 0;
3561c7bb472a78af74d755219cc0fc71c85ff5c2Timo Sirainen
ee8294dbc7bb549557f6ba1264d66b55fbef69b6Aki Tuomi /* get all ACL identifiers with a positive lookup right */
ae949831f1f668b5501b4b125e7f7b1767fb109bTimo Sirainen t_array_init(&ids_arr, 128);
2e652d2651b2800f99a17dcb3014a009fe4660d3Timo Sirainen for (ns = dict->user->namespaces; ns != NULL; ns = ns->next) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (acl_lookup_dict_rebuild_add_backend(ns, &ids_arr) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen /* sort identifiers and remove duplicates */
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen array_sort(&ids_arr, i_strcmp_p);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen ids = array_get_modifiable(&ids_arr, &count);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen for (i = 1, dest = 0; i < count; i++) {
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen if (strcmp(ids[dest], ids[i]) != 0) {
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen if (++dest != i)
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen ids[dest] = ids[i];
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen }
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen }
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen if (++dest < count)
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen array_delete(&ids_arr, dest, count-dest);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen /* if lookup failed at some point we can still add new ids,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen but we can't remove any existing ones */
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen if (acl_lookup_dict_rebuild_update(dict, &ids_arr, ret < 0) < 0)
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen ret = -1;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen return ret;
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen}
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainenstatic void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter)
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen{
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen struct dict_iterate_context *dict_iter;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen const char *const *idp, *prefix, *key, *value, *error;
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen size_t prefix_len;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen idp = array_idx(&iter->iter_ids, iter->iter_idx);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen iter->iter_idx++;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen iter->iter_value_idx = 0;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH,
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen *idp, "/", NULL);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen prefix_len = strlen(prefix);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen /* read all of it to memory. at least currently dict-proxy can support
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen only one iteration at a time, but the acl code can end up rebuilding
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen the dict, which opens another iteration. */
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen p_clear(iter->iter_value_pool);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen array_clear(&iter->iter_values);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen dict_iter = dict_iterate_init(iter->dict->dict, prefix,
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen DICT_ITERATE_FLAG_RECURSE);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen while (dict_iterate(dict_iter, &key, &value)) {
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen i_assert(prefix_len < strlen(key));
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen key = p_strdup(iter->iter_value_pool, key + prefix_len);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen array_append(&iter->iter_values, &key, 1);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen }
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen if (dict_iterate_deinit(&dict_iter, &error) < 0) {
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen i_error("%s", error);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen iter->failed = TRUE;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen }
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen}
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainenstruct acl_lookup_dict_iter *
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainenacl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen{
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen struct acl_user *auser = ACL_USER_CONTEXT(dict->user);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen struct acl_lookup_dict_iter *iter;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen const char *id;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen unsigned int i;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen pool_t pool;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen pool = pool_alloconly_create("acl lookup dict iter", 1024);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen iter = p_new(pool, struct acl_lookup_dict_iter, 1);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen iter->pool = pool;
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen iter->dict = dict;
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen p_array_init(&iter->iter_ids, pool, 16);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen id = "anyone";
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen array_append(&iter->iter_ids, &id, 1);
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen id = p_strconcat(pool, "user/", dict->user->username, NULL);
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen array_append(&iter->iter_ids, &id, 1);
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen i_array_init(&iter->iter_values, 64);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen iter->iter_value_pool =
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen pool_alloconly_create("acl lookup dict iter values", 1024);
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen /* get all groups we belong to */
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen if (auser->groups != NULL) {
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen for (i = 0; auser->groups[i] != NULL; i++) {
d519a0449d0e536a32db93305516fdbd7db6773dTimo Sirainen id = p_strconcat(pool, "group/", auser->groups[i],
d519a0449d0e536a32db93305516fdbd7db6773dTimo Sirainen NULL);
ee8294dbc7bb549557f6ba1264d66b55fbef69b6Aki Tuomi array_append(&iter->iter_ids, &id, 1);
ee8294dbc7bb549557f6ba1264d66b55fbef69b6Aki Tuomi }
3561c7bb472a78af74d755219cc0fc71c85ff5c2Timo Sirainen }
ae949831f1f668b5501b4b125e7f7b1767fb109bTimo Sirainen
ae949831f1f668b5501b4b125e7f7b1767fb109bTimo Sirainen /* iterate through all identifiers that match us, start with the
45af47783693b3ba2768c5ad34eeff68132382d0Timo Sirainen first one */
45af47783693b3ba2768c5ad34eeff68132382d0Timo Sirainen if (dict->dict != NULL)
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen acl_lookup_dict_iterate_read(iter);
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen else
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen array_clear(&iter->iter_ids);
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen return iter;
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen}
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainenconst char *
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainenacl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen{
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen const char *const *keys;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen unsigned int count;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen keys = array_get(&iter->iter_values, &count);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen if (iter->iter_value_idx < count)
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen return keys[iter->iter_value_idx++];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (iter->iter_idx < array_count(&iter->iter_ids)) {
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen /* get to the next iterator */
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen acl_lookup_dict_iterate_read(iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return acl_lookup_dict_iterate_visible_next(iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint acl_lookup_dict_iterate_visible_deinit(struct acl_lookup_dict_iter **_iter)
f43ce62fa945f597e8a48e09c53d46dcc95445d4Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct acl_lookup_dict_iter *iter = *_iter;
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen int ret = iter->failed ? -1 : 0;
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen *_iter = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&iter->iter_values);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_unref(&iter->iter_value_pool);
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen pool_unref(&iter->pool);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen return ret;
805d7834412465268486c50711962407ad13fbf6Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen