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