acl-cache.c revision 7fb70daba4e571eab5b64f496d20b9e37e31141b
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen/* Copyright (C) 2006 Timo 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 struct acl_mask *my_rights[ACL_ID_TYPE_COUNT];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *my_neg_rights[ACL_ID_TYPE_COUNT];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* Needs to be calculated from my_*rights if NULL. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct hash_table *objects; /* name => struct acl_object_cache* */
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 /* idx => right name. */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_t ARRAY_DEFINE(right_idx_name_map, const char *);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* name => idx */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_cache *acl_cache_init(struct acl_backend *backend)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_alloconly_create("ACL right names", 1024);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen cache->objects = hash_create(default_pool, default_pool, 0,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_create(default_pool, cache->right_names_pool, 0,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ARRAY_CREATE(&cache->right_idx_name_map, default_pool,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_deinit(struct acl_cache **_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void acl_cache_free_object_cache(struct acl_object_cache *obj_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < ACL_ID_TYPE_COUNT; i++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_rights[i]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_neg_rights[i]);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_mask *acl_cache_mask_init(struct acl_cache *cache, pool_t pool,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const char *const *rights)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned char *p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen bitmask = buffer_create_dynamic(pool_datastack_create(),
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 /* @UNSAFE */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask = p_malloc(pool, SIZEOF_ACL_MASK(bitmask->used));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen memcpy(mask->mask, bitmask->data, bitmask->used);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_mask_deinit(struct acl_mask **_mask)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenunsigned int acl_cache_right_lookup(struct acl_cache *cache, const char *right)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int idx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* use +1 for right_name_idx_map values because we can't add NULL
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx_p = hash_lookup(cache->right_name_idx_map, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* new right name, add it */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen name = p_strdup(cache->right_names_pool, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen idx = array_count(&cache->right_idx_name_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_append(&cache->right_idx_name_map, &name, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush(struct acl_cache *cache, const char *objname)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush_all(struct acl_cache *cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_update_rights_mask(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const char *const *rights,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_mask *change_mask, *old_mask, *new_mask;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i, size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_init(cache, default_pool, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* no changes */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* merge the masks */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* keep using the old mask */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* use the new mask, put old changes into it */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (old_mask == NULL || change_mask == NULL) {
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 if (new_mask != change_mask && change_mask != NULL)
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 Sirainenacl_cache_update_rights(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, rights->modify_mode,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, rights->neg_modify_mode,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_update(struct acl_cache *cache, const char *objname,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = i_new(struct acl_object_cache, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen hash_insert(cache->objects, obj_cache->name, obj_cache);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_is_authenticated(cache->backend))
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_is_in_group(cache->backend,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (acl_backend_user_name_equals(cache->backend,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_update_rights(cache, obj_cache, rights);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenconst char *const *acl_cache_get_names(struct acl_cache *cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int *count_r)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen *count_r = array_count(&cache->right_idx_name_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return array_idx(&cache->right_idx_name_map, 0);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_my_current_rights_recalculate(struct acl_object_cache *obj_cache)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned char *p;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i, j, right_size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen bitmask = buffer_create_dynamic(pool_datastack_create(),
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0; i < ACL_ID_TYPE_COUNT; i++) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* apply the positive rights */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen p = buffer_get_space_unsafe(bitmask, 0, right_size);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (j = 0; j < right_size; j++)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* apply the negative rights. they override positive
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 /* @UNSAFE */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen memcpy(mask->mask, bitmask->data, bitmask->used);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_get_my_rights(struct acl_cache *cache, const char *objname)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen obj_cache = hash_lookup(cache->objects, objname);