<commit_before>/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */

/* FIXME: If we don't have permission to change flags/keywords, the changes
   should still be stored temporarily for this session. However most clients
   don't care and it's a huge job, so I currently this isn't done. The same
   problem actually exists when opening read-only mailboxes. */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "mailbox-list-private.h"
#include "acl-api-private.h"
#include "acl-plugin.h"

#include <sys/stat.h>

#define ACL_MAIL_CONTEXT(obj) \
	MODULE_CONTEXT(obj, acl_mail_module)

struct acl_mailbox {
	union mailbox_module_context module_ctx;
	struct acl_object *aclobj;

	unsigned int save_hack:1;
};

struct acl_transaction_context {
	union mailbox_transaction_module_context module_ctx;
};

static MODULE_CONTEXT_DEFINE_INIT(acl_mail_module, &mail_module_register);
static struct acl_transaction_context acl_transaction_failure;

struct acl_object *acl_mailbox_get_aclobj(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	return abox->aclobj;
}

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;

	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 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;

	/* Next up is the "shared flag rights" */
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0)
		return FALSE;
	if ((box->private_flags_mask & MAIL_DELETED) == 0 &&
	    acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED) > 0)
		return FALSE;
	if ((box->private_flags_mask & MAIL_SEEN) == 0 &&
	    acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0)
		return FALSE;

	return TRUE;
}

static bool acl_allow_new_keywords(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	if (!abox->module_ctx.super.allow_new_keywords(box))
		return FALSE;

	return acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0;
}

static void acl_mailbox_close(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	acl_object_deinit(&abox->aclobj);
	abox->module_ctx.super.close(box);
}

static int
acl_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
		   bool directory)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	int ret;

	/* 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);
	if (ret <= 0) {
		if (ret < 0)
			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;
	}
	return abox->module_ctx.super.create(box, update, directory);
}

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, update);
}

static int
acl_get_write_rights(struct mailbox *box,
		     bool *flags_r, bool *flag_seen_r, bool *flag_del_r)
{
	int ret;
<commit_msg>acl: When creating a new child mailbox, copy parent's ACLs to it.<commit_after>/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */

/* FIXME: If we don't have permission to change flags/keywords, the changes
   should still be stored temporarily for this session. However most clients
   don't care and it's a huge job, so I currently this isn't done. The same
   problem actually exists when opening read-only mailboxes. */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "mailbox-list-private.h"
#include "acl-api-private.h"
#include "acl-plugin.h"

#include <sys/stat.h>

#define ACL_MAIL_CONTEXT(obj) \
	MODULE_CONTEXT(obj, acl_mail_module)

struct acl_mailbox {
	union mailbox_module_context module_ctx;
	struct acl_object *aclobj;

	unsigned int save_hack:1;
};

struct acl_transaction_context {
	union mailbox_transaction_module_context module_ctx;
};

static MODULE_CONTEXT_DEFINE_INIT(acl_mail_module, &mail_module_register);
static struct acl_transaction_context acl_transaction_failure;

struct acl_object *acl_mailbox_get_aclobj(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	return abox->aclobj;
}

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;

	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 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;

	/* Next up is the "shared flag rights" */
	if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0)
		return FALSE;
	if ((box->private_flags_mask & MAIL_DELETED) == 0 &&
	    acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED) > 0)
		return FALSE;
	if ((box->private_flags_mask & MAIL_SEEN) == 0 &&
	    acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0)
		return FALSE;

	return TRUE;
}

static bool acl_allow_new_keywords(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	if (!abox->module_ctx.super.allow_new_keywords(box))
		return FALSE;

	return acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0;
}

static void acl_mailbox_close(struct mailbox *box)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);

	acl_object_deinit(&abox->aclobj);
	abox->module_ctx.super.close(box);
}

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)
		(void)acl_object_update(abox->aclobj, &update);
	acl_object_list_deinit(&iter);
	acl_object_deinit(&parent_aclobj);
}
static int
acl_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
		   bool directory)
{
	struct acl_mailbox *abox = ACL_CONTEXT(box);
	int ret;

	/* 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);
	if (ret <= 0) {
		if (ret < 0)
			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;
	}
	if (abox->module_ctx.super.create(box, update, directory) < 0)
		return -1;

	acl_mailbox_copy_acls_from_parent(box);
	return 0;
}

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, update);
}

static int
acl_get_write_rights(struct mailbox *box,
		     bool *flags_r, bool *flag_seen_r, bool *flag_del_r)
{
	int ret;

{'fraction_non_alphanumeric': 0.10051202137132681, 'fraction_numerical': 0.00701246660730187, 'mean_word_length': 5.283216783216783, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2463955', 'n_tokens_mistral': 3560, 'n_tokens_neox': 3334, 'n_words': 755}