/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hash.h"
#include "sort.h"
#include "mail-storage-settings.h"
#include "mailbox-list.h"
#include "mail-namespace.h"
#include "mail-user.h"
#include "acl-cache.h"
#include "acl-api-private.h"
extern struct acl_backend_vfuncs acl_backend_vfile;
const char *const all_mailbox_rights[] = {
MAIL_ACL_LOOKUP,
MAIL_ACL_READ,
MAIL_ACL_WRITE,
MAIL_ACL_WRITE_SEEN,
MAIL_ACL_WRITE_DELETED,
MAIL_ACL_INSERT,
MAIL_ACL_POST,
MAIL_ACL_EXPUNGE,
MAIL_ACL_CREATE,
MAIL_ACL_DELETE,
MAIL_ACL_ADMIN,
NULL
};
static const char *const *owner_mailbox_rights = all_mailbox_rights;
static const char *const non_owner_mailbox_rights[] = { NULL };
struct acl_backend *
acl_backend_init(const char *data, struct mailbox_list *list,
const char *acl_username, const char *const *groups,
bool owner)
{
struct mail_user *user = mailbox_list_get_user(list);
struct acl_backend *backend;
unsigned int i, group_count;
if (user->mail_debug) {
i_debug("acl: initializing backend with data: %s", data);
i_debug("acl: acl username = %s", acl_username);
i_debug("acl: owner = %d", owner ? 1 : 0);
}
group_count = str_array_length(groups);
if (strncmp(data, "vfile:", 6) == 0)
data += 6;
else if (strcmp(data, "vfile") == 0)
data = "";
else
i_fatal("Unknown ACL backend: %s", t_strcut(data, ':'));
backend = acl_backend_vfile.alloc();
backend->debug = user->mail_debug;
backend->v = acl_backend_vfile;
backend->list = list;
backend->username = p_strdup(backend->pool, acl_username);
backend->owner = owner;
backend->globals_only =
mail_user_plugin_getenv_bool(user, "acl_globals_only");
if (group_count > 0) {
backend->group_count = group_count;
backend->groups =
p_new(backend->pool, const char *, group_count);
for (i = 0; i < group_count; i++) {
backend->groups[i] = p_strdup(backend->pool, groups[i]);
if (user->mail_debug)
i_debug("acl: group added: %s", groups[i]);
}
i_qsort(backend->groups, group_count, sizeof(const char *),
i_strcmp_p);
}
T_BEGIN {
if (acl_backend_vfile.init(backend, data) < 0)
i_fatal("acl: backend vfile init failed with data: %s",
data);
} T_END;
backend->default_rights = owner ? owner_mailbox_rights :
non_owner_mailbox_rights;
backend->default_aclmask =
acl_cache_mask_init(backend->cache, backend->pool,
backend->default_rights);
return backend;
}
void acl_backend_deinit(struct acl_backend **_backend)
{
struct acl_backend *backend = *_backend;
*_backend = NULL;
if (backend->default_aclobj != NULL)
acl_object_deinit(&backend->default_aclobj);
acl_cache_deinit(&backend->cache);
backend->v.deinit(backend);
}
const char *acl_backend_get_acl_username(struct acl_backend *backend)
{
return backend->username;
}
bool acl_backend_user_is_authenticated(struct acl_backend *backend)
{
return backend->username != NULL;
}
bool acl_backend_user_is_owner(struct acl_backend *backend)
{
return backend->owner;
}
bool acl_backend_user_name_equals(struct acl_backend *backend,
const char *username)
{
if (backend->username == NULL) {
/* anonymous user never matches */
return FALSE;
}
return strcmp(backend->username, username) == 0;
}
bool acl_backend_user_is_in_group(struct acl_backend *backend,
const char *group_name)
{
return i_bsearch(group_name, backend->groups, backend->group_count,
sizeof(const char *), bsearch_strcmp) != NULL;
}
bool acl_backend_rights_match_me(struct acl_backend *backend,
const struct acl_rights *rights)
{
switch (rights->id_type) {
case ACL_ID_ANYONE:
return TRUE;
case ACL_ID_AUTHENTICATED:
return acl_backend_user_is_authenticated(backend);
case ACL_ID_GROUP:
case ACL_ID_GROUP_OVERRIDE:
return acl_backend_user_is_in_group(backend, rights->identifier);
case ACL_ID_USER:
return acl_backend_user_name_equals(backend, rights->identifier);
case ACL_ID_OWNER:
return acl_backend_user_is_owner(backend);
case ACL_ID_TYPE_COUNT:
break;
}
i_unreached();
}
unsigned int acl_backend_lookup_right(struct acl_backend *backend,
const char *right)
{
return acl_cache_right_lookup(backend->cache, right);
}
struct acl_object *acl_backend_get_default_object(struct acl_backend *backend)
{
struct mail_user *user = mailbox_list_get_user(backend->list);
struct mail_namespace *ns = mailbox_list_get_namespace(backend->list);
const char *default_name = "";
if (backend->default_aclobj != NULL)
return backend->default_aclobj;
if (mail_user_plugin_getenv_bool(user, "acl_defaults_from_inbox")) {
if (ns->type == MAIL_NAMESPACE_TYPE_PRIVATE ||
ns->type == MAIL_NAMESPACE_TYPE_SHARED)
default_name = "INBOX";
}
backend->default_aclobj =
acl_object_init_from_name(backend, default_name);
return backend->default_aclobj;
}
int acl_backend_get_default_rights(struct acl_backend *backend,
const struct acl_mask **mask_r)
{
struct acl_object *aclobj = acl_backend_get_default_object(backend);
if (backend->v.object_refresh_cache(aclobj) < 0)
return -1;
*mask_r = acl_cache_get_my_rights(backend->cache, aclobj->name);
if (*mask_r == NULL)
*mask_r = backend->default_aclmask;
return 0;
}