]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
cbe5e6fb132dd3ebc8a29058d2068e6f926adc09
[openldap] / libraries / liblutil / passwd.c
1 /*
2  * lutil_password(credentials, password)
3  *
4  * Returns true if user supplied credentials matches
5  * the stored password. 
6  *
7  * Due to the use of the crypt(3) function 
8  * this routine is NOT thread-safe.
9  */
10
11 #include "portable.h"
12
13 #include <ac/stdlib.h>
14
15 #include <ac/string.h>
16 #include <ac/unistd.h>
17
18 #include "lutil_md5.h"
19 #include "lutil_sha1.h"
20 #include "lutil.h"
21
22 #ifdef HAVE_SHADOW_H
23 #       include <shadow.h>
24 #endif
25 #ifdef HAVE_PWD_H
26 #       include <pwd.h>
27 #endif
28
29 static int supported_hash(
30         const char* method,
31         const char** methods )
32 {
33         int i;
34
35         if(methods == NULL) {
36                 return 1;
37         }
38
39         for(i=0; methods[i] != NULL; i++) {
40                 if(strcasecmp(method, methods[i]) == 0) {
41                         return 1;
42                 }
43         }
44
45         return 0;
46 }
47
48 static const char *passwd_hash(
49         const char* passwd,
50         const char* method,
51         const char** methods )
52 {
53         int len;
54
55         if( !supported_hash( method, methods ) ) {
56                 return NULL;
57         }
58
59         len = strlen(method);
60
61         if( strncasecmp( passwd, method, len ) == 0 ) {
62                 return &passwd[len];
63         }
64
65         return NULL;
66 }
67
68 /*
69  * Return 0 if creds are good.
70  */
71 int
72 lutil_passwd(
73         const char *cred,
74         const char *passwd,
75         const char **methods)
76 {
77         const char *p;
78
79         if (cred == NULL || passwd == NULL) {
80                 return -1;
81         }
82
83         if ((p = passwd_hash( passwd, "{MD5}", methods )) != NULL ) {
84                 lutil_MD5_CTX MD5context;
85                 unsigned char MD5digest[16];
86                 char base64digest[25];  /* ceiling(sizeof(input)/3) * 4 + 1 */
87
88                 lutil_MD5Init(&MD5context);
89                 lutil_MD5Update(&MD5context,
90                                (const unsigned char *)cred, strlen(cred));
91                 lutil_MD5Final(MD5digest, &MD5context);
92
93                 if ( lutil_b64_ntop(MD5digest, sizeof(MD5digest),
94                         base64digest, sizeof(base64digest)) < 0)
95                 {
96                         return ( 1 );
97                 }
98
99                 return( strcmp(p, base64digest) );
100
101         } else if ((p = passwd_hash( passwd, "{SHA}", methods )) != NULL ) {
102                 lutil_SHA1_CTX SHA1context;
103                 unsigned char SHA1digest[20];
104                 char base64digest[29];  /* ceiling(sizeof(input)/3) * 4 + 1 */
105
106                 lutil_SHA1Init(&SHA1context);
107                 lutil_SHA1Update(&SHA1context,
108                                 (const unsigned char *) cred, strlen(cred));
109                 lutil_SHA1Final(SHA1digest, &SHA1context);
110
111                 if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest),
112                         base64digest, sizeof(base64digest)) < 0)
113                 {
114                         return ( 1 );
115                 }
116
117                 return( strcmp(p, base64digest) );
118
119         } else if ((p = passwd_hash( passwd, "{SSHA}", methods )) != NULL ) {
120                 lutil_SHA1_CTX SHA1context;
121                 unsigned char SHA1digest[20];
122                 int pw_len = strlen(p);
123                 int rc;
124                 unsigned char *orig_pass = NULL;
125  
126                 /* base64 un-encode password */
127                 orig_pass = (unsigned char *)malloc((size_t)(pw_len * 0.75 + 1));
128                 if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0)
129                 {
130                         free(orig_pass);
131                         return ( 1 );
132                 }
133  
134                 /* hash credentials with salt */
135                 lutil_SHA1Init(&SHA1context);
136                 lutil_SHA1Update(&SHA1context,
137                                 (const unsigned char *) cred, strlen(cred));
138                 lutil_SHA1Update(&SHA1context,
139                                 (const unsigned char *) orig_pass + sizeof(SHA1digest),
140                                 rc - sizeof(SHA1digest));
141                 lutil_SHA1Final(SHA1digest, &SHA1context);
142  
143                 /* compare */
144                 rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
145                 free(orig_pass);
146                 return(rc);
147
148         } else if ((p = passwd_hash( passwd, "{SMD5}", methods )) != NULL ) {
149                 lutil_MD5_CTX MD5context;
150                 unsigned char MD5digest[16];
151                 int pw_len = strlen(p);
152                 int rc;
153                 unsigned char *orig_pass = NULL;
154
155                 /* base64 un-encode password */
156                 orig_pass = (unsigned char *)malloc((size_t)(pw_len * 0.75 + 1));
157                 if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0)
158                 {
159                         free(orig_pass);
160                         return ( 1 );
161                 }
162
163                 /* hash credentials with salt */
164                 lutil_MD5Init(&MD5context);
165                 lutil_MD5Update(&MD5context,
166                                 (const unsigned char *) cred, strlen(cred));
167                 lutil_MD5Update(&MD5context,
168                                 (const unsigned char *) orig_pass + sizeof(MD5digest),
169                                 rc - sizeof(MD5digest));
170                 lutil_MD5Final(MD5digest, &MD5context);
171
172                 /* compare */
173                 rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
174                 free(orig_pass);
175                 return ( rc );
176
177 #ifdef SLAPD_CRYPT
178         } else if ((p = passwd_hash( passwd, "{CRYPT}", methods )) != NULL ) {
179                 return( strcmp(p, crypt(cred, p)) );
180
181 # if defined( HAVE_GETSPNAM ) \
182   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
183         } else if ((p = passwd_hash( passwd, "{UNIX}", methods )) != NULL ) {
184
185 #  ifdef HAVE_GETSPNAM
186                 struct spwd *spwd = getspnam(p);
187
188                 if(spwd == NULL) {
189                         return 1;       /* not found */
190                 }
191
192                 return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp));
193 #  else
194                 struct passwd *pwd = getpwnam(p);
195
196                 if(pwd == NULL) {
197                         return 1;       /* not found */
198                 }
199
200                 return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd));
201 #  endif
202 # endif
203 #endif
204         }
205
206 #ifdef SLAPD_CLEARTEXT
207         return supported_hash("{CLEARTEXT}", methods ) &&
208                 strcmp(passwd, cred) != 0;
209 #else
210         return( 1 );
211 #endif
212
213 }