~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2006-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
/* FIXME: If we don't have permission to change flags/keywords, the changes
4
4
   should still be stored temporarily for this session. However most clients
6
6
   problem actually exists when opening read-only mailboxes. */
7
7
#include "lib.h"
8
8
#include "array.h"
 
9
#include "ioloop.h"
9
10
#include "istream.h"
10
11
#include "mailbox-list-private.h"
11
12
#include "acl-api-private.h"
16
17
#define ACL_MAIL_CONTEXT(obj) \
17
18
        MODULE_CONTEXT(obj, acl_mail_module)
18
19
 
19
 
struct acl_mailbox {
20
 
        union mailbox_module_context module_ctx;
21
 
        struct acl_object *aclobj;
22
 
        bool skip_acl_checks;
23
 
        bool acl_enabled;
24
 
        bool no_read_right;
25
 
};
26
 
 
27
20
struct acl_transaction_context {
28
21
        union mailbox_transaction_module_context module_ctx;
29
22
};
125
118
        struct acl_mailbox *abox = ACL_CONTEXT(box);
126
119
        int ret;
127
120
 
128
 
        /* we already checked permissions in list.mailbox_create_dir().
129
 
           ignore ACLs in this mailbox until creation is complete, because
 
121
        /* we're looking up CREATE permission from our parent's rights */
 
122
        ret = acl_mailbox_list_have_right(box->list, box->name, TRUE,
 
123
                                          ACL_STORAGE_RIGHT_CREATE, NULL);
 
124
        if (ret <= 0) {
 
125
                if (ret < 0) {
 
126
                        mail_storage_set_internal_error(box->storage);
 
127
                        return -1;
 
128
                }
 
129
                /* Note that if user didn't have LOOKUP permission to parent
 
130
                   mailbox, this may reveal the mailbox's existence to user.
 
131
                   Can't help it. */
 
132
                mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
 
133
                                       MAIL_ERRSTR_NO_PERMISSION);
 
134
                return -1;
 
135
        }
 
136
 
 
137
        /* ignore ACLs in this mailbox until creation is complete, because
130
138
           super.create() may call e.g. mailbox_open() which will fail since
131
139
           we haven't yet copied ACLs to this mailbox. */
132
140
        abox->skip_acl_checks = TRUE;
133
 
        ret = abox->module_ctx.super.create(box, update, directory);
 
141
        ret = abox->module_ctx.super.create_box(box, update, directory);
134
142
        abox->skip_acl_checks = FALSE;
135
143
        if (ret == 0)
136
144
                acl_mailbox_copy_acls_from_parent(box);
146
154
        ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
147
155
        if (ret <= 0)
148
156
                return -1;
149
 
        return abox->module_ctx.super.update(box, update);
 
157
        return abox->module_ctx.super.update_box(box, update);
150
158
}
151
159
 
152
160
static void acl_mailbox_fail_not_found(struct mailbox *box)
179
187
        /* deletion might internally open the mailbox. let it succeed even if
180
188
           we don't have READ permission. */
181
189
        abox->skip_acl_checks = TRUE;
182
 
        ret = abox->module_ctx.super.delete(box);
 
190
        ret = abox->module_ctx.super.delete_box(box);
183
191
        abox->skip_acl_checks = FALSE;
184
192
        return ret;
185
193
}
186
194
 
187
195
static int
188
 
acl_mailbox_rename(struct mailbox *src, struct mailbox *dest,
189
 
                   bool rename_children)
 
196
acl_mailbox_rename(struct mailbox *src, struct mailbox *dest)
190
197
{
191
198
        struct acl_mailbox *abox = ACL_CONTEXT(src);
192
199
        int ret;
218
225
                return -1;
219
226
        }
220
227
 
221
 
        return abox->module_ctx.super.rename(src, dest, rename_children);
 
228
        return abox->module_ctx.super.rename_box(src, dest);
222
229
}
223
230
 
224
231
static int
321
328
                /* if we don't have permission, silently return success so
322
329
                   users won't see annoying error messages in case their
323
330
                   clients try automatic expunging. */
324
 
                if (ret < 0)
325
 
                        acl_transaction_set_failure(_mail->transaction);
 
331
                acl_transaction_set_failure(_mail->transaction);
326
332
                return;
327
333
        }
328
334
 
349
355
        MODULE_CONTEXT_SET_SELF(mail, acl_mail_module, amail);
350
356
}
351
357
 
352
 
static int acl_save_get_flags(struct mailbox *box, enum mail_flags *flags,
353
 
                              struct mail_keywords **keywords)
 
358
static int
 
359
acl_save_get_flags(struct mailbox *box, enum mail_flags *flags,
 
360
                   enum mail_flags *pvt_flags, struct mail_keywords **keywords)
354
361
{
355
362
        bool acl_flags, acl_flag_seen, acl_flag_del;
356
363
 
358
365
                                 &acl_flag_del) < 0)
359
366
                return -1;
360
367
 
361
 
        if (!acl_flag_seen)
 
368
        if (!acl_flag_seen) {
362
369
                *flags &= ~MAIL_SEEN;
363
 
        if (!acl_flag_del)
 
370
                *pvt_flags &= ~MAIL_SEEN;
 
371
        }
 
372
        if (!acl_flag_del) {
364
373
                *flags &= ~MAIL_DELETED;
 
374
                *pvt_flags &= ~MAIL_DELETED;
 
375
        }
365
376
        if (!acl_flags) {
366
377
                *flags &= MAIL_SEEN | MAIL_DELETED;
 
378
                *pvt_flags &= MAIL_SEEN | MAIL_DELETED;
367
379
                *keywords = NULL;
368
380
        }
369
381
        return 0;
380
392
                ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT;
381
393
        if (acl_mailbox_right_lookup(box, save_right) <= 0)
382
394
                return -1;
383
 
        if (acl_save_get_flags(box, &ctx->flags, &ctx->keywords) < 0)
 
395
        if (acl_save_get_flags(box, &ctx->data.flags,
 
396
                               &ctx->data.pvt_flags, &ctx->data.keywords) < 0)
384
397
                return -1;
385
398
 
386
399
        return abox->module_ctx.super.save_begin(ctx, input);
387
400
}
388
401
 
 
402
static bool
 
403
acl_copy_has_rights(struct mail_save_context *ctx, struct mail *mail)
 
404
{
 
405
        struct mailbox *destbox = ctx->transaction->box;
 
406
        enum acl_storage_rights save_right;
 
407
 
 
408
        if (ctx->moving) {
 
409
                if (acl_mailbox_right_lookup(mail->box,
 
410
                                             ACL_STORAGE_RIGHT_EXPUNGE) <= 0)
 
411
                        return FALSE;
 
412
        }
 
413
 
 
414
        save_right = (destbox->flags & MAILBOX_FLAG_POST_SESSION) != 0 ?
 
415
                ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT;
 
416
        if (acl_mailbox_right_lookup(destbox, save_right) <= 0)
 
417
                return FALSE;
 
418
        if (acl_save_get_flags(destbox, &ctx->data.flags,
 
419
                               &ctx->data.pvt_flags, &ctx->data.keywords) < 0)
 
420
                return FALSE;
 
421
        return TRUE;
 
422
}
 
423
 
389
424
static int
390
425
acl_copy(struct mail_save_context *ctx, struct mail *mail)
391
426
{
392
427
        struct mailbox_transaction_context *t = ctx->transaction;
393
428
        struct acl_mailbox *abox = ACL_CONTEXT(t->box);
394
 
        enum acl_storage_rights save_right;
395
429
 
396
 
        save_right = (t->box->flags & MAILBOX_FLAG_POST_SESSION) != 0 ?
397
 
                ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT;
398
 
        if (acl_mailbox_right_lookup(t->box, save_right) <= 0)
399
 
                return -1;
400
 
        if (acl_save_get_flags(t->box, &ctx->flags, &ctx->keywords) < 0)
401
 
                return -1;
 
430
        if (!acl_copy_has_rights(ctx, mail)) {
 
431
                mailbox_save_cancel(&ctx);
 
432
                return -1;
 
433
        }
402
434
 
403
435
        return abox->module_ctx.super.copy(ctx, mail);
404
436
}
535
567
                return;
536
568
        }
537
569
 
 
570
        if (box->list->ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
 
571
            (box->list->ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
 
572
                /* this is the root shared namespace, which itself doesn't
 
573
                   have any existing mailboxes. */
 
574
                return;
 
575
        }
 
576
 
538
577
        abox = p_new(box->pool, struct acl_mailbox, 1);
539
578
        abox->module_ctx.super = *v;
540
579
        box->vlast = &abox->module_ctx.super;
550
589
                v->exists = acl_mailbox_exists;
551
590
                v->open = acl_mailbox_open;
552
591
                v->get_status = acl_mailbox_get_status;
553
 
                v->create = acl_mailbox_create;
554
 
                v->update = acl_mailbox_update;
555
 
                v->delete = acl_mailbox_delete;
556
 
                v->rename = acl_mailbox_rename;
 
592
                v->create_box = acl_mailbox_create;
 
593
                v->update_box = acl_mailbox_update;
 
594
                v->delete_box = acl_mailbox_delete;
 
595
                v->rename_box = acl_mailbox_rename;
557
596
                v->save_begin = acl_save_begin;
558
597
                v->copy = acl_copy;
559
598
                v->transaction_commit = acl_transaction_commit;
 
599
                v->attribute_set = acl_attribute_set;
 
600
                v->attribute_get = acl_attribute_get;
 
601
                v->attribute_iter_init = acl_attribute_iter_init;
 
602
                v->attribute_iter_next = acl_attribute_iter_next;
 
603
                v->attribute_iter_deinit = acl_attribute_iter_deinit;
560
604
        }
561
605
        MODULE_CONTEXT_SET(box, acl_storage_module, abox);
562
606
}
 
607
 
 
608
static bool
 
609
acl_mailbox_update_removed_id(struct acl_object *aclobj,
 
610
                              const struct acl_rights_update *update)
 
611
{
 
612
        struct acl_object_list_iter *iter;
 
613
        struct acl_rights rights;
 
614
        int ret;
 
615
 
 
616
        if (update->modify_mode != ACL_MODIFY_MODE_CLEAR &&
 
617
            update->neg_modify_mode != ACL_MODIFY_MODE_CLEAR)
 
618
                return FALSE;
 
619
        if (update->modify_mode == ACL_MODIFY_MODE_CLEAR &&
 
620
            update->neg_modify_mode == ACL_MODIFY_MODE_CLEAR)
 
621
                return TRUE;
 
622
 
 
623
        /* mixed clear/non-clear. see if the identifier exists anymore */
 
624
        iter = acl_object_list_init(aclobj);
 
625
        while ((ret = acl_object_list_next(iter, &rights)) > 0) {
 
626
                if (rights.id_type == update->rights.id_type &&
 
627
                    null_strcmp(rights.identifier, update->rights.identifier) == 0)
 
628
                        break;
 
629
        }
 
630
        acl_object_list_deinit(&iter);
 
631
        return ret == 0;
 
632
}
 
633
 
 
634
int acl_mailbox_update_acl(struct mailbox_transaction_context *t,
 
635
                           const struct acl_rights_update *update)
 
636
{
 
637
        struct acl_object *aclobj;
 
638
        const char *key;
 
639
        time_t ts = update->last_change != 0 ?
 
640
                update->last_change : ioloop_time;
 
641
 
 
642
        key = t_strdup_printf(MAILBOX_ATTRIBUTE_PREFIX_ACL"%s",
 
643
                              acl_rights_get_id(&update->rights));
 
644
        aclobj = acl_mailbox_get_aclobj(t->box);
 
645
        if (acl_object_update(aclobj, update) < 0) {
 
646
                mail_storage_set_critical(t->box->storage, "Failed to set ACL");
 
647
                return -1;
 
648
        }
 
649
 
 
650
        /* FIXME: figure out some value lengths, so maybe some day
 
651
           quota could apply to ACLs as well. */
 
652
        if (acl_mailbox_update_removed_id(aclobj, update))
 
653
                mail_index_attribute_unset(t->itrans, FALSE, key, ts);
 
654
        else
 
655
                mail_index_attribute_set(t->itrans, FALSE, key, ts, 0);
 
656
        return 0;
 
657
}