acl-cache.c revision 7fb70daba4e571eab5b64f496d20b9e37e31141b
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen/* Copyright (C) 2006 Timo Sirainen */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "lib.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "array.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "hash.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "acl-cache.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "acl-api.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
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_object_cache {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen char *name;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *my_rights[ACL_ID_TYPE_COUNT];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *my_neg_rights[ACL_ID_TYPE_COUNT];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* Needs to be calculated from my_*rights if NULL. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *my_current_rights;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_cache {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_backend *backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct hash_table *objects; /* name => struct acl_object_cache* */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_t ARRAY_DEFINE(right_idx_name_map, const char *);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* name => idx */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct hash_table *right_name_idx_map;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_cache *acl_cache_init(struct acl_backend *backend)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_cache *cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache = i_new(struct acl_cache, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->backend = backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->right_names_pool =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_alloconly_create("ACL right names", 1024);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->objects = hash_create(default_pool, default_pool, 0,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen str_hash, (hash_cmp_callback_t *)strcmp);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->right_name_idx_map =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_create(default_pool, cache->right_names_pool, 0,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen str_hash, (hash_cmp_callback_t *)strcmp);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ARRAY_CREATE(&cache->right_idx_name_map, default_pool,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const char *, 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;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_free(&cache->right_idx_name_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_destroy(cache->right_name_idx_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_destroy(cache->objects);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < ACL_ID_TYPE_COUNT; i++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_rights[i] != NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_rights[i]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_neg_rights[i] != NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_neg_rights[i]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_current_rights != NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(obj_cache->name);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_mask *acl_cache_mask_init(struct acl_cache *cache, pool_t pool,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen t_push();
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights_count = strarray_length(rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen bitmask = buffer_create_dynamic(pool_datastack_create(),
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen 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;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen t_pop();
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen void *idx_p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen char *name;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* use +1 for right_name_idx_map values because we can't add NULL
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen values. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx_p = hash_lookup(cache->right_name_idx_map, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (idx_p == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* new right name, add it */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen name = p_strdup(cache->right_names_pool, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx = array_count(&cache->right_idx_name_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_append(&cache->right_idx_name_map, &name, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_insert(cache->right_name_idx_map, name,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen POINTER_CAST(idx + 1));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen } else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache != NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_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;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen void *key, *value;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen iter = hash_iterate_init(cache->objects);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen while (hash_iterate(iter, &key, &value)) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache = value;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_free_object_cache(obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_iterate_deinit(iter);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_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;
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 */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_update_rights(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const struct acl_rights *rights)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen enum acl_id_type id_type = rights->id_type;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, rights->modify_mode,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights->rights,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen &obj_cache->my_rights[id_type]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, rights->neg_modify_mode,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights->neg_rights,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen &obj_cache->my_neg_rights[id_type]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_update(struct acl_cache *cache, const char *objname,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const struct acl_rights *rights)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_cache *obj_cache;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache == NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = i_new(struct acl_object_cache, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache->name = i_strdup(objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_insert(cache->objects, obj_cache->name, obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen switch (rights->id_type) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_ANYONE:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_AUTHENTICATED:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_is_authenticated(cache->backend))
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_GROUP:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_GROUP_OVERRIDE:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_is_in_group(cache->backend,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights->identifier))
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_USER:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_name_equals(cache->backend,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights->identifier))
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen case ACL_ID_TYPE_COUNT:
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_unreached();
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo 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;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen buffer_t *bitmask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned char *p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i, j, right_size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen t_push();
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen bitmask = buffer_create_dynamic(pool_datastack_create(),
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen DEFAULT_ACL_RIGHTS_COUNT / CHAR_BIT);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < ACL_ID_TYPE_COUNT; i++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_rights[i] != NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* apply the positive rights */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen right_size = obj_cache->my_rights[i]->size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p = buffer_get_space_unsafe(bitmask, 0, right_size);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (j = 0; j < right_size; j++)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p[j] |= obj_cache->my_rights[i]->mask[j];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_neg_rights[i] != NULL) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* apply the negative rights. they override positive
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen rights. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen right_size = obj_cache->my_neg_rights[i]->size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p = buffer_get_space_unsafe(bitmask, 0, right_size);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (j = 0; j < right_size; j++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p[j] |=
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache->my_neg_rights[i]->mask[j];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* @UNSAFE */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache->my_current_rights = mask =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_malloc(SIZEOF_ACL_MASK(bitmask->used));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen memcpy(mask->mask, bitmask->data, bitmask->used);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask->pool = default_pool;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask->size = bitmask->used;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen t_pop();
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
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache == NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return NULL;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (obj_cache->my_current_rights == NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_my_current_rights_recalculate(obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return obj_cache->my_current_rights;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}