static int acl_mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r) { struct acl_mailbox *abox = ACL_CONTEXT(box); if (abox->module_ctx.super.get_status(box, items, status_r) < 0) return -1; if ((items & STATUS_PERMANENT_FLAGS) != 0) { if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) <= 0) { status_r->permanent_flags &= MAIL_DELETED|MAIL_SEEN; status_r->permanent_keywords = FALSE; status_r->allow_new_keywords = FALSE; } if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED) <= 0) status_r->permanent_flags &= ~MAIL_DELETED; if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) <= 0) status_r->permanent_flags &= ~MAIL_SEEN; } return 0; }
static int acl_mailbox_open_check_acl(struct mailbox *box) { struct acl_mailbox *abox = ACL_CONTEXT(box); struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(box->list); const unsigned int *idx_arr = alist->rights.acl_storage_right_idx; enum acl_storage_rights open_right; int ret; /* mailbox can be opened either for reading or appending new messages */ if ((box->flags & MAILBOX_FLAG_IGNORE_ACLS) != 0 || (box->list->ns->flags & NAMESPACE_FLAG_NOACL) != 0 || abox->skip_acl_checks) return 0; if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0) { open_right = (box->flags & MAILBOX_FLAG_POST_SESSION) != 0 ? ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT; } else { open_right = ACL_STORAGE_RIGHT_READ; } ret = acl_object_have_right(abox->aclobj, idx_arr[open_right]); if (ret <= 0) { if (ret == 0) { /* no access. */ acl_mailbox_fail_not_found(box); } return -1; } if (open_right != ACL_STORAGE_RIGHT_READ) { ret = acl_object_have_right(abox->aclobj, idx_arr[ACL_STORAGE_RIGHT_READ]); if (ret < 0) return -1; if (ret == 0) abox->no_read_right = TRUE; } return 0; }
int acl_mailbox_right_lookup(struct mailbox *box, unsigned int right_idx) { struct acl_mailbox *abox = ACL_CONTEXT(box); struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(box->list); int ret; if (abox->skip_acl_checks) return 1; ret = acl_object_have_right(abox->aclobj, alist->rights.acl_storage_right_idx[right_idx]); if (ret > 0) return 1; if (ret < 0) { mail_storage_set_internal_error(box->storage); return -1; } mail_storage_set_error(box->storage, MAIL_ERROR_PERM, MAIL_ERRSTR_NO_PERMISSION); return 0; }
static int acl_mailbox_create(struct mailbox *box, const struct mailbox_update *update, bool directory) { struct acl_mailbox *abox = ACL_CONTEXT(box); int ret; if (!mailbox_is_autocreated(box)) { /* we're looking up CREATE permission from our parent's rights */ ret = acl_mailbox_list_have_right(box->list, box->name, TRUE, ACL_STORAGE_RIGHT_CREATE, NULL); } else { /* mailbox is autocreated, so we need to treat it as if it already exists. ignore the "create" ACL here. */ ret = 1; } if (ret <= 0) { if (ret < 0) { mail_storage_set_internal_error(box->storage); return -1; } /* Note that if user didn't have LOOKUP permission to parent mailbox, this may reveal the mailbox's existence to user. Can't help it. */ mail_storage_set_error(box->storage, MAIL_ERROR_PERM, MAIL_ERRSTR_NO_PERMISSION); return -1; } /* ignore ACLs in this mailbox until creation is complete, because super.create() may call e.g. mailbox_open() which will fail since we haven't yet copied ACLs to this mailbox. */ abox->skip_acl_checks = TRUE; ret = abox->module_ctx.super.create_box(box, update, directory); abox->skip_acl_checks = FALSE; if (ret == 0) acl_mailbox_copy_acls_from_parent(box); return ret; }
static void acl_mailbox_copy_acls_from_parent(struct mailbox *box) { struct acl_mailbox *abox = ACL_CONTEXT(box); struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(box->list); struct acl_object *parent_aclobj; struct acl_object_list_iter *iter; struct acl_rights_update update; memset(&update, 0, sizeof(update)); update.modify_mode = ACL_MODIFY_MODE_REPLACE; update.neg_modify_mode = ACL_MODIFY_MODE_REPLACE; parent_aclobj = acl_object_init_from_parent(alist->rights.backend, box->name); iter = acl_object_list_init(parent_aclobj); while (acl_object_list_next(iter, &update.rights) > 0) { /* don't copy global ACL rights. */ if (!update.rights.global) (void)acl_object_update(abox->aclobj, &update); } acl_object_list_deinit(&iter); acl_object_deinit(&parent_aclobj); }
static bool acl_is_readonly(struct mailbox *box) { struct acl_mailbox *abox = ACL_CONTEXT(box); enum acl_storage_rights save_right; if (abox->module_ctx.super.is_readonly(box)) return TRUE; save_right = (box->flags & MAILBOX_FLAG_POST_SESSION) != 0 ? ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT; if (acl_mailbox_right_lookup(box, save_right) > 0) return FALSE; if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_EXPUNGE) > 0) return FALSE; if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0) return FALSE; if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED) > 0) return FALSE; if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0) return FALSE; return TRUE; }
struct acl_object *acl_mailbox_get_aclobj(struct mailbox *box) { struct acl_mailbox *abox = ACL_CONTEXT(box); return abox->aclobj; }