diff -r 84eea1977632 src/auth/auth-request.c --- a/src/auth/auth-request.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/auth-request.c Fri Jan 09 11:16:40 2009 -0500 @@ -506,6 +506,52 @@ else { passdb->iface.verify_plain(request, password, auth_request_verify_plain_callback); + } +} + +void auth_request_verify_reponse(struct auth_request *request, + const char *challenge, const char *response, + lookup_credentials_callback_t *callback) +{ + struct passdb_module *passdb = request->passdb->passdb; + const char *cache_key, *cache_cred, *cache_scheme; + const unsigned char *credentials; + size_t size; + enum passdb_result result; + + i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); + + request->private_callback.verify_plain = callback; + +#if 0 //FIXME + cache_key = passdb_cache == NULL ? NULL : passdb->cache_key; + if (cache_key != NULL) { + if (passdb_cache_lookup_credentials(request, cache_key, + &cache_cred, &cache_scheme, + &result, FALSE)) { + if (result == PASSDB_RESULT_OK && + !passdb_get_credentials(request, cache_cred, + cache_scheme, + &credentials, &size)) + result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE; + auth_request_lookup_credentials_finish( + result, credentials, size, request); + return; + } + } +#endif + + request->state = AUTH_REQUEST_STATE_PASSDB; + + if (passdb->iface.lookup_credentials == NULL) { + /* this passdb doesn't support credentials */ + auth_request_lookup_credentials_callback( + PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, 0, request); + } else if (passdb->blocking) { + passdb_blocking_lookup_credentials(request); + } else { + passdb->iface.lookup_credentials(request, + auth_request_lookup_credentials_callback); } } diff -r 84eea1977632 src/auth/auth-request.h --- a/src/auth/auth-request.h Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/auth-request.h Fri Jan 09 11:16:40 2009 -0500 @@ -128,6 +128,14 @@ void auth_request_lookup_credentials(struct auth_request *request, const char *scheme, lookup_credentials_callback_t *callback); +/* If passdb.verify_response() was used, callback will return success with + data=NULL and there's no need to verify it further. Otherwise if + passdb.lookup_credentials() was used the data won't be NULL and its + correctness must be verified against the challenge+response. */ +void auth_request_verify_reponse(struct auth_request *request, + const char *scheme, + const char *challenge, const char *response, + lookup_credentials_callback_t *callback); void auth_request_lookup_user(struct auth_request *request, userdb_callback_t *callback); diff -r 84eea1977632 src/auth/auth.c --- a/src/auth/auth.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/auth.c Fri Jan 09 11:16:40 2009 -0500 @@ -136,6 +136,17 @@ return FALSE; } +static bool auth_passdb_list_have_verify_response(struct auth *auth) +{ + struct auth_passdb *passdb; + + for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) { + if (passdb->passdb->iface.verify_response != NULL) + return TRUE; + } + return FALSE; +} + static bool auth_passdb_list_have_lookup_credentials(struct auth *auth) { struct auth_passdb *passdb; @@ -169,6 +180,9 @@ return FALSE; break; case MECH_PASSDB_NEED_VERIFY_RESPONSE: + if (!auth_passdb_list_have_verify_response(auth)) + return FALSE; + break; case MECH_PASSDB_NEED_LOOKUP_CREDENTIALS: if (!auth_passdb_list_have_lookup_credentials(auth)) return FALSE; diff -r 84eea1977632 src/auth/db-checkpassword.c --- a/src/auth/db-checkpassword.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/db-checkpassword.c Fri Jan 09 11:16:40 2009 -0500 @@ -49,6 +49,7 @@ safe_memset(request->password, 0, strlen(request->password)); i_free(request->password); } + i_free(request->challenge); i_free(request); } @@ -91,6 +92,7 @@ pipe, also pass some other possibly interesting information via environment. Use UCSPI names for local/remote IPs. */ env_put("PROTO=TCP"); /* UCSPI */ + env_put(t_strconcat("MECHANISM=", request->mech->mech_name, NULL)); env_put(t_strconcat("SERVICE=", request->service, NULL)); if (request->local_ip.family != 0) { env_put(t_strconcat("TCPLOCALIP=", @@ -157,35 +159,37 @@ void checkpassword_child_output(struct chkpw_auth_request *request) { - /* Send: username \0 password \0 timestamp \0. - Must be 512 bytes or less. The "timestamp" parameter is actually - useful only for APOP authentication. We don't support it, so - keep it empty */ + /* Send: username \0 password \0 timestamp \0. */ struct auth_request *auth_request = request->request; buffer_t *buf; - const unsigned char *data; - size_t size; ssize_t ret; buf = buffer_create_dynamic(pool_datastack_create(), 512+1); buffer_append(buf, auth_request->user, strlen(auth_request->user)+1); - if (request->password != NULL) - buffer_append(buf, request->password, strlen(request->password)+1); - else - buffer_append_c(buf, '\0'); - buffer_append_c(buf, '\0'); - data = buffer_get_data(buf, &size); + if (request->password == NULL) + buffer_append_c(buf, '\0'); + else { + buffer_append(buf, request->password, + strlen(request->password) + 1); + } + if (request->challenge == NULL) + buffer_append_c(buf, '\0'); + else { + buffer_append(buf, request->challenge, + strlen(request->challenge) + 1); + } - if (size > 512) { + if (buf->used > 512) { auth_request_log_error(request->request, "checkpassword", - "output larger than 512 bytes: %"PRIuSIZE_T, size); + "output larger than 512 bytes: %"PRIuSIZE_T, buf->used); request->finish_callback(request, request->internal_failure_code); return; } - ret = write(request->fd_out, data + request->write_pos, - size - request->write_pos); + ret = write(request->fd_out, + CONST_PTR_OFFSET(buf->data, request->write_pos), + buf->used - request->write_pos); if (ret <= 0) { if (ret < 0) { auth_request_log_error(request->request, @@ -197,7 +201,7 @@ } request->write_pos += ret; - if (request->write_pos < size) + if (request->write_pos < buf->used) return; io_remove(&request->io_out); diff -r 84eea1977632 src/auth/db-checkpassword.h --- a/src/auth/db-checkpassword.h Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/db-checkpassword.h Fri Jan 09 11:16:40 2009 -0500 @@ -22,7 +22,7 @@ pid_t pid; string_t *input_buf; - char *password; + char *challenge, *password; unsigned int write_pos; struct auth_request *request; diff -r 84eea1977632 src/auth/passdb-bsdauth.c --- a/src/auth/passdb-bsdauth.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-bsdauth.c Fri Jan 09 11:16:40 2009 -0500 @@ -78,6 +78,7 @@ bsdauth_verify_plain, NULL, + NULL, NULL }; #else diff -r 84eea1977632 src/auth/passdb-checkpassword.c --- a/src/auth/passdb-checkpassword.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-checkpassword.c Fri Jan 09 11:16:40 2009 -0500 @@ -143,8 +143,9 @@ } static void -checkpassword_verify_plain(struct auth_request *request, const char *password, - verify_plain_callback_t *callback) +checkpassword_verify_response(struct auth_request *request, + const char *challenge, const char *password, + verify_plain_callback_t *callback) { struct passdb_module *_module = request->passdb->passdb; struct checkpassword_passdb_module *module = @@ -199,6 +200,7 @@ chkpw_auth_request->fd_in = fd_in[0]; chkpw_auth_request->fd_out = fd_out[1]; chkpw_auth_request->pid = pid; + chkpw_auth_request->challenge = i_strdup(challenge); chkpw_auth_request->password = i_strdup(password); chkpw_auth_request->request = request; chkpw_auth_request->callback = callback; @@ -225,6 +227,13 @@ checkpassword_passdb_children = child_wait_new_with_pid(pid, sigchld_handler, module); } +} + +static void +checkpassword_verify_plain(struct auth_request *request, const char *password, + verify_plain_callback_t *callback) +{ + checkpassword_verify_response(request, NULL, password, callback); } static struct passdb_module * @@ -271,6 +280,7 @@ checkpassword_deinit, checkpassword_verify_plain, + checkpassword_verify_response, NULL, NULL }; diff -r 84eea1977632 src/auth/passdb-ldap.c --- a/src/auth/passdb-ldap.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-ldap.c Fri Jan 09 11:16:40 2009 -0500 @@ -424,6 +424,7 @@ passdb_ldap_deinit, ldap_verify_plain, + NULL, ldap_lookup_credentials, NULL }; diff -r 84eea1977632 src/auth/passdb-pam.c --- a/src/auth/passdb-pam.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-pam.c Fri Jan 09 11:16:40 2009 -0500 @@ -383,6 +383,7 @@ pam_verify_plain, NULL, + NULL, NULL }; #else diff -r 84eea1977632 src/auth/passdb-passwd-file.c --- a/src/auth/passdb-passwd-file.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-passwd-file.c Fri Jan 09 11:16:40 2009 -0500 @@ -186,6 +186,7 @@ passwd_file_deinit, passwd_file_verify_plain, + NULL, passwd_file_lookup_credentials, NULL }; diff -r 84eea1977632 src/auth/passdb-passwd.c --- a/src/auth/passdb-passwd.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-passwd.c Fri Jan 09 11:16:40 2009 -0500 @@ -82,6 +82,7 @@ passwd_verify_plain, NULL, + NULL, NULL }; diff -r 84eea1977632 src/auth/passdb-shadow.c --- a/src/auth/passdb-shadow.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-shadow.c Fri Jan 09 11:16:40 2009 -0500 @@ -82,6 +82,7 @@ shadow_verify_plain, NULL, + NULL, NULL }; #else diff -r 84eea1977632 src/auth/passdb-sia.c --- a/src/auth/passdb-sia.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-sia.c Fri Jan 09 11:16:40 2009 -0500 @@ -57,6 +57,7 @@ local_sia_verify_plain, NULL, + NULL, NULL }; #else diff -r 84eea1977632 src/auth/passdb-sql.c --- a/src/auth/passdb-sql.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-sql.c Fri Jan 09 11:16:40 2009 -0500 @@ -270,6 +270,7 @@ passdb_sql_deinit, sql_verify_plain, + NULL, sql_lookup_credentials, sql_set_credentials }; diff -r 84eea1977632 src/auth/passdb-vpopmail.c --- a/src/auth/passdb-vpopmail.c Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb-vpopmail.c Fri Jan 09 11:16:40 2009 -0500 @@ -197,6 +197,7 @@ vpopmail_deinit, vpopmail_verify_plain, + NULL, vpopmail_lookup_credentials, NULL }; diff -r 84eea1977632 src/auth/passdb.h --- a/src/auth/passdb.h Fri Jan 09 11:15:56 2009 -0500 +++ b/src/auth/passdb.h Fri Jan 09 11:16:40 2009 -0500 @@ -38,6 +38,11 @@ /* Check if plaintext password matches */ void (*verify_plain)(struct auth_request *request, const char *password, verify_plain_callback_t *callback); + /* Check if challenge+response pair authenticates the user successfully + for the request->mech auth mechanism. */ + void (*verify_response)(struct auth_request *request, + const char *challenge, const char *response, + verify_plain_callback_t *callback); /* Return authentication credentials, set in auth_request->credentials. */