/* * Validate a plaintext password against a smashed one. Uses either * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending * upon the format of the smashed input password. Returns APR_SUCCESS if * they match, or APR_EMISMATCH if they don't. If the platform doesn't * support crypt, then the default check is against a clear text string. */ APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, const char *hash) { char sample[200]; #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char *crypt_pw; #endif if (hash[0] == '$' && hash[1] == '2' && (hash[2] == 'a' || hash[2] == 'y') && hash[3] == '$') { if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) return APR_FROM_OS_ERROR(errno); } else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { /* * The hash was created using our custom algorithm. */ apr_md5_encode(passwd, hash, sample, sizeof(sample)); } else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { apr_sha1_base64(passwd, (int)strlen(passwd), sample); } else { /* * It's not our algorithm, so feed it to crypt() if possible. */ #if defined(WIN32) || defined(BEOS) || defined(NETWARE) return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_CRYPTD) apr_status_t rv; CRYPTD *buffer = malloc(sizeof(*buffer)); if (buffer == NULL) return APR_ENOMEM; crypt_pw = crypt_r(passwd, hash, buffer); if (!crypt_pw) rv = APR_EMISMATCH; else rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; free(buffer); return rv; #elif defined(CRYPT_R_STRUCT_CRYPT_DATA) apr_status_t rv; struct crypt_data *buffer = malloc(sizeof(*buffer)); if (buffer == NULL) return APR_ENOMEM; #ifdef __GLIBC_PREREQ /* * For not too old glibc (>= 2.3.2), it's enough to set * buffer.initialized = 0. For < 2.3.2 and for other platforms, * we need to zero the whole struct. */ #if __GLIBC_PREREQ(2,4) #define USE_CRYPT_DATA_INITALIZED #endif #endif #ifdef USE_CRYPT_DATA_INITALIZED buffer->initialized = 0; #else memset(buffer, 0, sizeof(*buffer)); #endif crypt_pw = crypt_r(passwd, hash, buffer); if (!crypt_pw) rv = APR_EMISMATCH; else rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; free(buffer); return rv; #else /* Do a bit of sanity checking since we know that crypt_r() * should always be used for threaded builds on AIX, and * problems in configure logic can result in the wrong * choice being made. */ #if defined(_AIX) && APR_HAS_THREADS #error Configuration error! crypt_r() should have been selected! #endif { apr_status_t rv; /* Handle thread safety issues by holding a mutex around the * call to crypt(). */ crypt_mutex_lock(); crypt_pw = crypt(passwd, hash); if (!crypt_pw) { rv = APR_EMISMATCH; } else { rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; } crypt_mutex_unlock(); return rv; } #endif } return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; }
/* * Validate a plaintext password against a smashed one. Uses either * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending * upon the format of the smashed input password. Returns APR_SUCCESS if * they match, or APR_EMISMATCH if they don't. If the platform doesn't * support crypt, then the default check is against a clear text string. */ APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, const char *hash) { char sample[200]; #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char *crypt_pw; #endif if (hash[0] == '$') { if (hash[1] == '2' && (hash[2] == 'a' || hash[2] == 'y') && hash[3] == '$') { if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) return APR_FROM_OS_ERROR(errno); } else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { /* * The hash was created using our custom algorithm. */ apr_md5_encode(passwd, hash, sample, sizeof(sample)); } } else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { apr_sha1_base64(passwd, (int)strlen(passwd), sample); } else { /* * It's not our algorithm, so feed it to crypt() if possible. */ #if defined(WIN32) || defined(BEOS) || defined(NETWARE) return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_CRYPTD) CRYPTD buffer; crypt_pw = crypt_r(passwd, hash, &buffer); if (!crypt_pw) { return APR_EMISMATCH; } return (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_STRUCT_CRYPT_DATA) struct crypt_data buffer; #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,4) buffer.initialized = 0; #else /* * glibc before 2.3.2 had a bug that required clearing the * whole struct */ memset(&buffer, 0, sizeof(buffer)); #endif crypt_pw = crypt_r(passwd, hash, &buffer); if (!crypt_pw) { return APR_EMISMATCH; } return (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #else /* Do a bit of sanity checking since we know that crypt_r() * should always be used for threaded builds on AIX, and * problems in configure logic can result in the wrong * choice being made. */ #if defined(_AIX) && APR_HAS_THREADS #error Configuration error! crypt_r() should have been selected! #endif { apr_status_t rv; /* Handle thread safety issues by holding a mutex around the * call to crypt(). */ crypt_mutex_lock(); crypt_pw = crypt(passwd, hash); if (!crypt_pw) { rv = APR_EMISMATCH; } else { rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; } crypt_mutex_unlock(); return rv; } #endif } return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; }