Deleted Added
full compact
apr_passwd.c (253734) apr_passwd.c (272076)
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
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
69/*
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.
75 */
76APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
77 const char *hash)
78{
79 char sample[200];
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];
80#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
86#if !CRYPT_MISSING
81 char *crypt_pw;
82#endif
83 if (hash[0] == '$'
84 && hash[1] == '2'
85 && (hash[2] == 'a' || hash[2] == 'y')
86 && hash[3] == '$') {
87 if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL)
88 return APR_FROM_OS_ERROR(errno);
89 }
90 else if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
91 /*
92 * The hash was created using our custom algorithm.
93 */
94 apr_md5_encode(passwd, hash, sample, sizeof(sample));
95 }
96 else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
97 apr_sha1_base64(passwd, (int)strlen(passwd), sample);
98 }
99 else {
100 /*
101 * It's not our algorithm, so feed it to crypt() if possible.
102 */
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 */
103#if defined(WIN32) || defined(BEOS) || defined(NETWARE)
109#if CRYPT_MISSING
104 return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
105#elif defined(CRYPT_R_CRYPTD)
106 apr_status_t rv;
107 CRYPTD *buffer = malloc(sizeof(*buffer));
108
109 if (buffer == NULL)
110 return APR_ENOMEM;
111 crypt_pw = crypt_r(passwd, hash, buffer);
112 if (!crypt_pw)
113 rv = APR_EMISMATCH;
114 else
115 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
116 free(buffer);
117 return rv;
118#elif defined(CRYPT_R_STRUCT_CRYPT_DATA)
119 apr_status_t rv;
120 struct crypt_data *buffer = malloc(sizeof(*buffer));
121
122 if (buffer == NULL)
123 return APR_ENOMEM;
124
125#ifdef __GLIBC_PREREQ
126 /*
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.
130 */
131#if __GLIBC_PREREQ(2,4)
132#define USE_CRYPT_DATA_INITALIZED
133#endif
134#endif
135
136#ifdef USE_CRYPT_DATA_INITALIZED
137 buffer->initialized = 0;
138#else
139 memset(buffer, 0, sizeof(*buffer));
140#endif
141
142 crypt_pw = crypt_r(passwd, hash, buffer);
143 if (!crypt_pw)
144 rv = APR_EMISMATCH;
145 else
146 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
147 free(buffer);
148 return rv;
149#else
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
153 * choice being made.
154 */
155#if defined(_AIX) && APR_HAS_THREADS
156#error Configuration error! crypt_r() should have been selected!
157#endif
158 {
159 apr_status_t rv;
160
161 /* Handle thread safety issues by holding a mutex around the
162 * call to crypt().
163 */
164 crypt_mutex_lock();
165 crypt_pw = crypt(passwd, hash);
166 if (!crypt_pw) {
167 rv = APR_EMISMATCH;
168 }
169 else {
170 rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
171 }
172 crypt_mutex_unlock();
173 return rv;
174 }
175#endif
176 }
177 return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
178}
179
180static const char * const bcrypt_id = "$2y$";
181APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw,
182 unsigned int count,
183 const unsigned char *salt,
184 apr_size_t salt_len,
185 char *out, apr_size_t out_len)
186{
187 char setting[40];
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);
193 return APR_SUCCESS;
194}
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}