bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
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. */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen /* name => object */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct acl_object_cache *) objects;
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. */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen /* name => idx+1 */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(char *, void *) right_name_idx_map;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenstruct acl_cache *acl_cache_init(struct acl_backend *backend,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_alloconly_create("ACL right names", 1024);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&cache->objects, default_pool, 0, str_hash, strcmp);
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 Sirainenvoid acl_cache_deinit(struct acl_cache **_cache)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&cache->right_name_idx_map);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void acl_cache_free_object_cache(struct acl_object_cache *obj_cache)
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen obj_cache->my_current_rights != &negative_cache_entry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
9e7eb7beae9828c66d944333264a79744d0313fbTimo Sirainen acl_cache_mask_deinit(&obj_cache->my_neg_rights);
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 unsigned char *p;
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 /* @UNSAFE */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen mask = p_malloc(pool, SIZEOF_ACL_MASK(bitmask->used));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen memcpy(mask->mask, bitmask->data, bitmask->used);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstruct acl_mask *acl_cache_mask_init(struct acl_cache *cache, pool_t pool,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *const *rights)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mask = acl_cache_mask_init_real(cache, pool, rights);
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainenstatic struct acl_mask *
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainenacl_cache_mask_dup(pool_t pool, const struct acl_mask *src)
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen mask = p_malloc(pool, SIZEOF_ACL_MASK(src->size));
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 /* use +1 for right_name_idx_map values because we can't add NULL
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen idx_p = hash_table_lookup(cache->right_name_idx_map, right);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* new right name, add it */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen const_name = name = p_strdup(cache->right_names_pool, right);
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,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush(struct acl_cache *cache, const char *objname)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenvoid acl_cache_flush_all(struct acl_cache *cache)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen iter = hash_table_iterate_init(cache->objects);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, cache->objects, &key, &obj_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 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 */
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen if (obj_cache->my_current_rights == &negative_cache_entry)
dfdb752a8e61fc03569845a94329ab14b91bb8f9Timo Sirainen acl_cache_mask_deinit(&obj_cache->my_current_rights);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenacl_cache_object_get(struct acl_cache *cache, const char *objname,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen obj_cache = i_malloc(MALLOC_ADD(sizeof(struct acl_object_cache),
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_insert(cache->objects, obj_cache->name, obj_cache);
27a7dee37444438522e04273ce17e6c48775b35cTimo Sirainenvoid acl_cache_update(struct acl_cache *cache, const char *objname,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache = acl_cache_object_get(cache, objname, &created);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen i_assert(obj_cache->my_current_rights != &negative_cache_entry);
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 acl_cache_update_rights_mask(cache, obj_cache, update->modify_mode,
55c2029f111653b7c70ec58d7efef531efea63ccTimo Sirainen acl_cache_update_rights_mask(cache, obj_cache, update->neg_modify_mode,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenvoid acl_cache_set_validity(struct acl_cache *cache, const char *objname,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache = acl_cache_object_get(cache, objname, &created);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen /* @UNSAFE: validity is stored after the cache record */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen memcpy(obj_cache + 1, validity, cache->validity_rec_size);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen /* negative cache entry */
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache->my_current_rights = &negative_cache_entry;
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainenvoid *acl_cache_get_validity(struct acl_cache *cache, const char *objname)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen return obj_cache == NULL ? NULL : (obj_cache + 1);
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 /* @UNSAFE */
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen /* apply the positive rights */
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen memcpy(mask->mask, obj_cache->my_rights->mask, mask->size);
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];
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenacl_cache_get_my_rights(struct acl_cache *cache, const char *objname)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen obj_cache = hash_table_lookup(cache->objects, objname);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen obj_cache->my_current_rights == &negative_cache_entry)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen acl_cache_my_current_rights_recalculate(obj_cache);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainenbool acl_cache_mask_isset(const struct acl_mask *mask, unsigned int right_idx)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen (mask->mask[mask_idx] & (1 << (right_idx % CHAR_BIT))) != 0;