Mercurial > dovecot > original-hg > dovecot-1.2
changeset 5598:971050640e3b HEAD
All password schemes can now be encoded with base64 or hex. The encoding is
".b64", ".base64" or ".hex" suffix in the scheme, eg. {plain.b64}.
Password scheme verification function can now be set to NULL, in which case
the verification is done by generating a new crypted password from given
plaintext password and comparing it.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 13 May 2007 15:17:09 +0300 |
parents | e9c43a73180c |
children | 6789ba80419b |
files | src/auth/Makefile.am src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-worker-client.c src/auth/mech-apop.c src/auth/mech-cram-md5.c src/auth/mech-digest-md5.c src/auth/mech-ntlm.c src/auth/mech-otp.c src/auth/mech-rpa.c src/auth/mech-skey.c src/auth/passdb-ldap.c src/auth/passdb-passwd-file.c src/auth/passdb.c src/auth/passdb.h src/auth/password-scheme-cram-md5.c src/auth/password-scheme-ntlm.c src/auth/password-scheme-rpa.c src/auth/password-scheme.c src/auth/password-scheme.h src/auth/userdb-static.c |
diffstat | 21 files changed, 582 insertions(+), 509 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/Makefile.am Sun May 13 15:17:09 2007 +0300 @@ -20,8 +20,6 @@ mycrypt.c \ password-scheme.c \ password-scheme-md5crypt.c \ - password-scheme-cram-md5.c \ - password-scheme-ntlm.c \ password-scheme-otp.c \ password-scheme-rpa.c
--- a/src/auth/auth-request.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/auth-request.c Sun May 13 15:17:09 2007 +0300 @@ -4,6 +4,7 @@ #include "ioloop.h" #include "buffer.h" #include "hash.h" +#include "hex-binary.h" #include "str.h" #include "safe-memset.h" #include "str-sanitize.h" @@ -449,9 +450,10 @@ } static void -auth_request_lookup_credentials_callback_finish(enum passdb_result result, - const char *password, - struct auth_request *request) +auth_request_lookup_credentials_finish(enum passdb_result result, + const unsigned char *credentials, + size_t size, + struct auth_request *request) { if (!auth_request_handle_passdb_callback(&result, request)) { /* try next passdb */ @@ -462,18 +464,20 @@ if (request->auth->verbose_debug_passwords && result == PASSDB_RESULT_OK) { auth_request_log_debug(request, "password", - "Credentials: %s", password); + "Credentials: %s", + binary_to_hex(credentials, size)); } request->private_callback. - lookup_credentials(result, password, request); + lookup_credentials(result, credentials, size, request); } } void auth_request_lookup_credentials_callback(enum passdb_result result, - const char *password, + const unsigned char *credentials, + size_t size, struct auth_request *request) { - const char *scheme; + const char *cache_cred, *cache_scheme; i_assert(request->state == AUTH_REQUEST_STATE_PASSDB); @@ -488,18 +492,21 @@ const char *cache_key = request->passdb->passdb->cache_key; if (passdb_cache_lookup_credentials(request, cache_key, - &password, &scheme, + &cache_cred, &cache_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 (result == PASSDB_RESULT_OK) { + if (!passdb_get_credentials(request, cache_cred, + cache_scheme, + &credentials, &size)) + result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE; } } - auth_request_lookup_credentials_callback_finish(result, password, - request); + auth_request_lookup_credentials_finish(result, credentials, size, + request); } void auth_request_lookup_credentials(struct auth_request *request, @@ -508,6 +515,8 @@ { 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); @@ -520,11 +529,13 @@ if (passdb_cache_lookup_credentials(request, cache_key, &cache_cred, &cache_scheme, &result, FALSE)) { - cache_cred = result != PASSDB_RESULT_OK ? NULL : - passdb_get_credentials(request, cache_cred, - cache_scheme); - auth_request_lookup_credentials_callback_finish( - result, cache_cred, request); + 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; } } @@ -539,7 +550,7 @@ } else { /* this passdb doesn't support credentials */ auth_request_lookup_credentials_callback( - PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, request); + PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, 0, request); } } @@ -1021,6 +1032,9 @@ const char *crypted_password, const char *scheme, const char *subsystem) { + const unsigned char *raw_password; + size_t raw_password_size; + const char *user; int ret; if (request->skip_password_check) { @@ -1034,16 +1048,29 @@ return 0; } + ret = password_decode(crypted_password, scheme, + &raw_password, &raw_password_size); + if (ret <= 0) { + if (ret < 0) { + auth_request_log_error(request, subsystem, + "Invalid password format for scheme %s", + scheme); + } else { + auth_request_log_error(request, subsystem, + "Unknown scheme %s", scheme); + } + return -1; + } + /* If original_username is set, use it. It may be important for some password schemes (eg. digest-md5). Otherwise the username is used only for logging purposes. */ - ret = password_verify(plain_password, crypted_password, scheme, - request->original_username != NULL ? - request->original_username : request->user); - if (ret < 0) { - auth_request_log_error(request, subsystem, - "Unknown password scheme %s", scheme); - } else if (ret == 0) { + user = request->original_username != NULL ? + request->original_username : request->user; + ret = password_verify(plain_password, user, scheme, + raw_password, raw_password_size); + i_assert(ret >= 0); + if (ret == 0) { auth_request_log_info(request, subsystem, "Password mismatch"); if (request->auth->verbose_debug_passwords) {
--- a/src/auth/auth-request.h Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/auth-request.h Sun May 13 15:17:09 2007 +0300 @@ -157,7 +157,8 @@ void auth_request_verify_plain_callback(enum passdb_result result, struct auth_request *request); void auth_request_lookup_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, + size_t size, struct auth_request *request); void auth_request_set_credentials(struct auth_request *request, const char *scheme, const char *data,
--- a/src/auth/auth-worker-client.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/auth-worker-client.c Sun May 13 15:17:09 2007 +0300 @@ -1,6 +1,7 @@ /* Copyright (C) 2005 Timo Sirainen */ #include "common.h" +#include "base64.h" #include "ioloop.h" #include "network.h" #include "istream.h" @@ -165,7 +166,8 @@ } static void -lookup_credentials_callback(enum passdb_result result, const char *credentials, +lookup_credentials_callback(enum passdb_result result, + const unsigned char *credentials, size_t size, struct auth_request *request) { struct auth_worker_client *client = request->context; @@ -180,8 +182,10 @@ if (result != PASSDB_RESULT_OK) str_printfa(str, "FAIL\t%d", result); else { - str_printfa(str, "OK\t%s\t{%s}%s\t", request->user, - request->credentials_scheme, credentials); + str_printfa(str, "OK\t%s\t{%s.b64}", request->user, + request->credentials_scheme); + base64_encode(credentials, size, str); + str_append_c(str, '\t'); if (request->extra_fields != NULL) { const char *field = auth_stream_reply_export(request->extra_fields);
--- a/src/auth/mech-apop.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-apop.c Sun May 13 15:17:09 2007 +0300 @@ -30,14 +30,14 @@ }; static bool verify_credentials(struct apop_auth_request *request, - const char *credentials) + const unsigned char *credentials, size_t size) { 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_update(&ctx, credentials, size); md5_final(&ctx, digest); return memcmp(digest, request->digest, 16) == 0; @@ -45,7 +45,7 @@ static void apop_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct apop_auth_request *request = @@ -53,7 +53,7 @@ switch (result) { case PASSDB_RESULT_OK: - if (verify_credentials(request, credentials)) + if (verify_credentials(request, credentials, size)) auth_request_success(auth_request, NULL, 0); else auth_request_fail(auth_request);
--- a/src/auth/mech-cram-md5.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-cram-md5.c Sun May 13 15:17:09 2007 +0300 @@ -47,26 +47,20 @@ } static bool verify_credentials(struct cram_auth_request *request, - const char *credentials) + const unsigned char *credentials, size_t size) { unsigned char digest[MD5_RESULTLEN]; - unsigned char context_digest[CRAM_MD5_CONTEXTLEN]; struct hmac_md5_context ctx; - buffer_t *context_digest_buf; const char *response_hex; - context_digest_buf = - buffer_create_data(pool_datastack_create(), - context_digest, sizeof(context_digest)); - - if (hex_to_binary(credentials, context_digest_buf) < 0) { + if (size != CRAM_MD5_CONTEXTLEN) { auth_request_log_error(&request->auth_request, "cram-md5", - "passdb credentials are not in hex"); + "invalid credentials length"); return FALSE; } - hmac_md5_set_cram_context(&ctx, context_digest); + hmac_md5_set_cram_context(&ctx, credentials); hmac_md5_update(&ctx, request->challenge, strlen(request->challenge)); hmac_md5_final(&ctx, digest); @@ -109,7 +103,7 @@ } static void credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct cram_auth_request *request = @@ -117,7 +111,7 @@ switch (result) { case PASSDB_RESULT_OK: - if (verify_credentials(request, credentials)) + if (verify_credentials(request, credentials, size)) auth_request_success(auth_request, NULL, 0); else auth_request_fail(auth_request);
--- a/src/auth/mech-digest-md5.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-digest-md5.c Sun May 13 15:17:09 2007 +0300 @@ -118,26 +118,17 @@ } static bool verify_credentials(struct digest_auth_request *request, - const char *credentials) + const unsigned char *credentials, size_t size) { struct md5_context ctx; - unsigned char digest[16]; + unsigned char digest[MD5_RESULTLEN]; const char *a1_hex, *a2_hex, *response_hex; - buffer_t *digest_buf; int i; /* get the MD5 password */ - if (strlen(credentials) != sizeof(digest)*2) { + if (size != MD5_RESULTLEN) { auth_request_log_error(&request->auth_request, "digest-md5", - "passdb credentials' length is wrong"); - return FALSE; - } - - digest_buf = buffer_create_data(pool_datastack_create(), - digest, sizeof(digest)); - if (hex_to_binary(credentials, digest_buf) < 0) { - auth_request_log_error(&request->auth_request, "digest-md5", - "passdb credentials are not in hex"); + "invalid credentials length"); return FALSE; } @@ -164,7 +155,7 @@ /* A1 */ md5_init(&ctx); - md5_update(&ctx, digest, 16); + md5_update(&ctx, credentials, size); md5_update(&ctx, ":", 1); md5_update(&ctx, request->nonce, strlen(request->nonce)); md5_update(&ctx, ":", 1); @@ -519,7 +510,7 @@ } static void credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct digest_auth_request *request = @@ -527,7 +518,7 @@ switch (result) { case PASSDB_RESULT_OK: - if (!verify_credentials(request, credentials)) { + if (!verify_credentials(request, credentials, size)) { auth_request_fail(auth_request); return; }
--- a/src/auth/mech-ntlm.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-ntlm.c Sun May 13 15:17:09 2007 +0300 @@ -30,14 +30,18 @@ struct ntlmssp_response *response; }; -static int lm_verify_credentials(struct ntlm_auth_request *request, - const char *credentials) +static bool lm_verify_credentials(struct ntlm_auth_request *request, + const unsigned char *credentials, size_t size) { 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; + + if (size != LM_HASH_SIZE) { + auth_request_log_error(&request->auth_request, "lm", + "invalid credentials length"); + return FALSE; + } response_length = ntlmssp_buffer_length(request->response, lm_response); @@ -49,21 +53,13 @@ return FALSE; } - hash_buffer = buffer_create_data(request->auth_request.pool, - hash, sizeof(hash)); - if (hex_to_binary(credentials, hash_buffer) < 0) { - auth_request_log_error(&request->auth_request, "ntlm", - "passdb credentials are not in hex"); - return FALSE; - } - - ntlmssp_v1_response(hash, request->challenge, lm_response); + ntlmssp_v1_response(credentials, request->challenge, lm_response); return memcmp(lm_response, client_response, LM_RESPONSE_SIZE) == 0; } static void lm_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct ntlm_auth_request *request = @@ -71,7 +67,7 @@ switch (result) { case PASSDB_RESULT_OK: - if (lm_verify_credentials(request, credentials)) + if (lm_verify_credentials(request, credentials, size)) auth_request_success(auth_request, NULL, 0); else auth_request_fail(auth_request); @@ -85,14 +81,13 @@ } } -static int ntlm_verify_credentials(struct ntlm_auth_request *request, - const char *credentials) +static int +ntlm_verify_credentials(struct ntlm_auth_request *request, + const unsigned char *credentials, size_t size) { 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; response_length = ntlmssp_buffer_length(request->response, ntlm_response); @@ -103,12 +98,10 @@ return request->ntlm2_negotiated ? -1 : 0; } - hash_buffer = buffer_create_data(auth_request->pool, - hash, sizeof(hash)); - if (hex_to_binary(credentials, hash_buffer) < 0) { + if (size != NTLMSSP_HASH_SIZE) { auth_request_log_error(&request->auth_request, "ntlm", - "passdb credentials are not in hex"); - return 0; + "invalid credentials length"); + return -1; } if (response_length > NTLMSSP_RESPONSE_SIZE) { @@ -121,7 +114,7 @@ * as a standalone server, not as NT domain member. */ ntlmssp_v2_response(auth_request->user, NULL, - hash, request->challenge, blob, + credentials, request->challenge, blob, response_length - NTLMSSP_V2_RESPONSE_SIZE, ntlm_v2_response); @@ -133,11 +126,11 @@ ntlmssp_buffer_data(request->response, lm_response); if (request->ntlm2_negotiated) - ntlmssp2_response(hash, request->challenge, + ntlmssp2_response(credentials, request->challenge, client_lm_response, ntlm_response); else - ntlmssp_v1_response(hash, request->challenge, + ntlmssp_v1_response(credentials, request->challenge, ntlm_response); return memcmp(ntlm_response, client_response, @@ -147,7 +140,7 @@ static void ntlm_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct ntlm_auth_request *request = @@ -156,7 +149,7 @@ switch (result) { case PASSDB_RESULT_OK: - ret = ntlm_verify_credentials(request, credentials); + ret = ntlm_verify_credentials(request, credentials, size); if (ret > 0) { auth_request_success(auth_request, NULL, 0); return;
--- a/src/auth/mech-otp.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-otp.c Sun May 13 15:17:09 2007 +0300 @@ -17,13 +17,14 @@ static void otp_send_challenge(struct auth_request *auth_request, - const char *credentials) + const unsigned char *credentials, size_t size) { struct otp_auth_request *request = (struct otp_auth_request *)auth_request; const char *answer; - if (otp_parse_dbentry(credentials, &request->state) != 0) { + if (otp_parse_dbentry(t_strndup(credentials, size), + &request->state) != 0) { auth_request_log_error(&request->auth_request, "otp", "invalid OTP data in passdb"); auth_request_fail(auth_request); @@ -56,12 +57,12 @@ static void skey_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { switch (result) { case PASSDB_RESULT_OK: - otp_send_challenge(auth_request, credentials); + otp_send_challenge(auth_request, credentials, size); break; case PASSDB_RESULT_INTERNAL_FAILURE: auth_request_internal_failure(auth_request); @@ -74,12 +75,12 @@ static void otp_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { switch (result) { case PASSDB_RESULT_OK: - otp_send_challenge(auth_request, credentials); + otp_send_challenge(auth_request, credentials, size); break; case PASSDB_RESULT_INTERNAL_FAILURE: auth_request_internal_failure(auth_request);
--- a/src/auth/mech-rpa.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-rpa.c Sun May 13 15:17:09 2007 +0300 @@ -438,26 +438,24 @@ } static bool verify_credentials(struct rpa_auth_request *request, - const char *credentials) + const unsigned char *credentials, size_t size) { unsigned char response[MD5_RESULTLEN]; - buffer_t *hash_buffer; - - if (strlen(credentials) != sizeof(request->pwd_md5)*2) - return FALSE; - hash_buffer = buffer_create_data(request->pool, request->pwd_md5, - sizeof(request->pwd_md5)); - if (hex_to_binary(credentials, hash_buffer) < 0) + if (size != sizeof(request->pwd_md5)) { + auth_request_log_error(&request->auth_request, "rpa", + "invalid credentials length"); return FALSE; + } + memcpy(request->pwd_md5, credentials, sizeof(request->pwd_md5)); rpa_user_response(request, response); return memcmp(response, request->user_response, sizeof(response)) == 0; } static void rpa_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct rpa_auth_request *request = @@ -467,7 +465,7 @@ switch (result) { case PASSDB_RESULT_OK: - if (!verify_credentials(request, credentials)) + if (!verify_credentials(request, credentials, size)) auth_request_fail(auth_request); else { token4 = mech_rpa_build_token4(request, &token4_size);
--- a/src/auth/mech-skey.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/mech-skey.c Sun May 13 15:17:09 2007 +0300 @@ -17,13 +17,14 @@ static void skey_send_challenge(struct auth_request *auth_request, - const char *credentials) + const unsigned char *credentials, size_t size) { struct otp_auth_request *request = (struct otp_auth_request *)auth_request; const char *answer; - if (otp_parse_dbentry(credentials, &request->state) != 0) { + if (otp_parse_dbentry(t_strndup(credentials, size), + &request->state) != 0) { auth_request_log_error(&request->auth_request, "skey", "invalid OTP data in passdb"); auth_request_fail(auth_request); @@ -62,12 +63,12 @@ static void otp_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { switch (result) { case PASSDB_RESULT_OK: - skey_send_challenge(auth_request, credentials); + skey_send_challenge(auth_request, credentials, size); break; case PASSDB_RESULT_INTERNAL_FAILURE: auth_request_internal_failure(auth_request); @@ -80,12 +81,12 @@ static void skey_credentials_callback(enum passdb_result result, - const char *credentials, + const unsigned char *credentials, size_t size, struct auth_request *auth_request) { switch (result) { case PASSDB_RESULT_OK: - skey_send_challenge(auth_request, credentials); + skey_send_challenge(auth_request, credentials, size); break; case PASSDB_RESULT_INTERNAL_FAILURE: auth_request_internal_failure(auth_request);
--- a/src/auth/passdb-ldap.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/passdb-ldap.c Sun May 13 15:17:09 2007 +0300 @@ -174,7 +174,7 @@ } if (auth_request->credentials_scheme != NULL) { - request->callback.lookup_credentials(passdb_result, NULL, + request->callback.lookup_credentials(passdb_result, NULL, 0, auth_request); } else { request->callback.verify_plain(passdb_result, auth_request);
--- a/src/auth/passdb-passwd-file.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/passdb-passwd-file.c Sun May 13 15:17:09 2007 +0300 @@ -102,7 +102,7 @@ pu = db_passwd_file_lookup(module->pwf, request); if (pu == NULL) { - callback(PASSDB_RESULT_USER_UNKNOWN, NULL, request); + callback(PASSDB_RESULT_USER_UNKNOWN, NULL, 0, request); return; }
--- a/src/auth/passdb.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/passdb.c Sun May 13 15:17:09 2007 +0300 @@ -53,32 +53,53 @@ NULL }; -const char * -passdb_get_credentials(struct auth_request *auth_request, - const char *password, const char *scheme) +bool passdb_get_credentials(struct auth_request *auth_request, + const char *input, const char *input_scheme, + const unsigned char **credentials_r, size_t *size_r) { const char *wanted_scheme = auth_request->credentials_scheme; + const char *plaintext; + int ret; - if (strcasecmp(wanted_scheme, "CRYPT") == 0) { + if (*wanted_scheme == '\0') { /* anything goes */ - return t_strdup_printf("{%s}%s", scheme, password); + *credentials_r = (const unsigned char *)input; + *size_r = strlen(input); + return TRUE; } - if (!password_scheme_is_alias(scheme, wanted_scheme)) { - if (!password_scheme_is_alias(scheme, "PLAIN")) { + ret = password_decode(input, input_scheme, credentials_r, size_r); + if (ret <= 0) { + if (ret < 0) { + auth_request_log_error(auth_request, "password", + "Invalid password format for scheme %s", + input_scheme); + } else { + auth_request_log_error(auth_request, "password", + "Unknown scheme %s", input_scheme); + } + return FALSE; + } + + if (!password_scheme_is_alias(input_scheme, wanted_scheme)) { + if (!password_scheme_is_alias(input_scheme, "PLAIN")) { auth_request_log_info(auth_request, "password", "Requested %s scheme, but we have only %s", - wanted_scheme, scheme); - return NULL; + wanted_scheme, input_scheme); + return FALSE; } /* we can generate anything out of plaintext passwords */ - password = password_generate(password, auth_request->user, - wanted_scheme); - i_assert(password != NULL); + plaintext = t_strndup(*credentials_r, *size_r); + if (!password_generate(plaintext, auth_request->user, + wanted_scheme, credentials_r, size_r)) { + auth_request_log_error(auth_request, "password", + "Requested unknown scheme %s", wanted_scheme); + return FALSE; + } } - return password; + return TRUE; } void passdb_handle_credentials(enum passdb_result result, @@ -86,16 +107,20 @@ lookup_credentials_callback_t *callback, struct auth_request *auth_request) { + const unsigned char *credentials; + size_t size = 0; + if (result != PASSDB_RESULT_OK) { - callback(result, NULL, auth_request); + callback(result, NULL, 0, auth_request); return; } - password = password == NULL ? NULL : - passdb_get_credentials(auth_request, password, scheme); - if (password == NULL) + if (password == NULL || + !passdb_get_credentials(auth_request, password, scheme, + &credentials, &size)) result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE; - callback(result, password, auth_request); + + callback(result, credentials, size, auth_request); } struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
--- a/src/auth/passdb.h Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/passdb.h Sun May 13 15:17:09 2007 +0300 @@ -21,7 +21,8 @@ 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 *password, + const unsigned char *credentials, + size_t size, struct auth_request *request); typedef void set_credentials_callback_t(enum passdb_result result, struct auth_request *request); @@ -62,9 +63,17 @@ struct passdb_module_interface iface; }; -const char * -passdb_get_credentials(struct auth_request *auth_request, - const char *password, const char *scheme); +/* Try to get credentials in wanted scheme (request->credentials_scheme) from + given input. Returns FALSE if this wasn't possible (unknown scheme, + conversion not possible or invalid credentials). + + If wanted scheme is "", the credentials are returned as-is without any + checks. This is useful mostly just to see if there exist any credentials + at all. */ +bool passdb_get_credentials(struct auth_request *auth_request, + const char *input, const char *input_scheme, + const unsigned char **credentials_r, + size_t *size_r); void passdb_handle_credentials(enum passdb_result result, const char *password, const char *scheme,
--- a/src/auth/password-scheme-cram-md5.c Sun May 13 14:53:05 2007 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* Copyright (C) 2003 Timo Sirainen / Joshua Goodall */ - -#include "lib.h" -#include "hmac-md5.h" -#include "hex-binary.h" -#include "password-scheme.h" - -const char *password_generate_cram_md5(const char *plaintext) -{ - struct hmac_md5_context ctx; - unsigned char context_digest[CRAM_MD5_CONTEXTLEN]; - - hmac_md5_init(&ctx, (const unsigned char *)plaintext, - strlen(plaintext)); - hmac_md5_get_cram_context(&ctx, context_digest); - return binary_to_hex(context_digest, sizeof(context_digest)); -}
--- a/src/auth/password-scheme-ntlm.c Sun May 13 14:53:05 2007 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ - -#include "lib.h" -#include "hex-binary.h" -#include "password-scheme.h" - -#include "ntlm.h" - -const char *password_generate_lm(const char *pw) -{ - unsigned char hash[LM_HASH_SIZE]; - - lm_hash(pw, hash); - - return binary_to_hex_ucase(hash, sizeof(hash)); -} - -const char *password_generate_ntlm(const char *pw) -{ - unsigned char hash[NTLMSSP_HASH_SIZE]; - - ntlm_v1_hash(pw, hash); - - return binary_to_hex_ucase(hash, sizeof(hash)); -}
--- a/src/auth/password-scheme-rpa.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/password-scheme-rpa.c Sun May 13 15:17:09 2007 +0300 @@ -24,17 +24,12 @@ return buffer_free_without_data(buf); } -const char *password_generate_rpa(const char *pw) +void password_generate_rpa(const char *pw, unsigned char result[]) { - unsigned char hash[MD5_RESULTLEN]; unsigned char *ucs2be_pw; size_t size; ucs2be_pw = ucs2be_str(unsafe_data_stack_pool, pw, &size); - - md5_get_digest(ucs2be_pw, size, hash); - + md5_get_digest(ucs2be_pw, size, result); safe_memset(ucs2be_pw, 0, size); - - return binary_to_hex(hash, sizeof(hash)); }
--- a/src/auth/password-scheme.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/password-scheme.c Sun May 13 15:17:09 2007 +0300 @@ -6,6 +6,8 @@ #include "hex-binary.h" #include "md4.h" #include "md5.h" +#include "hmac-md5.h" +#include "ntlm.h" #include "module-dir.h" #include "mycrypt.h" #include "randgen.h" @@ -23,20 +25,65 @@ static struct module *scheme_modules; #endif -int password_verify(const char *plaintext, const char *password, - const char *scheme, const char *user) +/* Lookup scheme and encoding by given name. The encoding is taken from + ".base64", ".b64" or ".hex" suffix if it exists, otherwise the default + encoding is used. */ +static const struct password_scheme * +password_scheme_lookup(const char *scheme, enum password_encoding *encoding_r) { const struct password_scheme *s; + const char *encoding = NULL; + unsigned int scheme_len; - if (password == NULL) - return 0; + *encoding_r = PW_ENCODING_NONE; + + for (scheme_len = 0; scheme[scheme_len] != '\0'; scheme_len++) { + if (scheme[scheme_len] == '.') { + encoding = scheme + scheme_len + 1; + break; + } + } for (s = schemes; s->name != NULL; s++) { - if (strcasecmp(s->name, scheme) == 0) - return s->password_verify(plaintext, password, user); + if (strncasecmp(s->name, scheme, scheme_len) == 0 && + s->name[scheme_len] == '\0') { + if (encoding == NULL) + *encoding_r = s->default_encoding; + else if (strcasecmp(encoding, "b64") == 0 || + strcasecmp(encoding, "base64") == 0) + *encoding_r = PW_ENCODING_BASE64; + else if (strcasecmp(encoding, "hex") == 0) + *encoding_r = PW_ENCODING_HEX; + else { + /* unknown encoding. treat as invalid scheme. */ + return NULL; + } + return s; + } } + return NULL; +} - return -1; +int password_verify(const char *plaintext, const char *user, const char *scheme, + const unsigned char *raw_password, size_t size) +{ + const struct password_scheme *s; + enum password_encoding encoding; + const unsigned char *generated; + size_t generated_size; + + s = password_scheme_lookup(scheme, &encoding); + if (s == NULL) + return -1; + + if (s->password_verify != NULL) + return s->password_verify(plaintext, user, raw_password, size); + + /* generic verification handler: generate the password and compare it + to the one in database */ + s->password_generate(plaintext, user, &generated, &generated_size); + return size != generated_size ? 0 : + memcmp(generated, raw_password, size) == 0; } const char *password_list_schemes(const struct password_scheme **listptr) @@ -52,25 +99,6 @@ return (*listptr)++->name; } -bool password_scheme_is_alias(const char *scheme1, const char *scheme2) -{ - const struct password_scheme *s, *s1 = NULL, *s2 = NULL; - - if (strcasecmp(scheme1, scheme2) == 0) - return TRUE; - - for (s = schemes; s->name != NULL; s++) { - if (strcasecmp(s->name, scheme1) == 0) - s1 = s; - else if (strcasecmp(s->name, scheme2) == 0) - s2 = s; - } - - /* if they've the same verify function, they're equivalent */ - return s1 != NULL && s2 != NULL && - s1->password_verify == s2->password_verify; -} - const char *password_get_scheme(const char **password) { const char *p, *scheme; @@ -102,421 +130,447 @@ return scheme; } -const char *password_generate(const char *plaintext, const char *user, - const char *scheme) +int password_decode(const char *password, const char *scheme, + const unsigned char **raw_password_r, size_t *size_r) { const struct password_scheme *s; + enum password_encoding encoding; + buffer_t *buf; + unsigned int len; + + s = password_scheme_lookup(scheme, &encoding); + if (s == NULL) + return 0; + + len = strlen(password); + if (encoding != PW_ENCODING_NONE && s->raw_password_len != 0 && + strchr(scheme, '.') == NULL) { + /* encoding not specified. we can autodetect between + base64 and hex encodings. */ + encoding = len == s->raw_password_len * 2 ? PW_ENCODING_HEX : + PW_ENCODING_BASE64; + } + + switch (encoding) { + case PW_ENCODING_NONE: + *raw_password_r = (const unsigned char *)password; + *size_r = len; + break; + case PW_ENCODING_BASE64: + buf = buffer_create_static_hard(pool_datastack_create(), + MAX_BASE64_DECODED_SIZE(len)); + if (base64_decode(password, len, NULL, buf) < 0) + return -1; + + *raw_password_r = buf->data; + *size_r = buf->used; + break; + case PW_ENCODING_HEX: + buf = buffer_create_static_hard(pool_datastack_create(), + len / 2 + 1); + if (hex_to_binary(password, buf) < 0) + return -1; + + *raw_password_r = buf->data; + *size_r = buf->used; + break; + } + if (s->raw_password_len != *size_r && s->raw_password_len != 0) { + /* password has invalid length */ + return -1; + } + return 1; +} + +bool password_generate(const char *plaintext, const char *user, + const char *scheme, + const unsigned char **raw_password_r, size_t *size_r) +{ + const struct password_scheme *s; + enum password_encoding encoding; + + s = password_scheme_lookup(scheme, &encoding); + if (s == NULL) + return FALSE; + + s->password_generate(plaintext, user, raw_password_r, size_r); + return TRUE; +} + +bool password_generate_encoded(const char *plaintext, const char *user, + const char *scheme, const char **password_r) +{ + const struct password_scheme *s; + const unsigned char *raw_password; + enum password_encoding encoding; + string_t *str; + size_t size; + + s = password_scheme_lookup(scheme, &encoding); + if (s == NULL) + return FALSE; + + s->password_generate(plaintext, user, &raw_password, &size); + switch (encoding) { + case PW_ENCODING_NONE: + *password_r = t_strndup(raw_password, size); + break; + case PW_ENCODING_BASE64: + str = t_str_new(MAX_BASE64_ENCODED_SIZE(size) + 1); + base64_encode(raw_password, size, str); + *password_r = str_c(str); + break; + case PW_ENCODING_HEX: + *password_r = binary_to_hex(raw_password, size); + break; + } + return TRUE; +} + +bool password_scheme_is_alias(const char *scheme1, const char *scheme2) +{ + const struct password_scheme *s, *s1 = NULL, *s2 = NULL; + + scheme1 = t_strcut(scheme1, '.'); + scheme2 = t_strcut(scheme2, '.'); + + if (strcasecmp(scheme1, scheme2) == 0) + return TRUE; for (s = schemes; s->name != NULL; s++) { - if (strcasecmp(s->name, scheme) == 0) - return s->password_generate(plaintext, user); + if (strcasecmp(s->name, scheme1) == 0) + s1 = s; + else if (strcasecmp(s->name, scheme2) == 0) + s2 = s; } - return NULL; + /* if they've the same generate function, they're equivalent */ + return s1 != NULL && s2 != NULL && + s1->password_generate == s2->password_generate; } -static bool crypt_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static bool +crypt_verify(const char *plaintext, const char *user __attr_unused__, + const unsigned char *raw_password, size_t size) { + const char *password; + + password = t_strndup(raw_password, size); return strcmp(mycrypt(plaintext, password), password) == 0; } -static const char *crypt_generate(const char *plaintext, - const char *user __attr_unused__) +static void +crypt_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - char salt[9]; + char salt[3]; + const char *password; - random_fill(salt, 2); + random_fill(salt, sizeof(salt)-1); salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)]; salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)]; salt[2] = '\0'; - return t_strdup(mycrypt(plaintext, salt)); + + password = t_strdup(mycrypt(plaintext, salt)); + *raw_password_r = (const unsigned char *)password; + *size_r = strlen(password); } -static bool md5_crypt_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static bool +md5_crypt_verify(const char *plaintext, const char *user __attr_unused__, + const unsigned char *raw_password, size_t size) { - const char *str; + const char *password, *str; + password = t_strndup(raw_password, size); str = password_generate_md5_crypt(plaintext, password); return strcmp(str, password) == 0; } -static const char *md5_crypt_generate(const char *plaintext, - const char *user __attr_unused__) +static void +md5_crypt_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { + const char *password; char salt[9]; - int i; + unsigned int i; - random_fill(salt, 8); - for (i = 0; i < 8; i++) + random_fill(salt, sizeof(salt)-1); + for (i = 0; i < sizeof(salt)-1; i++) salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)]; - salt[8] = '\0'; - return password_generate_md5_crypt(plaintext, salt); -} + salt[sizeof(salt)-1] = '\0'; -static const char *sha1_generate(const char *plaintext, - const char *user __attr_unused__) -{ - unsigned char digest[SHA1_RESULTLEN]; - string_t *str; - - sha1_get_digest(plaintext, strlen(plaintext), digest); - str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); - base64_encode(digest, sizeof(digest), str); - return str_c(str); + password = password_generate_md5_crypt(plaintext, salt); + *raw_password_r = (const unsigned char *)password; + *size_r = strlen(password); } -static const void * -password_decode(const char *password, unsigned int result_len) +static void +sha1_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - buffer_t *buf; - size_t len; - - len = strlen(password); - if (len == result_len*2) { - /* hex-encoded */ - buf = buffer_create_static_hard(pool_datastack_create(), - result_len); + unsigned char *digest; - if (hex_to_binary(password, buf) < 0) - return NULL; - } else { - /* base64-encoded */ - buf = buffer_create_static_hard(pool_datastack_create(), - MAX_BASE64_DECODED_SIZE(len)); + digest = t_malloc(SHA1_RESULTLEN); + sha1_get_digest(plaintext, strlen(plaintext), digest); - if (base64_decode(password, len, NULL, buf) < 0) - return NULL; - } - - return buf->used != result_len ? NULL : buf->data; + *raw_password_r = digest; + *size_r = SHA1_RESULTLEN; } -static bool sha1_verify(const char *plaintext, const char *password, - const char *user) -{ - unsigned char sha1_digest[SHA1_RESULTLEN]; - const char *data; - - sha1_get_digest(plaintext, strlen(plaintext), sha1_digest); - - data = password_decode(password, SHA1_RESULTLEN); - if (data == NULL) { - i_error("sha1_verify(%s): Invalid password encoding", user); - return 0; - } - - return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; -} - -static const char *ssha_generate(const char *plaintext, - const char *user __attr_unused__) +static void +ssha_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { #define SSHA_SALT_LEN 4 - unsigned char ssha_digest[SHA1_RESULTLEN + SSHA_SALT_LEN]; - unsigned char *salt = &ssha_digest[SHA1_RESULTLEN]; + unsigned char *digest, *salt; struct sha1_ctxt ctx; - string_t *str; + digest = t_malloc(SHA1_RESULTLEN + SSHA_SALT_LEN); + salt = digest + SHA1_RESULTLEN; random_fill(salt, SSHA_SALT_LEN); sha1_init(&ctx); sha1_loop(&ctx, plaintext, strlen(plaintext)); sha1_loop(&ctx, salt, SSHA_SALT_LEN); - sha1_result(&ctx, ssha_digest); + sha1_result(&ctx, digest); - str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(ssha_digest))+1); - base64_encode(ssha_digest, sizeof(ssha_digest), str); - return str_c(str); + *raw_password_r = digest; + *size_r = SHA1_RESULTLEN + SSHA_SALT_LEN; } -static bool ssha_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static bool ssha_verify(const char *plaintext, const char *user, + const unsigned char *raw_password, size_t size) { unsigned char sha1_digest[SHA1_RESULTLEN]; - buffer_t *buf; - const char *data; - size_t size, password_len; struct sha1_ctxt ctx; - /* format: base64-encoded MD5 hash and salt */ - password_len = strlen(password); - buf = buffer_create_static_hard(pool_datastack_create(), - MAX_BASE64_DECODED_SIZE(password_len)); - - if (base64_decode(password, password_len, NULL, buf) < 0) { - i_error("ssha_verify(%s): failed decoding SSHA base64", user); - return 0; - } - - data = buffer_get_data(buf, &size); + /* format: <SHA1 hash><salt> */ if (size <= SHA1_RESULTLEN) { - i_error("ssha_verify(%s): invalid SSHA base64 decode", user); - return 0; + i_error("ssha_verify(%s): SSHA password too short", user); + return FALSE; } sha1_init(&ctx); sha1_loop(&ctx, plaintext, strlen(plaintext)); - sha1_loop(&ctx, &data[SHA1_RESULTLEN], size-SHA1_RESULTLEN); + sha1_loop(&ctx, raw_password + SHA1_RESULTLEN, size - SHA1_RESULTLEN); sha1_result(&ctx, sha1_digest); - return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; + return memcmp(sha1_digest, raw_password, SHA1_RESULTLEN) == 0; } -static const char *smd5_generate(const char *plaintext, - const char *user __attr_unused__) +static void +smd5_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { #define SMD5_SALT_LEN 4 - unsigned char smd5_digest[MD5_RESULTLEN + SMD5_SALT_LEN]; - unsigned char *salt = &smd5_digest[MD5_RESULTLEN]; + unsigned char *digest, *salt; struct md5_context ctx; - string_t *str; + digest = t_malloc(SHA1_RESULTLEN + SSHA_SALT_LEN); + salt = digest + SHA1_RESULTLEN; random_fill(salt, SMD5_SALT_LEN); md5_init(&ctx); md5_update(&ctx, plaintext, strlen(plaintext)); md5_update(&ctx, salt, SMD5_SALT_LEN); - md5_final(&ctx, smd5_digest); + md5_final(&ctx, digest); - str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(smd5_digest))+1); - base64_encode(smd5_digest, sizeof(smd5_digest), str); - return str_c(str); + *raw_password_r = digest; + *size_r = SHA1_RESULTLEN + SSHA_SALT_LEN; } -static bool smd5_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static bool smd5_verify(const char *plaintext, const char *user, + const unsigned char *raw_password, size_t size) { unsigned char md5_digest[MD5_RESULTLEN]; - buffer_t *buf; - const char *data; - size_t size, password_len; struct md5_context ctx; - /* format: base64-encoded MD5 hash and salt */ - password_len = strlen(password); - buf = buffer_create_static_hard(pool_datastack_create(), - MAX_BASE64_DECODED_SIZE(password_len)); - - if (base64_decode(password, password_len, NULL, buf) < 0) { - i_error("smd5_verify(%s): failed decoding SMD5 base64", user); - return 0; - } - - data = buffer_get_data(buf, &size); + /* format: <MD5 hash><salt> */ if (size <= MD5_RESULTLEN) { - i_error("smd5_verify(%s): invalid SMD5 base64 decode", user); - return 0; + i_error("smd5_verify(%s): SMD5 password too short", user); + return FALSE; } md5_init(&ctx); md5_update(&ctx, plaintext, strlen(plaintext)); - md5_update(&ctx, &data[MD5_RESULTLEN], size-MD5_RESULTLEN); + md5_update(&ctx, raw_password + MD5_RESULTLEN, size - MD5_RESULTLEN); md5_final(&ctx, md5_digest); - return memcmp(md5_digest, data, MD5_RESULTLEN) == 0; -} - -static bool plain_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) -{ - return strcmp(password, plaintext) == 0; + return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0; } -static const char *plain_generate(const char *plaintext, - const char *user __attr_unused__) +static void +plain_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return plaintext; -} - -static bool cram_md5_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) -{ - return strcmp(password_generate_cram_md5(plaintext), password) == 0; + *raw_password_r = (const unsigned char *)plaintext, + *size_r = strlen(plaintext); } -static const char *cram_md5_generate(const char *plaintext, - const char *user __attr_unused__) +static void +cram_md5_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return password_generate_cram_md5(plaintext); + struct hmac_md5_context ctx; + unsigned char *context_digest; + + context_digest = t_malloc(CRAM_MD5_CONTEXTLEN); + hmac_md5_init(&ctx, (const unsigned char *)plaintext, + strlen(plaintext)); + hmac_md5_get_cram_context(&ctx, context_digest); + + *raw_password_r = context_digest; + *size_r = CRAM_MD5_CONTEXTLEN; } -static bool digest_md5_verify(const char *plaintext, const char *password, - const char *user) -{ - unsigned char digest[MD5_RESULTLEN]; - const char *realm, *str; - - /* user:realm:passwd */ - realm = strchr(user, '@'); - if (realm != NULL) realm++; else realm = ""; - - str = t_strconcat(t_strcut(user, '@'), ":", realm, ":", - plaintext, NULL); - md5_get_digest(str, strlen(str), digest); - str = binary_to_hex(digest, sizeof(digest)); - - return strcasecmp(str, password) == 0; -} - -static const char *digest_md5_generate(const char *plaintext, const char *user) +static void +digest_md5_generate(const char *plaintext, const char *user, + const unsigned char **raw_password_r, size_t *size_r) { const char *realm, *str; - unsigned char digest[MD5_RESULTLEN]; + unsigned char *digest; if (user == NULL) - i_fatal("digest_md5_generate(): username not given"); + i_panic("digest_md5_generate(): username not given"); /* user:realm:passwd */ realm = strchr(user, '@'); if (realm != NULL) realm++; else realm = ""; - str = t_strconcat(t_strcut(user, '@'), ":", realm, ":", - plaintext, NULL); + digest = t_malloc(MD5_RESULTLEN); + str = t_strdup_printf("%s:%s:%s", t_strcut(user, '@'), + realm, plaintext); md5_get_digest(str, strlen(str), digest); - return binary_to_hex(digest, sizeof(digest)); -} -static bool plain_md4_verify(const char *plaintext, const char *password, - const char *user) -{ - unsigned char digest[MD4_RESULTLEN]; - const void *data; - - md4_get_digest(plaintext, strlen(plaintext), digest); - - data = password_decode(password, MD4_RESULTLEN); - if (data == NULL) { - i_error("plain_md4_verify(%s): Invalid password encoding", - user); - return 0; - } - return memcmp(digest, data, MD4_RESULTLEN) == 0; + *raw_password_r = digest; + *size_r = MD5_RESULTLEN; } -static const char *plain_md4_generate(const char *plaintext, - const char *user __attr_unused__) -{ - unsigned char digest[MD4_RESULTLEN]; - - md4_get_digest(plaintext, strlen(plaintext), digest); - return binary_to_hex(digest, sizeof(digest)); -} - -static bool plain_md5_verify(const char *plaintext, const char *password, - const char *user) +static void +plain_md4_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - unsigned char digest[MD5_RESULTLEN]; - const void *data; - - md5_get_digest(plaintext, strlen(plaintext), digest); + unsigned char *digest; - data = password_decode(password, MD5_RESULTLEN); - if (data == NULL) { - i_error("plain_md5_verify(%s): Invalid password encoding", - user); - return 0; - } - return memcmp(digest, data, MD5_RESULTLEN) == 0; + digest = t_malloc(MD4_RESULTLEN); + md4_get_digest(plaintext, strlen(plaintext), digest); + + *raw_password_r = digest; + *size_r = MD4_RESULTLEN; } -static const char *plain_md5_generate(const char *plaintext, - const char *user __attr_unused__) +static void +plain_md5_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - unsigned char digest[MD5_RESULTLEN]; - - md5_get_digest(plaintext, strlen(plaintext), digest); - return binary_to_hex(digest, sizeof(digest)); -} + unsigned char *digest; -static const char *ldap_md5_generate(const char *plaintext, - const char *user __attr_unused__) -{ - unsigned char digest[MD5_RESULTLEN]; - string_t *str; + digest = t_malloc(MD5_RESULTLEN); + md5_get_digest(plaintext, strlen(plaintext), digest); - md5_get_digest(plaintext, strlen(plaintext), digest); - str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); - base64_encode(digest, sizeof(digest), str); - return str_c(str); + *raw_password_r = digest; + *size_r = MD5_RESULTLEN; } -static bool lm_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static void +lm_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return strcasecmp(password, password_generate_lm(plaintext)) == 0; -} + unsigned char *digest; -static const char *lm_generate(const char *plaintext, - const char *user __attr_unused__) -{ - return password_generate_lm(plaintext); + digest = t_malloc(LM_HASH_SIZE); + lm_hash(plaintext, digest); + + *raw_password_r = digest; + *size_r = LM_HASH_SIZE; } -static bool ntlm_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static void +ntlm_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return strcasecmp(password, password_generate_ntlm(plaintext)) == 0; + unsigned char *digest; + + digest = t_malloc(NTLMSSP_HASH_SIZE); + ntlm_v1_hash(plaintext, digest); + + *raw_password_r = digest; + *size_r = NTLMSSP_HASH_SIZE; } -static const char *ntlm_generate(const char *plaintext, - const char *user __attr_unused__) +static bool otp_verify(const char *plaintext, const char *user __attr_unused__, + const unsigned char *raw_password, size_t size) { - return password_generate_ntlm(plaintext); -} + const char *password; -static bool otp_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) -{ + password = t_strndup(raw_password, size); return strcasecmp(password, password_generate_otp(plaintext, password, -1)) == 0; } -static const char *otp_generate(const char *plaintext, - const char *user __attr_unused__) +static void +otp_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return password_generate_otp(plaintext, NULL, OTP_HASH_SHA1); + const char *password; + + password = password_generate_otp(plaintext, NULL, OTP_HASH_SHA1); + *raw_password_r = (const unsigned char *)password; + *size_r = strlen(password); } -static const char *skey_generate(const char *plaintext, - const char *user __attr_unused__) +static void +skey_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return password_generate_otp(plaintext, NULL, OTP_HASH_MD4); + const char *password; + + password = password_generate_otp(plaintext, NULL, OTP_HASH_MD4); + *raw_password_r = (const unsigned char *)password; + *size_r = strlen(password); } -static bool rpa_verify(const char *plaintext, const char *password, - const char *user __attr_unused__) +static void +rpa_generate(const char *plaintext, const char *user __attr_unused__, + const unsigned char **raw_password_r, size_t *size_r) { - return strcasecmp(password, password_generate_rpa(plaintext)) == 0; -} + unsigned char *digest; -static const char *rpa_generate(const char *plaintext, - const char *user __attr_unused__) -{ - return password_generate_rpa(plaintext); + digest = t_malloc(MD5_RESULTLEN); + password_generate_rpa(plaintext, digest); + + *raw_password_r = digest; + *size_r = MD5_RESULTLEN; } static const struct password_scheme default_schemes[] = { - { "CRYPT", crypt_verify, crypt_generate }, - { "MD5", md5_crypt_verify, md5_crypt_generate }, - { "MD5-CRYPT", md5_crypt_verify, md5_crypt_generate }, - { "SHA", sha1_verify, sha1_generate }, - { "SHA1", sha1_verify, sha1_generate }, - { "SMD5", smd5_verify, smd5_generate }, - { "SSHA", ssha_verify, ssha_generate }, - { "PLAIN", plain_verify, plain_generate }, - { "CLEARTEXT", plain_verify, plain_generate }, - { "CRAM-MD5", cram_md5_verify, cram_md5_generate }, - { "HMAC-MD5", cram_md5_verify, cram_md5_generate }, - { "DIGEST-MD5", digest_md5_verify, digest_md5_generate }, - { "PLAIN-MD4", plain_md4_verify, plain_md4_generate }, - { "PLAIN-MD5", plain_md5_verify, plain_md5_generate }, - { "LDAP-MD5", plain_md5_verify, ldap_md5_generate }, - { "LANMAN", lm_verify, lm_generate }, - { "NTLM", ntlm_verify, ntlm_generate }, - { "OTP", otp_verify, otp_generate }, - { "SKEY", otp_verify, skey_generate }, - { "RPA", rpa_verify, rpa_generate }, - { NULL, NULL, NULL } + { "CRYPT", PW_ENCODING_NONE, 0, crypt_verify, crypt_generate }, + { "MD5", PW_ENCODING_NONE, 0, md5_crypt_verify, md5_crypt_generate }, + { "MD5-CRYPT", PW_ENCODING_NONE, 0, + md5_crypt_verify, md5_crypt_generate }, + { "SHA", PW_ENCODING_BASE64, SHA1_RESULTLEN, NULL, sha1_generate }, + { "SHA1", PW_ENCODING_BASE64, SHA1_RESULTLEN, NULL, sha1_generate }, + { "SMD5", PW_ENCODING_BASE64, 0, smd5_verify, smd5_generate }, + { "SSHA", PW_ENCODING_BASE64, 0, ssha_verify, ssha_generate }, + { "PLAIN", PW_ENCODING_NONE, 0, NULL, plain_generate }, + { "CLEARTEXT", PW_ENCODING_NONE, 0, NULL, plain_generate }, + { "CRAM-MD5", PW_ENCODING_HEX, 0, NULL, cram_md5_generate }, + { "HMAC-MD5", PW_ENCODING_HEX, CRAM_MD5_CONTEXTLEN, + NULL, cram_md5_generate }, + { "DIGEST-MD5", PW_ENCODING_HEX, MD5_RESULTLEN, + NULL, digest_md5_generate }, + { "PLAIN-MD4", PW_ENCODING_HEX, MD4_RESULTLEN, + NULL, plain_md4_generate }, + { "PLAIN-MD5", PW_ENCODING_HEX, MD5_RESULTLEN, + NULL, plain_md5_generate }, + { "LDAP-MD5", PW_ENCODING_BASE64, MD5_RESULTLEN, + NULL, plain_md5_generate }, + { "LANMAN", PW_ENCODING_HEX, LM_HASH_SIZE, NULL, lm_generate }, + { "NTLM", PW_ENCODING_HEX, NTLMSSP_HASH_SIZE, NULL, ntlm_generate }, + { "OTP", PW_ENCODING_NONE, 0, otp_verify, otp_generate }, + { "SKEY", PW_ENCODING_NONE, 0, otp_verify, skey_generate }, + { "RPA", PW_ENCODING_HEX, MD5_RESULTLEN, NULL, rpa_generate }, + + { NULL, 0, 0, NULL, NULL } }; void password_schemes_init(void)
--- a/src/auth/password-scheme.h Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/password-scheme.h Sun May 13 15:17:09 2007 +0300 @@ -1,43 +1,65 @@ #ifndef __PASSWORD_SCHEME_H #define __PASSWORD_SCHEME_H +enum password_encoding { + PW_ENCODING_NONE, + PW_ENCODING_BASE64, + PW_ENCODING_HEX +}; + struct password_scheme { const char *name; + enum password_encoding default_encoding; + /* If non-zero, this is the expected raw password length. + It can be used to automatically detect encoding between + hex and base64 encoded passwords. */ + unsigned int raw_password_len; - bool (*password_verify)(const char *plaintext, const char *password, - const char *user); - const char *(*password_generate)(const char *plaintext, - const char *user); + bool (*password_verify)(const char *plaintext, const char *user, + const unsigned char *raw_password, size_t size); + void (*password_generate)(const char *plaintext, const char *user, + const unsigned char **raw_password_r, + size_t *size_r); }; /* Returns 1 = matched, 0 = didn't match, -1 = unknown scheme */ -int password_verify(const char *plaintext, const char *password, - const char *scheme, const char *user); +int password_verify(const char *plaintext, const char *user, const char *scheme, + const unsigned char *raw_password, size_t size); /* Extracts scheme from password, or returns NULL if it isn't found. If auth_request is given, it's used for debug logging. */ const char *password_get_scheme(const char **password); -/* Create wanted password scheme out of plaintext password and username. */ -const char *password_generate(const char *plaintext, const char *user, - const char *scheme); +/* Decode encoded (base64/hex) password to raw form. Returns 1 if ok, + 0 if scheme is unknown, -1 if password is invalid. */ +int password_decode(const char *password, const char *scheme, + const unsigned char **raw_password_r, size_t *size_r); + +/* Create password with wanted scheme out of plaintext password and username. + Potential base64/hex directives are ignored in scheme. Returns FALSE if + the scheme is unknown. */ +bool password_generate(const char *plaintext, const char *user, + const char *scheme, + const unsigned char **raw_password_r, size_t *size_r); +/* Like above, but generate encoded passwords. If hex/base64 directive isn't + specified in the scheme, the default encoding for the scheme is used. + Returns FALSE if the scheme is unknown. */ +bool password_generate_encoded(const char *plaintext, const char *user, + const char *scheme, const char **password_r); + +/* Returns TRUE if schemes are equivalent. */ +bool password_scheme_is_alias(const char *scheme1, const char *scheme2); /* Iterate through the list of password schemes, returning names */ const char *password_list_schemes(const struct password_scheme **listptr); -/* Returns TRUE if schemes are equivalent. */ -bool password_scheme_is_alias(const char *scheme1, const char *scheme2); - void password_schemes_init(void); void password_schemes_deinit(void); /* INTERNAL: */ const char *password_generate_md5_crypt(const char *pw, const char *salt); -const char *password_generate_cram_md5(const char *pw); -const char *password_generate_lm(const char *pw); -const char *password_generate_ntlm(const char *pw); const char *password_generate_otp(const char *pw, const char *state, unsigned int algo); -const char *password_generate_rpa(const char *pw); +void password_generate_rpa(const char *pw, unsigned char result[]); #endif
--- a/src/auth/userdb-static.c Sun May 13 14:53:05 2007 +0300 +++ b/src/auth/userdb-static.c Sun May 13 15:17:09 2007 +0300 @@ -62,7 +62,8 @@ static void static_credentials_callback(enum passdb_result result, - const char *password __attr_unused__, + const unsigned char *credentials __attr_unused__, + size_t size __attr_unused__, struct auth_request *auth_request) { struct static_context *ctx = auth_request->context; @@ -116,7 +117,7 @@ auth_request->state = AUTH_REQUEST_STATE_MECH_CONTINUE; auth_request->context = ctx; - auth_request_lookup_credentials(auth_request, "CRYPT", + auth_request_lookup_credentials(auth_request, "", static_credentials_callback); } else { static_lookup_real(auth_request, callback);