static int
acl_mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
	struct acl_mailbox *abox = ACL_CONTEXT(src);
	int ret;

	/* renaming requires rights to delete the old mailbox */
	ret = acl_mailbox_right_lookup(src, ACL_STORAGE_RIGHT_DELETE);
	if (ret <= 0) {
		if (ret == 0)
			acl_mailbox_fail_not_found(src);
		return -1;
	}

	/* and create the new one under the parent mailbox */
	T_BEGIN {
		ret = acl_mailbox_list_have_right(dest->list, dest->name, TRUE,
						ACL_STORAGE_RIGHT_CREATE, NULL);
	} T_END;

	if (ret <= 0) {
		if (ret == 0) {
			/* Note that if the mailbox didn't have LOOKUP
			   permission, this now reveals to user the mailbox's
			   existence. Can't help it. */
			mail_storage_set_error(src->storage, MAIL_ERROR_PERM,
					       MAIL_ERRSTR_NO_PERMISSION);
		} else {
			mail_storage_set_internal_error(src->storage);
		}
		return -1;
	}

	return abox->module_ctx.super.rename_box(src, dest);
}
static int
acl_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	int ret;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
	if (ret <= 0)
		return -1;
	return abox->module_ctx.super.update_box(box, update);
}
static bool
acl_copy_has_rights(struct mail_save_context *ctx, struct mail *mail)
{
	struct mailbox *destbox = ctx->transaction->box;
	enum acl_storage_rights save_right;

	if (ctx->moving) {
		if (acl_mailbox_right_lookup(mail->box,
					     ACL_STORAGE_RIGHT_EXPUNGE) <= 0)
			return FALSE;
	}

	save_right = (destbox->flags & MAILBOX_FLAG_POST_SESSION) != 0 ?
		ACL_STORAGE_RIGHT_POST : ACL_STORAGE_RIGHT_INSERT;
	if (acl_mailbox_right_lookup(destbox, save_right) <= 0)
		return FALSE;
	if (acl_save_get_flags(destbox, &ctx->data.flags,
			       &ctx->data.pvt_flags, &ctx->data.keywords) < 0)
		return FALSE;
	return TRUE;
}
static int acl_have_attribute_rights(struct mailbox *box)
{
	int ret;

	/* RFC 5464:

	   When the ACL extension [RFC4314] is present, users can only set and
	   retrieve private or shared mailbox annotations on a mailbox on which
	   they have the "l" right and any one of the "r", "s", "w", "i", or "p"
	   rights.
	*/
	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP);
	if (ret <= 0) {
		if (ret < 0)
			return -1;
		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
				T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
		return -1;
	}

	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_READ) > 0)
		return 0;
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0)
		return 0;
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0)
		return 0;
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_INSERT) > 0)
		return 0;
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_POST) > 0)
		return 0;
	return -1;
}
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_get_write_rights(struct mailbox *box,
		     bool *flags_r, bool *flag_seen_r, bool *flag_del_r)
{
	int ret;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE);
	if (ret < 0)
		return -1;
	*flags_r = ret > 0;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN);
	if (ret < 0)
		return -1;
	*flag_seen_r = ret > 0;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED);
	if (ret < 0)
		return -1;
	*flag_del_r = ret > 0;
	return 0;
}
static void acl_mailbox_fail_not_found(struct mailbox *box)
{
	int ret;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP);
	if (ret > 0) {
		mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
				       MAIL_ERRSTR_NO_PERMISSION);
	} else if (ret == 0) {
		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
				T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
	}
}
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;
}
示例#9
0
static int
acl_mailbox_delete(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	int ret;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_DELETE);
	if (ret <= 0) {
		if (ret == 0)
			acl_mailbox_fail_not_found(box);
		return -1;
	}

	return abox->module_ctx.super.delete_box(box);
}
static int
acl_save_begin(struct mail_save_context *ctx, struct istream *input)
{
	struct mailbox *box = ctx->transaction->box;
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	enum acl_storage_rights save_right;

	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 -1;
	if (acl_save_get_flags(box, &ctx->data.flags,
			       &ctx->data.pvt_flags, &ctx->data.keywords) < 0)
		return -1;

	return abox->module_ctx.super.save_begin(ctx, input);
}
static void acl_mail_expunge(struct mail *_mail)
{
	struct mail_private *mail = (struct mail_private *)_mail;
	union mail_module_context *amail = ACL_MAIL_CONTEXT(mail);
	int ret;

	ret = acl_mailbox_right_lookup(_mail->box, ACL_STORAGE_RIGHT_EXPUNGE);
	if (ret <= 0) {
		/* if we don't have permission, silently return success so
		   users won't see annoying error messages in case their
		   clients try automatic expunging. */
		acl_transaction_set_failure(_mail->transaction);
		return;
	}

	amail->super.expunge(_mail);
}
static void
acl_mail_update_keywords(struct mail *_mail, enum modify_type modify_type,
			 struct mail_keywords *keywords)
{
	struct mail_private *mail = (struct mail_private *)_mail;
	union mail_module_context *amail = ACL_MAIL_CONTEXT(mail);
	int ret;

	ret = acl_mailbox_right_lookup(_mail->box, ACL_STORAGE_RIGHT_WRITE);
	if (ret <= 0) {
		/* if we don't have permission, just silently return success. */
		if (ret < 0)
			acl_transaction_set_failure(_mail->transaction);
		return;
	}

	amail->super.update_keywords(_mail, modify_type, keywords);
}
static int
acl_mailbox_delete(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	int ret;

	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_DELETE);
	if (ret <= 0) {
		if (ret == 0)
			acl_mailbox_fail_not_found(box);
		return -1;
	}

	/* deletion might internally open the mailbox. let it succeed even if
	   we don't have READ permission. */
	abox->skip_acl_checks = TRUE;
	ret = abox->module_ctx.super.delete_box(box);
	abox->skip_acl_checks = FALSE;
	return ret;
}