summaryrefslogtreecommitdiffstats
path: root/src/plugins/acl/acl-backend.c
blob: 0514dc736f9cd6074ac8043b2936a00b7c0a4951 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* 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;

	e_debug(user->event, "acl: initializing backend with data: %s", data);
	e_debug(user->event, "acl: acl username = %s", acl_username);
	e_debug(user->event, "acl: owner = %d", owner ? 1 : 0);

	group_count = str_array_length(groups);

	if (str_begins(data, "vfile:"))
		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]);
			e_debug(user->event, "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;
}