changeset 12978:62945c9d6b47

auth: Don't log warnings/errors when guessing a password's scheme.
author Timo Sirainen <tss@iki.fi>
date Mon, 23 May 2011 15:38:16 +0300
parents 9490d57d2f7b
children 93c41a60f894
files src/auth/password-scheme-otp.c src/auth/password-scheme.c src/auth/password-scheme.h
diffstat 3 files changed, 88 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/password-scheme-otp.c	Mon May 23 15:37:43 2011 +0300
+++ b/src/auth/password-scheme-otp.c	Mon May 23 15:38:16 2011 +0300
@@ -12,16 +12,14 @@
 #include "randgen.h"
 #include "otp.h"
 
-const char *password_generate_otp(const char *pw, const char *data,
-				  unsigned int algo)
+int password_generate_otp(const char *pw, const char *data,
+			  unsigned int algo, const char **result_r)
 {
 	struct otp_state state;
 
 	if (data != NULL) {
-		if (otp_parse_dbentry(data, &state) != 0) {
-			i_warning("Invalid OTP data in passdb");
-			return "";
-		}
+		if (otp_parse_dbentry(data, &state) != 0)
+			return -1;
 	} else {
 		/* Generate new OTP credentials from plaintext */
 		unsigned char random_data[OTP_MAX_SEED_LEN / 2];
@@ -35,6 +33,6 @@
 	}
 
 	otp_hash(state.algo, state.seed, pw, state.seq, state.hash);
-
-	return otp_print_dbentry(&state);
+	*result_r = otp_print_dbentry(&state);
+	return 0;
 }
--- a/src/auth/password-scheme.c	Mon May 23 15:37:43 2011 +0300
+++ b/src/auth/password-scheme.c	Mon May 23 15:38:16 2011 +0300
@@ -74,7 +74,8 @@
 }
 
 int password_verify(const char *plaintext, const char *user, const char *scheme,
-		    const unsigned char *raw_password, size_t size)
+		    const unsigned char *raw_password, size_t size,
+		    const char **error_r)
 {
 	const struct password_scheme *s;
 	enum password_encoding encoding;
@@ -82,17 +83,21 @@
 	size_t generated_size;
 
 	s = password_scheme_lookup(scheme, &encoding);
-	if (s == NULL)
+	if (s == NULL) {
+		*error_r = "Unknown password scheme";
 		return -1;
+	}
 
-	if (s->password_verify != NULL)
-		return s->password_verify(plaintext, user, raw_password, size);
+	if (s->password_verify != NULL) {
+		return s->password_verify(plaintext, user, raw_password, size,
+					  error_r);
+	}
 
 	/* 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;
+		memcmp(generated, raw_password, size) == 0 ? 1 : 0;
 }
 
 const char *password_get_scheme(const char **password)
@@ -272,6 +277,7 @@
 	unsigned int i, count;
 	const unsigned char *raw_password;
 	size_t raw_password_size;
+	const char *error;
 
 	schemes = array_get(&password_schemes, &count);
 	for (i = 0; i < count; i++) {
@@ -280,31 +286,33 @@
 			continue;
 
 		if (password_verify(plain_password, user, schemes[i]->name,
-				    raw_password, raw_password_size) > 0)
+				    raw_password, raw_password_size,
+				    &error) > 0)
 			return schemes[i]->name;
 	}
 	return NULL;
 }
 
-bool crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
-		  const unsigned char *raw_password, size_t size)
+int crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
+		 const unsigned char *raw_password, size_t size,
+		 const char **error_r)
 {
 	const char *password, *crypted;
 
 	if (size == 0) {
 		/* the default mycrypt() handler would return match */
-		return FALSE;
+		return 0;
 	}
 
 	password = t_strndup(raw_password, size);
 	crypted = mycrypt(plaintext, password);
 	if (crypted == NULL) {
 		/* really shouldn't happen unless the system is broken */
-		i_error("crypt() failed: %m");
-		return FALSE;
+		*error_r = t_strdup_printf("crypt() failed: %m");
+		return -1;
 	}
 
-	return strcmp(crypted, password) == 0;
+	return strcmp(crypted, password) == 0 ? 1 : 0;
 }
 
 static void
@@ -320,9 +328,9 @@
 	*size_r = strlen(password);
 }
 
-static bool
+static int
 md5_verify(const char *plaintext, const char *user,
-	   const unsigned char *raw_password, size_t size)
+	   const unsigned char *raw_password, size_t size, const char **error_r)
 {
 	const char *password, *str;
 	const unsigned char *md5_password;
@@ -332,27 +340,27 @@
 	if (strncmp(password, "$1$", 3) == 0) {
 		/* MD5-CRYPT */
 		str = password_generate_md5_crypt(plaintext, password);
-		return strcmp(str, password) == 0;
+		return strcmp(str, password) == 0 ? 1 : 0;
 	} else if (password_decode(password, "PLAIN-MD5",
 				   &md5_password, &md5_size) < 0) {
-		i_error("md5_verify(%s): Not a valid MD5-CRYPT or "
-			"PLAIN-MD5 password", user);
-		return FALSE;
+		*error_r = "Not a valid MD5-CRYPT or PLAIN-MD5 password";
+		return -1;
 	} else {
 		return password_verify(plaintext, user, "PLAIN-MD5",
-				       md5_password, md5_size) > 0;
+				       md5_password, md5_size, error_r);
 	}
 }
 
-static bool
+static int
 md5_crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
-		 const unsigned char *raw_password, size_t size)
+		 const unsigned char *raw_password, size_t size,
+		 const char **error_r ATTR_UNUSED)
 {
 	const char *password, *str;
 
 	password = t_strndup(raw_password, size);
 	str = password_generate_md5_crypt(plaintext, password);
-	return strcmp(str, password) == 0;
+	return strcmp(str, password) == 0 ? 1 : 0;
 }
 
 static void
@@ -433,23 +441,24 @@
 	*size_r = SHA1_RESULTLEN + SSHA_SALT_LEN;
 }
 
-static bool ssha_verify(const char *plaintext, const char *user,
-			const unsigned char *raw_password, size_t size)
+static int ssha_verify(const char *plaintext, const char *user ATTR_UNUSED,
+		       const unsigned char *raw_password, size_t size,
+		       const char **error_r)
 {
 	unsigned char sha1_digest[SHA1_RESULTLEN];
 	struct sha1_ctxt ctx;
 
 	/* format: <SHA1 hash><salt> */
 	if (size <= SHA1_RESULTLEN) {
-		i_error("ssha_verify(%s): SSHA password too short", user);
-		return FALSE;
+		*error_r = "SSHA password is too short";
+		return -1;
 	}
 
 	sha1_init(&ctx);
 	sha1_loop(&ctx, plaintext, strlen(plaintext));
 	sha1_loop(&ctx, raw_password + SHA1_RESULTLEN, size - SHA1_RESULTLEN);
 	sha1_result(&ctx, sha1_digest);
-	return memcmp(sha1_digest, raw_password, SHA1_RESULTLEN) == 0;
+	return memcmp(sha1_digest, raw_password, SHA1_RESULTLEN) == 0 ? 1 : 0;
 }
 
 static void
@@ -473,16 +482,17 @@
 	*size_r = SHA256_RESULTLEN + SSHA256_SALT_LEN;
 }
 
-static bool ssha256_verify(const char *plaintext, const char *user,
-			   const unsigned char *raw_password, size_t size)
+static int ssha256_verify(const char *plaintext, const char *user ATTR_UNUSED,
+			  const unsigned char *raw_password, size_t size,
+			  const char **error_r)
 {
 	unsigned char sha256_digest[SHA256_RESULTLEN];
 	struct sha256_ctx ctx;
 
 	/* format: <SHA256 hash><salt> */
 	if (size <= SHA256_RESULTLEN) {
-		i_error("ssha256_verify(%s): SSHA256 password too short", user);
-		return FALSE;
+		*error_r = "SSHA256 password is too short";
+		return -1;
 	}
 
 	sha256_init(&ctx);
@@ -490,7 +500,8 @@
 	sha256_loop(&ctx, raw_password + SHA256_RESULTLEN,
 		    size - SHA256_RESULTLEN);
 	sha256_result(&ctx, sha256_digest);
-	return memcmp(sha256_digest, raw_password, SHA256_RESULTLEN) == 0;
+	return memcmp(sha256_digest, raw_password,
+		      SHA256_RESULTLEN) == 0 ? 1 : 0;
 }
 
 static void
@@ -514,16 +525,17 @@
 	*size_r = SHA512_RESULTLEN + SSHA512_SALT_LEN;
 }
 
-static bool ssha512_verify(const char *plaintext, const char *user,
-			   const unsigned char *raw_password, size_t size)
+static int ssha512_verify(const char *plaintext, const char *user ATTR_UNUSED,
+			  const unsigned char *raw_password, size_t size,
+			  const char **error_r)
 {
 	unsigned char sha512_digest[SHA512_RESULTLEN];
 	struct sha512_ctx ctx;
 
 	/* format: <SHA512 hash><salt> */
 	if (size <= SHA512_RESULTLEN) {
-		i_error("ssha512_verify(%s): SSHA512 password too short", user);
-		return FALSE;
+		*error_r = "SSHA512 password is too short";
+		return -1;
 	}
 
 	sha512_init(&ctx);
@@ -531,7 +543,8 @@
 	sha512_loop(&ctx, raw_password + SHA512_RESULTLEN,
 		    size - SHA512_RESULTLEN);
 	sha512_result(&ctx, sha512_digest);
-	return memcmp(sha512_digest, raw_password, SHA512_RESULTLEN) == 0;
+	return memcmp(sha512_digest, raw_password,
+		      SHA512_RESULTLEN) == 0 ? 1 : 0;
 }
 
 static void
@@ -555,23 +568,24 @@
 	*size_r = MD5_RESULTLEN + SMD5_SALT_LEN;
 }
 
-static bool smd5_verify(const char *plaintext, const char *user,
-			const unsigned char *raw_password, size_t size)
+static int smd5_verify(const char *plaintext, const char *user ATTR_UNUSED,
+		       const unsigned char *raw_password, size_t size,
+		       const char **error_r)
 {
 	unsigned char md5_digest[MD5_RESULTLEN];
 	struct md5_context ctx;
 
 	/* format: <MD5 hash><salt> */
 	if (size <= MD5_RESULTLEN) {
-		i_error("smd5_verify(%s): SMD5 password too short", user);
-		return FALSE;
+		*error_r = "SMD5 password is too short";
+		return -1;
 	}
 
 	md5_init(&ctx);
 	md5_update(&ctx, plaintext, strlen(plaintext));
 	md5_update(&ctx, raw_password + MD5_RESULTLEN, size - MD5_RESULTLEN);
 	md5_final(&ctx, md5_digest);
-	return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0;
+	return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0 ? 1 : 0;
 }
 
 static void
@@ -680,14 +694,19 @@
 	*size_r = NTLMSSP_HASH_SIZE;
 }
 
-static bool otp_verify(const char *plaintext, const char *user ATTR_UNUSED,
-		       const unsigned char *raw_password, size_t size)
+static int otp_verify(const char *plaintext, const char *user ATTR_UNUSED,
+		      const unsigned char *raw_password, size_t size,
+		      const char **error_r)
 {
-	const char *password;
+	const char *password, *generated;
 
 	password = t_strndup(raw_password, size);
-	return strcasecmp(password,
-		password_generate_otp(plaintext, password, -1)) == 0;
+	if (password_generate_otp(plaintext, password, -1, &generated) < 0) {
+		*error_r = "Invalid OTP data in passdb";
+		return -1;
+	}
+
+	return strcasecmp(password, generated) == 0 ? 1 : 0;
 }
 
 static void
@@ -696,7 +715,8 @@
 {
 	const char *password;
 
-	password = password_generate_otp(plaintext, NULL, OTP_HASH_SHA1);
+	if (password_generate_otp(plaintext, NULL, OTP_HASH_SHA1, &password) < 0)
+		i_unreached();
 	*raw_password_r = (const unsigned char *)password;
 	*size_r = strlen(password);
 }
@@ -707,7 +727,8 @@
 {
 	const char *password;
 
-	password = password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
+	if (password_generate_otp(plaintext, NULL, OTP_HASH_MD4, &password) < 0)
+		i_unreached();
 	*raw_password_r = (const unsigned char *)password;
 	*size_r = strlen(password);
 }
--- a/src/auth/password-scheme.h	Mon May 23 15:37:43 2011 +0300
+++ b/src/auth/password-scheme.h	Mon May 23 15:38:16 2011 +0300
@@ -15,8 +15,9 @@
 	   hex and base64 encoded passwords. */
 	unsigned int raw_password_len;
 
-	bool (*password_verify)(const char *plaintext, const char *user,
-				const unsigned char *raw_password, size_t size);
+	int (*password_verify)(const char *plaintext, const char *user,
+			       const unsigned char *raw_password, size_t size,
+			       const char **error_r);
 	void (*password_generate)(const char *plaintext, const char *user,
 				  const unsigned char **raw_password_r,
 				  size_t *size_r);
@@ -25,9 +26,11 @@
 
 extern ARRAY_TYPE(password_scheme_p) password_schemes;
 
-/* Returns 1 = matched, 0 = didn't match, -1 = unknown scheme */
+/* Returns 1 = matched, 0 = didn't match, -1 = unknown scheme or invalid
+   raw_password */
 int password_verify(const char *plaintext, const char *user, const char *scheme,
-		    const unsigned char *raw_password, size_t size);
+		    const unsigned char *raw_password, size_t size,
+		    const char **error_r);
 
 /* Extracts scheme from password, or returns NULL if it isn't found.
    If auth_request is given, it's used for debug logging. */
@@ -72,12 +75,13 @@
 /* INTERNAL: */
 const char *password_generate_salt(size_t len);
 const char *password_generate_md5_crypt(const char *pw, const char *salt);
-const char *password_generate_otp(const char *pw, const char *state,
-				  unsigned int algo);
+int password_generate_otp(const char *pw, const char *state,
+			  unsigned int algo, const char **result_r);
 void password_generate_rpa(const char *pw, unsigned char result[]);
 
-bool crypt_verify(const char *plaintext, const char *user,
-		  const unsigned char *raw_password, size_t size);
+int crypt_verify(const char *plaintext, const char *user,
+		 const unsigned char *raw_password, size_t size,
+		 const char **error_r);
 
 /* check wich of the algorithms Blowfisch, SHA-256 and SHA-512 are
    supported by the used libc's/glibc's crypt() */