]> git.sur5r.net Git - openldap/blob - libraries/liblutil/authpasswd.c
Framework for authpasswd. Needs work. Behind #ifdef
[openldap] / libraries / liblutil / authpasswd.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_authpassword(authpasswd, cred)
8  *
9  * Returns true if user supplied credentials (cred) matches
10  * the stored authentication password (authpasswd). 
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 #include <ac/string.h>
21
22 #ifdef SLAPD_KPASSWD
23 #       include <ac/krb.h>
24 #       include <ac/krb5.h>
25 #endif
26
27 #include <ac/param.h>
28
29 #include <ac/unistd.h>
30 #include <ac/crypt.h>
31
32 #ifdef HAVE_SHADOW_H
33 #       include <shadow.h>
34 #endif
35 #ifdef HAVE_PWD_H
36 #       include <pwd.h>
37 #endif
38
39 #include <lber.h>
40
41 #include "lutil_md5.h"
42 #include "lutil_sha1.h"
43 #include "lutil.h"
44
45 static const unsigned char crypt64[] =
46         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
47
48 struct pw_scheme;
49
50 typedef int (*PASSWD_CHK_FUNC)(
51         const struct pw_scheme *scheme,
52         const struct berval *passwd,
53         const struct berval *salt,
54         const struct berval *cred );
55
56 typedef int (*PASSWD_HASH_FUNC) (
57         const struct pw_scheme *scheme,
58         const struct berval *cred,
59         const struct berval *salt,
60         struct berval **passwd_out,
61         struct berval **salt_out );
62
63 /* password check routines */
64 static int chk_md5(
65         const struct pw_scheme *scheme,
66         const struct berval *passwd,
67         const struct berval *salt,
68         const struct berval *cred );
69
70 static int chk_sha1(
71         const struct pw_scheme *scheme,
72         const struct berval *passwd,
73         const struct berval *salt,
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 *salt,
80         const struct berval *cred );
81
82 static int chk_ext(
83         const struct pw_scheme *scheme,
84         const struct berval *passwd,
85         const struct berval *salt,
86         const struct berval *cred );
87
88 static int chk_ext_kerberos(
89         const struct pw_scheme *scheme,
90         const struct berval *passwd,
91         const struct berval *cred );
92
93 static int chk_ext_unix(
94         const struct pw_scheme *scheme,
95         const struct berval *passwd,
96         const struct berval *cred );
97
98
99 /* password hash routines */
100 static int *hash_sha1(
101         const struct pw_scheme *scheme,
102         const struct berval *cred,
103         const struct berval *salt,
104         struct berval **passwd_out,
105         struct berval **salt_out );
106
107 static int *hash_md5(
108         const struct pw_scheme *scheme,
109         const struct berval *cred,
110         const struct berval *salt,
111         struct berval **passwd_out,
112         struct berval **salt_out );
113
114 static int *hash_crypt(
115         const struct pw_scheme *scheme,
116         const struct berval *cred,
117         const struct berval *salt,
118         struct berval **passwd_out,
119         struct berval **salt_out );
120
121
122 struct pw_scheme {
123         struct berval name;
124         PASSWD_CHK_FUNC chk_fn;
125         PASSWD_HASH_FUNC hash_fn;
126         int saltbytes;
127 };
128
129 static const struct pw_scheme pw_schemes[] =
130 {
131         { {sizeof("SHA1")-1, "SHA1"},   chk_sha1, 0 /* hash_sha1 */, 4 },
132         { {sizeof("MD5")-1, "MD5"},             chk_md5, 0 /* hash_md5 */, 4 },
133
134 #ifdef SLAPD_CRYPT
135         { {sizeof("CRYPT")-1, "CRYPT"}, chk_crypt, hash_crypt, 2 },
136 #endif
137
138 #ifdef EXT_PASSWD
139         { {sizeof("EXTERNAL")-1, "EXTERNAL"}, chk_ext, NULL, 0 },
140 #endif
141
142         { {0, NULL}, NULL, NULL, 0 }
143 };
144
145 #ifdef EXT_PASSWD
146 struct ext_scheme {
147         struct berval name;
148         EXT_CHK_FUNC chk_fn;
149 };
150
151 static const struct ext_scheme ext_schemes[] =
152 {
153         { {0, NULL}, NULL, NULL, 0 }
154 };
155 #endif
156
157 static const struct pw_scheme *get_scheme(
158         const char *scheme )
159 {
160         int i;
161
162         if( scheme == NULL || *scheme == '\0' ) return NULL;
163
164         for( i=0; pw_schemes[i].name.bv_val; i++) {
165                 if( pw_schemes[i].name.bv_len == 0 ) continue;
166
167                 if( strncasecmp( scheme,
168                         pw_schemes[i].name.bv_val,
169                         pw_schemes[i].name.bv_len) == 0 )
170                 {
171                         return &pw_schemes[i];
172                 }
173         }
174
175         return NULL;
176 }
177
178 int lutil_authpasswd_scheme(
179         const char *scheme )
180 {
181         return get_scheme( scheme ) != NULL;
182 }
183
184
185 static int is_allowed_scheme( 
186         const char* scheme,
187         const char** schemes )
188 {
189         int i;
190
191         if( scheme == NULL || *scheme == '\0' ) return 1;
192
193         for( i=0; schemes[i] != NULL; i++ ) {
194                 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
195                         return 1;
196                 }
197         }
198         return 0;
199 }
200
201 static int parse_authpasswd(
202         char **scheme,
203         struct berval *salt,
204         struct berval *passwd )
205 {
206         *scheme = NULL;
207         return -1;
208 }
209
210 /*
211  * Return 0 if creds are good.
212  */
213 int
214 lutil_authpasswd(
215         const struct berval *value,     /* stored authpasswd */
216         const struct berval *cred,              /* user cred */
217         const char **schemes )
218 {
219         char *scheme;
220         struct berval salt, passwd;
221         const struct pw_scheme *pws;
222         int rc = -1;
223
224         if (cred == NULL || cred->bv_len == 0 ||
225                 value == NULL || value->bv_len == 0 )
226         {
227                 return -1;
228         }
229
230         rc = parse_authpasswd( &scheme, &salt, &passwd );
231
232         if( rc != 0 ) return -1;
233
234         if( !is_allowed_scheme( scheme, schemes ) ) {
235                 goto done;
236         }
237
238         pws = get_scheme( scheme );
239
240         if( pws == NULL || !pws->chk_fn ) {
241                 goto done;
242         };
243
244         rc = (pws->chk_fn)( pws, &salt, &passwd, cred );
245
246 done:
247         if( scheme != NULL ) {
248                 ber_memfree( scheme );
249                 ber_memfree( salt.bv_val );
250                 ber_memfree( passwd.bv_val );
251         }
252
253         return rc ? -1 : 0;
254 }
255
256 struct berval * lutil_authpasswd_generate( ber_len_t len )
257 {
258         struct berval *pw;
259
260         if( len < 1 ) return NULL;
261
262         pw = ber_memalloc( sizeof( struct berval ) );
263         if( pw == NULL ) return NULL;
264
265         pw->bv_len = len;
266         pw->bv_val = ber_memalloc( len + 1 );
267
268         if( pw->bv_val == NULL ) {
269                 ber_memfree( pw );
270                 return NULL;
271         }
272
273         if( lutil_entropy( pw->bv_val, pw->bv_len) < 0 ) {
274                 ber_bvfree( pw );
275                 return NULL; 
276         }
277
278         for( len = 0; len < pw->bv_len; len++ ) {
279                 pw->bv_val[len] = crypt64[
280                         pw->bv_val[len] % (sizeof(crypt64)-1) ];
281         }
282
283         pw->bv_val[len] = '\0';
284         
285         return pw;
286 }
287
288 int lutil_authpasswd_hash(
289         const struct berval * cred,
290         struct berval ** passwd_out,
291         struct berval ** salt_out,
292         const char * method )
293 {
294         const struct pw_scheme *sc;
295         int rc;
296
297         if( passwd_out == NULL ) return -1;
298         
299         sc = get_scheme( method );
300         if( sc == NULL || !sc->hash_fn ) return -1;
301
302         if( sc->saltbytes && salt_out != NULL ) {
303                 struct berval salt;
304                 salt.bv_val = ber_memalloc( sc->saltbytes );
305
306                 if( salt.bv_val == NULL ) {
307                         return -1;
308                 }
309                 salt.bv_len = sc->saltbytes;
310
311                 if( lutil_entropy( salt.bv_val, salt.bv_len ) < 0 ) {
312                         ber_memfree( salt.bv_val );
313                         return -1; 
314                 }
315
316                 rc = (sc->hash_fn)( sc, cred, &salt, passwd_out, NULL );
317                 ber_memfree( salt.bv_val );
318
319         } else if ( sc->saltbytes ) {
320                 /* wants salt, disallow */
321                 return -1;
322
323         } else {
324                 rc = (sc->hash_fn)( sc, cred, NULL, passwd_out, salt_out );
325         }
326
327         return rc;
328 }
329
330 static struct berval * base64(
331         const struct berval *value )
332 {
333         int rc;
334         struct berval *b64; 
335
336         assert( value != NULL );
337
338         if( value == NULL || value->bv_len == 0 ) return NULL;
339
340         b64 = ber_memalloc( sizeof(struct berval) );
341         if( b64 == NULL ) return NULL;
342
343         b64->bv_len = LUTIL_BASE64_ENCODE_LEN( value->bv_len );
344         b64->bv_val = ber_memalloc( b64->bv_len + 1 );
345
346         if( b64->bv_val == NULL ) {
347                 ber_memfree( b64 );
348                 return NULL;
349         }
350
351         rc = lutil_b64_ntop(
352                 value->bv_val, value->bv_len,
353                 b64->bv_val, b64->bv_len );
354
355         b64->bv_val[b64->bv_len] = '\0';
356
357         if( rc < 0 ) {
358                 ber_bvfree( b64 );
359                 return NULL;
360         }
361
362         return b64;
363 }
364
365 /* PASSWORD CHECK ROUTINES */
366
367 static int chk_sha1(
368         const struct pw_scheme *sc,
369         const struct berval * passwd,
370         const struct berval * salt,
371         const struct berval * cred )
372 {
373         lutil_SHA1_CTX SHA1context;
374         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
375         int rc;
376         unsigned char *orig_pass = NULL;
377         unsigned char *orig_salt = NULL;
378         int saltlen;
379  
380         if( passwd == NULL || passwd->bv_len == 0 ) {
381                 return 1;
382         }
383
384         /* decode base64 password */
385         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
386                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
387
388         if( orig_pass == NULL ) {
389                 rc = -1;
390                 goto done;
391         }
392
393         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
394
395         if( rc < 0 ) {
396                 goto done;
397         }
398
399         /* decode base64 salt */
400         if( salt != NULL && salt->bv_len > 0 ) {
401                 orig_salt = (unsigned char *) ber_memalloc( (size_t) (
402                         LUTIL_BASE64_DECODE_LEN(salt->bv_len) + 1) );
403
404                 if( orig_salt == NULL ) {
405                         rc = -1;
406                         goto done;
407                 }
408
409                 saltlen = lutil_b64_pton(passwd->bv_val, orig_salt, passwd->bv_len);
410
411                 if( saltlen < 0 ) {
412                         goto done;
413                 }
414         }
415
416         /* hash credentials with salt */
417         lutil_SHA1Init(&SHA1context);
418         lutil_SHA1Update(&SHA1context,
419                 (const unsigned char *) cred->bv_val, cred->bv_len);
420         if( orig_salt != NULL ) {
421                 lutil_SHA1Update(&SHA1context,
422                         orig_salt, saltlen );
423         }
424         lutil_SHA1Final(SHA1digest, &SHA1context);
425  
426         /* compare */
427         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
428
429 done:
430         ber_memfree(orig_pass);
431         ber_memfree(orig_salt);
432         return rc;
433 }
434
435 static int chk_md5(
436         const struct pw_scheme *sc,
437         const struct berval * passwd,
438         const struct berval * salt,
439         const struct berval * cred )
440 {
441         lutil_MD5_CTX MD5context;
442         unsigned char MD5digest[LUTIL_MD5_BYTES];
443         int rc;
444         unsigned char *orig_pass = NULL;
445         unsigned char *orig_salt = NULL;
446         int saltlen;
447  
448         if( passwd == NULL || passwd->bv_len == 0 ) {
449                 return 1;
450         }
451
452         /* decode base64 password */
453         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
454                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
455
456         if( orig_pass == NULL ) {
457                 rc = -1;
458                 goto done;
459         }
460
461         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
462
463         if( rc < 0 ) {
464                 goto done;
465         }
466
467         /* decode base64 salt */
468         if( salt != NULL && salt->bv_len > 0 ) {
469                 orig_salt = (unsigned char *) ber_memalloc( (size_t) (
470                         LUTIL_BASE64_DECODE_LEN(salt->bv_len) + 1) );
471
472                 if( orig_salt == NULL ) {
473                         rc = -1;
474                         goto done;
475                 }
476
477                 saltlen = lutil_b64_pton(passwd->bv_val, orig_salt, passwd->bv_len);
478
479                 if( saltlen < 0 ) {
480                         goto done;
481                 }
482         }
483
484         /* hash credentials with salt */
485         lutil_MD5Init(&MD5context);
486         lutil_MD5Update(&MD5context,
487                 (const unsigned char *) cred->bv_val, cred->bv_len);
488         if( orig_salt != NULL ) {
489                 lutil_MD5Update(&MD5context,
490                         orig_salt, saltlen );
491         }
492         lutil_MD5Final(MD5digest, &MD5context);
493  
494         /* compare */
495         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
496
497 done:
498         ber_memfree(orig_pass);
499         ber_memfree(orig_salt);
500         return rc;
501 }
502
503 #ifdef SLAPD_KPASSWD
504 static int chk_kerberos(
505         const struct pw_scheme *sc,
506         const struct berval * passwd,
507         const struct berval * cred,
508         const struct berval * salt )
509 {
510         int i;
511         int rtn;
512
513         for( i=0; i<cred->bv_len; i++) {
514                 if(cred->bv_val[i] == '\0') {
515                         return 1;       /* NUL character in password */
516                 }
517         }
518
519         if( cred->bv_val[i] != '\0' ) {
520                 return 1;       /* cred must behave like a string */
521         }
522
523         for( i=0; i<passwd->bv_len; i++) {
524                 if(passwd->bv_val[i] == '\0') {
525                         return 1;       /* NUL character in password */
526                 }
527         }
528
529         if( passwd->bv_val[i] != '\0' ) {
530                 return 1;       /* passwd must behave like a string */
531         }
532
533         rtn = 1;
534
535 #ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */
536         {
537 /* Portions:
538  * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan
539  * (Royal Institute of Technology, Stockholm, Sweden).
540  * All rights reserved.
541  *
542  * Redistribution and use in source and binary forms, with or without
543  * modification, are permitted provided that the following conditions
544  * are met:
545  *
546  * 1. Redistributions of source code must retain the above copyright
547  *    notice, this list of conditions and the following disclaimer.
548  *
549  * 2. Redistributions in binary form must reproduce the above copyright
550  *    notice, this list of conditions and the following disclaimer in the
551  *    documentation and/or other materials provided with the distribution.
552  *
553  * 3. Neither the name of the Institute nor the names of its contributors
554  *    may be used to endorse or promote products derived from this software
555  *    without specific prior written permission.
556  *
557  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
558  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
559  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
560  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
561  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
562  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
563  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
564  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
565  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
566  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
567  * SUCH DAMAGE.
568  */
569
570                 krb5_context context;
571                 krb5_error_code ret;
572                 krb5_creds creds;
573                 krb5_get_init_creds_opt get_options;
574                 krb5_verify_init_creds_opt verify_options;
575                 krb5_principal client, server;
576 #ifdef notdef
577                 krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
578 #endif
579
580                 ret = krb5_init_context( &context );
581                 if (ret) {
582                         return 1;
583                 }
584
585 #ifdef notdef
586                 krb5_get_init_creds_opt_set_preauth_list(&get_options,
587                         pre_auth_types, 1);
588 #endif
589
590                 krb5_get_init_creds_opt_init( &get_options );
591
592                 krb5_verify_init_creds_opt_init( &verify_options );
593         
594                 ret = krb5_parse_name( context, passwd->bv_val, &client );
595
596                 if (ret) {
597                         krb5_free_context( context );
598                         return 1;
599                 }
600
601                 ret = krb5_get_init_creds_password( context,
602                         &creds, client, cred->bv_val, NULL,
603                         NULL, 0, NULL, &get_options );
604
605                 if (ret) {
606                         krb5_free_principal( context, client );
607                         krb5_free_context( context );
608                         return 1;
609                 }
610
611                 {
612                         char host[MAXHOSTNAMELEN];
613
614                         if( gethostname( host, MAXHOSTNAMELEN ) != 0 ) {
615                                 krb5_free_principal( context, client );
616                                 krb5_free_context( context );
617                                 return 1;
618                         }
619
620                         ret = krb5_sname_to_principal( context,
621                                 host, "ldap", KRB5_NT_SRV_HST, &server );
622                 }
623
624                 if (ret) {
625                         krb5_free_principal( context, client );
626                         krb5_free_context( context );
627                         return 1;
628                 }
629
630                 ret = krb5_verify_init_creds( context,
631                         &creds, server, NULL, NULL, &verify_options );
632
633                 krb5_free_principal( context, client );
634                 krb5_free_principal( context, server );
635                 krb5_free_creds_contents( context, &creds );
636                 krb5_free_context( context );
637
638                 rtn = !!ret;
639         }
640 #elif   defined(HAVE_KRB4)
641         {
642                 /* Borrowed from Heimdal kpopper */
643 /* Portions:
644  * Copyright (c) 1989 Regents of the University of California.
645  * All rights reserved.  The Berkeley software License Agreement
646  * specifies the terms and conditions for redistribution.
647  */
648
649                 int status;
650                 char lrealm[REALM_SZ];
651                 char tkt[MAXHOSTNAMELEN];
652
653                 status = krb_get_lrealm(lrealm,1);
654                 if (status == KFAILURE) {
655                         return 1;
656                 }
657
658                 snprintf(tkt, sizeof(tkt), "%s_slapd.%u",
659                         TKT_ROOT, (unsigned)getpid());
660                 krb_set_tkt_string (tkt);
661
662                 status = krb_verify_user( passwd->bv_val, "", lrealm,
663                         cred->bv_val, 1, "ldap");
664
665                 dest_tkt(); /* no point in keeping the tickets */
666
667                 return status == KFAILURE;
668         }
669 #endif
670
671         return rtn;
672 }
673 #endif /* SLAPD_KPASSWD */
674
675 #ifdef SLAPD_CRYPT
676 static int chk_crypt(
677         const struct pw_scheme *sc,
678         const struct berval * passwd,
679         const struct berval * cred )
680 {
681         char *cr;
682         int i;
683
684         for( i=0; i<cred->bv_len; i++) {
685                 if(cred->bv_val[i] == '\0') {
686                         return 1;       /* NUL character in password */
687                 }
688         }
689
690         if( cred->bv_val[i] != '\0' ) {
691                 return 1;       /* cred must behave like a string */
692         }
693
694         if( passwd->bv_len < 2 ) {
695                 return 1;       /* passwd must be at least two characters long */
696         }
697
698         for( i=0; i<passwd->bv_len; i++) {
699                 if(passwd->bv_val[i] == '\0') {
700                         return 1;       /* NUL character in password */
701                 }
702         }
703
704         if( passwd->bv_val[i] != '\0' ) {
705                 return 1;       /* passwd must behave like a string */
706         }
707
708         cr = crypt( cred->bv_val, passwd->bv_val );
709
710         if( cr == NULL || cr[0] == '\0' ) {
711                 /* salt must have been invalid */
712                 return 1;
713         }
714
715         return strcmp( passwd->bv_val, cr );
716 }
717
718 # if defined( HAVE_GETSPNAM ) \
719   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
720 static int chk_unix(
721         const struct pw_scheme *sc,
722         const struct berval * passwd,
723         const struct berval * cred )
724 {
725         int i;
726         char *pw,*cr;
727
728         for( i=0; i<cred->bv_len; i++) {
729                 if(cred->bv_val[i] == '\0') {
730                         return 1;       /* NUL character in password */
731                 }
732         }
733         if( cred->bv_val[i] != '\0' ) {
734                 return 1;       /* cred must behave like a string */
735         }
736
737         for( i=0; i<passwd->bv_len; i++) {
738                 if(passwd->bv_val[i] == '\0') {
739                         return 1;       /* NUL character in password */
740                 }
741         }
742
743         if( passwd->bv_val[i] != '\0' ) {
744                 return 1;       /* passwd must behave like a string */
745         }
746
747 #  ifdef HAVE_GETSPNAM
748         {
749                 struct spwd *spwd = getspnam(passwd->bv_val);
750
751                 if(spwd == NULL) {
752                         return 1;       /* not found */
753                 }
754
755                 pw = spwd->sp_pwdp;
756         }
757
758 #  else
759         {
760                 struct passwd *pwd = getpwnam(passwd->bv_val);
761
762                 if(pwd == NULL) {
763                         return 1;       /* not found */
764                 }
765
766                 pw = pwd->pw_passwd;
767         }
768 #  endif
769
770         if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) {
771                 /* password must must be at least two characters long */
772                 return 1;
773         }
774
775         cr = crypt(cred->bv_val, pw);
776
777         if( cr == NULL || cr[0] == '\0' ) {
778                 /* salt must have been invalid */
779                 return 1;
780         }
781
782         return strcmp(pw, cr);
783
784 }
785 # endif
786 #endif
787
788 /* PASSWORD GENERATION ROUTINES */
789
790 #ifdef SLAPD_GENERATE
791
792 static struct berval *hash_ssha1(
793         const struct pw_scheme *scheme,
794         const struct berval *passwd )
795 {
796         lutil_SHA1_CTX  SHA1context;
797         unsigned char   SHA1digest[LUTIL_SHA1_BYTES];
798         unsigned char   saltdata[4];
799         struct berval digest;
800         struct berval salt;
801
802         digest.bv_val = SHA1digest;
803         digest.bv_len = sizeof(SHA1digest);
804         salt.bv_val = saltdata;
805         salt.bv_len = sizeof(saltdata);
806
807         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
808                 return NULL; 
809         }
810
811         lutil_SHA1Init( &SHA1context );
812         lutil_SHA1Update( &SHA1context,
813                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
814         lutil_SHA1Update( &SHA1context,
815                 (const unsigned char *)salt.bv_val, salt.bv_len );
816         lutil_SHA1Final( SHA1digest, &SHA1context );
817
818         return pw_string64( scheme, &digest, &salt);
819 }
820
821 static struct berval *hash_sha1(
822         const struct pw_scheme *scheme,
823         const struct berval  *passwd )
824 {
825         lutil_SHA1_CTX  SHA1context;
826         unsigned char   SHA1digest[20];
827         struct berval digest;
828         digest.bv_val = SHA1digest;
829         digest.bv_len = sizeof(SHA1digest);
830      
831         lutil_SHA1Init( &SHA1context );
832         lutil_SHA1Update( &SHA1context,
833                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
834         lutil_SHA1Final( SHA1digest, &SHA1context );
835             
836         return pw_string64( scheme, &digest, NULL);
837 }
838
839 static struct berval *hash_smd5(
840         const struct pw_scheme *scheme,
841         const struct berval  *passwd )
842 {
843         lutil_MD5_CTX   MD5context;
844         unsigned char   MD5digest[16];
845         unsigned char   saltdata[4];
846         struct berval digest;
847         struct berval salt;
848
849         digest.bv_val = MD5digest;
850         digest.bv_len = sizeof(MD5digest);
851         salt.bv_val = saltdata;
852         salt.bv_len = sizeof(saltdata);
853
854         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
855                 return NULL; 
856         }
857
858         lutil_MD5Init( &MD5context );
859         lutil_MD5Update( &MD5context,
860                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
861         lutil_MD5Update( &MD5context,
862                 (const unsigned char *) salt.bv_val, salt.bv_len );
863         lutil_MD5Final( MD5digest, &MD5context );
864
865         return pw_string64( scheme, &digest, &salt );
866 }
867
868 static struct berval *hash_md5(
869         const struct pw_scheme *scheme,
870         const struct berval  *passwd )
871 {
872         lutil_MD5_CTX   MD5context;
873         unsigned char   MD5digest[16];
874
875         struct berval digest;
876
877         digest.bv_val = MD5digest;
878         digest.bv_len = sizeof(MD5digest);
879
880         lutil_MD5Init( &MD5context );
881         lutil_MD5Update( &MD5context,
882                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
883         lutil_MD5Final( MD5digest, &MD5context );
884
885         return pw_string64( scheme, &digest, NULL );
886 ;
887 }
888
889 #ifdef SLAPD_CRYPT
890 static struct berval *hash_crypt(
891         const struct pw_scheme *scheme,
892         const struct berval *passwd )
893 {
894         struct berval hash;
895         unsigned char salt[3];
896         int i;
897
898         for( i=0; i<passwd->bv_len; i++) {
899                 if(passwd->bv_val[i] == '\0') {
900                         return NULL;    /* NUL character in password */
901                 }
902         }
903
904         if( passwd->bv_val[i] != '\0' ) {
905                 return NULL;    /* passwd must behave like a string */
906         }
907
908         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
909                 return NULL; 
910         }
911
912         salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
913         salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
914         salt[2] = '\0';
915
916         hash.bv_val = crypt( passwd->bv_val, salt );
917
918         if( hash.bv_val == NULL ) return NULL;
919
920         hash.bv_len = strlen( hash.bv_val );
921
922         if( hash.bv_len == 0 ) {
923                 return NULL;
924         }
925
926         return pw_string( scheme, &hash );
927 }
928 #endif
929 #endif