]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth-policy: Hook auth policy to auth code
authorAki Tuomi <aki.tuomi@dovecot.fi>
Fri, 3 Jun 2016 18:35:48 +0000 (21:35 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 28 Jun 2016 07:13:43 +0000 (10:13 +0300)
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

index b42f490ed0bfb852e00e62aac5a3601c22139f9c..66b3d4193ebea725e9120b417517aa01c944e8b7 100644 (file)
@@ -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_handle_failure(struct auth_request *request, const char *reply)
        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 @@ auth_request_handler_reply_success_finish(struct auth_request *request)
                   process to pick it up. delete it */
                auth_request_handler_remove(handler, request);
        }
+
+       auth_policy_report(request);
+
        handler->callback(str_c(str), handler->conn);
 }
 
index 7c6ee1c37660a070ab840d547fd94f9e5804f04b..f1f041e473b99270a2cb9580bb5c732761dc4e56 100644 (file)
@@ -157,6 +157,7 @@ auth_request_get_var_expand_table_full(const struct auth_request *auth_request,
        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 @@ auth_request_get_var_expand_table_full(const struct auth_request *auth_request,
        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;
 }
 
index 2b0c2aa4d86efe2bf75ed2a9206353f28006df44..1362ec3f861df95de34a71337309b9a3da2c80df 100644 (file)
@@ -9,7 +9,6 @@ auth_request_escape_func_t(const char *string,
 #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];
 
index beb707e31aef65e63edf2777a486753ff00c3143..691577324327f7062e49296b26248d41d1e9ea88 100644 (file)
@@ -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 auth_request_proxy_dns_lookup_ctx {
        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 get_log_prefix(string_t *str, struct auth_request *auth_request,
 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 @@ void auth_request_set_state(struct auth_request *request,
        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 @@ struct auth *auth_request_get_auth(struct auth_request *request)
 void auth_request_success(struct auth_request *request,
                          const void *data, size_t data_size)
 {
-       struct auth_stats *stats;
+       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 @@ auth_request_verify_plain_callback_finish(enum passdb_result result,
        } 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 @@ static bool auth_request_is_disabled_master_user(struct auth_request *request)
        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 @@ void auth_request_verify_plain(struct auth_request *request,
 
         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;
@@ -919,6 +1033,27 @@ void auth_request_lookup_credentials_callback(enum passdb_result result,
 void auth_request_lookup_credentials(struct auth_request *request,
                                     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;
@@ -932,7 +1067,8 @@ void auth_request_lookup_credentials(struct auth_request *request,
        }
        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;
index 989d2c79279a9b654691c40415b572215496f598..3a58b5f684c05c7dd2b28260e3dc75fe1bb954d7 100644 (file)
@@ -145,6 +145,7 @@ struct auth_request {
        unsigned int userdb_prefetch_set:1;
        unsigned int stats_sent:1;
        unsigned int policy_refusal:1;
+       unsigned int policy_processed:1;
 
        /* ... mechanism specific data ... */
 };
index 5a87c575ceda1f6fb34f9ba084a2915ba53faf80..99b68cb84f419fcaf15ce0941dfd0562ec91a1c9 100644 (file)
@@ -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 @@ static void main_init(void)
        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 @@ static void main_deinit(void)
                /* 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. */