]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
892a1b0f87a0f3c3c3a95fe28792e2f1d3a23f24
[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         if( salt ) ber_memfree( string.bv_val );
387         
388         if( rc < 0 ) {
389                 ber_bvfree( b64 );
390                 return NULL;
391         }
392
393         /* recompute length */
394         b64->bv_len = sc->name.bv_len + rc;
395         assert( strlen(b64->bv_val) == b64->bv_len );
396         return b64;
397 }
398
399 /* PASSWORD CHECK ROUTINES */
400
401 static int chk_ssha1(
402         const struct pw_scheme *sc,
403         const struct berval * passwd,
404         const struct berval * cred )
405 {
406         lutil_SHA1_CTX SHA1context;
407         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
408         int rc;
409         unsigned char *orig_pass = NULL;
410  
411         /* decode base64 password */
412         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
413                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
414
415         if( orig_pass == NULL ) return -1;
416
417         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
418
419         if(rc < 0) {
420                 ber_memfree(orig_pass);
421                 return -1;
422         }
423  
424         /* hash credentials with salt */
425         lutil_SHA1Init(&SHA1context);
426         lutil_SHA1Update(&SHA1context,
427                 (const unsigned char *) cred->bv_val, cred->bv_len);
428         lutil_SHA1Update(&SHA1context,
429                 (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
430                 rc - sizeof(SHA1digest));
431         lutil_SHA1Final(SHA1digest, &SHA1context);
432  
433         /* compare */
434         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
435         ber_memfree(orig_pass);
436         return rc ? 1 : 0;
437 }
438
439 static int chk_sha1(
440         const struct pw_scheme *sc,
441         const struct berval * passwd,
442         const struct berval * cred )
443 {
444         lutil_SHA1_CTX SHA1context;
445         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
446         int rc;
447         unsigned char *orig_pass = NULL;
448  
449         /* base64 un-encode password */
450         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
451                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
452
453         if( orig_pass == NULL ) return -1;
454
455         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
456
457         if( rc != sizeof(SHA1digest) ) {
458                 ber_memfree(orig_pass);
459                 return -1;
460         }
461  
462         /* hash credentials with salt */
463         lutil_SHA1Init(&SHA1context);
464         lutil_SHA1Update(&SHA1context,
465                 (const unsigned char *) cred->bv_val, cred->bv_len);
466         lutil_SHA1Final(SHA1digest, &SHA1context);
467  
468         /* compare */
469         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
470         ber_memfree(orig_pass);
471         return rc ? 1 : 0;
472 }
473
474 static int chk_smd5(
475         const struct pw_scheme *sc,
476         const struct berval * passwd,
477         const struct berval * cred )
478 {
479         lutil_MD5_CTX MD5context;
480         unsigned char MD5digest[LUTIL_MD5_BYTES];
481         int rc;
482         unsigned char *orig_pass = NULL;
483
484         /* base64 un-encode password */
485         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
486                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
487
488         if( orig_pass == NULL ) return -1;
489
490         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
491         if ( rc < 0 ) {
492                 ber_memfree(orig_pass);
493                 return -1;
494         }
495
496         /* hash credentials with salt */
497         lutil_MD5Init(&MD5context);
498         lutil_MD5Update(&MD5context,
499                 (const unsigned char *) cred->bv_val, cred->bv_len );
500         lutil_MD5Update(&MD5context,
501                 (const unsigned char *) &orig_pass[sizeof(MD5digest)],
502                 rc - sizeof(MD5digest));
503         lutil_MD5Final(MD5digest, &MD5context);
504
505         /* compare */
506         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
507         ber_memfree(orig_pass);
508         return rc ? 1 : 0;
509 }
510
511 static int chk_md5(
512         const struct pw_scheme *sc,
513         const struct berval * passwd,
514         const struct berval * cred )
515 {
516         lutil_MD5_CTX MD5context;
517         unsigned char MD5digest[LUTIL_MD5_BYTES];
518         int rc;
519         unsigned char *orig_pass = NULL;
520
521         /* base64 un-encode password */
522         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
523                 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
524
525         if( orig_pass == NULL ) return -1;
526
527         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
528         if ( rc != sizeof(MD5digest) ) {
529                 ber_memfree(orig_pass);
530                 return -1;
531         }
532
533         /* hash credentials with salt */
534         lutil_MD5Init(&MD5context);
535         lutil_MD5Update(&MD5context,
536                 (const unsigned char *) cred->bv_val, cred->bv_len );
537         lutil_MD5Final(MD5digest, &MD5context);
538
539         /* compare */
540         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
541         ber_memfree(orig_pass);
542         return rc ? 1 : 0;
543 }
544
545 #ifdef SLAPD_KPASSWD
546 static int chk_kerberos(
547         const struct pw_scheme *sc,
548         const struct berval * passwd,
549         const struct berval * cred )
550 {
551         int i;
552         int rtn;
553
554         for( i=0; i<cred->bv_len; i++) {
555                 if(cred->bv_val[i] == '\0') {
556                         return 1;       /* NUL character in password */
557                 }
558         }
559
560         if( cred->bv_val[i] != '\0' ) {
561                 return 1;       /* cred must behave like a string */
562         }
563
564         for( i=0; i<passwd->bv_len; i++) {
565                 if(passwd->bv_val[i] == '\0') {
566                         return 1;       /* NUL character in password */
567                 }
568         }
569
570         if( passwd->bv_val[i] != '\0' ) {
571                 return 1;       /* passwd must behave like a string */
572         }
573
574         rtn = 1;
575
576 #ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */
577         {
578 /* Portions:
579  * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan
580  * (Royal Institute of Technology, Stockholm, Sweden).
581  * All rights reserved.
582  *
583  * Redistribution and use in source and binary forms, with or without
584  * modification, are permitted provided that the following conditions
585  * are met:
586  *
587  * 1. Redistributions of source code must retain the above copyright
588  *    notice, this list of conditions and the following disclaimer.
589  *
590  * 2. Redistributions in binary form must reproduce the above copyright
591  *    notice, this list of conditions and the following disclaimer in the
592  *    documentation and/or other materials provided with the distribution.
593  *
594  * 3. Neither the name of the Institute nor the names of its contributors
595  *    may be used to endorse or promote products derived from this software
596  *    without specific prior written permission.
597  *
598  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
599  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
600  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
601  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
602  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
603  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
604  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
605  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
606  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
607  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
608  * SUCH DAMAGE.
609  */
610
611                 krb5_context context;
612                 krb5_error_code ret;
613                 krb5_creds creds;
614                 krb5_get_init_creds_opt get_options;
615                 krb5_verify_init_creds_opt verify_options;
616                 krb5_principal client, server;
617 #ifdef notdef
618                 krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
619 #endif
620
621                 ret = krb5_init_context( &context );
622                 if (ret) {
623                         return 1;
624                 }
625
626 #ifdef notdef
627                 krb5_get_init_creds_opt_set_preauth_list(&get_options,
628                         pre_auth_types, 1);
629 #endif
630
631                 krb5_get_init_creds_opt_init( &get_options );
632
633                 krb5_verify_init_creds_opt_init( &verify_options );
634         
635                 ret = krb5_parse_name( context, passwd->bv_val, &client );
636
637                 if (ret) {
638                         krb5_free_context( context );
639                         return 1;
640                 }
641
642                 ret = krb5_get_init_creds_password( context,
643                         &creds, client, cred->bv_val, NULL,
644                         NULL, 0, NULL, &get_options );
645
646                 if (ret) {
647                         krb5_free_principal( context, client );
648                         krb5_free_context( context );
649                         return 1;
650                 }
651
652                 {
653                         char host[MAXHOSTNAMELEN];
654
655                         if( gethostname( host, MAXHOSTNAMELEN ) != 0 ) {
656                                 krb5_free_principal( context, client );
657                                 krb5_free_context( context );
658                                 return 1;
659                         }
660
661                         ret = krb5_sname_to_principal( context,
662                                 host, "ldap", KRB5_NT_SRV_HST, &server );
663                 }
664
665                 if (ret) {
666                         krb5_free_principal( context, client );
667                         krb5_free_context( context );
668                         return 1;
669                 }
670
671                 ret = krb5_verify_init_creds( context,
672                         &creds, server, NULL, NULL, &verify_options );
673
674                 krb5_free_principal( context, client );
675                 krb5_free_principal( context, server );
676                 krb5_free_creds_contents( context, &creds );
677                 krb5_free_context( context );
678
679                 rtn = !!ret;
680         }
681 #elif   defined(HAVE_KRB4)
682         {
683                 /* Borrowed from Heimdal kpopper */
684 /* Portions:
685  * Copyright (c) 1989 Regents of the University of California.
686  * All rights reserved.  The Berkeley software License Agreement
687  * specifies the terms and conditions for redistribution.
688  */
689
690                 int status;
691                 char lrealm[REALM_SZ];
692                 char tkt[MAXHOSTNAMELEN];
693
694                 status = krb_get_lrealm(lrealm,1);
695                 if (status == KFAILURE) {
696                         return 1;
697                 }
698
699                 snprintf(tkt, sizeof(tkt), "%s_slapd.%u",
700                         TKT_ROOT, (unsigned)getpid());
701                 krb_set_tkt_string (tkt);
702
703                 status = krb_verify_user( passwd->bv_val, "", lrealm,
704                         cred->bv_val, 1, "ldap");
705
706                 dest_tkt(); /* no point in keeping the tickets */
707
708                 return status == KFAILURE;
709         }
710 #endif
711
712         return rtn;
713 }
714 #endif /* SLAPD_KPASSWD */
715
716 #ifdef SLAPD_CRYPT
717 static int chk_crypt(
718         const struct pw_scheme *sc,
719         const struct berval * passwd,
720         const struct berval * cred )
721 {
722         char *cr;
723         int i;
724
725         for( i=0; i<cred->bv_len; i++) {
726                 if(cred->bv_val[i] == '\0') {
727                         return 1;       /* NUL character in password */
728                 }
729         }
730
731         if( cred->bv_val[i] != '\0' ) {
732                 return -1;      /* cred must behave like a string */
733         }
734
735         if( passwd->bv_len < 2 ) {
736                 return -1;      /* passwd must be at least two characters long */
737         }
738
739         for( i=0; i<passwd->bv_len; i++) {
740                 if(passwd->bv_val[i] == '\0') {
741                         return -1;      /* NUL character in password */
742                 }
743         }
744
745         if( passwd->bv_val[i] != '\0' ) {
746                 return -1;      /* passwd must behave like a string */
747         }
748
749         cr = crypt( cred->bv_val, passwd->bv_val );
750
751         if( cr == NULL || cr[0] == '\0' ) {
752                 /* salt must have been invalid */
753                 return -1;
754         }
755
756         return strcmp( passwd->bv_val, cr ) ? 1 : 0;
757 }
758
759 # if defined( HAVE_GETSPNAM ) \
760   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
761 static int chk_unix(
762         const struct pw_scheme *sc,
763         const struct berval * passwd,
764         const struct berval * cred )
765 {
766         int i;
767         char *pw,*cr;
768
769         for( i=0; i<cred->bv_len; i++) {
770                 if(cred->bv_val[i] == '\0') {
771                         return -1;      /* NUL character in password */
772                 }
773         }
774         if( cred->bv_val[i] != '\0' ) {
775                 return -1;      /* cred must behave like a string */
776         }
777
778         for( i=0; i<passwd->bv_len; i++) {
779                 if(passwd->bv_val[i] == '\0') {
780                         return -1;      /* NUL character in password */
781                 }
782         }
783
784         if( passwd->bv_val[i] != '\0' ) {
785                 return -1;      /* passwd must behave like a string */
786         }
787
788 #  ifdef HAVE_GETSPNAM
789         {
790                 struct spwd *spwd = getspnam(passwd->bv_val);
791
792                 if(spwd == NULL) {
793                         return -1;      /* not found */
794                 }
795
796                 pw = spwd->sp_pwdp;
797         }
798
799 #  else
800         {
801                 struct passwd *pwd = getpwnam(passwd->bv_val);
802
803                 if(pwd == NULL) {
804                         return -1;      /* not found */
805                 }
806
807                 pw = pwd->pw_passwd;
808         }
809 #  endif
810
811         if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) {
812                 /* password must must be at least two characters long */
813                 return -1;
814         }
815
816         cr = crypt(cred->bv_val, pw);
817
818         if( cr == NULL || cr[0] == '\0' ) {
819                 /* salt must have been invalid */
820                 return -1;
821         }
822
823         return strcmp(pw, cr) ? 1 : 0;
824
825 }
826 # endif
827 #endif
828
829 /* PASSWORD GENERATION ROUTINES */
830
831 static struct berval *hash_ssha1(
832         const struct pw_scheme *scheme,
833         const struct berval  *passwd )
834 {
835         lutil_SHA1_CTX  SHA1context;
836         unsigned char   SHA1digest[LUTIL_SHA1_BYTES];
837         unsigned char   saltdata[4];
838         struct berval digest;
839         struct berval salt;
840
841         digest.bv_val = SHA1digest;
842         digest.bv_len = sizeof(SHA1digest);
843         salt.bv_val = saltdata;
844         salt.bv_len = sizeof(saltdata);
845
846         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
847                 return NULL; 
848         }
849
850         lutil_SHA1Init( &SHA1context );
851         lutil_SHA1Update( &SHA1context,
852                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
853         lutil_SHA1Update( &SHA1context,
854                 (const unsigned char *)salt.bv_val, salt.bv_len );
855         lutil_SHA1Final( SHA1digest, &SHA1context );
856
857         return pw_string64( scheme, &digest, &salt);
858 }
859
860 static struct berval *hash_sha1(
861         const struct pw_scheme *scheme,
862         const struct berval  *passwd )
863 {
864         lutil_SHA1_CTX  SHA1context;
865         unsigned char   SHA1digest[20];
866         struct berval digest;
867         digest.bv_val = SHA1digest;
868         digest.bv_len = sizeof(SHA1digest);
869      
870         lutil_SHA1Init( &SHA1context );
871         lutil_SHA1Update( &SHA1context,
872                 (const unsigned char *)passwd->bv_val, passwd->bv_len );
873         lutil_SHA1Final( SHA1digest, &SHA1context );
874             
875         return pw_string64( scheme, &digest, NULL);
876 }
877
878 static struct berval *hash_smd5(
879         const struct pw_scheme *scheme,
880         const struct berval  *passwd )
881 {
882         lutil_MD5_CTX   MD5context;
883         unsigned char   MD5digest[16];
884         unsigned char   saltdata[4];
885         struct berval digest;
886         struct berval salt;
887
888         digest.bv_val = MD5digest;
889         digest.bv_len = sizeof(MD5digest);
890         salt.bv_val = saltdata;
891         salt.bv_len = sizeof(saltdata);
892
893         if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
894                 return NULL; 
895         }
896
897         lutil_MD5Init( &MD5context );
898         lutil_MD5Update( &MD5context,
899                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
900         lutil_MD5Update( &MD5context,
901                 (const unsigned char *) salt.bv_val, salt.bv_len );
902         lutil_MD5Final( MD5digest, &MD5context );
903
904         return pw_string64( scheme, &digest, &salt );
905 }
906
907 static struct berval *hash_md5(
908         const struct pw_scheme *scheme,
909         const struct berval  *passwd )
910 {
911         lutil_MD5_CTX   MD5context;
912         unsigned char   MD5digest[16];
913
914         struct berval digest;
915
916         digest.bv_val = MD5digest;
917         digest.bv_len = sizeof(MD5digest);
918
919         lutil_MD5Init( &MD5context );
920         lutil_MD5Update( &MD5context,
921                 (const unsigned char *) passwd->bv_val, passwd->bv_len );
922         lutil_MD5Final( MD5digest, &MD5context );
923
924         return pw_string64( scheme, &digest, NULL );
925 ;
926 }
927
928 #ifdef SLAPD_CRYPT
929 static struct berval *hash_crypt(
930         const struct pw_scheme *scheme,
931         const struct berval *passwd )
932 {
933         struct berval hash;
934         unsigned char salt[3];
935         int i;
936
937         for( i=0; i<passwd->bv_len; i++) {
938                 if(passwd->bv_val[i] == '\0') {
939                         return NULL;    /* NUL character in password */
940                 }
941         }
942
943         if( passwd->bv_val[i] != '\0' ) {
944                 return NULL;    /* passwd must behave like a string */
945         }
946
947         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
948                 return NULL; 
949         }
950
951         salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
952         salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
953         salt[2] = '\0';
954
955         hash.bv_val = crypt( passwd->bv_val, salt );
956
957         if( hash.bv_val == NULL ) return NULL;
958
959         hash.bv_len = strlen( hash.bv_val );
960
961         if( hash.bv_len == 0 ) {
962                 return NULL;
963         }
964
965         return pw_string( scheme, &hash );
966 }
967 #endif