]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr-util/crypto/apr_passwd.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr-util / crypto / apr_passwd.c
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
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 #else
63
64 #error apr_password_validate() is not threadsafe.  rebuild APR without thread support.
65
66 #endif
67 #endif
68
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  */
76 APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, 
77                                                 const char *hash)
78 {
79     char sample[200];
80 #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
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          */
103 #if defined(WIN32) || defined(BEOS) || defined(NETWARE)
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
180 static const char * const bcrypt_id = "$2y$";
181 APU_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 }