3 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * lutil_authpassword(authpasswd, cred)
9 * Returns true if user supplied credentials (cred) matches
10 * the stored authentication password (authpasswd).
12 * Due to the use of the crypt(3) function
13 * this routine is NOT thread-safe.
18 #ifdef SLAP_AUTHPASSWD
21 #include <ac/stdlib.h>
22 #include <ac/string.h>
31 #include <ac/unistd.h>
43 #include "lutil_md5.h"
44 #include "lutil_sha1.h"
47 static const unsigned char crypt64[] =
48 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
52 typedef int (*PASSWD_CHK_FUNC)(
53 const struct pw_scheme *scheme,
54 const struct berval *passwd,
55 const struct berval *salt,
56 const struct berval *cred );
58 typedef int (*PASSWD_HASH_FUNC) (
59 const struct pw_scheme *scheme,
60 const struct berval *cred,
61 const struct berval *salt,
62 struct berval **passwd_out,
63 struct berval **salt_out );
65 /* password check routines */
67 const struct pw_scheme *scheme,
68 const struct berval *passwd,
69 const struct berval *salt,
70 const struct berval *cred );
72 #ifdef LUTIL_SHA1_BYTES
74 const struct pw_scheme *scheme,
75 const struct berval *passwd,
76 const struct berval *salt,
77 const struct berval *cred );
81 const struct pw_scheme *scheme,
82 const struct berval *passwd,
83 const struct berval *salt,
84 const struct berval *cred );
87 const struct pw_scheme *scheme,
88 const struct berval *passwd,
89 const struct berval *salt,
90 const struct berval *cred );
92 static int chk_ext_kerberos(
93 const struct pw_scheme *scheme,
94 const struct berval *passwd,
95 const struct berval *cred );
97 static int chk_ext_unix(
98 const struct pw_scheme *scheme,
99 const struct berval *passwd,
100 const struct berval *cred );
102 #ifdef LUTIL_SHA1_BYTES
103 /* password hash routines */
104 static int *hash_sha1(
105 const struct pw_scheme *scheme,
106 const struct berval *cred,
107 const struct berval *salt,
108 struct berval **passwd_out,
109 struct berval **salt_out );
112 static int *hash_md5(
113 const struct pw_scheme *scheme,
114 const struct berval *cred,
115 const struct berval *salt,
116 struct berval **passwd_out,
117 struct berval **salt_out );
119 static int *hash_crypt(
120 const struct pw_scheme *scheme,
121 const struct berval *cred,
122 const struct berval *salt,
123 struct berval **passwd_out,
124 struct berval **salt_out );
129 PASSWD_CHK_FUNC chk_fn;
130 PASSWD_HASH_FUNC hash_fn;
134 static const struct pw_scheme pw_schemes[] =
136 #ifdef LUTIL_SHA1_BYTES
137 { {sizeof("SHA1")-1, "SHA1"}, chk_sha1, 0 /* hash_sha1 */, 4 },
139 { {sizeof("MD5")-1, "MD5"}, chk_md5, 0 /* hash_md5 */, 4 },
142 { {sizeof("CRYPT")-1, "CRYPT"}, chk_crypt, hash_crypt, 2 },
146 { {sizeof("EXTERNAL")-1, "EXTERNAL"}, chk_ext, NULL, 0 },
149 { {0, NULL}, NULL, NULL, 0 }
158 static const struct ext_scheme ext_schemes[] =
160 { {0, NULL}, NULL, NULL, 0 }
164 static const struct pw_scheme *get_scheme(
169 if( scheme == NULL || *scheme == '\0' ) return NULL;
171 for( i=0; pw_schemes[i].name.bv_val; i++) {
172 if( pw_schemes[i].name.bv_len == 0 ) continue;
174 if( strncasecmp( scheme,
175 pw_schemes[i].name.bv_val,
176 pw_schemes[i].name.bv_len) == 0 )
178 return &pw_schemes[i];
185 int lutil_authpasswd_scheme(
188 return get_scheme( scheme ) != NULL;
192 static int is_allowed_scheme(
194 const char** schemes )
198 if( scheme == NULL || *scheme == '\0' ) return 1;
200 for( i=0; schemes[i] != NULL; i++ ) {
201 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
208 static int parse_authpasswd(
211 struct berval *passwd )
218 * Return 0 if creds are good.
222 const struct berval *value, /* stored authpasswd */
223 const struct berval *cred, /* user cred */
224 const char **schemes )
227 struct berval salt, passwd;
228 const struct pw_scheme *pws;
231 if (cred == NULL || cred->bv_len == 0 ||
232 value == NULL || value->bv_len == 0 )
237 rc = parse_authpasswd( &scheme, &salt, &passwd );
239 if( rc != 0 ) return -1;
241 if( !is_allowed_scheme( scheme, schemes ) ) {
245 pws = get_scheme( scheme );
247 if( pws == NULL || !pws->chk_fn ) {
251 rc = (pws->chk_fn)( pws, &salt, &passwd, cred );
254 if( scheme != NULL ) {
255 ber_memfree( scheme );
256 ber_memfree( salt.bv_val );
257 ber_memfree( passwd.bv_val );
263 struct berval * lutil_authpasswd_generate( ber_len_t len )
267 if( len < 1 ) return NULL;
269 pw = ber_memalloc( sizeof( struct berval ) );
270 if( pw == NULL ) return NULL;
273 pw->bv_val = ber_memalloc( len + 1 );
275 if( pw->bv_val == NULL ) {
280 if( lutil_entropy( pw->bv_val, pw->bv_len) < 0 ) {
285 for( len = 0; len < pw->bv_len; len++ ) {
286 pw->bv_val[len] = crypt64[
287 pw->bv_val[len] % (sizeof(crypt64)-1) ];
290 pw->bv_val[len] = '\0';
295 int lutil_authpasswd_hash(
296 const struct berval * cred,
297 struct berval ** passwd_out,
298 struct berval ** salt_out,
299 const char * method )
301 const struct pw_scheme *sc;
304 if( passwd_out == NULL ) return -1;
306 sc = get_scheme( method );
307 if( sc == NULL || !sc->hash_fn ) return -1;
309 if( sc->saltbytes && salt_out != NULL ) {
311 salt.bv_val = ber_memalloc( sc->saltbytes );
313 if( salt.bv_val == NULL ) {
316 salt.bv_len = sc->saltbytes;
318 if( lutil_entropy( salt.bv_val, salt.bv_len ) < 0 ) {
319 ber_memfree( salt.bv_val );
323 rc = (sc->hash_fn)( sc, cred, &salt, passwd_out, NULL );
324 ber_memfree( salt.bv_val );
326 } else if ( sc->saltbytes ) {
327 /* wants salt, disallow */
331 rc = (sc->hash_fn)( sc, cred, NULL, passwd_out, salt_out );
337 static struct berval * base64(
338 const struct berval *value )
343 assert( value != NULL );
345 if( value == NULL || value->bv_len == 0 ) return NULL;
347 b64 = ber_memalloc( sizeof(struct berval) );
348 if( b64 == NULL ) return NULL;
350 b64->bv_len = LUTIL_BASE64_ENCODE_LEN( value->bv_len );
351 b64->bv_val = ber_memalloc( b64->bv_len + 1 );
353 if( b64->bv_val == NULL ) {
359 value->bv_val, value->bv_len,
360 b64->bv_val, b64->bv_len );
362 b64->bv_val[b64->bv_len] = '\0';
372 /* PASSWORD CHECK ROUTINES */
374 #ifdef LUTIL_SHA1_BYTES
376 const struct pw_scheme *sc,
377 const struct berval * passwd,
378 const struct berval * salt,
379 const struct berval * cred )
381 lutil_SHA1_CTX SHA1context;
382 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
384 unsigned char *orig_pass = NULL;
385 unsigned char *orig_salt = NULL;
388 if( passwd == NULL || passwd->bv_len == 0 ) {
392 /* decode base64 password */
393 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
394 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
396 if( orig_pass == NULL ) {
401 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
407 /* decode base64 salt */
408 if( salt != NULL && salt->bv_len > 0 ) {
409 orig_salt = (unsigned char *) ber_memalloc( (size_t) (
410 LUTIL_BASE64_DECODE_LEN(salt->bv_len) + 1) );
412 if( orig_salt == NULL ) {
417 saltlen = lutil_b64_pton(passwd->bv_val, orig_salt, passwd->bv_len);
424 /* hash credentials with salt */
425 lutil_SHA1Init(&SHA1context);
426 lutil_SHA1Update(&SHA1context,
427 (const unsigned char *) cred->bv_val, cred->bv_len);
428 if( orig_salt != NULL ) {
429 lutil_SHA1Update(&SHA1context,
430 orig_salt, saltlen );
432 lutil_SHA1Final(SHA1digest, &SHA1context);
435 rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
438 ber_memfree(orig_pass);
439 ber_memfree(orig_salt);
445 const struct pw_scheme *sc,
446 const struct berval * passwd,
447 const struct berval * salt,
448 const struct berval * cred )
450 lutil_MD5_CTX MD5context;
451 unsigned char MD5digest[LUTIL_MD5_BYTES];
453 unsigned char *orig_pass = NULL;
454 unsigned char *orig_salt = NULL;
457 if( passwd == NULL || passwd->bv_len == 0 ) {
461 /* decode base64 password */
462 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
463 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
465 if( orig_pass == NULL ) {
470 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
476 /* decode base64 salt */
477 if( salt != NULL && salt->bv_len > 0 ) {
478 orig_salt = (unsigned char *) ber_memalloc( (size_t) (
479 LUTIL_BASE64_DECODE_LEN(salt->bv_len) + 1) );
481 if( orig_salt == NULL ) {
486 saltlen = lutil_b64_pton(passwd->bv_val, orig_salt, passwd->bv_len);
493 /* hash credentials with salt */
494 lutil_MD5Init(&MD5context);
495 lutil_MD5Update(&MD5context,
496 (const unsigned char *) cred->bv_val, cred->bv_len);
497 if( orig_salt != NULL ) {
498 lutil_MD5Update(&MD5context,
499 orig_salt, saltlen );
501 lutil_MD5Final(MD5digest, &MD5context);
504 rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
507 ber_memfree(orig_pass);
508 ber_memfree(orig_salt);
513 static int chk_kerberos(
514 const struct pw_scheme *sc,
515 const struct berval * passwd,
516 const struct berval * cred,
517 const struct berval * salt )
522 for( i=0; i<cred->bv_len; i++) {
523 if(cred->bv_val[i] == '\0') {
524 return 1; /* NUL character in password */
528 if( cred->bv_val[i] != '\0' ) {
529 return 1; /* cred must behave like a string */
532 for( i=0; i<passwd->bv_len; i++) {
533 if(passwd->bv_val[i] == '\0') {
534 return 1; /* NUL character in password */
538 if( passwd->bv_val[i] != '\0' ) {
539 return 1; /* passwd must behave like a string */
544 #ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */
547 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan
548 * (Royal Institute of Technology, Stockholm, Sweden).
549 * All rights reserved.
551 * Redistribution and use in source and binary forms, with or without
552 * modification, are permitted provided that the following conditions
555 * 1. Redistributions of source code must retain the above copyright
556 * notice, this list of conditions and the following disclaimer.
558 * 2. Redistributions in binary form must reproduce the above copyright
559 * notice, this list of conditions and the following disclaimer in the
560 * documentation and/or other materials provided with the distribution.
562 * 3. Neither the name of the Institute nor the names of its contributors
563 * may be used to endorse or promote products derived from this software
564 * without specific prior written permission.
566 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
567 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
568 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
569 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
570 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
571 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
572 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
573 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
574 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
575 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
579 krb5_context context;
582 krb5_get_init_creds_opt get_options;
583 krb5_verify_init_creds_opt verify_options;
584 krb5_principal client, server;
586 krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
589 ret = krb5_init_context( &context );
595 krb5_get_init_creds_opt_set_preauth_list(&get_options,
599 krb5_get_init_creds_opt_init( &get_options );
601 krb5_verify_init_creds_opt_init( &verify_options );
603 ret = krb5_parse_name( context, passwd->bv_val, &client );
606 krb5_free_context( context );
610 ret = krb5_get_init_creds_password( context,
611 &creds, client, cred->bv_val, NULL,
612 NULL, 0, NULL, &get_options );
615 krb5_free_principal( context, client );
616 krb5_free_context( context );
621 char *host = ldap_pvt_get_fqdn( NULL );
624 krb5_free_principal( context, client );
625 krb5_free_context( context );
629 ret = krb5_sname_to_principal( context,
630 host, "ldap", KRB5_NT_SRV_HST, &server );
636 krb5_free_principal( context, client );
637 krb5_free_context( context );
641 ret = krb5_verify_init_creds( context,
642 &creds, server, NULL, NULL, &verify_options );
644 krb5_free_principal( context, client );
645 krb5_free_principal( context, server );
646 krb5_free_creds_contents( context, &creds );
647 krb5_free_context( context );
651 #elif defined(HAVE_KRB4)
653 /* Borrowed from Heimdal kpopper */
655 * Copyright (c) 1989 Regents of the University of California.
656 * All rights reserved. The Berkeley software License Agreement
657 * specifies the terms and conditions for redistribution.
661 char lrealm[REALM_SZ];
662 char tkt[MAXHOSTNAMELEN];
664 status = krb_get_lrealm(lrealm,1);
665 if (status == KFAILURE) {
669 snprintf(tkt, sizeof(tkt), "%s_slapd.%u",
670 TKT_ROOT, (unsigned)getpid());
671 krb_set_tkt_string (tkt);
673 status = krb_verify_user( passwd->bv_val, "", lrealm,
674 cred->bv_val, 1, "ldap");
676 dest_tkt(); /* no point in keeping the tickets */
678 return status == KFAILURE;
684 #endif /* SLAPD_KPASSWD */
687 static int chk_crypt(
688 const struct pw_scheme *sc,
689 const struct berval * passwd,
690 const struct berval * cred )
695 for( i=0; i<cred->bv_len; i++) {
696 if(cred->bv_val[i] == '\0') {
697 return 1; /* NUL character in password */
701 if( cred->bv_val[i] != '\0' ) {
702 return 1; /* cred must behave like a string */
705 if( passwd->bv_len < 2 ) {
706 return 1; /* passwd must be at least two characters long */
709 for( i=0; i<passwd->bv_len; i++) {
710 if(passwd->bv_val[i] == '\0') {
711 return 1; /* NUL character in password */
715 if( passwd->bv_val[i] != '\0' ) {
716 return 1; /* passwd must behave like a string */
719 cr = crypt( cred->bv_val, passwd->bv_val );
721 if( cr == NULL || cr[0] == '\0' ) {
722 /* salt must have been invalid */
726 return strcmp( passwd->bv_val, cr );
729 # if defined( HAVE_GETSPNAM ) \
730 || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
732 const struct pw_scheme *sc,
733 const struct berval * passwd,
734 const struct berval * cred )
739 for( i=0; i<cred->bv_len; i++) {
740 if(cred->bv_val[i] == '\0') {
741 return 1; /* NUL character in password */
744 if( cred->bv_val[i] != '\0' ) {
745 return 1; /* cred must behave like a string */
748 for( i=0; i<passwd->bv_len; i++) {
749 if(passwd->bv_val[i] == '\0') {
750 return 1; /* NUL character in password */
754 if( passwd->bv_val[i] != '\0' ) {
755 return 1; /* passwd must behave like a string */
758 # ifdef HAVE_GETSPNAM
760 struct spwd *spwd = getspnam(passwd->bv_val);
763 return 1; /* not found */
771 struct passwd *pwd = getpwnam(passwd->bv_val);
774 return 1; /* not found */
781 if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) {
782 /* password must must be at least two characters long */
786 cr = crypt(cred->bv_val, pw);
788 if( cr == NULL || cr[0] == '\0' ) {
789 /* salt must have been invalid */
793 return strcmp(pw, cr);
799 /* PASSWORD GENERATION ROUTINES */
801 #ifdef SLAPD_GENERATE
803 #ifdef LUTIL_SHA1_BYTES
804 static struct berval *hash_ssha1(
805 const struct pw_scheme *scheme,
806 const struct berval *passwd )
808 lutil_SHA1_CTX SHA1context;
809 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
810 unsigned char saltdata[4];
811 struct berval digest;
814 digest.bv_val = SHA1digest;
815 digest.bv_len = sizeof(SHA1digest);
816 salt.bv_val = saltdata;
817 salt.bv_len = sizeof(saltdata);
819 if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
823 lutil_SHA1Init( &SHA1context );
824 lutil_SHA1Update( &SHA1context,
825 (const unsigned char *)passwd->bv_val, passwd->bv_len );
826 lutil_SHA1Update( &SHA1context,
827 (const unsigned char *)salt.bv_val, salt.bv_len );
828 lutil_SHA1Final( SHA1digest, &SHA1context );
830 return pw_string64( scheme, &digest, &salt);
833 static struct berval *hash_sha1(
834 const struct pw_scheme *scheme,
835 const struct berval *passwd )
837 lutil_SHA1_CTX SHA1context;
838 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
839 struct berval digest;
840 digest.bv_val = SHA1digest;
841 digest.bv_len = sizeof(SHA1digest);
843 lutil_SHA1Init( &SHA1context );
844 lutil_SHA1Update( &SHA1context,
845 (const unsigned char *)passwd->bv_val, passwd->bv_len );
846 lutil_SHA1Final( SHA1digest, &SHA1context );
848 return pw_string64( scheme, &digest, NULL);
852 static struct berval *hash_smd5(
853 const struct pw_scheme *scheme,
854 const struct berval *passwd )
856 lutil_MD5_CTX MD5context;
857 unsigned char MD5digest[LUTIL_MD5_BYTES];
858 unsigned char saltdata[4];
859 struct berval digest;
862 digest.bv_val = MD5digest;
863 digest.bv_len = sizeof(MD5digest);
864 salt.bv_val = saltdata;
865 salt.bv_len = sizeof(saltdata);
867 if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
871 lutil_MD5Init( &MD5context );
872 lutil_MD5Update( &MD5context,
873 (const unsigned char *) passwd->bv_val, passwd->bv_len );
874 lutil_MD5Update( &MD5context,
875 (const unsigned char *) salt.bv_val, salt.bv_len );
876 lutil_MD5Final( MD5digest, &MD5context );
878 return pw_string64( scheme, &digest, &salt );
881 static struct berval *hash_md5(
882 const struct pw_scheme *scheme,
883 const struct berval *passwd )
885 lutil_MD5_CTX MD5context;
886 unsigned char MD5digest[LUTIL_MD5_BYTES];
888 struct berval digest;
890 digest.bv_val = MD5digest;
891 digest.bv_len = sizeof(MD5digest);
893 lutil_MD5Init( &MD5context );
894 lutil_MD5Update( &MD5context,
895 (const unsigned char *) passwd->bv_val, passwd->bv_len );
896 lutil_MD5Final( MD5digest, &MD5context );
898 return pw_string64( scheme, &digest, NULL );
903 static struct berval *hash_crypt(
904 const struct pw_scheme *scheme,
905 const struct berval *passwd )
908 unsigned char salt[3];
911 for( i=0; i<passwd->bv_len; i++) {
912 if(passwd->bv_val[i] == '\0') {
913 return NULL; /* NUL character in password */
917 if( passwd->bv_val[i] != '\0' ) {
918 return NULL; /* passwd must behave like a string */
921 if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
925 salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
926 salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
929 hash.bv_val = crypt( passwd->bv_val, salt );
931 if( hash.bv_val == NULL ) return NULL;
933 hash.bv_len = strlen( hash.bv_val );
935 if( hash.bv_len == 0 ) {
939 return pw_string( scheme, &hash );
943 #endif /* SLAPD_AUTHPASSWD */