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