[dovecot-cvs] dovecot/src/auth Makefile.am, 1.53, 1.54 auth-request.c, 1.98, 1.99 auth-request.h, 1.38, 1.39 auth-worker-client.c, 1.34, 1.35 mech-apop.c, 1.27, 1.28 mech-cram-md5.c, 1.29, 1.30 mech-digest-md5.c, 1.46, 1.47 mech-ntlm.c, 1.30, 1.31 mech-otp.c, 1.4, 1.5 mech-rpa.c, 1.32, 1.33 mech-skey.c, 1.4, 1.5 passdb-ldap.c, 1.62, 1.63 passdb-passwd-file.c, 1.31, 1.32 passdb.c, 1.50, 1.51 passdb.h, 1.40, 1.41 password-scheme-cram-md5.c, 1.5, NONE password-scheme-ntlm.c, 1.2, NONE password-scheme-rpa.c, 1.3, 1.4 password-scheme.c, 1.33, 1.34 password-scheme.h, 1.11, 1.12 userdb-static.c, 1.26, 1.27
tss at dovecot.org
tss at dovecot.org
Sun May 13 15:17:12 EEST 2007
Update of /var/lib/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv10070
Modified Files:
Makefile.am auth-request.c auth-request.h auth-worker-client.c
mech-apop.c mech-cram-md5.c mech-digest-md5.c mech-ntlm.c
mech-otp.c mech-rpa.c mech-skey.c passdb-ldap.c
passdb-passwd-file.c passdb.c passdb.h password-scheme-rpa.c
password-scheme.c password-scheme.h userdb-static.c
Removed Files:
password-scheme-cram-md5.c password-scheme-ntlm.c
Log Message:
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.
Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -d -r1.53 -r1.54
--- Makefile.am 22 Feb 2007 21:50:47 -0000 1.53
+++ Makefile.am 13 May 2007 12:17:09 -0000 1.54
@@ -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
Index: auth-request.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-request.c,v
retrieving revision 1.98
retrieving revision 1.99
diff -u -d -r1.98 -r1.99
--- auth-request.c 13 May 2007 08:24:06 -0000 1.98
+++ auth-request.c 13 May 2007 12:17:09 -0000 1.99
@@ -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) {
Index: auth-request.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-request.h,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- auth-request.h 13 May 2007 08:24:06 -0000 1.38
+++ auth-request.h 13 May 2007 12:17:09 -0000 1.39
@@ -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,
Index: auth-worker-client.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-worker-client.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- auth-worker-client.c 13 May 2007 08:24:06 -0000 1.34
+++ auth-worker-client.c 13 May 2007 12:17:09 -0000 1.35
@@ -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);
Index: mech-apop.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-apop.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- mech-apop.c 13 May 2007 08:24:06 -0000 1.27
+++ mech-apop.c 13 May 2007 12:17:09 -0000 1.28
@@ -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);
Index: mech-cram-md5.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-cram-md5.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- mech-cram-md5.c 13 May 2007 10:18:51 -0000 1.29
+++ mech-cram-md5.c 13 May 2007 12:17:09 -0000 1.30
@@ -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);
Index: mech-digest-md5.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-digest-md5.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -d -r1.46 -r1.47
--- mech-digest-md5.c 13 May 2007 08:24:06 -0000 1.46
+++ mech-digest-md5.c 13 May 2007 12:17:09 -0000 1.47
@@ -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) {
- 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) {
+ if (size != MD5_RESULTLEN) {
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;
}
Index: mech-ntlm.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-ntlm.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- mech-ntlm.c 13 May 2007 08:24:06 -0000 1.30
+++ mech-ntlm.c 13 May 2007 12:17:09 -0000 1.31
@@ -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;
Index: mech-otp.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-otp.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- mech-otp.c 13 May 2007 08:24:06 -0000 1.4
+++ mech-otp.c 13 May 2007 12:17:09 -0000 1.5
@@ -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);
Index: mech-rpa.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-rpa.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- mech-rpa.c 13 May 2007 11:53:05 -0000 1.32
+++ mech-rpa.c 13 May 2007 12:17:09 -0000 1.33
@@ -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);
Index: mech-skey.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-skey.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- mech-skey.c 13 May 2007 08:24:06 -0000 1.4
+++ mech-skey.c 13 May 2007 12:17:09 -0000 1.5
@@ -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);
Index: passdb-ldap.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-ldap.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -d -r1.62 -r1.63
--- passdb-ldap.c 13 May 2007 08:24:06 -0000 1.62
+++ passdb-ldap.c 13 May 2007 12:17:09 -0000 1.63
@@ -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);
Index: passdb-passwd-file.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-passwd-file.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- passdb-passwd-file.c 8 Nov 2006 20:22:08 -0000 1.31
+++ passdb-passwd-file.c 13 May 2007 12:17:09 -0000 1.32
@@ -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;
}
Index: passdb.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- passdb.c 13 May 2007 08:24:06 -0000 1.50
+++ passdb.c 13 May 2007 12:17:09 -0000 1.51
@@ -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,
Index: passdb.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.h,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- passdb.h 13 May 2007 08:24:06 -0000 1.40
+++ passdb.h 13 May 2007 12:17:09 -0000 1.41
@@ -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,
--- password-scheme-cram-md5.c DELETED ---
--- password-scheme-ntlm.c DELETED ---
Index: password-scheme-rpa.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/password-scheme-rpa.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- password-scheme-rpa.c 8 Oct 2006 23:18:18 -0000 1.3
+++ password-scheme-rpa.c 13 May 2007 12:17:09 -0000 1.4
@@ -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));
}
Index: password-scheme.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/password-scheme.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- password-scheme.c 13 May 2007 11:30:16 -0000 1.33
+++ password-scheme.c 13 May 2007 12:17:09 -0000 1.34
@@ -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;
- for (s = schemes; s->name != NULL; s++) {
- if (strcasecmp(s->name, scheme) == 0)
- return s->password_generate(plaintext, user);
+ 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;
}
- return NULL;
+ 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;
}
-static bool crypt_verify(const char *plaintext, const char *password,
- const char *user __attr_unused__)
+bool password_generate(const char *plaintext, const char *user,
+ const char *scheme,
+ const unsigned char **raw_password_r, size_t *size_r)
{
- return strcmp(mycrypt(plaintext, password), password) == 0;
+ 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;
}
-static const char *crypt_generate(const char *plaintext,
- const char *user __attr_unused__)
+bool password_generate_encoded(const char *plaintext, const char *user,
+ const char *scheme, const char **password_r)
{
- char salt[9];
+ const struct password_scheme *s;
+ const unsigned char *raw_password;
+ enum password_encoding encoding;
+ string_t *str;
+ size_t size;
- random_fill(salt, 2);
- 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));
+ 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;
}
-static bool md5_crypt_verify(const char *plaintext, const char *password,
- const char *user __attr_unused__)
+bool password_scheme_is_alias(const char *scheme1, const char *scheme2)
{
- const char *str;
+ const struct password_scheme *s, *s1 = NULL, *s2 = NULL;
- str = password_generate_md5_crypt(plaintext, password);
- return strcmp(str, password) == 0;
+ 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, scheme1) == 0)
+ s1 = s;
+ else if (strcasecmp(s->name, scheme2) == 0)
+ s2 = s;
+ }
+
+ /* if they've the same generate function, they're equivalent */
+ return s1 != NULL && s2 != NULL &&
+ s1->password_generate == s2->password_generate;
}
-static const char *md5_crypt_generate(const char *plaintext,
- 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)
{
- char salt[9];
- int i;
+ const char *password;
- random_fill(salt, 8);
- for (i = 0; i < 8; i++)
- salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
- salt[8] = '\0';
- return password_generate_md5_crypt(plaintext, salt);
+ password = t_strndup(raw_password, size);
+ return strcmp(mycrypt(plaintext, password), password) == 0;
}
-static const char *sha1_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)
{
- unsigned char digest[SHA1_RESULTLEN];
- string_t *str;
+ char salt[3];
+ const char *password;
- 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);
+ 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';
+
+ password = t_strdup(mycrypt(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 bool
+md5_crypt_verify(const char *plaintext, const char *user __attr_unused__,
+ const unsigned char *raw_password, size_t size)
{
- buffer_t *buf;
- size_t len;
+ const char *password, *str;
- len = strlen(password);
- if (len == result_len*2) {
- /* hex-encoded */
- buf = buffer_create_static_hard(pool_datastack_create(),
- result_len);
+ password = t_strndup(raw_password, size);
+ str = password_generate_md5_crypt(plaintext, password);
+ return strcmp(str, password) == 0;
+}
- 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));
+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];
+ unsigned int i;
- if (base64_decode(password, len, NULL, buf) < 0)
- return NULL;
- }
+ 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[sizeof(salt)-1] = '\0';
- return buf->used != result_len ? NULL : buf->data;
+ password = password_generate_md5_crypt(plaintext, salt);
+ *raw_password_r = (const unsigned char *)password;
+ *size_r = strlen(password);
}
-static bool sha1_verify(const char *plaintext, const char *password,
- const char *user)
+static void
+sha1_generate(const char *plaintext, const char *user __attr_unused__,
+ const unsigned char **raw_password_r, size_t *size_r)
{
- unsigned char sha1_digest[SHA1_RESULTLEN];
- const char *data;
-
- sha1_get_digest(plaintext, strlen(plaintext), sha1_digest);
+ unsigned char *digest;
- data = password_decode(password, SHA1_RESULTLEN);
- if (data == NULL) {
- i_error("sha1_verify(%s): Invalid password encoding", user);
- return 0;
- }
+ digest = t_malloc(SHA1_RESULTLEN);
+ sha1_get_digest(plaintext, strlen(plaintext), digest);
- return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0;
+ *raw_password_r = digest;
+ *size_r = SHA1_RESULTLEN;
}
-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;
-}
-
-static const char *plain_generate(const char *plaintext,
- const char *user __attr_unused__)
-{
- 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;
+ return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0;
}
-static const char *cram_md5_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 password_generate_cram_md5(plaintext);
+ *raw_password_r = (const unsigned char *)plaintext,
+ *size_r = strlen(plaintext);
}
-static bool digest_md5_verify(const char *plaintext, const char *password,
- const char *user)
+static void
+cram_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];
- const char *realm, *str;
-
- /* user:realm:passwd */
- realm = strchr(user, '@');
- if (realm != NULL) realm++; else realm = "";
+ struct hmac_md5_context ctx;
+ unsigned char *context_digest;
- str = t_strconcat(t_strcut(user, '@'), ":", realm, ":",
- plaintext, NULL);
- md5_get_digest(str, strlen(str), digest);
- str = binary_to_hex(digest, sizeof(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);
- return strcasecmp(str, password) == 0;
+ *raw_password_r = context_digest;
+ *size_r = CRAM_MD5_CONTEXTLEN;
}
-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__)
+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[MD4_RESULTLEN];
+ unsigned char *digest;
+ digest = t_malloc(MD4_RESULTLEN);
md4_get_digest(plaintext, strlen(plaintext), digest);
- return binary_to_hex(digest, sizeof(digest));
+
+ *raw_password_r = digest;
+ *size_r = MD4_RESULTLEN;
}
-static bool plain_md5_verify(const char *plaintext, const char *password,
- const char *user)
+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];
- const void *data;
+ unsigned char *digest;
+ digest = t_malloc(MD5_RESULTLEN);
md5_get_digest(plaintext, strlen(plaintext), 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;
+ *raw_password_r = digest;
+ *size_r = MD5_RESULTLEN;
}
-static const char *plain_md5_generate(const char *plaintext,
- 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)
{
- 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(LM_HASH_SIZE);
+ lm_hash(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 = LM_HASH_SIZE;
}
-static bool lm_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_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(NTLMSSP_HASH_SIZE);
+ ntlm_v1_hash(plaintext, digest);
-static bool ntlm_verify(const char *plaintext, const char *password,
- const char *user __attr_unused__)
-{
- return strcasecmp(password, password_generate_ntlm(plaintext)) == 0;
+ *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;
-static const char *skey_generate(const char *plaintext,
- const char *user __attr_unused__)
-{
- return password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
+ password = password_generate_otp(plaintext, NULL, OTP_HASH_SHA1);
+ *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
+skey_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;
+ const char *password;
+
+ password = password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
+ *raw_password_r = (const unsigned char *)password;
+ *size_r = strlen(password);
}
-static const char *rpa_generate(const char *plaintext,
- 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 password_generate_rpa(plaintext);
+ unsigned char *digest;
+
+ 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)
Index: password-scheme.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/password-scheme.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- password-scheme.h 13 May 2007 08:24:06 -0000 1.11
+++ password-scheme.h 13 May 2007 12:17:09 -0000 1.12
@@ -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);
-/* Iterate through the list of password schemes, returning names */
-const char *password_list_schemes(const struct password_scheme **listptr);
+/* 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);
+
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
Index: userdb-static.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/userdb-static.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- userdb-static.c 13 May 2007 08:24:06 -0000 1.26
+++ userdb-static.c 13 May 2007 12:17:09 -0000 1.27
@@ -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);
More information about the dovecot-cvs
mailing list