/src/httpd/srclib/apr/crypto/apr_passwd.c
Line | Count | Source (jump to first uncovered line) |
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_private.h" |
21 | | #include "apr_sha1.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 | | |
40 | | static 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 | | |
51 | | static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; |
52 | | static void crypt_mutex_lock(void) |
53 | | { |
54 | | pthread_mutex_lock(&crypt_mutex); |
55 | | } |
56 | | |
57 | | static void crypt_mutex_unlock(void) |
58 | | { |
59 | | pthread_mutex_unlock(&crypt_mutex); |
60 | | } |
61 | | |
62 | | #elif defined(OS2) |
63 | | |
64 | | static HMTX crypt_mutex = 0; |
65 | | static void crypt_mutex_lock() |
66 | | { |
67 | | if (crypt_mutex == 0) { |
68 | | /* Prevent race condition where two threads could try to create the |
69 | | * mutex concurrently |
70 | | */ |
71 | | DosEnterCritSec(); |
72 | | |
73 | | if (crypt_mutex == 0) { |
74 | | DosCreateMutexSem(NULL, &crypt_mutex, 0, FALSE); |
75 | | } |
76 | | |
77 | | DosExitCritSec(); |
78 | | } |
79 | | |
80 | | DosRequestMutexSem(crypt_mutex, SEM_INDEFINITE_WAIT); |
81 | | } |
82 | | |
83 | | static void crypt_mutex_unlock() |
84 | | { |
85 | | DosReleaseMutexSem(crypt_mutex); |
86 | | } |
87 | | |
88 | | #else |
89 | | |
90 | | #error apr_password_validate() is not threadsafe. rebuild APR without thread support. |
91 | | |
92 | | #endif |
93 | | #endif |
94 | | |
95 | | #if defined(WIN32) || defined(BEOS) || defined(NETWARE) || defined(__ANDROID__) |
96 | | #define CRYPT_MISSING 1 |
97 | | #else |
98 | | #define CRYPT_MISSING 0 |
99 | | #endif |
100 | | |
101 | | /* |
102 | | * Validate a plaintext password against a smashed one. Uses either |
103 | | * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending |
104 | | * upon the format of the smashed input password. Returns APR_SUCCESS if |
105 | | * they match, or APR_EMISMATCH if they don't. If the platform doesn't |
106 | | * support crypt, then the default check is against a clear text string. |
107 | | */ |
108 | | APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd, |
109 | | const char *hash) |
110 | 0 | { |
111 | 0 | char sample[200]; |
112 | 0 | #if !CRYPT_MISSING |
113 | 0 | char *crypt_pw; |
114 | 0 | #endif |
115 | 0 | if (hash[0] == '$' |
116 | 0 | && hash[1] == '2' |
117 | 0 | && (hash[2] == 'a' || hash[2] == 'y') |
118 | 0 | && hash[3] == '$') { |
119 | 0 | if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) |
120 | 0 | return APR_FROM_OS_ERROR(errno); |
121 | 0 | } |
122 | 0 | else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { |
123 | | /* |
124 | | * The hash was created using our custom algorithm. |
125 | | */ |
126 | 0 | apr_md5_encode(passwd, hash, sample, sizeof(sample)); |
127 | 0 | } |
128 | 0 | else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { |
129 | 0 | apr_sha1_base64(passwd, (int)strlen(passwd), sample); |
130 | 0 | } |
131 | 0 | else { |
132 | | /* |
133 | | * It's not our algorithm, so feed it to crypt() if possible. |
134 | | */ |
135 | | #if CRYPT_MISSING |
136 | | return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; |
137 | | #elif defined(CRYPT_R_CRYPTD) |
138 | | apr_status_t rv; |
139 | | CRYPTD *buffer = malloc(sizeof(*buffer)); |
140 | | |
141 | | if (buffer == NULL) |
142 | | return APR_ENOMEM; |
143 | | crypt_pw = crypt_r(passwd, hash, buffer); |
144 | | if (!crypt_pw) |
145 | | rv = APR_EMISMATCH; |
146 | | else |
147 | | rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; |
148 | | free(buffer); |
149 | | return rv; |
150 | | #elif defined(CRYPT_R_STRUCT_CRYPT_DATA) |
151 | 0 | apr_status_t rv; |
152 | 0 | struct crypt_data *buffer = malloc(sizeof(*buffer)); |
153 | |
|
154 | 0 | if (buffer == NULL) |
155 | 0 | return APR_ENOMEM; |
156 | | |
157 | 0 | #ifdef __GLIBC_PREREQ |
158 | | /* |
159 | | * For not too old glibc (>= 2.3.2), it's enough to set |
160 | | * buffer.initialized = 0. For < 2.3.2 and for other platforms, |
161 | | * we need to zero the whole struct. |
162 | | */ |
163 | 0 | #if __GLIBC_PREREQ(2,4) |
164 | 0 | #define USE_CRYPT_DATA_INITALIZED |
165 | 0 | #endif |
166 | 0 | #endif |
167 | | |
168 | 0 | #ifdef USE_CRYPT_DATA_INITALIZED |
169 | 0 | buffer->initialized = 0; |
170 | | #else |
171 | | memset(buffer, 0, sizeof(*buffer)); |
172 | | #endif |
173 | |
|
174 | 0 | crypt_pw = crypt_r(passwd, hash, buffer); |
175 | 0 | if (!crypt_pw) |
176 | 0 | rv = APR_EMISMATCH; |
177 | 0 | else |
178 | 0 | rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; |
179 | 0 | free(buffer); |
180 | 0 | return rv; |
181 | | #else |
182 | | /* Do a bit of sanity checking since we know that crypt_r() |
183 | | * should always be used for threaded builds on AIX, and |
184 | | * problems in configure logic can result in the wrong |
185 | | * choice being made. |
186 | | */ |
187 | | #if defined(_AIX) && APR_HAS_THREADS |
188 | | #error Configuration error! crypt_r() should have been selected! |
189 | | #endif |
190 | | { |
191 | | apr_status_t rv; |
192 | | |
193 | | /* Handle thread safety issues by holding a mutex around the |
194 | | * call to crypt(). |
195 | | */ |
196 | | crypt_mutex_lock(); |
197 | | crypt_pw = crypt(passwd, hash); |
198 | | if (!crypt_pw) { |
199 | | rv = APR_EMISMATCH; |
200 | | } |
201 | | else { |
202 | | rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; |
203 | | } |
204 | | crypt_mutex_unlock(); |
205 | | return rv; |
206 | | } |
207 | | #endif |
208 | 0 | } |
209 | 0 | return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; |
210 | 0 | } |
211 | | |
212 | | static const char * const bcrypt_id = "$2y$"; |
213 | | APR_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw, |
214 | | unsigned int count, |
215 | | const unsigned char *salt, |
216 | | apr_size_t salt_len, |
217 | | char *out, apr_size_t out_len) |
218 | 0 | { |
219 | 0 | char setting[40]; |
220 | 0 | if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt, |
221 | 0 | salt_len, setting, sizeof(setting)) == NULL) |
222 | 0 | return APR_FROM_OS_ERROR(errno); |
223 | 0 | if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL) |
224 | 0 | return APR_FROM_OS_ERROR(errno); |
225 | 0 | return APR_SUCCESS; |
226 | 0 | } |