--- lib/checkpw.c.orig Tue Sep 9 11:38:13 2003 +++ lib/checkpw.c Wed Feb 4 10:45:33 2004 @@ -134,6 +134,9 @@ const char *service __attribute__((unused)), const char *user_realm __attribute__((unused))) { + char *salt = NULL; /* Buffer for MD5 salt from cryptstring */ + char *encryptedPass = NULL; /* Buffer for crypt()ed password */ + int i; /* Loop counter */ int ret = SASL_FAIL; char *userid = NULL; char *realm = NULL; @@ -182,20 +185,57 @@ /* At the point this has been called, the username has been canonified * and we've done the auxprop lookup. This should be easy. */ - if(auxprop_values[0].name - && auxprop_values[0].values - && auxprop_values[0].values[0] - && !strcmp(auxprop_values[0].values[0], passwd)) { + + /* BRUTAL hacks by jmalone@category4.com to support crypt()ed + * passwords as used in vpopmail. + * + * Basically, the format is MD5 salt (starts with $1$ and is 12 + * bytes long. We need to crypt the version supplied for checking + * so that it matches the password as stored in vpopmail's sql + * database. + * + * Based on pam_mysql.c by + * Gunay ARSLAN + * James O'Kane + * Steve Brown, + * B.J. Black, + * Kyle Smith, + */ + + encryptedPass = malloc(41); /* This is the hard pw size limit + * in vpopomail */ + salt = malloc(14); /* 12-byte salt + null + fudge factor */ + + if(salt == NULL || encryptedPass == NULL) { + /* Gotta do something here because there was a memory alloc + * problem. Ideally, we throw a meaningful error, but at + * least this prevents us from continuing and writing to bad + * memory + */ + return SASL_BADAUTH; + } + + if(auxprop_values[0].name && auxprop_values[0].values[0]) { + /* copy the salt out of the crypt string */ + strncpy(salt, auxprop_values[0].values[0], 12); + salt[12] = '\0'; + + /* create the crypt()ed version to compare against */ + strncpy(encryptedPass, crypt(passwd, salt), 40); + } + + if(encryptedPass && !strcmp(auxprop_values[0].values[0], encryptedPass)) { /* We have a plaintext version and it matched! */ - return SASL_OK; + ret = SASL_OK; + } else if(auxprop_values[1].name && auxprop_values[1].values && auxprop_values[1].values[0]) { const char *db_secret = auxprop_values[1].values[0]; sasl_secret_t *construct; - ret = _sasl_make_plain_secret(db_secret, passwd, - strlen(passwd), + ret = _sasl_make_plain_secret(db_secret, encryptedPass, + strlen(encryptedPass), &construct); if (ret != SASL_OK) { goto done; @@ -216,6 +256,14 @@ } done: + /* Clean up after Josh's hacks */ + free(salt); + + /* Don't just free it - forget it, too */ + for (i = strlen(encryptedPass); i >= 0; i--) + encryptedPass[i] = 0; + free(encryptedPass); + if (userid) sasl_FREE(userid); if (realm) sasl_FREE(realm);