]> git.sur5r.net Git - openldap/blobdiff - libraries/liblutil/passwd.c
Add experimental code to check simple bind passwords
[openldap] / libraries / liblutil / passwd.c
index 561750f69bda72e62fcf6d7130c2dfac6d323528..866d68228bf50cb45e3399102803f840ab26fe35 100644 (file)
@@ -4,10 +4,13 @@
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 /*
- * lutil_password(credentials, password)
+ * int lutil_passwd(
+ *     const struct berval *passwd,
+ *     const struct berval *cred,
+ *     const char **schemes )
  *
- * Returns true if user supplied credentials matches
- * the stored password. 
+ * Returns true if user supplied credentials (cred) matches
+ * the stored password (passwd)
  *
  * Due to the use of the crypt(3) function 
  * this routine is NOT thread-safe.
 #include <ac/stdlib.h>
 #include <ac/string.h>
 
+#ifdef SLAPD_SPASSWD
+#      include <sasl.h>
+#endif
+
 #ifdef SLAPD_KPASSWD
 #      include <ac/krb.h>
 #      include <ac/krb5.h>
@@ -83,10 +90,19 @@ static int chk_sha1(
        const struct berval *passwd,
        const struct berval *cred );
 
+#ifdef SLAPD_SPASSWD
+static int chk_sasl(
+       const struct pw_scheme *scheme,
+       const struct berval *passwd,
+       const struct berval *cred );
+#endif
+
+#ifdef SLAPD_KPASSWD
 static int chk_kerberos(
        const struct pw_scheme *scheme,
        const struct berval *passwd,
        const struct berval *cred );
+#endif
 
 static int chk_crypt(
        const struct pw_scheme *scheme,
@@ -129,6 +145,10 @@ static const struct pw_scheme pw_schemes[] =
        { {sizeof("{SMD5}")-1, "{SMD5}"},       chk_smd5, hash_smd5 },
        { {sizeof("{MD5}")-1, "{MD5}"},         chk_md5, hash_md5 },
 
+#ifdef SLAPD_SPASSWD
+       { {sizeof("{SASL}")-1, "{SASL}"}, chk_sasl, NULL },
+#endif
+
 #ifdef SLAPD_KPASSWD
        { {sizeof("{KERBEROS}")-1, "{KERBEROS}"}, chk_kerberos, NULL },
 #endif
@@ -380,15 +400,16 @@ static struct berval * pw_string64(
                string.bv_val, string.bv_len,
                &b64->bv_val[sc->name.bv_len], b64len );
 
-       b64->bv_val[b64->bv_len] = '\0';
-
        if( salt ) ber_memfree( string.bv_val );
-
+       
        if( rc < 0 ) {
                ber_bvfree( b64 );
                return NULL;
        }
 
+       /* recompute length */
+       b64->bv_len = sc->name.bv_len + rc;
+       assert( strlen(b64->bv_val) == b64->bv_len );
        return b64;
 }
 
@@ -404,7 +425,7 @@ static int chk_ssha1(
        int rc;
        unsigned char *orig_pass = NULL;
  
-       /* base64 un-encode password */
+       /* decode base64 password */
        orig_pass = (unsigned char *) ber_memalloc( (size_t) (
                LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
 
@@ -414,7 +435,7 @@ static int chk_ssha1(
 
        if(rc < 0) {
                ber_memfree(orig_pass);
-               return 1;
+               return -1;
        }
  
        /* hash credentials with salt */
@@ -429,7 +450,7 @@ static int chk_ssha1(
        /* compare */
        rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
        ber_memfree(orig_pass);
-       return rc;
+       return rc ? 1 : 0;
 }
 
 static int chk_sha1(
@@ -452,7 +473,7 @@ static int chk_sha1(
 
        if( rc != sizeof(SHA1digest) ) {
                ber_memfree(orig_pass);
-               return 1;
+               return -1;
        }
  
        /* hash credentials with salt */
@@ -464,7 +485,7 @@ static int chk_sha1(
        /* compare */
        rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
        ber_memfree(orig_pass);
-       return rc;
+       return rc ? 1 : 0;
 }
 
 static int chk_smd5(
@@ -486,7 +507,7 @@ static int chk_smd5(
        rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
        if ( rc < 0 ) {
                ber_memfree(orig_pass);
-               return 1;
+               return -1;
        }
 
        /* hash credentials with salt */
@@ -501,7 +522,7 @@ static int chk_smd5(
        /* compare */
        rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
        ber_memfree(orig_pass);
-       return rc;
+       return rc ? 1 : 0;
 }
 
 static int chk_md5(
@@ -523,7 +544,7 @@ static int chk_md5(
        rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
        if ( rc != sizeof(MD5digest) ) {
                ber_memfree(orig_pass);
-               return 1;
+               return -1;
        }
 
        /* hash credentials with salt */
@@ -535,8 +556,61 @@ static int chk_md5(
        /* compare */
        rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
        ber_memfree(orig_pass);
-       return rc;
+       return rc ? 1 : 0;
+}
+
+#ifdef SLAPD_SPASSWD
+#ifdef HAVE_CYRUS_SASL
+sasl_conn_t *lutil_passwd_sasl_conn = NULL;
+#endif
+
+static int chk_sasl(
+       const struct pw_scheme *sc,
+       const struct berval * passwd,
+       const struct berval * cred )
+{
+       int i;
+       int rtn;
+
+       for( i=0; i<cred->bv_len; i++) {
+               if(cred->bv_val[i] == '\0') {
+                       return 1;       /* NUL character in password */
+               }
+       }
+
+       if( cred->bv_val[i] != '\0' ) {
+               return 1;       /* cred must behave like a string */
+       }
+
+       for( i=0; i<passwd->bv_len; i++) {
+               if(passwd->bv_val[i] == '\0') {
+                       return 1;       /* NUL character in password */
+               }
+       }
+
+       if( passwd->bv_val[i] != '\0' ) {
+               return 1;       /* passwd must behave like a string */
+       }
+
+       rtn = 1;
+
+#ifdef HAVE_CYRUS_SASL
+       if( lutil_passwd_sasl_conn != NULL ) {
+               const char *errstr = NULL;
+               int sc;
+
+               sc = sasl_checkpass( lutil_passwd_sasl_conn,
+                       passwd->bv_val, passwd->bv_len,
+                       cred->bv_val, cred->bv_len,
+                       &errstr );
+
+               rtn = ( sc != SASL_OK );
+       }
+#endif
+
+       return rtn;
 }
+#endif
 
 #ifdef SLAPD_KPASSWD
 static int chk_kerberos(
@@ -614,7 +688,7 @@ static int chk_kerberos(
                krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
 #endif
 
-               krb5_init_context( &context );
+               ret = krb5_init_context( &context );
                if (ret) {
                        return 1;
                }
@@ -715,6 +789,7 @@ static int chk_crypt(
        const struct berval * passwd,
        const struct berval * cred )
 {
+       char *cr;
        int i;
 
        for( i=0; i<cred->bv_len; i++) {
@@ -724,20 +799,31 @@ static int chk_crypt(
        }
 
        if( cred->bv_val[i] != '\0' ) {
-               return 1;       /* cred must behave like a string */
+               return -1;      /* cred must behave like a string */
+       }
+
+       if( passwd->bv_len < 2 ) {
+               return -1;      /* passwd must be at least two characters long */
        }
 
        for( i=0; i<passwd->bv_len; i++) {
                if(passwd->bv_val[i] == '\0') {
-                       return 1;       /* NUL character in password */
+                       return -1;      /* NUL character in password */
                }
        }
 
        if( passwd->bv_val[i] != '\0' ) {
-               return 1;       /* passwd must behave like a string */
+               return -1;      /* passwd must behave like a string */
+       }
+
+       cr = crypt( cred->bv_val, passwd->bv_val );
+
+       if( cr == NULL || cr[0] == '\0' ) {
+               /* salt must have been invalid */
+               return -1;
        }
 
-       return strcmp(passwd->bv_val, crypt(cred->bv_val, passwd->bv_val));
+       return strcmp( passwd->bv_val, cr ) ? 1 : 0;
 }
 
 # if defined( HAVE_GETSPNAM ) \
@@ -748,25 +834,25 @@ static int chk_unix(
        const struct berval * cred )
 {
        int i;
-       char *pw;
+       char *pw,*cr;
 
        for( i=0; i<cred->bv_len; i++) {
                if(cred->bv_val[i] == '\0') {
-                       return 1;       /* NUL character in password */
+                       return -1;      /* NUL character in password */
                }
        }
        if( cred->bv_val[i] != '\0' ) {
-               return 1;       /* cred must behave like a string */
+               return -1;      /* cred must behave like a string */
        }
 
        for( i=0; i<passwd->bv_len; i++) {
                if(passwd->bv_val[i] == '\0') {
-                       return 1;       /* NUL character in password */
+                       return -1;      /* NUL character in password */
                }
        }
 
        if( passwd->bv_val[i] != '\0' ) {
-               return 1;       /* passwd must behave like a string */
+               return -1;      /* passwd must behave like a string */
        }
 
 #  ifdef HAVE_GETSPNAM
@@ -774,7 +860,7 @@ static int chk_unix(
                struct spwd *spwd = getspnam(passwd->bv_val);
 
                if(spwd == NULL) {
-                       return 1;       /* not found */
+                       return -1;      /* not found */
                }
 
                pw = spwd->sp_pwdp;
@@ -785,22 +871,33 @@ static int chk_unix(
                struct passwd *pwd = getpwnam(passwd->bv_val);
 
                if(pwd == NULL) {
-                       return 1;       /* not found */
+                       return -1;      /* not found */
                }
 
                pw = pwd->pw_passwd;
        }
 #  endif
 
-       if( pw == NULL || *pw == '\0' ) return 1;
+       if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) {
+               /* password must must be at least two characters long */
+               return -1;
+       }
 
-       return strcmp(pw, crypt(cred->bv_val, pw));
+       cr = crypt(cred->bv_val, pw);
+
+       if( cr == NULL || cr[0] == '\0' ) {
+               /* salt must have been invalid */
+               return -1;
+       }
+
+       return strcmp(pw, cr) ? 1 : 0;
 
 }
 # endif
 #endif
 
-/* PASSWORD CHECK ROUTINES */
+/* PASSWORD GENERATION ROUTINES */
+
 static struct berval *hash_ssha1(
        const struct pw_scheme *scheme,
        const struct berval  *passwd )
@@ -928,8 +1025,13 @@ static struct berval *hash_crypt(
        hash.bv_val = crypt( passwd->bv_val, salt );
 
        if( hash.bv_val == NULL ) return NULL;
+
        hash.bv_len = strlen( hash.bv_val );
 
+       if( hash.bv_len == 0 ) {
+               return NULL;
+       }
+
        return pw_string( scheme, &hash );
 }
 #endif