]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
Move crypt(3) prototypes from <ac/unistd.h> to <ac/crypt.h> (new) to
[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[25];  /* ceiling(sizeof(input)/3) * 4 + 1 */
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[29];  /* ceiling(sizeof(input)/3) * 4 + 1 */
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)(pw_len * 0.75 + 1));
154                 if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0)
155                 {
156                         free(orig_pass);
157                         return ( 1 );
158                 }
159  
160                 /* hash credentials with salt */
161                 lutil_SHA1Init(&SHA1context);
162                 lutil_SHA1Update(&SHA1context,
163                                 (const unsigned char *) cred, strlen(cred));
164                 lutil_SHA1Update(&SHA1context,
165                                 (const unsigned char *) orig_pass + sizeof(SHA1digest),
166                                 rc - sizeof(SHA1digest));
167                 lutil_SHA1Final(SHA1digest, &SHA1context);
168  
169                 /* compare */
170                 rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
171                 free(orig_pass);
172                 return(rc);
173
174         } else if ((p = passwd_scheme( passwd, "{SMD5}", schemes )) != NULL ) {
175                 lutil_MD5_CTX MD5context;
176                 unsigned char MD5digest[16];
177                 int pw_len = strlen(p);
178                 int rc;
179                 unsigned char *orig_pass = NULL;
180
181                 /* base64 un-encode password */
182                 orig_pass = (unsigned char *)malloc((size_t)(pw_len * 0.75 + 1));
183                 if ((rc = lutil_b64_pton(p, orig_pass, pw_len)) < 0)
184                 {
185                         free(orig_pass);
186                         return ( 1 );
187                 }
188
189                 /* hash credentials with salt */
190                 lutil_MD5Init(&MD5context);
191                 lutil_MD5Update(&MD5context,
192                                 (const unsigned char *) cred, strlen(cred));
193                 lutil_MD5Update(&MD5context,
194                                 (const unsigned char *) orig_pass + sizeof(MD5digest),
195                                 rc - sizeof(MD5digest));
196                 lutil_MD5Final(MD5digest, &MD5context);
197
198                 /* compare */
199                 rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
200                 free(orig_pass);
201                 return ( rc );
202
203 #ifdef SLAPD_CRYPT
204         } else if ((p = passwd_scheme( passwd, "{CRYPT}", schemes )) != NULL ) {
205                 return( strcmp(p, crypt(cred, p)) );
206
207 # if defined( HAVE_GETSPNAM ) \
208   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
209         } else if ((p = passwd_scheme( passwd, "{UNIX}", schemes )) != NULL ) {
210
211 #  ifdef HAVE_GETSPNAM
212                 struct spwd *spwd = getspnam(p);
213
214                 if(spwd == NULL) {
215                         return 1;       /* not found */
216                 }
217
218                 return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp));
219 #  else
220                 struct passwd *pwd = getpwnam(p);
221
222                 if(pwd == NULL) {
223                         return 1;       /* not found */
224                 }
225
226                 return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd));
227 #  endif
228 # endif
229 #endif
230         }
231
232 #ifdef SLAPD_CLEARTEXT
233         return is_allowed_scheme("{CLEARTEXT}", schemes ) &&
234                 strcmp(passwd, cred) != 0;
235 #else
236         return( 1 );
237 #endif
238
239 }