bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstruct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen uri = mail_user_plugin_getenv(user, "acl_shared_dict");
20e04227229970d148801c507946666e2a9bd838Timo Sirainen if (dict_init(uri, &dict_set, &dict->dict, &error) < 0)
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen i_error("acl: dict_init(%s) failed: %s", uri, error);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk "shared mailbox listing is disabled");
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenvoid acl_lookup_dict_deinit(struct acl_lookup_dict **_dict)
7c598f384223a1364e8040c1e2a4cad8d00edde6Timo Sirainenbool acl_lookup_dict_is_enabled(struct acl_lookup_dict *dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_write_rights_id(string_t *dest, const struct acl_rights *right)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* don't bother separating these */
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainenacl_rights_is_same_user(const struct acl_rights *right, struct mail_user *user)
ee2f574898ccaee14eabc80213295c5d93d126c2Timo Sirainen strcmp(right->identifier, user->username) == 0;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenstatic int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
2721a77c55f8ec730a205c4514d8448e05d500bbTimo Sirainen if ((ns->flags & NAMESPACE_FLAG_NOACL) != 0 || ns->owner == NULL ||
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);
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)) {
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi if (acl_backend_nonowner_lookups_iter_deinit(&ctx) < 0) ret = -1;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen const char *prefix, *key, *value, *const *old_ids, *const *new_ids, *p;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen unsigned int newi, oldi, old_count, new_count;
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 prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen iter = dict_iterate_init(dict->dict, prefix, DICT_ITERATE_FLAG_RECURSE);
2fff31fd2f101c772ec6899f94b4fe2c858febadTimo Sirainen /* prefix/$type/$dest/$source */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (p != NULL && strcmp(p + 1, username) == 0) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("acl: dict iteration failed: %s - can't update dict", error);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* sort the existing identifiers */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* sync the identifiers */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen old_ids = array_get(&old_ids_arr, &old_count);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen for (newi = oldi = 0; newi < new_count || oldi < old_count; ) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen } else if (ret < 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* new identifier, add it */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen } else if (!no_removes) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* old identifier removed */
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (dict_transaction_commit(&dt, &error) < 0) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_error("acl: dict commit failed: %s", error);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenint acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get all ACL identifiers with a positive lookup right */
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 /* sort identifiers and remove duplicates */
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)
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainenstatic void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter)
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *const *idp, *prefix, *key, *value, *error;
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen idp = array_idx(&iter->iter_ids, iter->iter_idx);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH,
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 dict_iter = dict_iterate_init(iter->dict->dict, prefix,
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen while (dict_iterate(dict_iter, &key, &value)) {
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen key = p_strdup(iter->iter_value_pool, key + prefix_len);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&dict_iter, &error) < 0) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen struct acl_user *auser = ACL_USER_CONTEXT(dict->user);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen unsigned int i;
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 id = p_strconcat(pool, "user/", dict->user->username, NULL);
e72a7cb3abe222299bc6dc08b11c891b2f0c8febTimo Sirainen pool_alloconly_create("acl lookup dict iter values", 1024);
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get all groups we belong to */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen id = p_strconcat(pool, "group/", auser->groups[i],
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* iterate through all identifiers that match us, start with the
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainenacl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen if (iter->iter_idx < array_count(&iter->iter_ids)) {
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen /* get to the next iterator */
81e6e1ef0feef60644a4c4b745d82a4c98223affTimo Sirainen return acl_lookup_dict_iterate_visible_next(iter);