~ubuntu-branches/ubuntu/trusty/dovecot/trusty-updates

« back to all changes in this revision

Viewing changes to src/plugins/acl/acl-attributes.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (1.15.3) (96.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20140108093549-814nkqdcxfbvgktg
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "str.h"
 
5
#include "mail-storage-private.h"
 
6
#include "acl-api-private.h"
 
7
#include "acl-plugin.h"
 
8
#include "acl-storage.h"
 
9
 
 
10
struct acl_mailbox_attribute_iter {
 
11
        struct mailbox_attribute_iter iter;
 
12
        struct mailbox_attribute_iter *super;
 
13
 
 
14
        struct acl_object_list_iter *acl_iter;
 
15
        string_t *acl_name;
 
16
 
 
17
        bool failed;
 
18
};
 
19
 
 
20
static int
 
21
acl_attribute_update_acl(struct mailbox_transaction_context *t, const char *key,
 
22
                         const struct mail_attribute_value *value)
 
23
{
 
24
        const char *value_str, *id, *const *rights, *error;
 
25
        struct acl_rights_update update;
 
26
 
 
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);
 
35
                return -1;
 
36
        }
 
37
 
 
38
        if (mailbox_attribute_value_to_string(t->box->storage, value,
 
39
                                              &value_str) < 0)
 
40
                return -1;
 
41
 
 
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);
 
50
                return -1;
 
51
        }
 
52
        /* FIXME: this should actually be done only at commit().. */
 
53
        return acl_mailbox_update_acl(t, &update);
 
54
}
 
55
 
 
56
static int acl_attribute_get_acl(struct mailbox *box, const char *key,
 
57
                                 struct mail_attribute_value *value_r)
 
58
{
 
59
        struct acl_object *aclobj = acl_mailbox_get_aclobj(box);
 
60
        struct acl_object_list_iter *iter;
 
61
        struct acl_rights rights, wanted_rights;
 
62
        const char *id;
 
63
        int ret;
 
64
 
 
65
        memset(value_r, 0, sizeof(*value_r));
 
66
 
 
67
        if (!box->storage->user->dsyncing) {
 
68
                mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
 
69
                                       MAIL_ERRSTR_NO_PERMISSION);
 
70
                return -1;
 
71
        }
 
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);
 
76
 
 
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));
 
82
                return -1;
 
83
        }
 
84
 
 
85
        iter = acl_object_list_init(aclobj);
 
86
        while ((ret = acl_object_list_next(iter, &rights)) > 0) {
 
87
                if (!rights.global &&
 
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);
 
91
                        break;
 
92
                }
 
93
        }
 
94
        if (ret < 0)
 
95
                mail_storage_set_internal_error(box->storage);
 
96
        acl_object_list_deinit(&iter);
 
97
        return ret;
 
98
}
 
99
 
 
100
static int acl_have_attribute_rights(struct mailbox *box)
 
101
{
 
102
        int ret;
 
103
 
 
104
        /* RFC 5464:
 
105
 
 
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"
 
109
           rights.
 
110
        */
 
111
        ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP);
 
112
        if (ret <= 0) {
 
113
                if (ret < 0)
 
114
                        return -1;
 
115
                mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
 
116
                                T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
 
117
                return -1;
 
118
        }
 
119
 
 
120
        if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_READ) > 0)
 
121
                return 0;
 
122
        if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0)
 
123
                return 0;
 
124
        if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0)
 
125
                return 0;
 
126
        if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_INSERT) > 0)
 
127
                return 0;
 
128
        if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_POST) > 0)
 
129
                return 0;
 
130
        return -1;
 
131
}
 
132
 
 
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)
 
136
{
 
137
        struct acl_mailbox *abox = ACL_CONTEXT(t->box);
 
138
 
 
139
        if (acl_have_attribute_rights(t->box) < 0)
 
140
                return -1;
 
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);
 
145
}
 
146
 
 
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)
 
150
{
 
151
        struct acl_mailbox *abox = ACL_CONTEXT(t->box);
 
152
 
 
153
        if (acl_have_attribute_rights(t->box) < 0)
 
154
                return -1;
 
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);
 
159
}
 
160
 
 
161
struct mailbox_attribute_iter *
 
162
acl_attribute_iter_init(struct mailbox *box, enum mail_attribute_type type,
 
163
                        const char *prefix)
 
164
{
 
165
        struct acl_mailbox *abox = ACL_CONTEXT(box);
 
166
        struct acl_mailbox_attribute_iter *aiter;
 
167
 
 
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;
 
172
        else {
 
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);
 
182
                }
 
183
        }
 
184
        return &aiter->iter;
 
185
}
 
186
 
 
187
static const char *
 
188
acl_attribute_iter_next_acl(struct acl_mailbox_attribute_iter *aiter)
 
189
{
 
190
        struct acl_rights rights;
 
191
        int ret;
 
192
 
 
193
        while ((ret = acl_object_list_next(aiter->acl_iter, &rights)) > 0) {
 
194
                if (rights.global)
 
195
                        continue;
 
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);
 
199
        }
 
200
        if (ret < 0) {
 
201
                mail_storage_set_internal_error(aiter->iter.box->storage);
 
202
                aiter->failed = TRUE;
 
203
                return NULL;
 
204
        }
 
205
        acl_object_list_deinit(&aiter->acl_iter);
 
206
        return NULL;
 
207
}
 
208
 
 
209
const char *acl_attribute_iter_next(struct mailbox_attribute_iter *iter)
 
210
{
 
211
        struct acl_mailbox_attribute_iter *aiter =
 
212
                (struct acl_mailbox_attribute_iter *)iter;
 
213
        struct acl_mailbox *abox = ACL_CONTEXT(iter->box);
 
214
        const char *key;
 
215
 
 
216
        if (aiter->super == NULL)
 
217
                return NULL;
 
218
        if (aiter->acl_iter != NULL) {
 
219
                if ((key = acl_attribute_iter_next_acl(aiter)) != NULL)
 
220
                        return key;
 
221
        }
 
222
        return abox->module_ctx.super.attribute_iter_next(aiter->super);
 
223
}
 
224
 
 
225
int acl_attribute_iter_deinit(struct mailbox_attribute_iter *iter)
 
226
{
 
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;
 
231
 
 
232
        if (aiter->super != NULL) {
 
233
                if (abox->module_ctx.super.attribute_iter_deinit(aiter->super) < 0)
 
234
                        ret = -1;
 
235
        }
 
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);
 
240
        i_free(aiter);
 
241
        return ret;
 
242
}