Mercurial > dovecot > core-2.2
changeset 1195:789b0346308e HEAD
crypt-password checking was broken. added support for md5crypt passwords.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 19 Feb 2003 13:28:56 +0200 |
parents | 31deba59422f |
children | eb2c2da659df |
files | src/auth/Makefile.am src/auth/md5crypt.c src/auth/md5crypt.h src/auth/password-scheme.c |
diffstat | 4 files changed, 182 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Tue Feb 18 22:58:30 2003 +0200 +++ b/src/auth/Makefile.am Wed Feb 19 13:28:56 2003 +0200 @@ -26,6 +26,7 @@ login-connection.c \ main.c \ master-connection.c \ + md5crypt.c \ mech.c \ mech-cyrus-sasl2.c \ mech-plain.c \ @@ -56,6 +57,7 @@ common.h \ login-connection.h \ master-connection.h \ + md5crypt.h \ mech.h \ mycrypt.h \ passdb.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/md5crypt.c Wed Feb 19 13:28:56 2003 +0200 @@ -0,0 +1,147 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* + * Ported from FreeBSD to Linux, only minimal changes. --marekm + */ + +/* + * Adapted from shadow-19990607 by Tudor Bosman, tudorb@jm.nu + */ + +#include "lib.h" +#include "md5.h" +#include "md5crypt.h" + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static char *magic = "$1$"; /* + * This string is magic for + * this algorithm. Having + * it this way, we can get + * get better later on + */ + +static void +to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ + +char * +md5_crypt(const char *pw, const char *salt) +{ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[16]; + int sl,pl,i,j; + struct md5_context ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + md5_init(&ctx); + + /* The password first, since that is what is most unknown */ + md5_update(&ctx,pw,strlen(pw)); + + /* Then our magic string */ + md5_update(&ctx,magic,strlen(magic)); + + /* Then the raw salt */ + md5_update(&ctx,sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + md5_init(&ctx1); + md5_update(&ctx1,pw,strlen(pw)); + md5_update(&ctx1,sp,sl); + md5_update(&ctx1,pw,strlen(pw)); + md5_final(&ctx1,final); + for(pl = strlen(pw); pl > 0; pl -= 16) + md5_update(&ctx,final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + /* Then something really weird... */ + for (j=0,i = strlen(pw); i ; i >>= 1) + if(i&1) + md5_update(&ctx, final+j, 1); + else + md5_update(&ctx, pw+j, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + md5_final(&ctx,final); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for(i=0;i<1000;i++) { + md5_init(&ctx1); + if(i & 1) + md5_update(&ctx1,pw,strlen(pw)); + else + md5_update(&ctx1,final,16); + + if(i % 3) + md5_update(&ctx1,sp,sl); + + if(i % 7) + md5_update(&ctx1,pw,strlen(pw)); + + if(i & 1) + md5_update(&ctx1,final,16); + else + md5_update(&ctx1,pw,strlen(pw)); + md5_final(&ctx1,final); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; + l = final[11] ; to64(p,l,2); p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + return passwd; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/md5crypt.h Wed Feb 19 13:28:56 2003 +0200 @@ -0,0 +1,6 @@ +#ifndef __MD5CRYPT_H +#define __MD5CRYPT_H + +char *md5_crypt(const char *pw, const char *salt); + +#endif
--- a/src/auth/password-scheme.c Tue Feb 18 22:58:30 2003 +0200 +++ b/src/auth/password-scheme.c Wed Feb 19 13:28:56 2003 +0200 @@ -3,10 +3,14 @@ #include "lib.h" #include "hex-binary.h" #include "md5.h" +#include "md5crypt.h" #include "mycrypt.h" #include "randgen.h" #include "password-scheme.h" +static const char *salt_chars = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + int password_verify(const char *plaintext, const char *password, const char *scheme, const char *user) { @@ -17,7 +21,10 @@ return 0; if (strcasecmp(scheme, "CRYPT") == 0) - return strcmp(mycrypt(password, plaintext), plaintext) == 0; + return strcmp(mycrypt(plaintext, password), password) == 0; + + if (strcasecmp(scheme, "MD5") == 0) + return strcmp(md5_crypt(plaintext, password), password) == 0; if (strcasecmp(scheme, "PLAIN") == 0) return strcmp(password, plaintext) == 0; @@ -48,7 +55,15 @@ { const char *p, *scheme; - if (*password == NULL || **password != '{') + if (*password == NULL) + return NULL; + + if (strncmp(*password, "$1$", 3) == 0) { + *password = t_strcut(*password + 3, '$'); + return "MD5"; + } + + if (**password != '{') return NULL; p = strchr(*password, '}'); @@ -63,11 +78,10 @@ const char *password_generate(const char *plaintext, const char *user, const char *scheme) { - static const char *salt_chars = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; const char *realm, *str; unsigned char digest[16]; - char salt[3]; + char salt[9]; + int i; if (strcasecmp(scheme, "CRYPT") == 0) { random_fill(salt, 2); @@ -77,6 +91,14 @@ return t_strdup(mycrypt(plaintext, salt)); } + if (strcasecmp(scheme, "MD5") == 0) { + random_fill(salt, 8); + for (i = 0; i < 8; i++) + salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)]; + salt[8] = '\0'; + return t_strdup(md5_crypt(plaintext, salt)); + } + if (strcasecmp(scheme, "PLAIN") == 0) return plaintext;