]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
efab836b8742cb0bf43d16ecd1617cca248aaa9e
[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 <stdio.h>
19 #include <ac/stdlib.h>
20
21 #include <ac/string.h>
22 #include <ac/unistd.h>
23 #include <ac/crypt.h>
24
25 #include <lber.h>
26
27 #include "lutil_md5.h"
28 #include "lutil_sha1.h"
29 #include "lutil.h"
30
31 #ifdef HAVE_SHADOW_H
32 #       include <shadow.h>
33 #endif
34 #ifdef HAVE_PWD_H
35 #       include <pwd.h>
36 #endif
37
38 struct pw_scheme;
39
40 typedef int (*PASSWD_CHK_FUNC)(
41         const struct pw_scheme *scheme,
42         const struct berval *passwd,
43         const struct berval *cred );
44
45 typedef struct berval * (*PASSWD_GEN_FUNC) (
46         const struct pw_scheme *scheme,
47         const struct berval *passwd );
48
49 struct pw_scheme {
50         struct berval name;
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 struct berval *passwd,
59         const struct berval *cred );
60
61 static int chk_smd5(
62         const struct pw_scheme *scheme,
63         const struct berval *passwd,
64         const struct berval *cred );
65
66 static int chk_ssha1(
67         const struct pw_scheme *scheme,
68         const struct berval *passwd,
69         const struct berval *cred );
70
71 static int chk_sha1(
72         const struct pw_scheme *scheme,
73         const struct berval *passwd,
74         const struct berval *cred );
75
76 static int chk_crypt(
77         const struct pw_scheme *scheme,
78         const struct berval *passwd,
79         const struct berval *cred );
80
81 static int chk_unix(
82         const struct pw_scheme *scheme,
83         const struct berval *passwd,
84         const struct berval *cred );
85
86
87 /* password generation routines */
88 static struct berval *gen_sha1(
89         const struct pw_scheme *scheme,
90         const struct berval *passwd );
91
92 static struct berval *gen_ssha1(
93         const struct pw_scheme *scheme,
94         const struct berval *passwd );
95
96 static struct berval *gen_smd5(
97         const struct pw_scheme *scheme,
98         const struct berval *passwd );
99
100 static struct berval *gen_md5(
101         const struct pw_scheme *scheme,
102         const struct berval *passwd );
103
104 static struct berval *gen_crypt(
105         const struct pw_scheme *scheme,
106         const struct berval *passwd );
107
108
109 static const struct pw_scheme pw_schemes[] =
110 {
111         { {sizeof("{SSHA}")-1, "{SSHA}"},       chk_ssha1, gen_ssha1 },
112         { {sizeof("{SHA}")-1, "{SHA}"},         chk_sha1, gen_sha1 },
113
114         { {sizeof("{SMD5}")-1, "{SMD5}"},       chk_smd5, gen_smd5 },
115         { {sizeof("{MD5}")-1, "{MD5}"},         chk_md5, gen_md5 },
116
117 #ifdef SLAPD_CRYPT
118         { {sizeof("{CRYPT}")-1, "{CRYPT}"},     chk_crypt, gen_crypt },
119 #endif
120 # if defined( HAVE_GETSPNAM ) \
121   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
122         { {sizeof("{UNIX}")-1, "{UNIX}"},       chk_unix, NULL },
123 #endif
124
125 #ifdef SLAPD_CLEARTEXT
126         /* psuedo scheme */
127         { {0, "{CLEARTEXT}"}, NULL, NULL },
128 #endif
129
130         { {0, NULL}, NULL, 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.bv_val; i++) {
139                 if( pw_schemes[i].name.bv_len == 0 ) continue;
140
141                 if( strncasecmp(scheme, pw_schemes[i].name.bv_val,
142                         pw_schemes[i].name.bv_len) == 0 )
143                 {
144                         return &pw_schemes[i];
145                 }
146         }
147
148         return NULL;
149 }
150
151 int lutil_passwd_scheme(
152         const char* scheme )
153 {
154         if( scheme == NULL ) {
155                 return 0;
156         }
157
158         return get_scheme(scheme) != NULL;
159 }
160
161
162 static int is_allowed_scheme( 
163         const char* scheme,
164         const char** schemes )
165 {
166         int i;
167
168         if( schemes == NULL ) return 1;
169
170         for( i=0; schemes[i] != NULL; i++ ) {
171                 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
172                         return 1;
173                 }
174         }
175         return 0;
176 }
177
178 static struct berval *passwd_scheme(
179         const struct pw_scheme *scheme,
180         const struct berval * passwd,
181         const char** allowed )
182 {
183         if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) {
184                 return NULL;
185         }
186
187         if( passwd->bv_len >= scheme->name.bv_len ) {
188                 if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) {
189                         struct berval *bv = ber_memalloc( sizeof(struct berval) );
190
191                         if( bv == NULL ) return NULL;
192
193                         bv->bv_val = &passwd->bv_val[scheme->name.bv_len];
194                         bv->bv_len = passwd->bv_len - scheme->name.bv_len;
195
196                         return bv;
197                 }
198         }
199
200         return NULL;
201 }
202
203 /*
204  * Return 0 if creds are good.
205  */
206 int
207 lutil_passwd(
208         const struct berval *passwd,    /* stored passwd */
209         const struct berval *cred,              /* user cred */
210         const char **schemes )
211 {
212         int i;
213
214         if (cred == NULL || cred->bv_len == 0 ||
215                 passwd == NULL || passwd->bv_len == 0 )
216         {
217                 return -1;
218         }
219
220         for( i=0; pw_schemes[i].name.bv_val != NULL; i++ ) {
221                 if( pw_schemes[i].chk_fn ) {
222                         struct berval *p = passwd_scheme( &pw_schemes[i],
223                                 passwd, schemes );
224
225                         if( p != NULL ) {
226                                 int rc = (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred );
227
228                                 /* only free the berval structure as the bv_val points
229                                  * into passwd->bv_val
230                                  */
231                                 ber_memfree( p );
232                                 
233                                 return rc;
234                         }
235                 }
236         }
237
238 #ifdef SLAPD_CLEARTEXT
239         if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
240                 return passwd->bv_len == cred->bv_len
241                         ? memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
242                         : 1;
243         }
244 #else
245         return 1;
246 #endif
247
248 }
249
250 struct berval * lutil_passwd_generate(
251         const struct berval * passwd,
252         const char * method )
253 {
254         const struct pw_scheme *sc = get_scheme( method );
255
256         if( sc == NULL ) return NULL;
257         if( ! sc->gen_fn ) return NULL;
258
259         return (sc->gen_fn)( sc, passwd );
260 }
261
262 static struct berval * pw_string(
263         const struct pw_scheme *sc,
264         const struct berval *passwd )
265 {
266         struct berval *pw = ber_memalloc( sizeof( struct berval ) );
267         if( pw == NULL ) return NULL;
268
269         pw->bv_len = sc->name.bv_len + passwd->bv_len;
270         pw->bv_val = ber_memalloc( pw->bv_len + 1 );
271
272         if( pw->bv_val == NULL ) {
273                 ber_memfree( pw );
274                 return NULL;
275         }
276
277         memcpy( pw->bv_val, sc->name.bv_val, sc->name.bv_len );
278         memcpy( &pw->bv_val[sc->name.bv_len], passwd->bv_val, passwd->bv_len );
279
280         pw->bv_val[pw->bv_len] = '\0';
281         return pw;
282 }
283
284 static struct berval * pw_string64(
285         const struct pw_scheme *sc,
286         const struct berval *hash,
287         const struct berval *salt )
288 {
289         int rc;
290         struct berval string;
291         struct berval *b64 = ber_memalloc( sizeof(struct berval) );
292         size_t b64len;
293
294         if( b64 == NULL ) return NULL;
295
296         if( salt ) {
297                 /* need to base64 combined string */
298                 string.bv_len = hash->bv_len + salt->bv_len;
299                 string.bv_val = ber_memalloc( string.bv_len + 1 );
300
301                 if( string.bv_val == NULL ) {
302                         ber_memfree( b64 );
303                         return NULL;
304                 }
305
306                 memcpy( string.bv_val, hash->bv_val,
307                         hash->bv_len );
308                 memcpy( &string.bv_val[hash->bv_len], salt->bv_val,
309                         salt->bv_len );
310                 string.bv_val[string.bv_len] = '\0';
311
312         } else {
313                 string = *hash;
314         }
315
316         b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1;
317         b64->bv_len = b64len + sc->name.bv_len;
318         b64->bv_val = ber_memalloc( b64->bv_len + 1 );
319
320         if( b64->bv_val == NULL ) {
321                 if( salt ) ber_memfree( string.bv_val );
322                 ber_memfree( b64 );
323                 return NULL;
324         }
325
326         memcpy(b64->bv_val, sc->name.bv_val, sc->name.bv_len);
327
328         rc = lutil_b64_ntop(
329                 string.bv_val, string.bv_len,
330                 &b64->bv_val[sc->name.bv_len], b64len );
331
332         b64->bv_val[b64->bv_len] = '\0';
333
334         if( salt ) ber_memfree( string.bv_val );
335
336         if( rc < 0 ) {
337                 ber_bvfree( b64 );
338                 return NULL;
339         }
340
341         return b64;
342 }
343
344 /* PASSWORD CHECK ROUTINES */
345
346 static int chk_ssha1(
347         const struct pw_scheme *sc,
348         const struct berval * passwd,
349         const struct berval * cred )
350 {
351         lutil_SHA1_CTX SHA1context;
352         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
353         int rc;
354         unsigned char *orig_pass = NULL;
355  
356         /* base64 un-encode password */
357         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
358                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
359
360         if( orig_pass == NULL ) return -1;
361
362         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
363
364         if(rc < 0) {
365                 ber_memfree(orig_pass);
366                 return 1;
367         }
368  
369         /* hash credentials with salt */
370         lutil_SHA1Init(&SHA1context);
371         lutil_SHA1Update(&SHA1context,
372                 (const unsigned char *) cred->bv_val, cred->bv_len);
373         lutil_SHA1Update(&SHA1context,
374                 (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
375                 rc - sizeof(SHA1digest));
376         lutil_SHA1Final(SHA1digest, &SHA1context);
377  
378         /* compare */
379         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
380         ber_memfree(orig_pass);
381         return rc;
382 }
383
384 static int chk_sha1(
385         const struct pw_scheme *sc,
386         const struct berval * passwd,
387         const struct berval * cred )
388 {
389         lutil_SHA1_CTX SHA1context;
390         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
391         int rc;
392         unsigned char *orig_pass = NULL;
393  
394         /* base64 un-encode password */
395         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
396                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
397
398         if( orig_pass == NULL ) return -1;
399
400         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
401
402         if( rc != sizeof(SHA1digest) ) {
403                 ber_memfree(orig_pass);
404                 return 1;
405         }
406  
407         /* hash credentials with salt */
408         lutil_SHA1Init(&SHA1context);
409         lutil_SHA1Update(&SHA1context,
410                 (const unsigned char *) cred->bv_val, cred->bv_len);
411         lutil_SHA1Final(SHA1digest, &SHA1context);
412  
413         /* compare */
414         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
415         ber_memfree(orig_pass);
416         return rc;
417 }
418
419 static int chk_smd5(
420         const struct pw_scheme *sc,
421         const struct berval * passwd,
422         const struct berval * cred )
423 {
424         lutil_MD5_CTX MD5context;
425         unsigned char MD5digest[LUTIL_MD5_BYTES];
426         int rc;
427         unsigned char *orig_pass = NULL;
428
429         /* base64 un-encode password */
430         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
431                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
432
433         if( orig_pass == NULL ) return -1;
434
435         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
436         if ( rc < 0 ) {
437                 ber_memfree(orig_pass);
438                 return 1;
439         }
440
441         /* hash credentials with salt */
442         lutil_MD5Init(&MD5context);
443         lutil_MD5Update(&MD5context,
444                 (const unsigned char *) cred->bv_val, cred->bv_len );
445         lutil_MD5Update(&MD5context,
446                 (const unsigned char *) &orig_pass[sizeof(MD5digest)],
447                 rc - sizeof(MD5digest));
448         lutil_MD5Final(MD5digest, &MD5context);
449
450         /* compare */
451         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
452         ber_memfree(orig_pass);
453         return rc;
454 }
455
456 static int chk_md5(
457         const struct pw_scheme *sc,
458         const struct berval * passwd,
459         const struct berval * cred )
460 {
461         lutil_MD5_CTX MD5context;
462         unsigned char MD5digest[LUTIL_MD5_BYTES];
463         int rc;
464         unsigned char *orig_pass = NULL;
465
466         /* base64 un-encode password */
467         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
468                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
469
470         if( orig_pass == NULL ) return -1;
471
472         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
473         if ( rc != sizeof(MD5digest) ) {
474                 ber_memfree(orig_pass);
475                 return 1;
476         }
477
478         /* hash credentials with salt */
479         lutil_MD5Init(&MD5context);
480         lutil_MD5Update(&MD5context,
481                 (const unsigned char *) cred->bv_val, cred->bv_len );
482         lutil_MD5Final(MD5digest, &MD5context);
483
484         /* compare */
485         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
486         ber_memfree(orig_pass);
487         return rc;
488 }
489
490 #ifdef SLAPD_CRYPT
491 static int chk_crypt(
492         const struct pw_scheme *sc,
493         const struct berval * passwd,
494         const struct berval * cred )
495 {
496         int i;
497
498         for( i=0; i<cred->bv_len; i++) {
499                 if(cred->bv_val[i] == '\0') {
500                         return 1;       /* NUL character in password */
501                 }
502         }
503
504         if( cred->bv_val[i] != '\0' ) {
505                 return 1;       /* cred must behave like a string */
506         }
507
508         for( i=0; i<passwd->bv_len; i++) {
509                 if(passwd->bv_val[i] == '\0') {
510                         return 1;       /* NUL character in password */
511                 }
512         }
513
514         if( passwd->bv_val[i] != '\0' ) {
515                 return 1;       /* passwd must behave like a string */
516         }
517
518         return strcmp(passwd->bv_val, crypt(cred->bv_val, passwd->bv_val));
519 }
520
521 # if defined( HAVE_GETSPNAM ) \
522   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
523 static int chk_unix(
524         const struct pw_scheme *sc,
525         const struct berval * passwd,
526         const struct berval * cred )
527 {
528         int i;
529         char *pw;
530
531         for( i=0; i<cred->bv_len; i++) {
532                 if(cred->bv_val[i] == '\0') {
533                         return 1;       /* NUL character in password */
534                 }
535         }
536         if( cred->bv_val[i] != '\0' ) {
537                 return 1;       /* cred must behave like a string */
538         }
539
540         for( i=0; i<passwd->bv_len; i++) {
541                 if(passwd->bv_val[i] == '\0') {
542                         return 1;       /* NUL character in password */
543                 }
544         }
545
546         if( passwd->bv_val[i] != '\0' ) {
547                 return 1;       /* passwd must behave like a string */
548         }
549
550 #  ifdef HAVE_GETSPNAM
551         {
552                 struct spwd *spwd = getspnam(passwd->bv_val);
553
554                 if(spwd == NULL) {
555                         return 1;       /* not found */
556                 }
557
558                 pw = spwd->sp_pwdp;
559         }
560
561 #  else
562         {
563                 struct passwd *pwd = getpwnam(passwd->bv_val);
564
565                 if(pwd == NULL) {
566                         return 1;       /* not found */
567                 }
568
569                 pw = pwd->pw_passwd;
570         }
571 #  endif
572
573         if( pw == NULL || *pw == '\0' ) return 1;
574
575         return strcmp(pw, crypt(cred->bv_val, pw));
576
577 }
578 # endif
579 #endif
580
581 /* PASSWORD CHECK ROUTINES */
582 static struct berval *gen_ssha1(
583         const struct pw_scheme *scheme,
584         const struct berval  *passwd )
585 {
586         lutil_SHA1_CTX  SHA1context;
587         unsigned char   SHA1digest[LUTIL_SHA1_BYTES];
588         unsigned char   saltdata[4];
589         struct berval digest;
590         struct berval salt;
591
592         digest.bv_val = SHA1digest;
593         digest.bv_len = sizeof(SHA1digest);
594         salt.bv_val = saltdata;
595         salt.bv_len = sizeof(saltdata);
596
597         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
598                 return NULL; 
599         }
600
601         lutil_SHA1Init( &SHA1context );
602         lutil_SHA1Update( &SHA1context,
603                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
604         lutil_SHA1Update( &SHA1context,
605                 (const unsigned char *)salt.bv_val, salt.bv_len );
606         lutil_SHA1Final( SHA1digest, &SHA1context );
607
608         return pw_string64( scheme, &digest, &salt);
609 }
610
611 static struct berval *gen_sha1(
612         const struct pw_scheme *scheme,
613         const struct berval  *passwd )
614 {
615         lutil_SHA1_CTX  SHA1context;
616         unsigned char   SHA1digest[20];
617         struct berval digest;
618         digest.bv_val = SHA1digest;
619         digest.bv_len = sizeof(SHA1digest);
620      
621         lutil_SHA1Init( &SHA1context );
622         lutil_SHA1Update( &SHA1context,
623                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
624         lutil_SHA1Final( SHA1digest, &SHA1context );
625             
626         return pw_string64( scheme, &digest, NULL);
627 }
628
629 static struct berval *gen_smd5(
630         const struct pw_scheme *scheme,
631         const struct berval  *passwd )
632 {
633         lutil_MD5_CTX   MD5context;
634         unsigned char   MD5digest[16];
635         unsigned char   saltdata[4];
636         struct berval digest;
637         struct berval salt;
638
639         digest.bv_val = MD5digest;
640         digest.bv_len = sizeof(MD5digest);
641         salt.bv_val = saltdata;
642         salt.bv_len = sizeof(saltdata);
643
644         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
645                 return NULL; 
646         }
647
648         lutil_MD5Init( &MD5context );
649         lutil_MD5Update( &MD5context,
650                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
651         lutil_MD5Update( &MD5context,
652                 (const unsigned char *) salt.bv_val, salt.bv_len );
653         lutil_MD5Final( MD5digest, &MD5context );
654
655         return pw_string64( scheme, &digest, &salt );
656 }
657
658 static struct berval *gen_md5(
659         const struct pw_scheme *scheme,
660         const struct berval  *passwd )
661 {
662         lutil_MD5_CTX   MD5context;
663         unsigned char   MD5digest[16];
664
665         struct berval digest;
666
667         digest.bv_val = MD5digest;
668         digest.bv_len = sizeof(MD5digest);
669
670         lutil_MD5Init( &MD5context );
671         lutil_MD5Update( &MD5context,
672                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
673         lutil_MD5Final( MD5digest, &MD5context );
674
675         return pw_string64( scheme, &digest, NULL );
676 ;
677 }
678
679 #ifdef SLAPD_CRYPT
680 static struct berval *gen_crypt(
681         const struct pw_scheme *scheme,
682         const struct berval *passwd )
683 {
684         static const unsigned char crypt64[] =
685                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
686
687         struct berval hash;
688         unsigned char salt[3];
689         int i;
690
691         for( i=0; i<passwd->bv_len; i++) {
692                 if(passwd->bv_val[i] == '\0') {
693                         return NULL;    /* NUL character in password */
694                 }
695         }
696
697         if( passwd->bv_val[i] != '\0' ) {
698                 return NULL;    /* passwd must behave like a string */
699         }
700
701         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
702                 return NULL; 
703         }
704
705         salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
706         salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
707         salt[2] = '\0';
708
709         hash.bv_val = crypt( passwd->bv_val, salt );
710
711         if( hash.bv_val = NULL ) return NULL;
712         hash.bv_len = strlen( hash.bv_val );
713
714         return pw_string( scheme, &hash );
715 }
716 #endif