bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "lib.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "array.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "hash.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "acl-cache.h"
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen#include "acl-api-private.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen/* Give more than enough so that the arrays should never have to be grown.
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen IMAP ACLs define only 10 standard rights and 10 user-defined rights. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#define DEFAULT_ACL_RIGHTS_COUNT 64
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen#define ACL_GLOBAL_COUNT 2
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_object_cache {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen char *name;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen struct acl_mask *my_rights, *my_neg_rights;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *my_current_rights;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_cache {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_backend *backend;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen /* name => object */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct acl_object_cache *) objects;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen size_t validity_rec_size;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* Right names mapping is used for faster rights checking. Note that
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_mask bitmask relies on the order to never change, so only new
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights can be added to the mapping. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_t right_names_pool;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* idx => right name. */
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(const char *) right_idx_name_map;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen /* name => idx+1 */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(char *, void *) right_name_idx_map;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenstatic struct acl_mask negative_cache_entry;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenstruct acl_cache *acl_cache_init(struct acl_backend *backend,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen size_t validity_rec_size)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_cache *cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache = i_new(struct acl_cache, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->backend = backend;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen cache->validity_rec_size = validity_rec_size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->right_names_pool =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_alloconly_create("ACL right names", 1024);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&cache->objects, default_pool, 0, str_hash, strcmp);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&cache->right_name_idx_map,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen cache->right_names_pool, 0, str_hash, strcmp);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&cache->right_idx_name_map, DEFAULT_ACL_RIGHTS_COUNT);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_deinit(struct acl_cache **_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_cache *cache = *_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *_cache = NULL;
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen acl_cache_flush_all(cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_free(&cache->right_idx_name_map);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&cache->right_name_idx_map);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&cache->objects);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&cache->right_names_pool);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void acl_cache_free_object_cache(struct acl_object_cache *obj_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen if (obj_cache->my_current_rights != NULL &&
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen obj_cache->my_current_rights != &negative_cache_entry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
9e7eb7beae9828c66d944333264a79744d0313fbTimo Sirainen if (obj_cache->my_rights != NULL)
9e7eb7beae9828c66d944333264a79744d0313fbTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_rights);
9e7eb7beae9828c66d944333264a79744d0313fbTimo Sirainen if (obj_cache->my_neg_rights != NULL)
9e7eb7beae9828c66d944333264a79744d0313fbTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_neg_rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(obj_cache->name);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic struct acl_mask *
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenacl_cache_mask_init_real(struct acl_cache *cache, pool_t pool,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *const *rights)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int rights_count, i, idx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned char *p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen buffer_t *bitmask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
d3837c0362588792db3e3148d217f31ff3172922Timo Sirainen rights_count = str_array_length(rights);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi bitmask = t_buffer_create(DEFAULT_ACL_RIGHTS_COUNT / CHAR_BIT);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < rights_count; i++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx = acl_cache_right_lookup(cache, rights[i]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p = buffer_get_space_unsafe(bitmask, idx / CHAR_BIT, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *p |= 1 << (idx % CHAR_BIT);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* @UNSAFE */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask = p_malloc(pool, SIZEOF_ACL_MASK(bitmask->used));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen memcpy(mask->mask, bitmask->data, bitmask->used);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask->pool = pool;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask->size = bitmask->used;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return mask;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstruct acl_mask *acl_cache_mask_init(struct acl_cache *cache, pool_t pool,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *const *rights)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct acl_mask *mask;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mask = acl_cache_mask_init_real(cache, pool, rights);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainenstatic struct acl_mask *
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainenacl_cache_mask_dup(pool_t pool, const struct acl_mask *src)
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen{
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen struct acl_mask *mask;
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen mask = p_malloc(pool, SIZEOF_ACL_MASK(src->size));
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen memcpy(mask->mask, src->mask, src->size);
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen mask->pool = pool;
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen mask->size = src->size;
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen return mask;
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen}
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_mask_deinit(struct acl_mask **_mask)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *mask = *_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *_mask = NULL;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p_free(mask->pool, mask);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenunsigned int acl_cache_right_lookup(struct acl_cache *cache, const char *right)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int idx;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *idx_p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen char *name;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen const char *const_name;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* use +1 for right_name_idx_map values because we can't add NULL
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen values. */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen idx_p = hash_table_lookup(cache->right_name_idx_map, right);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen if (idx_p == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* new right name, add it */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen const_name = name = p_strdup(cache->right_names_pool, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx = array_count(&cache->right_idx_name_map);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen array_append(&cache->right_idx_name_map, &const_name, 1);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(cache->right_name_idx_map, name,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(idx + 1));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen } else {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen idx = POINTER_CAST_TO(idx_p, unsigned int)-1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return idx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush(struct acl_cache *cache, const char *objname)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache != NULL) {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_remove(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_free_object_cache(obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush_all(struct acl_cache *cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct hash_iterate_context *iter;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen char *key;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen struct acl_object_cache *obj_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen iter = hash_table_iterate_init(cache->objects);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, cache->objects, &key, &obj_cache))
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_free_object_cache(obj_cache);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_iterate_deinit(&iter);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_clear(cache->objects, FALSE);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_update_rights_mask(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen enum acl_modify_mode modify_mode,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const char *const *rights,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask **mask_p)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *change_mask, *old_mask, *new_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i, size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen bool changed = TRUE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen change_mask = rights == NULL ? NULL :
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_init(cache, default_pool, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen old_mask = *mask_p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen new_mask = old_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen switch (modify_mode) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_MODIFY_MODE_ADD:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen new_mask = change_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (change_mask == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* no changes */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen changed = FALSE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* merge the masks */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask->size >= change_mask->size) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* keep using the old mask */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < change_mask->size; i++)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen old_mask->mask[i] |= change_mask->mask[i];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen } else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* use the new mask, put old changes into it */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < old_mask->size; i++)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen change_mask->mask[i] |= old_mask->mask[i];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen new_mask = change_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_MODIFY_MODE_REMOVE:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask == NULL || change_mask == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen changed = FALSE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* remove changed bits from old mask */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen size = I_MIN(old_mask->size, change_mask->size);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < size; i++)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen old_mask->mask[i] &= ~change_mask->mask[i];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_MODIFY_MODE_REPLACE:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask == NULL && change_mask == NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen changed = FALSE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen new_mask = change_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen case ACL_MODIFY_MODE_CLEAR:
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_unreached();
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (new_mask != old_mask) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *mask_p = new_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask != NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&old_mask);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (new_mask != change_mask && change_mask != NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&change_mask);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (changed && obj_cache->my_current_rights != NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* current rights need to be recalculated */
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen if (obj_cache->my_current_rights == &negative_cache_entry)
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen obj_cache->my_current_rights = NULL;
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen else
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenstatic struct acl_object_cache *
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenacl_cache_object_get(struct acl_cache *cache, const char *objname,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen bool *created_r)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache == NULL) {
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen obj_cache = i_malloc(MALLOC_ADD(sizeof(struct acl_object_cache),
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen cache->validity_rec_size));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache->name = i_strdup(objname);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_insert(cache->objects, obj_cache->name, obj_cache);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen *created_r = TRUE;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen } else {
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen *created_r = FALSE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen return obj_cache;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen}
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
27a7dee37444438522e04273ce17e6c48775b35cTimo Sirainenvoid acl_cache_update(struct acl_cache *cache, const char *objname,
27a7dee37444438522e04273ce17e6c48775b35cTimo Sirainen const struct acl_rights_update *update)
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen{
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen struct acl_object_cache *obj_cache;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen bool created;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache = acl_cache_object_get(cache, objname, &created);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen i_assert(obj_cache->my_current_rights != &negative_cache_entry);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen if (created && update->modify_mode != ACL_MODIFY_MODE_REPLACE) {
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen /* since the rights aren't being replaced, start with our
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen default rights */
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen obj_cache->my_rights =
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen acl_cache_mask_dup(default_pool,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen cache->backend->default_aclmask);
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen }
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, update->modify_mode,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen update->rights.rights,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen &obj_cache->my_rights);
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, update->neg_modify_mode,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen update->rights.neg_rights,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen &obj_cache->my_neg_rights);
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen}
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenvoid acl_cache_set_validity(struct acl_cache *cache, const char *objname,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen const void *validity)
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen{
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen struct acl_object_cache *obj_cache;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen bool created;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache = acl_cache_object_get(cache, objname, &created);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen /* @UNSAFE: validity is stored after the cache record */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen memcpy(obj_cache + 1, validity, cache->validity_rec_size);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen if (created) {
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen /* negative cache entry */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache->my_current_rights = &negative_cache_entry;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen }
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen}
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainenvoid *acl_cache_get_validity(struct acl_cache *cache, const char *objname)
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen{
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen struct acl_object_cache *obj_cache;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen return obj_cache == NULL ? NULL : (obj_cache + 1);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen}
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenconst char *const *acl_cache_get_names(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int *count_r)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *count_r = array_count(&cache->right_idx_name_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return array_idx(&cache->right_idx_name_map, 0);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_my_current_rights_recalculate(struct acl_object_cache *obj_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *mask;
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen unsigned int i, size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* @UNSAFE */
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen size = obj_cache->my_rights == NULL ? 0 :
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen obj_cache->my_rights->size;
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen mask = i_malloc(SIZEOF_ACL_MASK(size));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask->pool = default_pool;
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen mask->size = size;
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen /* apply the positive rights */
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen if (obj_cache->my_rights != NULL)
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen memcpy(mask->mask, obj_cache->my_rights->mask, mask->size);
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen if (obj_cache->my_neg_rights != NULL) {
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen /* apply the negative rights. they override positive rights. */
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen size = I_MIN(mask->size, obj_cache->my_neg_rights->size);
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen for (i = 0; i < size; i++)
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen mask->mask[i] &= ~obj_cache->my_neg_rights->mask[i];
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen }
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen obj_cache->my_current_rights = mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenconst struct acl_mask *
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_get_my_rights(struct acl_cache *cache, const char *objname)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen if (obj_cache == NULL ||
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache->my_current_rights == &negative_cache_entry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return NULL;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (obj_cache->my_current_rights == NULL) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen acl_cache_my_current_rights_recalculate(obj_cache);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return obj_cache->my_current_rights;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainenbool acl_cache_mask_isset(const struct acl_mask *mask, unsigned int right_idx)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen{
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen unsigned int mask_idx;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen mask_idx = right_idx / CHAR_BIT;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen return mask_idx < mask->size &&
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen (mask->mask[mask_idx] & (1 << (right_idx % CHAR_BIT))) != 0;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen}