changeset 20420:5b48cdd7b54c

auth-policy: Hook auth policy to auth code
author Aki Tuomi <aki.tuomi@dovecot.fi>
date Fri, 03 Jun 2016 21:35:48 +0300
parents 0dc214cf2e30
children 7b66c4d15cbb
files src/auth/auth-request-handler.c src/auth/auth-request-var-expand.c src/auth/auth-request-var-expand.h src/auth/auth-request.c src/auth/auth-request.h src/auth/main.c
diffstat 6 files changed, 151 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-request-handler.c	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/auth-request-handler.c	Fri Jun 03 21:35:48 2016 +0300
@@ -16,7 +16,7 @@
 #include "auth-token.h"
 #include "auth-master-connection.h"
 #include "auth-request-handler.h"
-
+#include "policy.h"
 
 #define AUTH_FAILURE_DELAY_CHECK_MSECS 500
 
@@ -215,6 +215,8 @@
 	auth_request_ref(request);
 	auth_request_handler_remove(handler, request);
 
+	auth_policy_report(request);
+
 	if (auth_fields_exists(request->extra_fields, "nodelay")) {
 		/* passdb specifically requested not to delay the reply. */
 		handler->callback(reply, handler->conn);
@@ -267,6 +269,9 @@
 		   process to pick it up. delete it */
 		auth_request_handler_remove(handler, request);
 	}
+
+	auth_policy_report(request);
+
 	handler->callback(str_c(str), handler->conn);
 }
 
--- a/src/auth/auth-request-var-expand.c	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/auth-request-var-expand.c	Fri Jun 03 21:35:48 2016 +0300
@@ -157,6 +157,7 @@
 	tab[29].value = strchr(orig_user, '@');
 	if (tab[29].value != NULL)
 		tab[29].value = escape_func(tab[29].value+1, auth_request);
+
 	if (auth_request->master_user != NULL)
 		auth_user = auth_request->master_user;
 	else
@@ -166,7 +167,6 @@
 	tab[32].value = strchr(auth_user, '@');
 	if (tab[32].value != NULL)
 		tab[32].value = escape_func(tab[32].value+1, auth_request);
-
 	return ret_tab;
 }
 
--- a/src/auth/auth-request-var-expand.h	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/auth-request-var-expand.h	Fri Jun 03 21:35:48 2016 +0300
@@ -9,7 +9,6 @@
 #define AUTH_REQUEST_VAR_TAB_USERNAME_IDX 1
 #define AUTH_REQUEST_VAR_TAB_DOMAIN_IDX 2
 #define AUTH_REQUEST_VAR_TAB_COUNT 33
-
 extern const struct var_expand_table
 auth_request_var_expand_static_tab[AUTH_REQUEST_VAR_TAB_COUNT+1];
 
--- a/src/auth/auth-request.c	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/auth-request.c	Fri Jun 03 21:35:48 2016 +0300
@@ -18,6 +18,7 @@
 #include "auth-request-stats.h"
 #include "auth-client-connection.h"
 #include "auth-master-connection.h"
+#include "policy.h"
 #include "passdb.h"
 #include "passdb-blocking.h"
 #include "passdb-cache.h"
@@ -40,6 +41,22 @@
 	struct dns_lookup *dns_lookup;
 };
 
+struct auth_policy_check_ctx {
+	enum {
+		AUTH_POLICY_CHECK_TYPE_PLAIN,
+		AUTH_POLICY_CHECK_TYPE_LOOKUP,
+		AUTH_POLICY_CHECK_TYPE_SUCCESS,
+	} type;
+	struct auth_request *request;
+	const char *scheme;
+	char *password;
+
+	buffer_t *success_data;
+
+	verify_plain_callback_t *callback_plain;
+	lookup_credentials_callback_t *callback_lookup;
+};
+
 const char auth_default_subsystems[2];
 
 unsigned int auth_request_state_count[AUTH_REQUEST_STATE_MAX];
@@ -49,6 +66,17 @@
 static void
 auth_request_userdb_import(struct auth_request *request, const char *args);
 
+static
+void auth_request_verify_plain_continue(struct auth_request *request,
+					char *password,
+					verify_plain_callback_t *callback);
+static
+void auth_request_lookup_credentials_policy_continue(struct auth_request *request,
+						     const char *scheme,
+						     lookup_credentials_callback_t *callback);
+static
+void auth_request_policy_check_callback(int result, void *context);
+
 struct auth_request *
 auth_request_new(const struct mech_module *mech)
 {
@@ -98,6 +126,8 @@
 	if (request->state == state)
 		return;
 
+	i_assert(request->to_penalty == NULL);
+
 	i_assert(auth_request_state_count[request->state] > 0);
 	auth_request_state_count[request->state]--;
 	auth_request_state_count[state]++;
@@ -127,8 +157,23 @@
 void auth_request_success(struct auth_request *request,
 			  const void *data, size_t data_size)
 {
+	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
+
+	/* perform second policy lookup here */
+
+	struct auth_policy_check_ctx *ctx = p_new(request->pool, struct auth_policy_check_ctx, 1);
+	ctx->request = request;
+	ctx->success_data = buffer_create_dynamic(request->pool, data_size);
+	buffer_append(ctx->success_data, data, data_size);
+        ctx->type = AUTH_POLICY_CHECK_TYPE_SUCCESS;
+	auth_policy_check(request, ctx->password, auth_request_policy_check_callback, ctx);
+}
+
+static
+void auth_request_success_continue(struct auth_request *request,
+				   const void *data, size_t data_size)
+{
 	struct auth_stats *stats;
-
 	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
 
 	if (request->failed || !request->passdb_success) {
@@ -710,7 +755,7 @@
 	} else {
 		auth_request_ref(request);
 		request->passdb_result = result;
-		request->private_callback.verify_plain(result, request);
+		request->private_callback.verify_plain(request->passdb_result, request);
 		auth_request_unref(&request);
 	}
 }
@@ -775,10 +820,78 @@
 	return TRUE;
 }
 
+static
+void auth_request_policy_penalty_finish(void *context)
+{
+	struct auth_policy_check_ctx *ctx = context;
+
+	if (ctx->request->to_penalty != NULL)
+		timeout_remove(&ctx->request->to_penalty);
+
+	i_assert(ctx->request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
+
+	switch(ctx->type) {
+	case AUTH_POLICY_CHECK_TYPE_PLAIN:
+		auth_request_verify_plain_continue(ctx->request, ctx->password, ctx->callback_plain);
+		return;
+	case AUTH_POLICY_CHECK_TYPE_LOOKUP:
+		auth_request_lookup_credentials_policy_continue(ctx->request, ctx->scheme, ctx->callback_lookup);
+		return;
+	case AUTH_POLICY_CHECK_TYPE_SUCCESS:
+		auth_request_success_continue(ctx->request, ctx->success_data->data, ctx->success_data->used);
+		return;
+	default:
+		i_unreached();
+	}
+}
+
+static
+void auth_request_policy_check_callback(int result, void *context)
+{
+	struct auth_policy_check_ctx *ctx = context;
+
+	ctx->request->policy_processed = TRUE;
+
+	if (result == -1) {
+		/* fail it right here and now */
+		auth_request_fail(ctx->request);
+	} else if (ctx->type != AUTH_POLICY_CHECK_TYPE_SUCCESS && result > 0 && !ctx->request->no_penalty) {
+		ctx->request->to_penalty = timeout_add(result * 1000,
+				auth_request_policy_penalty_finish,
+				context);
+	} else {
+		auth_request_policy_penalty_finish(context);
+	}
+}
+
 void auth_request_verify_plain(struct auth_request *request,
 			       const char *password,
 			       verify_plain_callback_t *callback)
 {
+	struct auth_policy_check_ctx *ctx;
+
+	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
+
+	ctx = p_new(request->pool, struct auth_policy_check_ctx, 1);
+	ctx->request = request;
+	if (request->mech_password == NULL)
+		ctx->password = p_strdup(request->pool, password);
+	else
+		ctx->password = request->mech_password;
+	ctx->callback_plain = callback;
+	ctx->type = AUTH_POLICY_CHECK_TYPE_PLAIN;
+
+	if (request->policy_processed)
+		auth_request_verify_plain_continue(request, ctx->password, callback);
+	else
+		auth_policy_check(request, ctx->password, auth_request_policy_check_callback, ctx);
+}
+
+static
+void auth_request_verify_plain_continue(struct auth_request *request,
+					char *password,
+					verify_plain_callback_t *callback) {
+
 	struct auth_passdb *passdb;
 	enum passdb_result result;
 	const char *cache_key;
@@ -799,7 +912,8 @@
 
         passdb = request->passdb;
 	if (request->mech_password == NULL)
-		request->mech_password = p_strdup(request->pool, password);
+		/* this is allocated on start */
+		request->mech_password = password;
 	else
 		i_assert(request->mech_password == password);
 	request->private_callback.verify_plain = callback;
@@ -920,6 +1034,27 @@
 				     const char *scheme,
 				     lookup_credentials_callback_t *callback)
 {
+	struct auth_policy_check_ctx *ctx;
+
+	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
+
+	ctx = p_new(request->pool, struct auth_policy_check_ctx, 1);
+	ctx->request = request;
+	if (request->credentials_scheme == NULL)
+		ctx->scheme = p_strdup(request->pool, scheme);
+	else
+		ctx->scheme = request->credentials_scheme;
+	ctx->callback_lookup = callback;
+	ctx->type = AUTH_POLICY_CHECK_TYPE_LOOKUP;
+
+	auth_policy_check(request, ctx->password, auth_request_policy_check_callback, ctx);
+}
+
+static
+void auth_request_lookup_credentials_policy_continue(struct auth_request *request,
+						     const char *scheme,
+						     lookup_credentials_callback_t *callback)
+{
 	struct auth_passdb *passdb;
 	const char *cache_key, *cache_cred, *cache_scheme;
 	enum passdb_result result;
@@ -932,7 +1067,8 @@
 	}
 	passdb = request->passdb;
 
-	request->credentials_scheme = p_strdup(request->pool, scheme);
+	if (request->credentials_scheme == NULL)
+		request->credentials_scheme = p_strdup(request->pool, scheme);
 	request->private_callback.lookup_credentials = callback;
 
 	cache_key = passdb_cache == NULL ? NULL : passdb->cache_key;
--- a/src/auth/auth-request.h	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/auth-request.h	Fri Jun 03 21:35:48 2016 +0300
@@ -145,6 +145,7 @@
 	unsigned int userdb_prefetch_set:1;
 	unsigned int stats_sent:1;
 	unsigned int policy_refusal:1;
+	unsigned int policy_processed:1;
 
 	/* ... mechanism specific data ... */
 };
--- a/src/auth/main.c	Fri Jun 03 20:21:42 2016 +0300
+++ b/src/auth/main.c	Fri Jun 03 21:35:48 2016 +0300
@@ -30,6 +30,7 @@
 #include "auth-master-connection.h"
 #include "auth-client-connection.h"
 #include "auth-postfix-connection.h"
+#include "policy.h"
 
 #include <unistd.h>
 #include <sys/stat.h>
@@ -246,6 +247,7 @@
 	auth_worker_server_init();
 	auths_init();
 	auth_request_handler_init();
+	auth_policy_init();
 
 	if (worker) {
 		/* workers have only a single connection from the master
@@ -265,6 +267,7 @@
 		/* cancel all pending anvil penalty lookups */
 		auth_penalty_deinit(&auth_penalty);
 	}
+	auth_policy_deinit();
 	/* deinit auth workers, which aborts pending requests */
         auth_worker_server_deinit();
 	/* deinit passdbs and userdbs. it aborts any pending async requests. */