1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_strings.h" 18#include "apr_md5.h" 19#include "apr_lib.h" 20#include "apr_sha1.h" 21#include "apu_config.h" 22#include "crypt_blowfish.h" 23 24#if APR_HAVE_STRING_H 25#include <string.h> 26#endif 27#if APR_HAVE_CRYPT_H 28#include <crypt.h> 29#endif 30#if APR_HAVE_UNISTD_H 31#include <unistd.h> 32#endif 33#if APR_HAVE_PTHREAD_H 34#include <pthread.h> 35#endif 36#if APR_HAVE_STDLIB_H 37#include <stdlib.h> 38#endif 39 40static const char * const apr1_id = "$apr1$"; 41 42#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) 43#if defined(APU_CRYPT_THREADSAFE) || !APR_HAS_THREADS || \ 44 defined(CRYPT_R_CRYPTD) || defined(CRYPT_R_STRUCT_CRYPT_DATA) 45 46#define crypt_mutex_lock() 47#define crypt_mutex_unlock() 48 49#elif APR_HAVE_PTHREAD_H && defined(PTHREAD_MUTEX_INITIALIZER) 50 51static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; 52static void crypt_mutex_lock(void) 53{ 54 pthread_mutex_lock(&crypt_mutex); 55} 56 57static void crypt_mutex_unlock(void) 58{ 59 pthread_mutex_unlock(&crypt_mutex); 60} 61 62#else 63 64#error apr_password_validate() is not threadsafe. rebuild APR without thread support. 65 66#endif 67#endif 68 69#if defined(WIN32) || defined(BEOS) || defined(NETWARE) || defined(__ANDROID__) 70#define CRYPT_MISSING 1 71#else 72#define CRYPT_MISSING 0 73#endif 74 75/* 76 * Validate a plaintext password against a smashed one. Uses either 77 * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending 78 * upon the format of the smashed input password. Returns APR_SUCCESS if 79 * they match, or APR_EMISMATCH if they don't. If the platform doesn't 80 * support crypt, then the default check is against a clear text string. 81 */ 82APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, 83 const char *hash) 84{ 85 char sample[200]; 86#if !CRYPT_MISSING 87 char *crypt_pw; 88#endif 89 if (hash[0] == '$' 90 && hash[1] == '2' 91 && (hash[2] == 'a' || hash[2] == 'y') 92 && hash[3] == '$') { 93 if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) 94 return APR_FROM_OS_ERROR(errno); 95 } 96 else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { 97 /* 98 * The hash was created using our custom algorithm. 99 */ 100 apr_md5_encode(passwd, hash, sample, sizeof(sample)); 101 } 102 else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { 103 apr_sha1_base64(passwd, (int)strlen(passwd), sample); 104 } 105 else { 106 /* 107 * It's not our algorithm, so feed it to crypt() if possible. 108 */ 109#if CRYPT_MISSING 110 return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; 111#elif defined(CRYPT_R_CRYPTD) 112 apr_status_t rv; 113 CRYPTD *buffer = malloc(sizeof(*buffer)); 114 115 if (buffer == NULL) 116 return APR_ENOMEM; 117 crypt_pw = crypt_r(passwd, hash, buffer); 118 if (!crypt_pw) 119 rv = APR_EMISMATCH; 120 else 121 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; 122 free(buffer); 123 return rv; 124#elif defined(CRYPT_R_STRUCT_CRYPT_DATA) 125 apr_status_t rv; 126 struct crypt_data *buffer = malloc(sizeof(*buffer)); 127 128 if (buffer == NULL) 129 return APR_ENOMEM; 130 131#ifdef __GLIBC_PREREQ 132 /* 133 * For not too old glibc (>= 2.3.2), it's enough to set 134 * buffer.initialized = 0. For < 2.3.2 and for other platforms, 135 * we need to zero the whole struct. 136 */ 137#if __GLIBC_PREREQ(2,4) 138#define USE_CRYPT_DATA_INITALIZED 139#endif 140#endif 141 142#ifdef USE_CRYPT_DATA_INITALIZED 143 buffer->initialized = 0; 144#else 145 memset(buffer, 0, sizeof(*buffer)); 146#endif 147 148 crypt_pw = crypt_r(passwd, hash, buffer); 149 if (!crypt_pw) 150 rv = APR_EMISMATCH; 151 else 152 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; 153 free(buffer); 154 return rv; 155#else 156 /* Do a bit of sanity checking since we know that crypt_r() 157 * should always be used for threaded builds on AIX, and 158 * problems in configure logic can result in the wrong 159 * choice being made. 160 */ 161#if defined(_AIX) && APR_HAS_THREADS 162#error Configuration error! crypt_r() should have been selected! 163#endif 164 { 165 apr_status_t rv; 166 167 /* Handle thread safety issues by holding a mutex around the 168 * call to crypt(). 169 */ 170 crypt_mutex_lock(); 171 crypt_pw = crypt(passwd, hash); 172 if (!crypt_pw) { 173 rv = APR_EMISMATCH; 174 } 175 else { 176 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; 177 } 178 crypt_mutex_unlock(); 179 return rv; 180 } 181#endif 182 } 183 return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; 184} 185 186static const char * const bcrypt_id = "$2y$"; 187APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw, 188 unsigned int count, 189 const unsigned char *salt, 190 apr_size_t salt_len, 191 char *out, apr_size_t out_len) 192{ 193 char setting[40]; 194 if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt, 195 salt_len, setting, sizeof(setting)) == NULL) 196 return APR_FROM_OS_ERROR(errno); 197 if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL) 198 return APR_FROM_OS_ERROR(errno); 199 return APR_SUCCESS; 200} 201