bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "lib.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "array.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "str.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "dict.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "mail-user.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "mail-namespace.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "acl-api-private.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "acl-storage.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "acl-plugin.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#include "acl-lookup-dict.h"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen#define DICT_SHARED_BOXES_PATH "shared-boxes/"
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstruct acl_lookup_dict {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct mail_user *user;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct dict *dict;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen};
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstruct acl_lookup_dict_iter {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen pool_t pool;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_lookup_dict *dict;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen pool_t iter_value_pool;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ARRAY_TYPE(const_string) iter_ids;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen ARRAY_TYPE(const_string) iter_values;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen unsigned int iter_idx, iter_value_idx;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool failed:1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen};
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstruct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_lookup_dict *dict;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen const char *uri, *error;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen dict = i_new(struct acl_lookup_dict, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen dict->user = user;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen uri = mail_user_plugin_getenv(user, "acl_shared_dict");
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (uri != NULL) {
20e04227229970d148801c507946666e2a9bd838Timo Sirainen struct dict_settings dict_set;
20e04227229970d148801c507946666e2a9bd838Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&dict_set);
20e04227229970d148801c507946666e2a9bd838Timo Sirainen dict_set.username = "";
20e04227229970d148801c507946666e2a9bd838Timo Sirainen dict_set.base_dir = user->set->base_dir;
20e04227229970d148801c507946666e2a9bd838Timo Sirainen if (dict_init(uri, &dict_set, &dict->dict, &error) < 0)
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen i_error("acl: dict_init(%s) failed: %s", uri, error);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen } else if (user->mail_debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("acl: No acl_shared_dict setting - "
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk "shared mailbox listing is disabled");
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return dict;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenvoid acl_lookup_dict_deinit(struct acl_lookup_dict **_dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_lookup_dict *dict = *_dict;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen *_dict = NULL;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (dict->dict != NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen dict_deinit(&dict->dict);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen i_free(dict);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainenbool acl_lookup_dict_is_enabled(struct acl_lookup_dict *dict)
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainen{
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainen return dict->dict != NULL;
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainen}
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstatic void
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_write_rights_id(string_t *dest, const struct acl_rights *right)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen switch (right->id_type) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_ANYONE:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_AUTHENTICATED:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* don't bother separating these */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(dest, "anyone");
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen break;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_USER:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(dest, "user/");
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(dest, right->identifier);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen break;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_GROUP:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_GROUP_OVERRIDE:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(dest, "group/");
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(dest, right->identifier);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen break;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_OWNER:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen case ACL_ID_TYPE_COUNT:
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen i_unreached();
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainenstatic bool
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainenacl_rights_is_same_user(const struct acl_rights *right, struct mail_user *user)
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen{
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen return right->id_type == ACL_ID_USER &&
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen strcmp(right->identifier, user->username) == 0;
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen}
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstatic int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ARRAY_TYPE(const_string) *ids)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_backend *backend;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_mailbox_list_context *ctx;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_object *aclobj;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_object_list_iter *iter;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_rights rights;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen const char *name, *id_dup;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen string_t *id;
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi int ret = 0;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
2721a77c55f8ec730a205c4514d8448e05d500bbTimo Sirainen if ((ns->flags & NAMESPACE_FLAG_NOACL) != 0 || ns->owner == NULL ||
2721a77c55f8ec730a205c4514d8448e05d500bbTimo Sirainen ACL_LIST_CONTEXT(ns->list) == NULL)
671ecc41b231616d7193a5319e5ba95c6a299aabTimo Sirainen return 0;
671ecc41b231616d7193a5319e5ba95c6a299aabTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id = t_str_new(128);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen backend = acl_mailbox_list_get_backend(ns->list);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ctx = acl_backend_nonowner_lookups_iter_init(backend);
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi while (acl_backend_nonowner_lookups_iter_next(ctx, &name)) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen aclobj = acl_object_init_from_name(backend, name);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen iter = acl_object_list_init(aclobj);
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi while (acl_object_list_next(iter, &rights)) {
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen /* avoid pointless user -> user entries,
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen which some clients do */
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen if (acl_rights_has_nonowner_lookup_changes(&rights) &&
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen !acl_rights_is_same_user(&rights, ns->owner)) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_truncate(id, 0);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen acl_lookup_dict_write_rights_id(id, &rights);
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen str_append_c(id, '/');
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen str_append(id, ns->owner->username);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id_dup = t_strdup(str_c(id));
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_append(ids, &id_dup, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi if (acl_object_list_deinit(&iter) < 0) ret = -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen acl_object_deinit(&aclobj);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi if (acl_backend_nonowner_lookups_iter_deinit(&ctx) < 0) ret = -1;
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi return ret;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstatic int
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen const ARRAY_TYPE(const_string) *new_ids_arr,
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen bool no_removes)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen const char *username = dict->user->username;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct dict_iterate_context *iter;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct dict_transaction_context *dt;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen const char *prefix, *key, *value, *const *old_ids, *const *new_ids, *p;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *error;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ARRAY_TYPE(const_string) old_ids_arr;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen unsigned int newi, oldi, old_count, new_count;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen string_t *path;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t prefix_len;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen int ret;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen /* get all existing identifiers for the user. we might be able to
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen sync identifiers also for other users whose shared namespaces we
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen have, but it's possible that the other users have other namespaces
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen that aren't visible to us, so we don't want to remove anything
1fa4e468e2784b14bb461830a20c947340688a57Timo Sirainen that could break them. */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen t_array_init(&old_ids_arr, 128);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen prefix_len = strlen(prefix);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen iter = dict_iterate_init(dict->dict, prefix, DICT_ITERATE_FLAG_RECURSE);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen while (dict_iterate(iter, &key, &value)) {
2fff31fd2f101c772ec6899f94b4fe2c858febadTimo Sirainen /* prefix/$type/$dest/$source */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen key += prefix_len;
2fff31fd2f101c772ec6899f94b4fe2c858febadTimo Sirainen p = strrchr(key, '/');
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (p != NULL && strcmp(p + 1, username) == 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen key = t_strdup_until(key, p);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_append(&old_ids_arr, &key, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&iter, &error) < 0) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("acl: dict iteration failed: %s - can't update dict", error);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* sort the existing identifiers */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&old_ids_arr, i_strcmp_p);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* sync the identifiers */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen path = t_str_new(256);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(path, prefix);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen dt = dict_transaction_begin(dict->dict);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen old_ids = array_get(&old_ids_arr, &old_count);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen new_ids = array_get(new_ids_arr, &new_count);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen for (newi = oldi = 0; newi < new_count || oldi < old_count; ) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ret = newi == new_count ? 1 :
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen oldi == old_count ? -1 :
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen strcmp(new_ids[newi], old_ids[oldi]);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (ret == 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen newi++; oldi++;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen } else if (ret < 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* new identifier, add it */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_truncate(path, prefix_len);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(path, new_ids[newi]);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen dict_set(dt, str_c(path), "1");
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen newi++;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen } else if (!no_removes) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* old identifier removed */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_truncate(path, prefix_len);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(path, old_ids[oldi]);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append_c(path, '/');
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen str_append(path, username);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen dict_unset(dt, str_c(path));
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen oldi++;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (dict_transaction_commit(&dt, &error) < 0) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_error("acl: dict commit failed: %s", error);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return 0;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenint acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct mail_namespace *ns;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ARRAY_TYPE(const_string) ids_arr;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen const char **ids;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen unsigned int i, dest, count;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen int ret = 0;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (dict->dict == NULL)
372d3167088e17ccece2b922961c05cb8a7e4e03Timo Sirainen return 0;
372d3167088e17ccece2b922961c05cb8a7e4e03Timo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get all ACL identifiers with a positive lookup right */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen t_array_init(&ids_arr, 128);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen for (ns = dict->user->namespaces; ns != NULL; ns = ns->next) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (acl_lookup_dict_rebuild_add_backend(ns, &ids_arr) < 0)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ret = -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* sort identifiers and remove duplicates */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&ids_arr, i_strcmp_p);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen ids = array_get_modifiable(&ids_arr, &count);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen for (i = 1, dest = 0; i < count; i++) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (strcmp(ids[dest], ids[i]) != 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (++dest != i)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ids[dest] = ids[i];
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (++dest < count)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_delete(&ids_arr, dest, count-dest);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* if lookup failed at some point we can still add new ids,
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen but we can't remove any existing ones */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (acl_lookup_dict_rebuild_update(dict, &ids_arr, ret < 0) < 0)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen ret = -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return ret;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainenstatic void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen struct dict_iterate_context *dict_iter;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *const *idp, *prefix, *key, *value, *error;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t prefix_len;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen idp = array_idx(&iter->iter_ids, iter->iter_idx);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen iter->iter_idx++;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen iter->iter_value_idx = 0;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH,
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen *idp, "/", NULL);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen prefix_len = strlen(prefix);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen /* read all of it to memory. at least currently dict-proxy can support
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen only one iteration at a time, but the acl code can end up rebuilding
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen the dict, which opens another iteration. */
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen p_clear(iter->iter_value_pool);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen array_clear(&iter->iter_values);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen dict_iter = dict_iterate_init(iter->dict->dict, prefix,
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen DICT_ITERATE_FLAG_RECURSE);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen while (dict_iterate(dict_iter, &key, &value)) {
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen i_assert(prefix_len < strlen(key));
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen key = p_strdup(iter->iter_value_pool, key + prefix_len);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen array_append(&iter->iter_values, &key, 1);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen }
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&dict_iter, &error) < 0) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("%s", error);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen iter->failed = TRUE;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstruct acl_lookup_dict_iter *
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_user *auser = ACL_USER_CONTEXT(dict->user);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_lookup_dict_iter *iter;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen const char *id;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen unsigned int i;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen pool_t pool;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
3131b3878de3245db7552234e66d437e8fde9351Aki Tuomi i_assert(auser != NULL);
3131b3878de3245db7552234e66d437e8fde9351Aki Tuomi
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen pool = pool_alloconly_create("acl lookup dict iter", 1024);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen iter = p_new(pool, struct acl_lookup_dict_iter, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen iter->pool = pool;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen iter->dict = dict;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen p_array_init(&iter->iter_ids, pool, 16);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id = "anyone";
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_append(&iter->iter_ids, &id, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id = p_strconcat(pool, "user/", dict->user->username, NULL);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_append(&iter->iter_ids, &id, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen i_array_init(&iter->iter_values, 64);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen iter->iter_value_pool =
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen pool_alloconly_create("acl lookup dict iter values", 1024);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get all groups we belong to */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (auser->groups != NULL) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen for (i = 0; auser->groups[i] != NULL; i++) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id = p_strconcat(pool, "group/", auser->groups[i],
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen NULL);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen array_append(&iter->iter_ids, &id, 1);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* iterate through all identifiers that match us, start with the
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen first one */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (dict->dict != NULL)
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen acl_lookup_dict_iterate_read(iter);
fdf03f944a0f9d51720c144f6a905dd83fde638aTimo Sirainen else
fdf03f944a0f9d51720c144f6a905dd83fde638aTimo Sirainen array_clear(&iter->iter_ids);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return iter;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenconst char *
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen const char *const *keys;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen unsigned int count;
372d3167088e17ccece2b922961c05cb8a7e4e03Timo Sirainen
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen keys = array_get(&iter->iter_values, &count);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen if (iter->iter_value_idx < count)
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen return keys[iter->iter_value_idx++];
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (iter->iter_idx < array_count(&iter->iter_ids)) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get to the next iterator */
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen acl_lookup_dict_iterate_read(iter);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return acl_lookup_dict_iterate_visible_next(iter);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen }
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return NULL;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenint acl_lookup_dict_iterate_visible_deinit(struct acl_lookup_dict_iter **_iter)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen{
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_lookup_dict_iter *iter = *_iter;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen int ret = iter->failed ? -1 : 0;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen *_iter = NULL;
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen array_free(&iter->iter_values);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen pool_unref(&iter->iter_value_pool);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen pool_unref(&iter->pool);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return ret;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen}