# HG changeset patch # User Aki Tuomi # Date 1464978948 -10800 # Node ID 5b48cdd7b54ce6fc133ab408f13cd9029855a98e # Parent 0dc214cf2e30576e2c2e3cd2e6adba7690e2d23e auth-policy: Hook auth policy to auth code diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/auth-request-handler.c --- 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); } diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/auth-request-var-expand.c --- 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; } diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/auth-request-var-expand.h --- 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]; diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/auth-request.c --- 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; diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/auth-request.h --- 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 ... */ }; diff -r 0dc214cf2e30 -r 5b48cdd7b54c src/auth/main.c --- 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 #include @@ -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. */