# HG changeset patch # User Timo Sirainen # Date 1105118840 -7200 # Node ID 052f3a5743af810bca0099dc8cec43e5746cfea1 # Parent 3e5faae6f10bc16e1bfba566d88a3cc055eb9a41 Make FAIL reply contain "temp" parameter if the authentication failed because of temporary internal error. Also cleaned up the auth code a bit. diff -r 3e5faae6f10b -r 052f3a5743af doc/auth-protocol.txt --- a/doc/auth-protocol.txt Fri Jan 07 19:24:12 2005 +0200 +++ b/doc/auth-protocol.txt Fri Jan 07 19:27:20 2005 +0200 @@ -111,9 +111,10 @@ FAIL parameters may contain "reason=.." parameter which should be sent to remote user instead of a standard "Authentication failed" message. For -example "invalid base64 data" or "temporary internal failure". It should -NOT be used to give exact reason for authentication failure (ie. "user not -found" vs. "password mismatch"). +example "invalid base64 data". It should NOT be used to give exact reason +for authentication failure (ie. "user not found" vs. "password mismatch"). +Sending "temp" parameter indicates that the error was a temporary internal +failure, eg. connection was lost to SQL database. CONT command means that the authentication continues, and more data is expected from client to finish the authentication. Given base64 data should diff -r 3e5faae6f10b -r 052f3a5743af src/auth/auth-client-connection.c --- a/src/auth/auth-client-connection.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/auth-client-connection.c Fri Jan 07 19:27:20 2005 +0200 @@ -89,6 +89,8 @@ str_append_c(str, '\t'); str_append(str, request->extra_fields); } + if (request->internal_failure) + str_append(str, "\ttemp"); break; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-anonymous.c --- a/src/auth/mech-anonymous.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-anonymous.c Fri Jan 07 19:27:20 2005 +0200 @@ -22,7 +22,7 @@ request->callback = callback; request->user = p_strdup(request->pool, anonymous_username); - mech_auth_finish(request, NULL, 0, TRUE); + mech_auth_success(request, NULL, 0); } static void diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-apop.c --- a/src/auth/mech-apop.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-apop.c Fri Jan 07 19:27:20 2005 +0200 @@ -31,27 +31,42 @@ unsigned char digest[16]; }; +static int verify_credentials(struct apop_auth_request *request, + const char *credentials) +{ + unsigned char digest[16]; + struct md5_context ctx; + + md5_init(&ctx); + md5_update(&ctx, request->challenge, strlen(request->challenge)); + md5_update(&ctx, credentials, strlen(credentials)); + md5_final(&ctx, digest); + + return memcmp(digest, request->digest, 16) == 0; +} + static void -apop_credentials_callback(const char *credentials, +apop_credentials_callback(enum passdb_result result, + const char *credentials, struct auth_request *auth_request) { struct apop_auth_request *request = (struct apop_auth_request *)auth_request; - unsigned char digest[16]; - struct md5_context ctx; - int ret = FALSE; - if (credentials != NULL) { - md5_init(&ctx); - md5_update(&ctx, request->challenge, - strlen(request->challenge)); - md5_update(&ctx, credentials, strlen(credentials)); - md5_final(&ctx, digest); - - ret = memcmp(digest, request->digest, 16) == 0; + switch (result) { + case PASSDB_RESULT_OK: + if (verify_credentials(request, credentials)) + mech_auth_success(auth_request, NULL, 0); + else + mech_auth_fail(auth_request); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + break; + default: + mech_auth_fail(auth_request); + break; } - - mech_auth_finish(auth_request, NULL, 0, ret); } static void @@ -72,7 +87,7 @@ i_info("apop(%s): no initial respone", get_log_prefix(auth_request)); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -92,7 +107,7 @@ i_info("apop(%s): invalid challenge", get_log_prefix(auth_request)); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } request->challenge = p_strdup(request->pool, (const char *)data); @@ -109,7 +124,7 @@ i_info("apop(%s): malformed data", get_log_prefix(auth_request)); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } tmp++; @@ -120,7 +135,7 @@ i_info("apop(%s): %s", get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-cram-md5.c --- a/src/auth/mech-cram-md5.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-cram-md5.c Fri Jan 07 19:27:20 2005 +0200 @@ -55,15 +55,15 @@ buffer_t *context_digest_buf; const char *response_hex; - if (credentials == NULL) - return FALSE; - context_digest_buf = buffer_create_data(pool_datastack_create(), context_digest, sizeof(context_digest)); - if (hex_to_binary(credentials, context_digest_buf) < 0) + if (hex_to_binary(credentials, context_digest_buf) < 0) { + i_error("cram-md5(%s): passdb credentials are not in hex", + get_log_prefix(&request->auth_request)); return FALSE; + } hmac_md5_set_cram_context(&ctx, context_digest); hmac_md5_update(&ctx, request->challenge, strlen(request->challenge)); @@ -109,20 +109,26 @@ return TRUE; } -static void credentials_callback(const char *result, +static void credentials_callback(enum passdb_result result, + const char *credentials, struct auth_request *auth_request) { struct cram_auth_request *request = (struct cram_auth_request *)auth_request; - if (verify_credentials(request, result)) - mech_auth_finish(auth_request, NULL, 0, TRUE); - else { - if (verbose) { - i_info("cram-md5(%s): authentication failed", - get_log_prefix(auth_request)); - } - mech_auth_finish(auth_request, NULL, 0, FALSE); + switch (result) { + case PASSDB_RESULT_OK: + if (verify_credentials(request, credentials)) + mech_auth_success(auth_request, NULL, 0); + else + mech_auth_fail(auth_request); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + break; + default: + mech_auth_fail(auth_request); + break; } } @@ -154,9 +160,7 @@ if (verbose) i_info("cram-md5(%s): %s", get_log_prefix(auth_request), error); - - /* failed */ - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); } static void diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-digest-md5.c --- a/src/auth/mech-digest-md5.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-digest-md5.c Fri Jan 07 19:27:20 2005 +0200 @@ -118,13 +118,19 @@ int i; /* get the MD5 password */ - if (credentials == NULL || strlen(credentials) != sizeof(digest)*2) + if (strlen(credentials) != sizeof(digest)*2) { + i_error("digest-md5(%s): passdb credentials' length is wrong", + get_log_prefix(&request->auth_request)); return FALSE; + } digest_buf = buffer_create_data(pool_datastack_create(), digest, sizeof(digest)); - if (hex_to_binary(credentials, digest_buf) < 0) + if (hex_to_binary(credentials, digest_buf) < 0) { + i_error("digest-md5(%s): passdb credentials are not in hex", + get_log_prefix(&request->auth_request)); return FALSE; + } /* response = @@ -508,20 +514,31 @@ return !failed; } -static void credentials_callback(const char *result, +static void credentials_callback(enum passdb_result result, + const char *credentials, struct auth_request *auth_request) { struct digest_auth_request *request = (struct digest_auth_request *)auth_request; - if (!verify_credentials(request, result)) { - mech_auth_finish(auth_request, NULL, 0, FALSE); - return; + switch (result) { + case PASSDB_RESULT_OK: + if (!verify_credentials(request, credentials)) { + mech_auth_fail(auth_request); + return; + } + + request->authenticated = TRUE; + auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE, + request->rspauth, strlen(request->rspauth)); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + break; + default: + mech_auth_fail(auth_request); + break; } - - request->authenticated = TRUE; - auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE, - request->rspauth, strlen(request->rspauth)); } static void @@ -536,7 +553,7 @@ if (request->authenticated) { /* authentication is done, we were just waiting the last word from client */ - mech_auth_finish(auth_request, NULL, 0, TRUE); + mech_auth_success(auth_request, NULL, 0); return; } @@ -566,7 +583,7 @@ get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); } static void diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-login.c --- a/src/auth/mech-login.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-login.c Fri Jan 07 19:27:20 2005 +0200 @@ -17,7 +17,17 @@ static void verify_callback(enum passdb_result result, struct auth_request *request) { - mech_auth_finish(request, NULL, 0, result == PASSDB_RESULT_OK); + switch (result) { + case PASSDB_RESULT_OK: + mech_auth_success(request, NULL, 0); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(request); + break; + default: + mech_auth_fail(request); + break; + } } static void @@ -38,7 +48,7 @@ i_info("login(%s): %s", get_log_prefix(request), error); } - mech_auth_finish(request, NULL, 0, FALSE); + mech_auth_fail(request); return; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-ntlm.c --- a/src/auth/mech-ntlm.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-ntlm.c Fri Jan 07 19:27:20 2005 +0200 @@ -33,64 +33,77 @@ struct ntlmssp_response *response; }; -static void -lm_credentials_callback(const char *credentials, - struct auth_request *auth_request) +static int lm_verify_credentials(struct ntlm_auth_request *request, + const char *credentials) { - struct ntlm_auth_request *request = - (struct ntlm_auth_request *)auth_request; const unsigned char *client_response; unsigned char lm_response[LM_RESPONSE_SIZE]; unsigned char hash[LM_HASH_SIZE]; unsigned int response_length; buffer_t *hash_buffer; - int ret; response_length = ntlmssp_buffer_length(request->response, lm_response); client_response = ntlmssp_buffer_data(request->response, lm_response); - if (credentials == NULL || response_length < LM_RESPONSE_SIZE) { - mech_auth_finish(auth_request, NULL, 0, FALSE); - return; + if (response_length < LM_RESPONSE_SIZE) { + i_error("ntlm(%s): passdb credentials' length is too small", + get_log_prefix(&request->auth_request)); + return FALSE; } - hash_buffer = buffer_create_data(auth_request->pool, + hash_buffer = buffer_create_data(request->auth_request.pool, hash, sizeof(hash)); - hex_to_binary(credentials, hash_buffer); + if (hex_to_binary(credentials, hash_buffer) < 0) { + i_error("ntlm(%s): passdb credentials are not in hex", + get_log_prefix(&request->auth_request)); + return FALSE; + } ntlmssp_v1_response(hash, request->challenge, lm_response); - - ret = memcmp(lm_response, client_response, LM_RESPONSE_SIZE) == 0; - - mech_auth_finish(auth_request, NULL, 0, ret); + return memcmp(lm_response, client_response, LM_RESPONSE_SIZE) == 0; } static void -ntlm_credentials_callback(const char *credentials, - struct auth_request *auth_request) +lm_credentials_callback(enum passdb_result result, + const char *credentials, + struct auth_request *auth_request) { struct ntlm_auth_request *request = (struct ntlm_auth_request *)auth_request; + + switch (result) { + case PASSDB_RESULT_OK: + if (lm_verify_credentials(request, credentials)) + mech_auth_success(auth_request, NULL, 0); + else + mech_auth_fail(auth_request); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + break; + default: + mech_auth_fail(auth_request); + break; + } +} + +static int ntlm_verify_credentials(struct ntlm_auth_request *request, + const char *credentials) +{ + struct auth_request *auth_request = &request->auth_request; const unsigned char *client_response; unsigned char hash[NTLMSSP_HASH_SIZE]; unsigned int response_length; buffer_t *hash_buffer; - int ret; response_length = ntlmssp_buffer_length(request->response, ntlm_response); client_response = ntlmssp_buffer_data(request->response, ntlm_response); - if (credentials == NULL || response_length == 0) { - /* We can't use LM authentication if NTLM2 was negotiated */ - if (request->ntlm2_negotiated) - mech_auth_finish(auth_request, NULL, 0, FALSE); - else - passdb->lookup_credentials(auth_request, - PASSDB_CREDENTIALS_LANMAN, - lm_credentials_callback); - return; + if (response_length == 0) { + /* try LM authentication unless NTLM2 was negotiated */ + return request->ntlm2_negotiated ? -1 : 0; } hash_buffer = buffer_create_data(auth_request->pool, @@ -112,8 +125,8 @@ response_length - NTLMSSP_V2_RESPONSE_SIZE, ntlm_v2_response); - ret = memcmp(ntlm_v2_response, client_response, - NTLMSSP_V2_RESPONSE_SIZE) == 0; + return memcmp(ntlm_v2_response, client_response, + NTLMSSP_V2_RESPONSE_SIZE) == 0 ? 1 : -1; } else { unsigned char ntlm_response[NTLMSSP_RESPONSE_SIZE]; const unsigned char *client_lm_response = @@ -127,11 +140,43 @@ ntlmssp_v1_response(hash, request->challenge, ntlm_response); - ret = memcmp(ntlm_response, client_response, - NTLMSSP_RESPONSE_SIZE) == 0; + return memcmp(ntlm_response, client_response, + NTLMSSP_RESPONSE_SIZE) == 0 ? 1 : -1; + } +} + +static void +ntlm_credentials_callback(enum passdb_result result, + const char *credentials, + struct auth_request *auth_request) +{ + struct ntlm_auth_request *request = + (struct ntlm_auth_request *)auth_request; + int ret; + + switch (result) { + case PASSDB_RESULT_OK: + ret = ntlm_verify_credentials(request, credentials); + if (ret > 0) { + mech_auth_success(auth_request, NULL, 0); + return; + } + if (ret < 0) { + mech_auth_fail(auth_request); + return; + } + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + return; + default: + break; } - mech_auth_finish(auth_request, NULL, 0, ret); + /* NTLM credentials not found or didn't want to use them, + try with LM credentials */ + passdb->lookup_credentials(auth_request, PASSDB_CREDENTIALS_LANMAN, + lm_credentials_callback); } static void @@ -158,7 +203,7 @@ get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -183,7 +228,7 @@ get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -199,7 +244,7 @@ i_info("ntlm(%s): %s", get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-plain.c --- a/src/auth/mech-plain.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-plain.c Fri Jan 07 19:27:20 2005 +0200 @@ -8,7 +8,17 @@ static void verify_callback(enum passdb_result result, struct auth_request *request) { - mech_auth_finish(request, NULL, 0, result == PASSDB_RESULT_OK); + switch (result) { + case PASSDB_RESULT_OK: + mech_auth_success(request, NULL, 0); + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(request); + break; + default: + mech_auth_fail(request); + break; + } } static void @@ -48,7 +58,7 @@ i_info("plain(%s): invalid input", get_log_prefix(request)); } - mech_auth_finish(request, NULL, 0, FALSE); + mech_auth_fail(request); } else { /* split and save user/realm */ if (strchr(authenid, '@') == NULL && default_realm != NULL) { @@ -65,7 +75,7 @@ i_info("plain(%s): %s", get_log_prefix(request), error); } - mech_auth_finish(request, NULL, 0, FALSE); + mech_auth_fail(request); } else { passdb->verify_plain(request, pass, verify_callback); } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech-rpa.c --- a/src/auth/mech-rpa.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech-rpa.c Fri Jan 07 19:27:20 2005 +0200 @@ -29,7 +29,7 @@ int phase; /* cached: */ - unsigned char *pwd_md5; + unsigned char pwd_md5[16]; size_t service_len; const unsigned char *service_ucs2be; size_t username_len; @@ -399,36 +399,48 @@ return buffer_free_without_data(buf); } +static int verify_credentials(struct rpa_auth_request *request, + const char *credentials) +{ + unsigned char response[16]; + buffer_t *hash_buffer; + + hash_buffer = buffer_create_data(request->pool, request->pwd_md5, 16); + hex_to_binary(credentials, hash_buffer); + + rpa_user_response(request, response); + return memcmp(response, request->user_response, 16) == 0; +} + static void -rpa_credentials_callback(const char *credentials, +rpa_credentials_callback(enum passdb_result result, + const char *credentials, struct auth_request *auth_request) { struct rpa_auth_request *request = (struct rpa_auth_request *)auth_request; - unsigned char response[16]; - buffer_t *hash_buffer; const unsigned char *token4; size_t token4_size; - if (credentials == NULL) { - mech_auth_finish(auth_request, NULL, 0, FALSE); - return; + switch (result) { + case PASSDB_RESULT_OK: + if (!verify_credentials(request, credentials)) + mech_auth_fail(auth_request); + else { + token4 = mech_rpa_build_token4(request, &token4_size); + auth_request->callback(auth_request, + AUTH_CLIENT_RESULT_CONTINUE, + token4, token4_size); + request->phase = 2; + } + break; + case PASSDB_RESULT_INTERNAL_FAILURE: + mech_auth_internal_failure(auth_request); + break; + default: + mech_auth_fail(auth_request); + break; } - - request->pwd_md5 = p_malloc(request->pool, 16); - hash_buffer = buffer_create_data(request->pool, request->pwd_md5, 16); - hex_to_binary(credentials, hash_buffer); - - rpa_user_response(request, response); - if (memcmp(response, request->user_response, 16) != 0) { - mech_auth_finish(auth_request, NULL, 0, FALSE); - return; - } - - token4 = mech_rpa_build_token4(request, &token4_size); - auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE, - token4, token4_size); - request->phase = 2; } static void @@ -446,7 +458,7 @@ i_info("rpa(%s): invalid token 1, %s", get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -478,7 +490,7 @@ i_info("rpa(%s): invalid token 3, %s", get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -487,7 +499,7 @@ i_info("rpa(%s): %s", get_log_prefix(auth_request), error); } - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); return; } @@ -500,7 +512,6 @@ const unsigned char *data, size_t data_size) { static const unsigned char client_ack[3] = { 0x60, 0x01, 0x00 }; - int ret = TRUE; if ((data_size != sizeof(client_ack)) || (memcmp(data, client_ack, sizeof(client_ack)) != 0)) { @@ -508,10 +519,10 @@ i_info("rpa(%s): invalid token 5 or client rejects us", get_log_prefix(auth_request)); } - ret = FALSE; + mech_auth_fail(auth_request); + } else { + mech_auth_success(auth_request, NULL, 0); } - - mech_auth_finish(auth_request, NULL, 0, ret); } static void @@ -535,7 +546,7 @@ mech_rpa_auth_phase3(auth_request, data, data_size); break; default: - mech_auth_finish(auth_request, NULL, 0, FALSE); + mech_auth_fail(auth_request); break; } } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech.c --- a/src/auth/mech.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech.c Fri Jan 07 19:27:20 2005 +0200 @@ -127,37 +127,9 @@ auth_request_unref(request); } -void mech_auth_finish(struct auth_request *request, - const void *data, size_t data_size, int success) +void mech_auth_success(struct auth_request *request, + const void *data, size_t data_size) { - if (!success) { - if (request->no_failure_delay) { - /* passdb specifically requested to to delay the - reply. */ - request->callback(request, AUTH_CLIENT_RESULT_FAILURE, - NULL, 0); - auth_request_destroy(request); - return; - } - - /* failure. don't announce it immediately to avoid - a) timing attacks, b) flooding */ - if (auth_failures_buf->used > 0) { - const struct auth_request *const *requests; - - requests = auth_failures_buf->data; - requests += auth_failures_buf->used/sizeof(*requests)-1; - i_assert(*requests != request); - } - - buffer_append(auth_failures_buf, &request, sizeof(request)); - - /* make sure the request isn't found anymore */ - auth_request_ref(request); - auth_request_destroy(request); - return; - } - request->successful = TRUE; if (request->conn != NULL) { request->callback(request, AUTH_CLIENT_RESULT_SUCCESS, @@ -172,6 +144,38 @@ } } +void mech_auth_fail(struct auth_request *request) +{ + if (request->no_failure_delay) { + /* passdb specifically requested to to delay the reply. */ + request->callback(request, AUTH_CLIENT_RESULT_FAILURE, NULL, 0); + auth_request_destroy(request); + return; + } + + /* failure. don't announce it immediately to avoid + a) timing attacks, b) flooding */ + if (auth_failures_buf->used > 0) { + const struct auth_request *const *requests; + + requests = auth_failures_buf->data; + requests += auth_failures_buf->used/sizeof(*requests)-1; + i_assert(*requests != request); + } + + buffer_append(auth_failures_buf, &request, sizeof(request)); + + /* make sure the request isn't found anymore */ + auth_request_ref(request); + auth_request_destroy(request); +} + +void mech_auth_internal_failure(struct auth_request *request) +{ + request->internal_failure = TRUE; + mech_auth_fail(request); +} + int mech_fix_username(char *username, const char **error_r) { unsigned char *p; diff -r 3e5faae6f10b -r 052f3a5743af src/auth/mech.h --- a/src/auth/mech.h Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/mech.h Fri Jan 07 19:27:20 2005 +0200 @@ -35,6 +35,7 @@ mech_callback_t *callback; unsigned int successful:1; + unsigned int internal_failure:1; unsigned int accept_input:1; unsigned int no_failure_delay:1; unsigned int no_login:1; @@ -81,8 +82,10 @@ const string_t *auth_mechanisms_get_list(void); -void mech_auth_finish(struct auth_request *request, - const void *data, size_t data_size, int success); +void mech_auth_success(struct auth_request *request, + const void *data, size_t data_size); +void mech_auth_fail(struct auth_request *request); +void mech_auth_internal_failure(struct auth_request *request); int mech_fix_username(char *username, const char **error_r); diff -r 3e5faae6f10b -r 052f3a5743af src/auth/passdb-ldap.c --- a/src/auth/passdb-ldap.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/passdb-ldap.c Fri Jan 07 19:27:20 2005 +0200 @@ -54,12 +54,14 @@ struct passdb_ldap_request *ldap_request = (struct passdb_ldap_request *) request; struct auth_request *auth_request = request->context; + enum passdb_result result; LDAPMessage *entry; BerElement *ber; char *attr, **vals; const char *user, *password, *scheme; int ret; + result = PASSDB_RESULT_USER_UNKNOWN; user = auth_request->user; password = NULL; @@ -69,6 +71,8 @@ i_error("ldap(%s): ldap_search() failed: %s", get_log_prefix(auth_request), ldap_err2string(ret)); + + result = PASSDB_RESULT_INTERNAL_FAILURE; res = NULL; } } @@ -105,7 +109,7 @@ } } - /* LDAP result is free'd now. we can check if auth_request is + /* LDAP result is freed now. we can check if auth_request is even needed anymore */ if (!auth_request_unref(auth_request)) return; @@ -117,7 +121,7 @@ } if (ldap_request->credentials != -1) { - passdb_handle_credentials(ldap_request->credentials, + passdb_handle_credentials(result, ldap_request->credentials, password, scheme, ldap_request->callback.lookup_credentials, auth_request); @@ -126,8 +130,7 @@ /* verify plain */ if (password == NULL) { - ldap_request->callback.verify_plain(PASSDB_RESULT_USER_UNKNOWN, - auth_request); + ldap_request->callback.verify_plain(result, auth_request); return; } @@ -219,7 +222,9 @@ scheme = passdb_ldap_conn->conn->set. default_pass_scheme; } - passdb_handle_credentials(credentials, result, scheme, + passdb_handle_credentials(result != NULL ? PASSDB_RESULT_OK : + PASSDB_RESULT_USER_UNKNOWN, + credentials, result, scheme, callback, request); return; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/passdb-passwd-file.c --- a/src/auth/passdb-passwd-file.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/passdb-passwd-file.c Fri Jan 07 19:27:20 2005 +0200 @@ -56,14 +56,14 @@ pu = db_passwd_file_lookup(passdb_pwf, request); if (pu == NULL) { - callback(NULL, request); + callback(PASSDB_RESULT_USER_UNKNOWN, NULL, request); return; } crypted_pass = pu->password; scheme = password_get_scheme(&crypted_pass); - passdb_handle_credentials(credentials, crypted_pass, + passdb_handle_credentials(PASSDB_RESULT_OK, credentials, crypted_pass, scheme, callback, request); } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/passdb-sql.c --- a/src/auth/passdb-sql.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/passdb-sql.c Fri Jan 07 19:27:20 2005 +0200 @@ -57,9 +57,11 @@ { struct passdb_sql_request *sql_request = context; struct auth_request *auth_request = sql_request->auth_request; + enum passdb_result passdb_result; const char *user, *password, *scheme; int ret, idx; + passdb_result = PASSDB_RESULT_USER_UNKNOWN; user = auth_request->user; password = NULL; @@ -68,6 +70,7 @@ i_error("sql(%s): Password query failed: %s", get_log_prefix(auth_request), sql_result_get_error(result)); + passdb_result = PASSDB_RESULT_INTERNAL_FAILURE; } else if (ret == 0) { if (verbose) { i_info("sql(%s): Unknown user", @@ -101,8 +104,8 @@ } if (sql_request->credentials != -1) { - passdb_handle_credentials(sql_request->credentials, - password, scheme, + passdb_handle_credentials(passdb_result, + sql_request->credentials, password, scheme, sql_request->callback.lookup_credentials, auth_request); i_free(sql_request); @@ -111,8 +114,7 @@ /* verify plain */ if (password == NULL) { - sql_request->callback.verify_plain(PASSDB_RESULT_USER_UNKNOWN, - auth_request); + sql_request->callback.verify_plain(passdb_result, auth_request); i_free(sql_request); return; } @@ -129,8 +131,8 @@ } sql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK : - PASSDB_RESULT_PASSWORD_MISMATCH, - auth_request); + PASSDB_RESULT_PASSWORD_MISMATCH, + auth_request); i_free(sql_request); } @@ -186,7 +188,9 @@ &result, &scheme)) { if (scheme == NULL) scheme = passdb_sql_conn->set.default_pass_scheme; - passdb_handle_credentials(credentials, result, scheme, + passdb_handle_credentials(result != NULL ? PASSDB_RESULT_OK : + PASSDB_RESULT_USER_UNKNOWN, + credentials, result, scheme, callback, request); return; } diff -r 3e5faae6f10b -r 052f3a5743af src/auth/passdb.c --- a/src/auth/passdb.c Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/passdb.c Fri Jan 07 19:27:20 2005 +0200 @@ -71,44 +71,49 @@ return "??"; } -void passdb_handle_credentials(enum passdb_credentials credentials, +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 *wanted_scheme; + if (result != PASSDB_RESULT_OK) { + callback(result, NULL, auth_request); + return; + } + i_assert(password != NULL); + if (credentials == PASSDB_CREDENTIALS_CRYPT) { /* anything goes */ - if (password != NULL) - password = t_strdup_printf("{%s}%s", scheme, password); - callback(password, auth_request); + password = t_strdup_printf("{%s}%s", scheme, password); + callback(result, password, auth_request); return; } - if (password != NULL) { - wanted_scheme = passdb_credentials_to_str(credentials); - if (strcasecmp(scheme, wanted_scheme) != 0) { - if (strcasecmp(scheme, "PLAIN") == 0 || - strcasecmp(scheme, "CLEARTEXT") == 0) { - /* we can generate anything out of plaintext - passwords */ - password = password_generate(password, - auth_request->user, - wanted_scheme); - } else { - if (verbose) { - i_info("password(%s): Requested %s " - "scheme, but we have only %s", - auth_request->user, - wanted_scheme, scheme); - } - password = NULL; + wanted_scheme = passdb_credentials_to_str(credentials); + if (strcasecmp(scheme, wanted_scheme) != 0) { + if (strcasecmp(scheme, "PLAIN") != 0 && + strcasecmp(scheme, "CLEARTEXT") != 0) { + if (verbose) { + i_info("password(%s): Requested %s " + "scheme, but we have only %s", + auth_request->user, + wanted_scheme, scheme); } + callback(PASSDB_RESULT_SCHEME_NOT_AVAILABLE, + NULL, auth_request); + return; } + + /* we can generate anything out of plaintext passwords */ + password = password_generate(password, auth_request->user, + wanted_scheme); + i_assert(password != NULL); } - callback(password, auth_request); + callback(PASSDB_RESULT_OK, password, auth_request); } void passdb_preinit(void) diff -r 3e5faae6f10b -r 052f3a5743af src/auth/passdb.h --- a/src/auth/passdb.h Fri Jan 07 19:24:12 2005 +0200 +++ b/src/auth/passdb.h Fri Jan 07 19:27:20 2005 +0200 @@ -22,6 +22,7 @@ PASSDB_RESULT_USER_UNKNOWN = -1, PASSDB_RESULT_USER_DISABLED = -2, PASSDB_RESULT_INTERNAL_FAILURE = -3, + PASSDB_RESULT_SCHEME_NOT_AVAILABLE = -4, PASSDB_RESULT_PASSWORD_MISMATCH = 0, PASSDB_RESULT_OK = 1, @@ -29,7 +30,8 @@ typedef void verify_plain_callback_t(enum passdb_result result, struct auth_request *request); -typedef void lookup_credentials_callback_t(const char *result, +typedef void lookup_credentials_callback_t(enum passdb_result result, + const char *credentials, struct auth_request *request); struct passdb_module { @@ -50,7 +52,8 @@ lookup_credentials_callback_t *callback); }; -void passdb_handle_credentials(enum passdb_credentials credentials, +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);