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.
70 * Validate a plaintext password against a smashed one. Uses either
71 * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending
72 * upon the format of the smashed input password. Returns APR_SUCCESS if
73 * they match, or APR_EMISMATCH if they don't. If the platform doesn't
74 * support crypt, then the default check is against a clear text string.
76 APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
80 #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
85 && (hash[2] == 'a' || hash[2] == 'y')
87 if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL)
88 return APR_FROM_OS_ERROR(errno);
90 else if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
92 * The hash was created using our custom algorithm.
94 apr_md5_encode(passwd, hash, sample, sizeof(sample));
96 else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
97 apr_sha1_base64(passwd, (int)strlen(passwd), sample);
101 * It's not our algorithm, so feed it to crypt() if possible.
103 #if defined(WIN32) || defined(BEOS) || defined(NETWARE)
104 return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
105 #elif defined(CRYPT_R_CRYPTD)
107 CRYPTD *buffer = malloc(sizeof(*buffer));
111 crypt_pw = crypt_r(passwd, hash, buffer);
115 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
118 #elif defined(CRYPT_R_STRUCT_CRYPT_DATA)
120 struct crypt_data *buffer = malloc(sizeof(*buffer));
125 #ifdef __GLIBC_PREREQ
127 * For not too old glibc (>= 2.3.2), it's enough to set
128 * buffer.initialized = 0. For < 2.3.2 and for other platforms,
129 * we need to zero the whole struct.
131 #if __GLIBC_PREREQ(2,4)
132 #define USE_CRYPT_DATA_INITALIZED
136 #ifdef USE_CRYPT_DATA_INITALIZED
137 buffer->initialized = 0;
139 memset(buffer, 0, sizeof(*buffer));
142 crypt_pw = crypt_r(passwd, hash, buffer);
146 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
150 /* Do a bit of sanity checking since we know that crypt_r()
151 * should always be used for threaded builds on AIX, and
152 * problems in configure logic can result in the wrong
155 #if defined(_AIX) && APR_HAS_THREADS
156 #error Configuration error! crypt_r() should have been selected!
161 /* Handle thread safety issues by holding a mutex around the
165 crypt_pw = crypt(passwd, hash);
170 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
172 crypt_mutex_unlock();
177 return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
180 static const char * const bcrypt_id = "$2y$";
181 APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw,
183 const unsigned char *salt,
185 char *out, apr_size_t out_len)
188 if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt,
189 salt_len, setting, sizeof(setting)) == NULL)
190 return APR_FROM_OS_ERROR(errno);
191 if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL)
192 return APR_FROM_OS_ERROR(errno);