]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/passwd.c
Per ITS#419, don't require SLAPD_RLOOKUPS when HAVE_TCPD
[openldap] / servers / slapd / passwd.c
index b06cd71e056fdad8cbe4c8a7dfcec2c68e5372f7..124d674dbbd3c0e9830a54b33044027e8f3801d7 100644 (file)
 
 #include <lutil.h>
 
-static int passwd_main(
+int passwd_extop(
        SLAP_EXTOP_CALLBACK_FN ext_callback,
-       Connection *conn, Operation *op, char *oid,
-       struct berval *reqdata, struct berval **rspdata, char **text )
+       Connection *conn, Operation *op,
+       char *reqoid,
+       struct berval *reqdata,
+       char **rspoid,
+       struct berval **rspdata,
+       LDAPControl ***rspctrls,
+       char **text,
+       struct berval ***refs )
 {
        int rc;
-       BerElement *ber;
-       struct berval *cred = NULL;
-       ber_int_t type;
 
-       assert( oid != NULL );
-       assert( strcmp( LDAP_EXOP_X_MODIFY_PASSWD, oid ) == 0 );
+       assert( reqoid != NULL );
+       assert( strcmp( LDAP_EXOP_X_MODIFY_PASSWD, reqoid ) == 0 );
 
        if( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
                *text = ch_strdup("only authenicated users may change passwords");
                return LDAP_STRONG_AUTH_REQUIRED;
        }
 
-       if( reqdata == NULL || reqdata->bv_len == 0 ) {
-               *text = ch_strdup("data missing");
-               return LDAP_PROTOCOL_ERROR;
+       if( conn->c_authz_backend != NULL && conn->c_authz_backend->be_extended )
+       {
+               if( global_readonly || conn->c_authz_backend->be_readonly ) {
+                       *text = ch_strdup("authorization database is read only");
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+
+               } else if( conn->c_authz_backend->be_update_ndn != NULL ) {
+                       /* we SHOULD return a referral in this case */
+                       *refs = conn->c_authz_backend->be_update_refs;
+                       rc = LDAP_REFERRAL;
+
+               } else {
+                       rc = conn->c_authz_backend->be_extended(
+                               conn->c_authz_backend, conn, op,
+                               reqoid, reqdata,
+                               rspoid, rspdata, rspctrls,
+                               text, refs );
+               }
+
+       } else {
+               *text = ch_strdup("operation not supported for current user");
+               rc = LDAP_UNWILLING_TO_PERFORM;
+       }
+
+       return rc;
+}
+
+int slap_passwd_parse( struct berval *reqdata,
+       struct berval **id,
+       struct berval **old,
+       struct berval **new,
+       char **text )
+{
+       int rc = LDAP_SUCCESS;
+       ber_tag_t tag;
+       ber_len_t len;
+       BerElement *ber;
+
+       if( reqdata == NULL ) {
+               return LDAP_SUCCESS;
        }
 
        ber = ber_init( reqdata );
 
        if( ber == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ber_init failed\n",
+                       0, 0, 0 );
                *text = ch_strdup("password decoding error");
                return LDAP_PROTOCOL_ERROR;
        }
 
-       rc = ber_scanf(ber, "{iO}", &type, &cred );
-       ber_free( ber, 1 );
+       tag = ber_scanf( ber, "{" /*}*/ );
 
-       if( rc == LBER_ERROR ) {
-               *text = ch_strdup("data decoding error");
-               return LDAP_PROTOCOL_ERROR;
+       if( tag != LBER_ERROR ) {
+               tag = ber_peek_tag( ber, &len );
        }
 
-       if( cred == NULL || cred->bv_len == 0 ) {
-               *text = ch_strdup("password missing");
-               return LDAP_PROTOCOL_ERROR;
+       if( tag == LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID ) {
+               if( id == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID not allowed.\n",
+                               0, 0, 0 );
+                       *text = "user must change own password";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
+
+               tag = ber_scanf( ber, "O", id );
+
+               if( tag == LBER_ERROR ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n",
+                               0, 0, 0 );
+                       goto decoding_error;
+               }
+
+               tag = ber_peek_tag( ber, &len);
        }
 
-       if( type != 0 ) {
-               ber_bvfree( cred );
-               *text = ch_strdup("password type unknown");
-               return LDAP_PROTOCOL_ERROR;
+       if( tag == LDAP_TAG_EXOP_X_MODIFY_PASSWD_OLD ) {
+               if( old == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD not allowed.\n",
+                               0, 0, 0 );
+                       *text = "use bind to verify old password";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
+
+               tag = ber_scanf( ber, "O", old );
+
+               if( tag == LBER_ERROR ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n",
+                               0, 0, 0 );
+                       goto decoding_error;
+               }
+
+               tag = ber_peek_tag( ber, &len);
        }
 
-       if( conn->c_authz_backend != NULL &&
-               conn->c_authz_backend->be_extended )
-       {
-               rc = conn->c_authz_backend->be_extended(
-                       conn->c_authz_backend,
-                       conn, op,
-                       oid, cred, rspdata, text );
+       if( tag == LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW ) {
+               if( new == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW not allowed.\n",
+                               0, 0, 0 );
+                       *text = "user specified passwords disallowed";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
 
-       } else {
-               *text = ch_strdup("operation not supported for current user");
-               rc = LDAP_UNWILLING_TO_PERFORM;
+               tag = ber_scanf( ber, "O", new );
+
+               if( tag == LBER_ERROR ) {
+                       Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD parse failed.\n",
+                               0, 0, 0 );
+                       goto decoding_error;
+               }
+
+               tag = ber_peek_tag( ber, &len );
+       }
+
+       if( len != 0 ) {
+decoding_error:
+               Debug( LDAP_DEBUG_TRACE,
+                       "slap_passwd_parse: decoding error, len=%ld\n",
+                       (long) len, 0, 0 );
+
+               *text = ch_strdup("data decoding error");
+               rc = LDAP_PROTOCOL_ERROR;
+       }
+
+done:
+       if( rc != LDAP_SUCCESS ) {
+               if( id != NULL ) {
+                       ber_bvfree( *id );
+                       *id = NULL;
+               }
+
+               if( old != NULL ) {
+                       ber_bvfree( *old );
+                       *old = NULL;
+               }
+
+               if( new != NULL ) {
+                       ber_bvfree( *new );
+                       *new = NULL;
+               }
        }
 
-       ber_bvfree( cred );
+       ber_free( ber, 1 );
        return rc;
 }
 
-int
-slap_passwd_init( void )
+struct berval * slap_passwd_return(
+       struct berval           *cred )
 {
-       return load_extop( LDAP_EXOP_X_MODIFY_PASSWD, passwd_main );
+       int rc;
+       struct berval *bv;
+       BerElement *ber = ber_alloc_t(LBER_USE_DER);
+
+       assert( cred != NULL );
+
+       Debug( LDAP_DEBUG_TRACE, "slap_passwd_return: %ld\n",
+               (long) cred->bv_len, 0, 0 );
+
+       if( ber == NULL ) return NULL;
+       
+       rc = ber_printf( ber, "{tO}",
+               LDAP_TAG_EXOP_X_MODIFY_PASSWD_GEN, cred );
+
+       if( rc == -1 ) {
+               ber_free( ber, 1 );
+               return NULL;
+       }
+
+       (void) ber_flatten( ber, &bv );
+
+       ber_free( ber, 1 );
+
+       return bv;
 }
 
 int
@@ -103,10 +230,7 @@ slap_passwd_check(
                ldap_pvt_thread_mutex_lock( &crypt_mutex );
 #endif
 
-               result = lutil_passwd(
-                       a->a_vals[i]->bv_val,
-                       cred->bv_val,
-                       NULL );
+               result = lutil_passwd( a->a_vals[i], cred, NULL );
 
 #ifdef SLAPD_CRYPT
                ldap_pvt_thread_mutex_unlock( &crypt_mutex );
@@ -118,31 +242,33 @@ slap_passwd_check(
        return( 1 );
 }
 
-struct berval * slap_passwd_generate(
+struct berval * slap_passwd_generate( void )
+{
+       Debug( LDAP_DEBUG_TRACE, "slap_passwd_generate\n", 0, 0, 0 );
+
+       /*
+        * generate passwords of only 8 characters as some getpass(3)
+        * implementations truncate at 8 characters.
+        */
+       return lutil_passwd_generate( 8 );
+}
+
+struct berval * slap_passwd_hash(
        struct berval * cred )
 {
        char* hash = default_passwd_hash ? default_passwd_hash : "{SSHA}";
 
-       struct berval *new = ber_memalloc( sizeof(struct berval) );
-
-       if( new == NULL ) return NULL;
+       struct berval *new;
 
 #ifdef SLAPD_CRYPT
        ldap_pvt_thread_mutex_lock( &crypt_mutex );
 #endif
 
-       new->bv_val = lutil_passwd_generate( cred->bv_val , hash );
+       new = lutil_passwd_hash( cred , hash );
        
 #ifdef SLAPD_CRYPT
        ldap_pvt_thread_mutex_unlock( &crypt_mutex );
 #endif
 
-       if( new->bv_val == NULL ) {
-               ber_bvfree( new );
-               return NULL;
-       }
-
-       new->bv_len = strlen( new->bv_val );
-
        return new;
 }