]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
89ae997be99d84bfc4daedda137be8ee546a8027
[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 <lber.h>
25
26 #include "lutil_md5.h"
27 #include "lutil_sha1.h"
28 #include "lutil.h"
29
30 #ifdef HAVE_SHADOW_H
31 #       include <shadow.h>
32 #endif
33 #ifdef HAVE_PWD_H
34 #       include <pwd.h>
35 #endif
36
37 struct pw_scheme;
38
39 typedef int (*PASSWD_CHK_FUNC)(
40         const struct pw_scheme *scheme,
41         const char *passwd,
42         const char *cred );
43
44 typedef char * (*PASSWD_GEN_FUNC) (
45         const struct pw_scheme *scheme,
46         const char *passwd );
47
48 struct pw_scheme {
49         char *name;
50         size_t namelen;
51         PASSWD_CHK_FUNC chk_fn;
52         PASSWD_GEN_FUNC gen_fn;
53 };
54
55 /* password check routines */
56 static int chk_md5(
57         const struct pw_scheme *scheme,
58         const char *passwd,
59         const char *cred );
60
61 static int chk_smd5(
62         const struct pw_scheme *scheme,
63         const char *passwd,
64         const char *cred );
65
66 static int chk_ssha1(
67         const struct pw_scheme *scheme,
68         const char *passwd,
69         const char *cred );
70
71 static int chk_sha1(
72         const struct pw_scheme *scheme,
73         const char *passwd,
74         const char *cred );
75
76 static int chk_crypt(
77         const struct pw_scheme *scheme,
78         const char *passwd,
79         const char *cred );
80
81 static int chk_unix(
82         const struct pw_scheme *scheme,
83         const char *passwd,
84         const char *cred );
85
86
87 /* password generation routines */
88 static char *gen_sha1(
89         const struct pw_scheme *scheme,
90         const char *passwd );
91
92 static char *gen_ssha1(
93         const struct pw_scheme *scheme,
94         const char *passwd );
95
96 static char *gen_smd5(
97         const struct pw_scheme *scheme,
98         const char *passwd );
99
100 static char *gen_md5(
101         const struct pw_scheme *scheme,
102         const char *passwd );
103
104 static char *gen_crypt(
105         const struct pw_scheme *scheme,
106         const char *passwd );
107
108
109 static const struct pw_scheme pw_schemes[] =
110 {
111         { "{SSHA}", sizeof("{SSHA}")-1, chk_ssha1, gen_ssha1 },
112         { "{SHA}", sizeof("{SHA}")-1, chk_sha1, gen_sha1 },
113
114         { "{SMD5}", sizeof("{SMD5}")-1, chk_smd5, gen_smd5 },
115         { "{MD5}", sizeof("{MD5}")-1, chk_md5, gen_md5 },
116
117 #ifdef SLAPD_CRYPT
118         { "{CRYPT}", sizeof("{CRYPT}")-1, chk_crypt, gen_crypt },
119 #endif
120 # if defined( HAVE_GETSPNAM ) \
121   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
122         { "{UNIX}",     sizeof("{UNIX}")-1, chk_unix, NULL },
123 #endif
124
125 #ifdef SLAPD_CLEARTEXT
126         /* psuedo scheme */
127         { "{CLEARTEXT}", 0, NULL, NULL },
128 #endif
129
130         NULL,
131 };
132
133 static const struct pw_scheme *get_scheme(
134         const char* scheme )
135 {
136         int i;
137
138         for( i=0; pw_schemes[i].name != NULL; i++) {
139                 if( pw_schemes[i].namelen == 0 ) continue;
140
141                 if( strncasecmp(scheme, pw_schemes[i].name,
142                         pw_schemes[i].namelen) == 0 )
143                 {
144                         return &pw_schemes[i];
145                 }
146         }
147
148         return NULL;
149 }
150
151
152 static int is_allowed_scheme( 
153         const char* scheme,
154         const char** schemes )
155 {
156         int i;
157
158         if( schemes == NULL ) return 1;
159
160         for( i=0; schemes[i] != NULL; i++ ) {
161                 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
162                         return 1;
163                 }
164         }
165         return 0;
166 }
167
168 static const char *passwd_scheme(
169         const struct pw_scheme *scheme,
170         const char* passwd,
171         const char** allowed )
172 {
173         if( !is_allowed_scheme( scheme->name, allowed ) ) {
174                 return NULL;
175         }
176
177         if( strncasecmp( passwd, scheme->name, scheme->namelen ) == 0 ) {
178                 return &passwd[scheme->namelen];
179         }
180
181         return NULL;
182 }
183
184 /*
185  * Return 0 if creds are good.
186  */
187 int
188 lutil_passwd(
189         const char *passwd,     /* stored passwd */
190         const char *cred,       /* user cred */
191         const char **schemes )
192 {
193         int i;
194
195         if (cred == NULL || passwd == NULL) {
196                 return -1;
197         }
198
199         for( i=0; pw_schemes[i].name != NULL; i++ ) {
200                 if( pw_schemes[i].chk_fn ) {
201                         const char *p = passwd_scheme( &pw_schemes[i],
202                                 passwd, schemes );
203
204                         if( p != NULL ) {
205                                 return (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred );
206                         }
207                 }
208         }
209
210 #ifdef SLAPD_CLEARTEXT
211         if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
212                 return strcmp( cred, passwd );
213         }
214 #else
215         return 1;
216 #endif
217
218 }
219
220 char * lutil_passwd_generate(
221         const char * passwd,
222         const char * method )
223 {
224         const struct pw_scheme *sc = get_scheme( method );
225
226         if( sc == NULL ) return NULL;
227         if( ! sc->gen_fn ) return NULL;
228
229         return (sc->gen_fn)( sc, passwd );
230 }
231
232 static char * pw_string(
233         const struct pw_scheme *sc,
234         const char *passwd)
235 {
236         size_t pwlen = strlen( passwd );
237         char *pw = ber_memalloc( sc->namelen + pwlen + 1 );
238
239         if( pw == NULL ) return NULL;
240
241         memcpy( pw, sc->name, sc->namelen );
242         memcpy( &pw[sc->namelen], passwd, pwlen );
243         pw[sc->namelen + pwlen] = '\0';
244
245         return pw;
246 }
247
248 static char * pw_string64(
249         const struct pw_scheme *sc,
250         const unsigned char *hash, size_t hashlen,
251         const unsigned char *salt, size_t saltlen )
252 {
253         int rc;
254         char *string = NULL;
255         size_t b64len;
256         size_t len = hashlen + saltlen;
257         char *b64;
258
259         if( saltlen ) {
260                 /* need to base64 combined string */
261                 string = ber_memalloc( hashlen + saltlen );
262
263                 if( string == NULL ) {
264                         return NULL;
265                 }
266
267                 memcpy( string, hash, len );
268                 memcpy( &string[len], salt, saltlen );
269
270         } else {
271                 string = (char *) hash;
272         }
273
274         b64len = LUTIL_BASE64_ENCODE_LEN( len ) + 1;
275         b64 = ber_memalloc( b64len + sc->namelen );
276
277         if( b64 == NULL ) {
278                 if( saltlen ) ber_memfree( string );
279                 return NULL;
280         }
281
282         memcpy(b64, sc->name, sc->namelen);
283
284         rc = lutil_b64_ntop( string, len, &b64[sc->namelen], b64len );
285
286         if( saltlen ) ber_memfree( string );
287
288         if( rc < 0 ) {
289                 free( b64 );
290                 return NULL;
291         }
292
293         return b64;
294 }
295
296 /* PASSWORD CHECK ROUTINES */
297
298 static int chk_ssha1(
299         const struct pw_scheme *sc,
300         const char* passwd,
301         const char* cred )
302 {
303         lutil_SHA1_CTX SHA1context;
304         unsigned char SHA1digest[20];
305         int pw_len = strlen(passwd);
306         int rc;
307         unsigned char *orig_pass = NULL;
308  
309         /* base64 un-encode password */
310         orig_pass = (unsigned char *) malloc( (size_t) (
311                 LUTIL_BASE64_DECODE_LEN(pw_len) + 1) );
312
313         if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) {
314                 free(orig_pass);
315                 return 1;
316         }
317  
318         /* hash credentials with salt */
319         lutil_SHA1Init(&SHA1context);
320         lutil_SHA1Update(&SHA1context,
321                 (const unsigned char *) cred, strlen(cred));
322         lutil_SHA1Update(&SHA1context,
323                 (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
324                 rc - sizeof(SHA1digest));
325         lutil_SHA1Final(SHA1digest, &SHA1context);
326  
327         /* compare */
328         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
329         free(orig_pass);
330         return rc;
331 }
332
333 static int chk_sha1(
334         const struct pw_scheme *sc,
335         const char* passwd,
336         const char* cred )
337 {
338         lutil_SHA1_CTX SHA1context;
339         unsigned char SHA1digest[20];
340         char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(SHA1digest))+1]; 
341
342         lutil_SHA1Init(&SHA1context);
343         lutil_SHA1Update(&SHA1context,
344                 (const unsigned char *) cred, strlen(cred));
345         lutil_SHA1Final(SHA1digest, &SHA1context);
346
347         if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest),
348                 base64digest, sizeof(base64digest)) < 0)
349         {
350                 return 1;
351         }
352
353         return strcmp(passwd, base64digest);
354 }
355
356 static int chk_smd5(
357         const struct pw_scheme *sc,
358         const char* passwd,
359         const char* cred )
360 {
361         lutil_MD5_CTX MD5context;
362         unsigned char MD5digest[16];
363         int pw_len = strlen(passwd);
364         int rc;
365         unsigned char *orig_pass = NULL;
366
367         /* base64 un-encode password */
368         orig_pass = (unsigned char *) malloc( (size_t) (
369                 LUTIL_BASE64_DECODE_LEN(pw_len) + 1) );
370
371         if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) {
372                 free(orig_pass);
373                 return 1;
374         }
375
376         /* hash credentials with salt */
377         lutil_MD5Init(&MD5context);
378         lutil_MD5Update(&MD5context,
379                 (const unsigned char *) cred, strlen(cred));
380         lutil_MD5Update(&MD5context,
381                 (const unsigned char *) &orig_pass[sizeof(MD5digest)],
382                 rc - sizeof(MD5digest));
383         lutil_MD5Final(MD5digest, &MD5context);
384
385         /* compare */
386         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
387         free(orig_pass);
388         return rc;
389 }
390
391 static int chk_md5(
392         const struct pw_scheme *sc,
393         const char* passwd,
394         const char* cred )
395 {
396         lutil_MD5_CTX MD5context;
397         unsigned char MD5digest[16];
398         char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(MD5digest))+1]; 
399
400         lutil_MD5Init(&MD5context);
401         lutil_MD5Update(&MD5context,
402                 (const unsigned char *)cred, strlen(cred));
403         lutil_MD5Final(MD5digest, &MD5context);
404
405         if ( lutil_b64_ntop(MD5digest, sizeof(MD5digest),
406                 base64digest, sizeof(base64digest)) < 0 )
407         {
408                 return 1;
409         }
410
411         return strcmp(passwd, base64digest);
412 }
413
414 #ifdef SLAPD_CRYPT
415 static int chk_crypt(
416         const struct pw_scheme *sc,
417         const char* passwd,
418         const char* cred )
419 {
420         return strcmp(passwd, crypt(cred, passwd));
421 }
422
423 # if defined( HAVE_GETSPNAM ) \
424   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
425 static int chk_unix(
426         const struct pw_scheme *sc,
427         const char* cred,
428         const char* p )
429 {
430 #  ifdef HAVE_GETSPNAM
431         struct spwd *spwd = getspnam(p);
432
433         if(spwd == NULL) {
434                 return 1;       /* not found */
435         }
436
437         return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp));
438 #  else
439         struct passwd *pwd = getpwnam(p);
440
441         if(pwd == NULL) {
442                 return 1;       /* not found */
443         }
444
445         return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd));
446 #  endif
447 # endif
448 }
449 #endif
450
451 /* PASSWORD CHECK ROUTINES */
452 static char *gen_ssha1(
453         const struct pw_scheme *scheme,
454         const char *passwd )
455 {
456         lutil_SHA1_CTX  SHA1context;
457         unsigned char   SHA1digest[20];
458         unsigned char   salt[4];
459
460         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
461                 return NULL; 
462         }
463
464         lutil_SHA1Init( &SHA1context );
465         lutil_SHA1Update( &SHA1context,
466                 (const unsigned char *)passwd, strlen(passwd) );
467         lutil_SHA1Update( &SHA1context,
468                 (const unsigned char *)salt, sizeof(salt) );
469         lutil_SHA1Final( SHA1digest, &SHA1context );
470
471         return pw_string64( scheme,
472                 SHA1digest, sizeof(SHA1digest),
473                 salt, sizeof(salt));
474 }
475
476 static char *gen_sha1(
477         const struct pw_scheme *scheme,
478         const char *passwd )
479 {
480         lutil_SHA1_CTX  SHA1context;
481         unsigned char   SHA1digest[20];
482      
483         lutil_SHA1Init( &SHA1context );
484         lutil_SHA1Update( &SHA1context,
485                 (const unsigned char *)passwd, strlen(passwd) );
486         lutil_SHA1Final( SHA1digest, &SHA1context );
487             
488         return pw_string64( scheme,
489                 SHA1digest, sizeof(SHA1digest),
490                 NULL, 0);
491 }
492
493 static char *gen_smd5(
494         const struct pw_scheme *scheme,
495         const char *passwd )
496 {
497         lutil_MD5_CTX   MD5context;
498         unsigned char   MD5digest[16];
499         unsigned char   salt[4];
500
501         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
502                 return NULL; 
503         }
504
505         lutil_MD5Init( &MD5context );
506         lutil_MD5Update( &MD5context,
507                 (const unsigned char *) passwd, strlen(passwd) );
508
509         lutil_MD5Update( &MD5context,
510                 (const unsigned char *) salt, sizeof(salt) );
511
512         lutil_MD5Final( MD5digest, &MD5context );
513
514         return pw_string64( scheme,
515                 MD5digest, sizeof(MD5digest),
516                 salt, sizeof(salt) );
517 }
518
519 static char *gen_md5(
520         const struct pw_scheme *scheme,
521         const char *passwd )
522 {
523         lutil_MD5_CTX   MD5context;
524         unsigned char   MD5digest[16];
525
526         lutil_MD5Init( &MD5context );
527         lutil_MD5Update( &MD5context,
528                 (const unsigned char *) passwd, strlen(passwd) );
529
530         lutil_MD5Final( MD5digest, &MD5context );
531
532         return pw_string64( scheme,
533                 MD5digest, sizeof(MD5digest),
534                 NULL, 0 );
535 }
536
537 #ifdef SLAPD_CRYPT
538 static char *gen_crypt(
539         const struct pw_scheme *scheme,
540         const char *passwd )
541 {
542         static const unsigned char crypt64[] =
543                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
544
545         char *hash = NULL;
546         unsigned char salt[2];
547
548         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
549                 return NULL; 
550         }
551
552         salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
553         salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
554
555         hash = crypt( passwd, salt );
556
557         if( hash = NULL ) return NULL;
558
559         return pw_string( scheme, hash );
560 }
561 #endif