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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "apr_strings.h"
21 #include "apu_config.h"
22 #include "crypt_blowfish.h"
33 #if APR_HAVE_PTHREAD_H
40 static const char * const apr1_id = "$apr1$";
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)
46 #define crypt_mutex_lock()
47 #define crypt_mutex_unlock()
49 #elif APR_HAVE_PTHREAD_H && defined(PTHREAD_MUTEX_INITIALIZER)
51 static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
52 static void crypt_mutex_lock(void)
54 pthread_mutex_lock(&crypt_mutex);
57 static void crypt_mutex_unlock(void)
59 pthread_mutex_unlock(&crypt_mutex);
64 #error apr_password_validate() is not threadsafe. rebuild APR without thread support.
69 #if defined(WIN32) || defined(BEOS) || defined(NETWARE) || defined(__ANDROID__)
70 #define CRYPT_MISSING 1
72 #define CRYPT_MISSING 0
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.
82 APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
91 && (hash[2] == 'a' || hash[2] == 'y')
93 if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL)
94 return APR_FROM_OS_ERROR(errno);
96 else if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
98 * The hash was created using our custom algorithm.
100 apr_md5_encode(passwd, hash, sample, sizeof(sample));
102 else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
103 apr_sha1_base64(passwd, (int)strlen(passwd), sample);
107 * It's not our algorithm, so feed it to crypt() if possible.
110 return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
111 #elif defined(CRYPT_R_CRYPTD)
113 CRYPTD *buffer = malloc(sizeof(*buffer));
117 crypt_pw = crypt_r(passwd, hash, buffer);
121 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
124 #elif defined(CRYPT_R_STRUCT_CRYPT_DATA)
126 struct crypt_data *buffer = malloc(sizeof(*buffer));
131 #ifdef __GLIBC_PREREQ
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.
137 #if __GLIBC_PREREQ(2,4)
138 #define USE_CRYPT_DATA_INITALIZED
142 #ifdef USE_CRYPT_DATA_INITALIZED
143 buffer->initialized = 0;
145 memset(buffer, 0, sizeof(*buffer));
148 crypt_pw = crypt_r(passwd, hash, buffer);
152 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
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
161 #if defined(_AIX) && APR_HAS_THREADS
162 #error Configuration error! crypt_r() should have been selected!
167 /* Handle thread safety issues by holding a mutex around the
171 crypt_pw = crypt(passwd, hash);
176 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
178 crypt_mutex_unlock();
183 return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
186 static const char * const bcrypt_id = "$2y$";
187 APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw,
189 const unsigned char *salt,
191 char *out, apr_size_t out_len)
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);