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