| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "apr_strings.h" |
| #include "apr_md5.h" |
| #include "apr_lib.h" |
| #include "apr_private.h" |
| #include "apr_sha1.h" |
| #include "crypt_blowfish.h" |
| |
| #if APR_HAVE_STRING_H |
| #include <string.h> |
| #endif |
| #if APR_HAVE_CRYPT_H |
| #include <crypt.h> |
| #endif |
| #if APR_HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #if APR_HAVE_PTHREAD_H |
| #include <pthread.h> |
| #endif |
| #if APR_HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| |
| static const char * const apr1_id = "$apr1$"; |
| |
| #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) |
| #if defined(APU_CRYPT_THREADSAFE) || !APR_HAS_THREADS || \ |
| defined(CRYPT_R_CRYPTD) || defined(CRYPT_R_STRUCT_CRYPT_DATA) |
| |
| #define crypt_mutex_lock() |
| #define crypt_mutex_unlock() |
| |
| #elif APR_HAVE_PTHREAD_H && defined(PTHREAD_MUTEX_INITIALIZER) |
| |
| static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; |
| static void crypt_mutex_lock(void) |
| { |
| pthread_mutex_lock(&crypt_mutex); |
| } |
| |
| static void crypt_mutex_unlock(void) |
| { |
| pthread_mutex_unlock(&crypt_mutex); |
| } |
| |
| #elif defined(OS2) |
| |
| static HMTX crypt_mutex = 0; |
| static void crypt_mutex_lock() |
| { |
| if (crypt_mutex == 0) { |
| /* Prevent race condition where two threads could try to create the |
| * mutex concurrently |
| */ |
| DosEnterCritSec(); |
| |
| if (crypt_mutex == 0) { |
| DosCreateMutexSem(NULL, &crypt_mutex, 0, FALSE); |
| } |
| |
| DosExitCritSec(); |
| } |
| |
| DosRequestMutexSem(crypt_mutex, SEM_INDEFINITE_WAIT); |
| } |
| |
| static void crypt_mutex_unlock() |
| { |
| DosReleaseMutexSem(crypt_mutex); |
| } |
| |
| #else |
| |
| #error apr_password_validate() is not threadsafe. rebuild APR without thread support. |
| |
| #endif |
| #endif |
| |
| #if defined(WIN32) || defined(BEOS) || defined(NETWARE) || defined(__ANDROID__) |
| #define CRYPT_MISSING 1 |
| #else |
| #define CRYPT_MISSING 0 |
| #endif |
| |
| /* |
| * 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. |
| */ |
| APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd, |
| const char *hash) |
| { |
| char sample[200]; |
| #if !CRYPT_MISSING |
| 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 CRYPT_MISSING |
| 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; |
| } |
| |
| static const char * const bcrypt_id = "$2y$"; |
| APR_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw, |
| unsigned int count, |
| const unsigned char *salt, |
| apr_size_t salt_len, |
| char *out, apr_size_t out_len) |
| { |
| char setting[40]; |
| if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt, |
| salt_len, setting, sizeof(setting)) == NULL) |
| return APR_FROM_OS_ERROR(errno); |
| if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL) |
| return APR_FROM_OS_ERROR(errno); |
| return APR_SUCCESS; |
| } |