dovecot-2.2: quota: If overquota-flag in userdb is wrong, execut...

dovecot at dovecot.org dovecot at dovecot.org
Thu Mar 5 22:41:53 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/a54408ed4767
changeset: 18293:a54408ed4767
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Mar 06 00:40:46 2015 +0200
description:
quota: If overquota-flag in userdb is wrong, execute a configured script.
The idea here is that a quota_warning script could set user's overquota-flag
to e.g. LDAP where MTA could reject mails already at RCPT TO stage. The
quota_warning scripts however have race conditions that are difficult (or
impossible) to fix, so sometimes the overquota-flag could become wrong and
might require manual intervention to fix it. This feature is supposed to
solve the issue by comparing the overquota-flag's status to the actual
current quota usage and execute a script to fix up the situation if needed.
This script is of course racy as well, but there's always the next login
that can fix the situation. Also it's pretty rare that user's quota is
jumping just around the limit.

The overquota-flag name in userdb must be "quota_over_flag". There are two
settings to configure what to do:

plugin {
  # If quota_over_flag=TRUE, the overquota-flag is enabled. Otherwise not.
  quota_over_flag_value = TRUE

  # Any non-empty value for quota_over_flag means user is over quota.
  # Wildcards can be used in a generic way, e.g. "*yes" or "*TRUE*"
  #quota_over_flag_value = *

  # Service script to execute if overquota-flag is wrong. Configured the
  # same as quota_warning scripts. The current quota_over_flag's value is
  # appended as the last parameter.
  quota_over_script = quota-warning mismatch %u
}

diffstat:

 src/plugins/quota/quota-private.h |   2 +
 src/plugins/quota/quota-storage.c |   2 +
 src/plugins/quota/quota.c         |  68 +++++++++++++++++++++++++++++++++++++-
 src/plugins/quota/quota.h         |   3 +
 4 files changed, 73 insertions(+), 2 deletions(-)

diffs (146 lines):

diff -r a9952ceeac61 -r a54408ed4767 src/plugins/quota/quota-private.h
--- a/src/plugins/quota/quota-private.h	Thu Mar 05 23:02:48 2015 +0200
+++ b/src/plugins/quota/quota-private.h	Fri Mar 06 00:40:46 2015 +0200
@@ -81,6 +81,8 @@
 struct quota_root_settings {
 	/* Unique quota root name. */
 	const char *name;
+	/* Name in settings, e.g. "quota", "quota2", .. */
+	const char *set_name;
 
 	struct quota_settings *set;
 	const char *args;
diff -r a9952ceeac61 -r a54408ed4767 src/plugins/quota/quota-storage.c
--- a/src/plugins/quota/quota-storage.c	Thu Mar 05 23:02:48 2015 +0200
+++ b/src/plugins/quota/quota-storage.c	Fri Mar 06 00:40:46 2015 +0200
@@ -631,4 +631,6 @@
 	roots = array_get(&quota->roots, &count);
 	for (i = 0; i < count; i++)
 		quota_root_set_namespace(roots[i], namespaces);
+
+	quota_over_flag_check(namespaces->user, quota);
 }
diff -r a9952ceeac61 -r a54408ed4767 src/plugins/quota/quota.c
--- a/src/plugins/quota/quota.c	Thu Mar 05 23:02:48 2015 +0200
+++ b/src/plugins/quota/quota.c	Fri Mar 06 00:40:46 2015 +0200
@@ -7,6 +7,7 @@
 #include "net.h"
 #include "write-full.h"
 #include "eacces-error.h"
+#include "wildcard-match.h"
 #include "dict.h"
 #include "mailbox-list-private.h"
 #include "quota-private.h"
@@ -191,6 +192,7 @@
 
 	if (quota_root_settings_init(quota_set, env, &root_set, error_r) < 0)
 		return -1;
+	root_set->set_name = p_strdup(quota_set->pool, root_name);
 	if (quota_root_add_rules(user, root_name, root_set, error_r) < 0)
 		return -1;
 	if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
@@ -823,7 +825,8 @@
 	return 0;
 }
 
-static void quota_warning_execute(struct quota_root *root, const char *cmd)
+static void quota_warning_execute(struct quota_root *root, const char *cmd,
+				  const char *last_arg)
 {
 	const char *socket_path, *const *args;
 	string_t *str;
@@ -833,6 +836,14 @@
 		i_debug("quota: Executing warning: %s", cmd);
 
 	args = t_strsplit_spaces(cmd, " ");
+	if (last_arg != NULL) {
+		unsigned int count = str_array_length(args);
+		const char **new_args = t_new(const char *, count + 2);
+
+		memcpy(new_args, args, sizeof(const char *) * count);
+		new_args[count] = last_arg;
+		args = new_args;
+	}
 	socket_path = args[0];
 	args++;
 
@@ -892,7 +903,7 @@
 		if (quota_warning_match(&warnings[i],
 					bytes_before, bytes_current,
 					count_before, count_current)) {
-			quota_warning_execute(root, warnings[i].command);
+			quota_warning_execute(root, warnings[i].command, NULL);
 			break;
 		}
 	}
@@ -951,6 +962,59 @@
 	return ret;
 }
 
+static void
+quota_over_flag_check_root(struct mail_user *user, struct quota_root *root)
+{
+	const char *name, *flag_mask, *overquota_value, *overquota_script;
+	const char *const *resources;
+	unsigned int i;
+	uint64_t value, limit;
+	bool overquota_flag, cur_overquota = FALSE;
+	int ret;
+
+	name = t_strconcat(root->set->set_name, "_over_script", NULL);
+	overquota_script = mail_user_plugin_getenv(user, name);
+	if (overquota_script == NULL)
+		return;
+
+	/* e.g.: quota_over_flag_value=TRUE or quota_over_flag_value=*  */
+	name = t_strconcat(root->set->set_name, "_over_flag_value", NULL);
+	flag_mask = mail_user_plugin_getenv(user, name);
+	if (flag_mask == NULL)
+		return;
+
+	/* compare quota_over_flag's value to quota_over_flag_value and
+	   save the result. */
+	name = t_strconcat(root->set->set_name, "_over_flag", NULL);
+	overquota_value = mail_user_plugin_getenv(user, name);
+	overquota_flag = overquota_value != NULL &&
+		overquota_value[0] != '\0' &&
+		wildcard_match_icase(overquota_value, flag_mask);
+
+	resources = quota_root_get_resources(root);
+	for (i = 0; resources[i] != NULL; i++) {
+		ret = quota_get_resource(root, "", resources[i], &value, &limit);
+		if (ret < 0) {
+			/* can't reliably verify this */
+			return;
+		}
+		if (ret > 0 && value > limit)
+			cur_overquota = TRUE;
+	}
+	if (cur_overquota != overquota_flag)
+		quota_warning_execute(root, overquota_script, overquota_value);
+}
+
+void quota_over_flag_check(struct mail_user *user, struct quota *quota)
+{
+	struct quota_root *const *roots;
+	unsigned int i, count;
+
+	roots = array_get(&quota->roots, &count);
+	for (i = 0; i < count; i++)
+		quota_over_flag_check_root(user, roots[i]);
+}
+
 void quota_transaction_rollback(struct quota_transaction_context **_ctx)
 {
 	struct quota_transaction_context *ctx = *_ctx;
diff -r a9952ceeac61 -r a54408ed4767 src/plugins/quota/quota.h
--- a/src/plugins/quota/quota.h	Thu Mar 05 23:02:48 2015 +0200
+++ b/src/plugins/quota/quota.h	Fri Mar 06 00:40:46 2015 +0200
@@ -83,4 +83,7 @@
 /* Mark the quota to be recalculated */
 void quota_recalculate(struct quota_transaction_context *ctx);
 
+/* Execute quota_over_scripts if needed. */
+void quota_over_flag_check(struct mail_user *user, struct quota *quota);
+
 #endif


More information about the dovecot-cvs mailing list