1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
5
#include "mail-storage-private.h"
6
#include "acl-api-private.h"
7
#include "acl-plugin.h"
8
#include "acl-storage.h"
10
struct acl_mailbox_attribute_iter {
11
struct mailbox_attribute_iter iter;
12
struct mailbox_attribute_iter *super;
14
struct acl_object_list_iter *acl_iter;
21
acl_attribute_update_acl(struct mailbox_transaction_context *t, const char *key,
22
const struct mail_attribute_value *value)
24
const char *value_str, *id, *const *rights, *error;
25
struct acl_rights_update update;
27
/* for now allow only dsync to update ACLs this way.
28
if this check is removed, it should be replaced by a setting, since
29
some admins may still have configured Dovecot using dovecot-acl
30
files directly that they don't want users to update. and in any case
31
ACL_STORAGE_RIGHT_ADMIN must be checked then. */
32
if (!t->box->storage->user->dsyncing) {
33
mail_storage_set_error(t->box->storage, MAIL_ERROR_PERM,
34
MAIL_ERRSTR_NO_PERMISSION);
38
if (mailbox_attribute_value_to_string(t->box->storage, value,
42
memset(&update, 0, sizeof(update));
43
update.modify_mode = ACL_MODIFY_MODE_REPLACE;
44
update.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
45
update.last_change = value->last_change;
46
id = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL);
47
rights = value_str == NULL ? NULL : t_strsplit(value_str, " ");
48
if (acl_rights_update_import(&update, id, rights, &error) < 0) {
49
mail_storage_set_error(t->box->storage, MAIL_ERROR_PARAMS, error);
52
/* FIXME: this should actually be done only at commit().. */
53
return acl_mailbox_update_acl(t, &update);
56
static int acl_attribute_get_acl(struct mailbox *box, const char *key,
57
struct mail_attribute_value *value_r)
59
struct acl_object *aclobj = acl_mailbox_get_aclobj(box);
60
struct acl_object_list_iter *iter;
61
struct acl_rights rights, wanted_rights;
65
memset(value_r, 0, sizeof(*value_r));
67
if (!box->storage->user->dsyncing) {
68
mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
69
MAIL_ERRSTR_NO_PERMISSION);
72
/* set last_change for all ACL objects, even if they don't exist
73
(because they could have been removed by the last change, and dsync
74
can use this information) */
75
(void)acl_object_last_changed(aclobj, &value_r->last_change);
77
memset(&wanted_rights, 0, sizeof(wanted_rights));
78
id = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL);
79
if (acl_identifier_parse(id, &wanted_rights) < 0) {
80
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
81
t_strdup_printf("Invalid ID: %s", id));
85
iter = acl_object_list_init(aclobj);
86
while ((ret = acl_object_list_next(iter, &rights)) > 0) {
88
rights.id_type == wanted_rights.id_type &&
89
null_strcmp(rights.identifier, wanted_rights.identifier) == 0) {
90
value_r->value = acl_rights_export(&rights);
95
mail_storage_set_internal_error(box->storage);
96
acl_object_list_deinit(&iter);
100
static int acl_have_attribute_rights(struct mailbox *box)
106
When the ACL extension [RFC4314] is present, users can only set and
107
retrieve private or shared mailbox annotations on a mailbox on which
108
they have the "l" right and any one of the "r", "s", "w", "i", or "p"
111
ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP);
115
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
116
T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
120
if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_READ) > 0)
122
if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0)
124
if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0)
126
if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_INSERT) > 0)
128
if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_POST) > 0)
133
int acl_attribute_set(struct mailbox_transaction_context *t,
134
enum mail_attribute_type type, const char *key,
135
const struct mail_attribute_value *value)
137
struct acl_mailbox *abox = ACL_CONTEXT(t->box);
139
if (acl_have_attribute_rights(t->box) < 0)
141
if (strncmp(key, MAILBOX_ATTRIBUTE_PREFIX_ACL,
142
strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL)) == 0)
143
return acl_attribute_update_acl(t, key, value);
144
return abox->module_ctx.super.attribute_set(t, type, key, value);
147
int acl_attribute_get(struct mailbox_transaction_context *t,
148
enum mail_attribute_type type, const char *key,
149
struct mail_attribute_value *value_r)
151
struct acl_mailbox *abox = ACL_CONTEXT(t->box);
153
if (acl_have_attribute_rights(t->box) < 0)
155
if (strncmp(key, MAILBOX_ATTRIBUTE_PREFIX_ACL,
156
strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL)) == 0)
157
return acl_attribute_get_acl(t->box, key, value_r);
158
return abox->module_ctx.super.attribute_get(t, type, key, value_r);
161
struct mailbox_attribute_iter *
162
acl_attribute_iter_init(struct mailbox *box, enum mail_attribute_type type,
165
struct acl_mailbox *abox = ACL_CONTEXT(box);
166
struct acl_mailbox_attribute_iter *aiter;
168
aiter = i_new(struct acl_mailbox_attribute_iter, 1);
169
aiter->iter.box = box;
170
if (acl_have_attribute_rights(box) < 0)
171
aiter->failed = TRUE;
173
aiter->super = abox->module_ctx.super.
174
attribute_iter_init(box, type, prefix);
175
if (box->storage->user->dsyncing &&
176
type == MAIL_ATTRIBUTE_TYPE_SHARED &&
177
strncmp(prefix, MAILBOX_ATTRIBUTE_PREFIX_ACL,
178
strlen(prefix)) == 0) {
179
aiter->acl_iter = acl_object_list_init(abox->aclobj);
180
aiter->acl_name = str_new(default_pool, 128);
181
str_append(aiter->acl_name, MAILBOX_ATTRIBUTE_PREFIX_ACL);
188
acl_attribute_iter_next_acl(struct acl_mailbox_attribute_iter *aiter)
190
struct acl_rights rights;
193
while ((ret = acl_object_list_next(aiter->acl_iter, &rights)) > 0) {
196
str_truncate(aiter->acl_name, strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL));
197
acl_rights_write_id(aiter->acl_name, &rights);
198
return str_c(aiter->acl_name);
201
mail_storage_set_internal_error(aiter->iter.box->storage);
202
aiter->failed = TRUE;
205
acl_object_list_deinit(&aiter->acl_iter);
209
const char *acl_attribute_iter_next(struct mailbox_attribute_iter *iter)
211
struct acl_mailbox_attribute_iter *aiter =
212
(struct acl_mailbox_attribute_iter *)iter;
213
struct acl_mailbox *abox = ACL_CONTEXT(iter->box);
216
if (aiter->super == NULL)
218
if (aiter->acl_iter != NULL) {
219
if ((key = acl_attribute_iter_next_acl(aiter)) != NULL)
222
return abox->module_ctx.super.attribute_iter_next(aiter->super);
225
int acl_attribute_iter_deinit(struct mailbox_attribute_iter *iter)
227
struct acl_mailbox_attribute_iter *aiter =
228
(struct acl_mailbox_attribute_iter *)iter;
229
struct acl_mailbox *abox = ACL_CONTEXT(iter->box);
230
int ret = aiter->failed ? -1 : 0;
232
if (aiter->super != NULL) {
233
if (abox->module_ctx.super.attribute_iter_deinit(aiter->super) < 0)
236
if (aiter->acl_iter != NULL)
237
acl_object_list_deinit(&aiter->acl_iter);
238
if (aiter->acl_name != NULL)
239
str_free(&aiter->acl_name);