Mercurial > dovecot > original-hg > dovecot-1.2
changeset 3655:62fc6883faeb HEAD
Fixes and cleanups to credentials handling. Also fixed auth caching to work
more correctly in case of internal failures.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 16 Oct 2005 15:03:37 +0300 |
parents | 9adec8bb8a53 |
children | fda241fa5d77 |
files | src/auth/auth-request.c src/auth/auth-worker-client.c src/auth/passdb-blocking.c src/auth/passdb-cache.c src/auth/passdb-cache.h src/auth/passdb-ldap.c src/auth/passdb-passwd-file.c src/auth/passdb-sql.c src/auth/passdb.c src/auth/passdb.h |
diffstat | 10 files changed, 169 insertions(+), 129 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/auth-request.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/auth-request.c Sun Oct 16 15:03:37 2005 +0300 @@ -29,6 +29,7 @@ request->refcount = 1; request->created = ioloop_time; + request->credentials = -1; request->auth = auth; request->mech = mech; @@ -51,6 +52,7 @@ auth_request->auth = auth; auth_request->passdb = auth->passdbs; auth_request->userdb = auth->userdbs; + auth_request->credentials = -1; return auth_request; } @@ -163,6 +165,21 @@ const char *extra_fields; string_t *str; + switch (result) { + case PASSDB_RESULT_USER_UNKNOWN: + case PASSDB_RESULT_PASSWORD_MISMATCH: + case PASSDB_RESULT_OK: + case PASSDB_RESULT_SCHEME_NOT_AVAILABLE: + /* can be cached */ + break; + case PASSDB_RESULT_USER_DISABLED: + /* FIXME: we can't cache this now, or cache lookup would + return success. */ + return; + case PASSDB_RESULT_INTERNAL_FAILURE: + i_unreached(); + } + extra_fields = request->extra_fields == NULL ? NULL : auth_stream_reply_export(request->extra_fields); i_assert(extra_fields == NULL || @@ -214,69 +231,84 @@ auth_cache_insert(passdb_cache, request, passdb->cache_key, str_c(str)); } -void auth_request_verify_plain_callback(enum passdb_result result, - struct auth_request *request) +static int +auth_request_handle_passdb_callback(enum passdb_result *result, + struct auth_request *request) { - const char *cache_key; - - i_assert(request->state == AUTH_REQUEST_STATE_PASSDB); - - request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; - - auth_request_save_cache(request, result); - - cache_key = passdb_cache == NULL ? NULL : - request->passdb->passdb->cache_key; - if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) { - /* lookup failed. if we're looking here only because the - request was expired in cache, fallback to using cached - expired record. */ - if (passdb_cache_verify_plain(request, cache_key, - request->mech_password, - &result, TRUE)) { - request->private_callback.verify_plain(result, request); - safe_memset(request->mech_password, 0, - strlen(request->mech_password)); - return; - } - } - if (request->passdb_password != NULL) { safe_memset(request->passdb_password, 0, strlen(request->passdb_password)); } - if (result != PASSDB_RESULT_USER_UNKNOWN && request->passdb->deny) { - /* user found from deny passdb. deny this authentication. */ - auth_request_log_info(request, "passdb", - "User found from deny passdb"); - result = PASSDB_RESULT_USER_DISABLED; - } else if (result != PASSDB_RESULT_OK && - result != PASSDB_RESULT_USER_DISABLED && + if (request->passdb->deny && *result != PASSDB_RESULT_USER_UNKNOWN) { + /* deny passdb. we can get through this step only if the + lookup returned that user doesn't exist in it. internal + errors are fatal here. */ + if (*result != PASSDB_RESULT_INTERNAL_FAILURE) { + auth_request_log_info(request, "passdb", + "User found from deny passdb"); + *result = PASSDB_RESULT_USER_DISABLED; + } + } else if (*result != PASSDB_RESULT_OK && + *result != PASSDB_RESULT_USER_DISABLED && request->passdb->next != NULL) { /* try next passdb. */ - if (result == PASSDB_RESULT_INTERNAL_FAILURE) + if (*result == PASSDB_RESULT_INTERNAL_FAILURE) { + /* remember that we have had an internal failure. at + the end return internal failure if we couldn't + successfully login. */ request->passdb_internal_failure = TRUE; + } if (request->extra_fields != NULL) auth_stream_reply_reset(request->extra_fields); - request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; + return FALSE; + } else if (request->passdb_internal_failure && + *result != PASSDB_RESULT_OK) { + /* one of the passdb lookups returned internal failure. + it may have had the correct password, so return internal + failure instead of plain failure. */ + *result = PASSDB_RESULT_INTERNAL_FAILURE; + } + + return TRUE; +} + +void auth_request_verify_plain_callback(enum passdb_result result, + struct auth_request *request) +{ + i_assert(request->state == AUTH_REQUEST_STATE_PASSDB); + + request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; + + if (result != PASSDB_RESULT_INTERNAL_FAILURE) + auth_request_save_cache(request, result); + else { + /* lookup failed. if we're looking here only because the + request was expired in cache, fallback to using cached + expired record. */ + const char *cache_key = request->passdb->passdb->cache_key; + + if (passdb_cache_verify_plain(request, cache_key, + request->mech_password, + &result, TRUE)) { + auth_request_log_info(request, "passdb", + "Fallbacking to expired data from cache"); + } + } + + if (!auth_request_handle_passdb_callback(&result, request)) { + /* try next passdb */ request->passdb = request->passdb->next; auth_request_verify_plain(request, request->mech_password, request->private_callback.verify_plain); - return; - } else if (request->passdb_internal_failure && - result != PASSDB_RESULT_OK) { - /* one of the passdb lookups returned internal failure. - it may have had the correct password, so return internal - failure instead of plain failure. */ - result = PASSDB_RESULT_INTERNAL_FAILURE; + } else { + auth_request_ref(request); + request->private_callback.verify_plain(result, request); + safe_memset(request->mech_password, 0, + strlen(request->mech_password)); + auth_request_unref(request); } - - auth_request_ref(request); - request->private_callback.verify_plain(result, request); - safe_memset(request->mech_password, 0, strlen(request->mech_password)); - auth_request_unref(request); } void auth_request_verify_plain(struct auth_request *request, @@ -303,6 +335,7 @@ } request->state = AUTH_REQUEST_STATE_PASSDB; + request->credentials = -1; if (passdb->blocking) passdb_blocking_verify_plain(request); @@ -313,41 +346,45 @@ } void auth_request_lookup_credentials_callback(enum passdb_result result, - const char *credentials, + const char *password, struct auth_request *request) { - const char *cache_key, *scheme; + const char *scheme; i_assert(request->state == AUTH_REQUEST_STATE_PASSDB); request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; - auth_request_save_cache(request, result); - if (request->passdb_password != NULL) { - safe_memset(request->passdb_password, 0, - strlen(request->passdb_password)); - } - - cache_key = passdb_cache == NULL ? NULL : - request->passdb->passdb->cache_key; - if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) { + if (result != PASSDB_RESULT_INTERNAL_FAILURE) + auth_request_save_cache(request, result); + else { /* lookup failed. if we're looking here only because the request was expired in cache, fallback to using cached expired record. */ + const char *cache_key = request->passdb->passdb->cache_key; + if (passdb_cache_lookup_credentials(request, cache_key, - &credentials, &scheme, - TRUE)) { - passdb_handle_credentials(credentials != NULL ? - PASSDB_RESULT_OK : PASSDB_RESULT_USER_UNKNOWN, - request->credentials, credentials, scheme, - request->private_callback.lookup_credentials, - request); - return; + &password, &scheme, + &result, TRUE)) { + auth_request_log_info(request, "passdb", + "Fallbacking to expired data from cache"); + password = result != PASSDB_RESULT_OK ? NULL : + passdb_get_credentials(request, password, + scheme); + if (password == NULL && result == PASSDB_RESULT_OK) + result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE; } } - request->private_callback.lookup_credentials(result, credentials, - request); + if (!auth_request_handle_passdb_callback(&result, request)) { + /* try next passdb */ + request->passdb = request->passdb->next; + auth_request_lookup_credentials(request, request->credentials, + request->private_callback.lookup_credentials); + } else { + request->private_callback. + lookup_credentials(result, password, request); + } } void auth_request_lookup_credentials(struct auth_request *request, @@ -355,18 +392,17 @@ lookup_credentials_callback_t *callback) { struct passdb_module *passdb = request->passdb->passdb; - const char *cache_key, *result, *scheme; + const char *cache_key, *password, *scheme; + enum passdb_result result; i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); cache_key = passdb_cache == NULL ? NULL : passdb->cache_key; if (cache_key != NULL) { if (passdb_cache_lookup_credentials(request, cache_key, - &result, &scheme, FALSE)) { - passdb_handle_credentials(result != NULL ? - PASSDB_RESULT_OK : - PASSDB_RESULT_USER_UNKNOWN, - credentials, result, scheme, + &password, &scheme, + &result, FALSE)) { + passdb_handle_credentials(result, password, scheme, callback, request); return; } @@ -378,9 +414,13 @@ if (passdb->blocking) passdb_blocking_lookup_credentials(request); - else { - passdb->lookup_credentials(request, credentials, + else if (passdb->lookup_credentials != NULL) { + passdb->lookup_credentials(request, auth_request_lookup_credentials_callback); + } else { + /* this passdb doesn't support credentials */ + auth_request_lookup_credentials_callback( + PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, request); } }
--- a/src/auth/auth-worker-client.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/auth-worker-client.c Sun Oct 16 15:03:37 2005 +0300 @@ -221,8 +221,7 @@ } auth_request->passdb->passdb-> - lookup_credentials(auth_request, credentials, - lookup_credentials_callback); + lookup_credentials(auth_request, lookup_credentials_callback); } static void
--- a/src/auth/passdb-blocking.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-blocking.c Sun Oct 16 15:03:37 2005 +0300 @@ -135,8 +135,7 @@ result = PASSDB_RESULT_INTERNAL_FAILURE; } - passdb_handle_credentials(result, request->credentials, - password, scheme, + passdb_handle_credentials(result, password, scheme, auth_request_lookup_credentials_callback, request); }
--- a/src/auth/passdb-cache.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-cache.c Sun Oct 16 15:03:37 2005 +0300 @@ -82,8 +82,10 @@ } int passdb_cache_lookup_credentials(struct auth_request *request, - const char *key, const char **result_r, - const char **scheme_r, int use_expired) + const char *key, const char **password_r, + const char **scheme_r, + enum passdb_result *result_r, + int use_expired) { const char *value, *const *list; int expired; @@ -97,7 +99,8 @@ if (*value == '\0') { /* negative cache entry */ - *result_r = NULL; + *result_r = PASSDB_RESULT_USER_UNKNOWN; + *password_r = NULL; *scheme_r = NULL; return TRUE; } @@ -105,8 +108,9 @@ list = t_strsplit(value, "\t"); list_save(request, list + 1); - *result_r = list[0]; - *scheme_r = password_get_scheme(result_r); + *result_r = PASSDB_RESULT_OK; + *password_r = list[0]; + *scheme_r = password_get_scheme(password_r); i_assert(*scheme_r != NULL); return TRUE; }
--- a/src/auth/passdb-cache.h Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-cache.h Sun Oct 16 15:03:37 2005 +0300 @@ -10,8 +10,10 @@ const char *password, enum passdb_result *result_r, int use_expired); int passdb_cache_lookup_credentials(struct auth_request *request, - const char *key, const char **result_r, - const char **scheme_r, int use_expired); + const char *key, const char **password_r, + const char **scheme_r, + enum passdb_result *result_r, + int use_expired); void passdb_cache_init(void); void passdb_cache_deinit(void);
--- a/src/auth/passdb-ldap.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-ldap.c Sun Oct 16 15:03:37 2005 +0300 @@ -24,7 +24,6 @@ struct passdb_ldap_request { struct ldap_request request; - enum passdb_credentials credentials; union { verify_plain_callback_t *verify_plain; lookup_credentials_callback_t *lookup_credentials; @@ -139,9 +138,8 @@ /* auth_request_set_field() sets scheme */ i_assert(password == NULL || scheme != NULL); - if (ldap_request->credentials != -1) { - passdb_handle_credentials(passdb_result, - ldap_request->credentials, password, scheme, + if (auth_request->credentials != -1) { + passdb_handle_credentials(passdb_result, password, scheme, ldap_request->callback.lookup_credentials, auth_request); return; @@ -210,20 +208,17 @@ struct passdb_ldap_request *ldap_request; ldap_request = p_new(request->pool, struct passdb_ldap_request, 1); - ldap_request->credentials = -1; ldap_request->callback.verify_plain = callback; ldap_lookup_pass(request, &ldap_request->request); } static void ldap_lookup_credentials(struct auth_request *request, - enum passdb_credentials credentials, lookup_credentials_callback_t *callback) { struct passdb_ldap_request *ldap_request; ldap_request = p_new(request->pool, struct passdb_ldap_request, 1); - ldap_request->credentials = credentials; ldap_request->callback.lookup_credentials = callback; ldap_lookup_pass(request, &ldap_request->request);
--- a/src/auth/passdb-passwd-file.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-passwd-file.c Sun Oct 16 15:03:37 2005 +0300 @@ -46,7 +46,6 @@ static void passwd_file_lookup_credentials(struct auth_request *request, - enum passdb_credentials credentials, lookup_credentials_callback_t *callback) { struct passwd_user *pu; @@ -61,8 +60,8 @@ crypted_pass = pu->password; scheme = password_get_scheme(&crypted_pass); - passdb_handle_credentials(PASSDB_RESULT_OK, credentials, crypted_pass, - scheme, callback, request); + passdb_handle_credentials(PASSDB_RESULT_OK, crypted_pass, scheme, + callback, request); } static void passwd_file_init(const char *args)
--- a/src/auth/passdb-sql.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb-sql.c Sun Oct 16 15:03:37 2005 +0300 @@ -19,7 +19,6 @@ struct passdb_sql_request { struct auth_request *auth_request; - enum passdb_credentials credentials; union { verify_plain_callback_t *verify_plain; lookup_credentials_callback_t *lookup_credentials; @@ -92,9 +91,8 @@ /* auth_request_set_field() sets scheme */ i_assert(password == NULL || scheme != NULL); - if (sql_request->credentials != -1) { - passdb_handle_credentials(passdb_result, - sql_request->credentials, password, scheme, + if (auth_request->credentials != -1) { + passdb_handle_credentials(passdb_result, password, scheme, sql_request->callback.lookup_credentials, auth_request); return; @@ -144,21 +142,18 @@ sql_request = p_new(request->pool, struct passdb_sql_request, 1); sql_request->auth_request = request; - sql_request->credentials = -1; sql_request->callback.verify_plain = callback; sql_lookup_pass(sql_request); } static void sql_lookup_credentials(struct auth_request *request, - enum passdb_credentials credentials, lookup_credentials_callback_t *callback) { struct passdb_sql_request *sql_request; sql_request = p_new(request->pool, struct passdb_sql_request, 1); sql_request->auth_request = request; - sql_request->credentials = credentials; sql_request->callback.lookup_credentials = callback; sql_lookup_pass(sql_request);
--- a/src/auth/passdb.c Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb.c Sun Oct 16 15:03:37 2005 +0300 @@ -74,37 +74,25 @@ return "??"; } -void passdb_handle_credentials(enum passdb_result result, - enum passdb_credentials credentials, - const char *password, const char *scheme, - lookup_credentials_callback_t *callback, - struct auth_request *auth_request) +const char * +passdb_get_credentials(struct auth_request *auth_request, + const char *password, const char *scheme) { const char *wanted_scheme; - if (result != PASSDB_RESULT_OK) { - callback(result, NULL, auth_request); - return; - } - i_assert(password != NULL); - - if (credentials == PASSDB_CREDENTIALS_CRYPT) { + if (auth_request->credentials == PASSDB_CREDENTIALS_CRYPT) { /* anything goes */ - password = t_strdup_printf("{%s}%s", scheme, password); - callback(result, password, auth_request); - return; + return t_strdup_printf("{%s}%s", scheme, password); } - wanted_scheme = passdb_credentials_to_str(credentials); + wanted_scheme = passdb_credentials_to_str(auth_request->credentials); if (strcasecmp(scheme, wanted_scheme) != 0) { if (strcasecmp(scheme, "PLAIN") != 0 && strcasecmp(scheme, "CLEARTEXT") != 0) { auth_request_log_info(auth_request, "password", "Requested %s scheme, but we have only %s", wanted_scheme, scheme); - callback(PASSDB_RESULT_SCHEME_NOT_AVAILABLE, - NULL, auth_request); - return; + return NULL; } /* we can generate anything out of plaintext passwords */ @@ -113,7 +101,24 @@ i_assert(password != NULL); } - callback(PASSDB_RESULT_OK, password, auth_request); + return password; +} + +void passdb_handle_credentials(enum passdb_result result, + const char *password, const char *scheme, + lookup_credentials_callback_t *callback, + struct auth_request *auth_request) +{ + if (result != PASSDB_RESULT_OK) { + callback(result, NULL, auth_request); + return; + } + i_assert(password != NULL); + + password = passdb_get_credentials(auth_request, password, scheme); + if (password == NULL) + result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE; + callback(result, password, auth_request); } struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
--- a/src/auth/passdb.h Sun Oct 16 13:37:18 2005 +0300 +++ b/src/auth/passdb.h Sun Oct 16 15:03:37 2005 +0300 @@ -31,7 +31,7 @@ typedef void verify_plain_callback_t(enum passdb_result result, struct auth_request *request); typedef void lookup_credentials_callback_t(enum passdb_result result, - const char *credentials, + const char *password, struct auth_request *request); struct passdb_module { @@ -54,15 +54,17 @@ void (*verify_plain)(struct auth_request *request, const char *password, verify_plain_callback_t *callback); - /* Return authentication credentials. Type is authentication mechanism - specific value that is requested. */ + /* Return authentication credentials, set in + auth_request->credentials. */ void (*lookup_credentials)(struct auth_request *request, - enum passdb_credentials credentials, lookup_credentials_callback_t *callback); }; +const char * +passdb_get_credentials(struct auth_request *auth_request, + const char *password, const char *scheme); + void passdb_handle_credentials(enum passdb_result result, - enum passdb_credentials credentials, const char *password, const char *scheme, lookup_credentials_callback_t *callback, struct auth_request *auth_request);