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