acl-lookup-dict.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2008-2016 Dovecot authors, see the included COPYING file */
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainenstruct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user)
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen uri = mail_user_plugin_getenv(user, "acl_shared_dict");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dict_init(uri, &dict_set, &dict->dict, &error) < 0)
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen i_error("acl: dict_init(%s) failed: %s", uri, error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "shared mailbox listing is disabled");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid acl_lookup_dict_deinit(struct acl_lookup_dict **_dict)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenbool acl_lookup_dict_is_enabled(struct acl_lookup_dict *dict)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenacl_lookup_dict_write_rights_id(string_t *dest, const struct acl_rights *right)
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen /* don't bother separating these */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenacl_rights_is_same_user(const struct acl_rights *right, struct mail_user *user)
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen strcmp(right->identifier, user->username) == 0;
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainenstatic int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen if ((ns->flags & NAMESPACE_FLAG_NOACL) != 0 || ns->owner == NULL ||
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);
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 if (acl_object_list_deinit(&iter) < 0) ret = -1;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen if (acl_backend_nonowner_lookups_iter_deinit(&ctx) < 0) ret = -1;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainenacl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen const char *prefix, *key, *value, *const *old_ids, *const *new_ids, *p;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int newi, oldi, old_count, new_count;
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 prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = dict_iterate_init(dict->dict, prefix, DICT_ITERATE_FLAG_RECURSE);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen /* prefix/$type/$dest/$source */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (p != NULL && strcmp(p + 1, username) == 0) {
c7be65f5adbc2990fbe6eeffb6df5054a8a49d9dTimo Sirainen i_error("acl: dict iteration failed: %s - can't update dict", error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* sort the existing identifiers */
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen /* sync the identifiers */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen old_ids = array_get(&old_ids_arr, &old_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (newi = oldi = 0; newi < new_count || oldi < old_count; ) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (ret < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* new identifier, add it */
36723cf206a7b64b9d972ab0719bbfaacc9316faTimo Sirainen } else if (!no_removes) {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen /* old identifier removed */
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen if (dict_transaction_commit(&dt, &error) < 0) {
14b1d2a2634e75b988078baee1e8ad678de28a04Timo Sirainen i_error("acl: dict commit failed: %s", error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char **ids;
ee8294dbc7bb549557f6ba1264d66b55fbef69b6Aki Tuomi /* get all ACL identifiers with a positive lookup right */
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)
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen /* sort identifiers and remove duplicates */
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)
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainenstatic void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter)
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen const char *const *idp, *prefix, *key, *value, *error;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen idp = array_idx(&iter->iter_ids, iter->iter_idx);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH,
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 dict_iter = dict_iterate_init(iter->dict->dict, prefix,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen while (dict_iterate(dict_iter, &key, &value)) {
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen key = p_strdup(iter->iter_value_pool, key + prefix_len);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen if (dict_iterate_deinit(&dict_iter, &error) < 0) {
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainenacl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen struct acl_user *auser = ACL_USER_CONTEXT(dict->user);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen const char *id;
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen unsigned int i;
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen pool = pool_alloconly_create("acl lookup dict iter", 1024);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen iter = p_new(pool, struct acl_lookup_dict_iter, 1);
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen id = p_strconcat(pool, "user/", dict->user->username, NULL);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen pool_alloconly_create("acl lookup dict iter values", 1024);
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen /* get all groups we belong to */
d519a0449d0e536a32db93305516fdbd7db6773dTimo Sirainen id = p_strconcat(pool, "group/", auser->groups[i],
ae949831f1f668b5501b4b125e7f7b1767fb109bTimo Sirainen /* iterate through all identifiers that match us, start with the
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainenacl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen const char *const *keys;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen unsigned int count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (iter->iter_idx < array_count(&iter->iter_ids)) {
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen /* get to the next iterator */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return acl_lookup_dict_iterate_visible_next(iter);