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