]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldap/bind.c
ITS#5138 don't scan past the sequence of attributes
[openldap] / servers / slapd / back-ldap / bind.c
index 8232009fd4bc3a00791e5e906ab05368bf3cfbec..eb3d49703b20f02acb6a5296f94625228998f7bb 100644 (file)
@@ -173,10 +173,23 @@ ldap_back_bind( Operation *op, SlapReply *rs )
        ldapinfo_t              *li = (ldapinfo_t *) op->o_bd->be_private;
        ldapconn_t              *lc;
 
-       int                     rc = 0;
+       LDAPControl             **ctrls = NULL;
+       struct berval           save_o_dn;
+       int                     save_o_do_not_cache,
+                               rc = 0;
        ber_int_t               msgid;
        ldap_back_send_t        retrying = LDAP_BACK_RETRYING;
 
+       /* allow rootdn as a means to auth without the need to actually
+        * contact the proxied DSA */
+       switch ( be_rootdn_bind( op, rs ) ) {
+       case SLAP_CB_CONTINUE:
+               break;
+
+       default:
+               return rs->sr_err;
+       }
+
        lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
        if ( !lc ) {
                return rs->sr_err;
@@ -195,11 +208,27 @@ ldap_back_bind( Operation *op, SlapReply *rs )
        }
        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
+       /* don't add proxyAuthz; set the bindDN */
+       save_o_dn = op->o_dn;
+       save_o_do_not_cache = op->o_do_not_cache;
+       op->o_dn = op->o_req_dn;
+       op->o_do_not_cache = 1;
+
+       ctrls = op->o_ctrls;
+       rc = ldap_back_controls_add( op, rs, lc, &ctrls );
+       op->o_dn = save_o_dn;
+       op->o_do_not_cache = save_o_do_not_cache;
+       if ( rc != LDAP_SUCCESS ) {
+               send_ldap_result( op, rs );
+               ldap_back_release_conn( li, lc );
+               return( rc );
+       }
+
 retry:;
        /* method is always LDAP_AUTH_SIMPLE if we got here */
        rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
                        LDAP_SASL_SIMPLE,
-                       &op->orb_cred, op->o_ctrls, NULL, &msgid );
+                       &op->orb_cred, ctrls, NULL, &msgid );
        /* FIXME: should we always retry, or only when piping the bind
         * in the "override" connection pool? */
        rc = ldap_back_op_result( lc, op, rs, msgid,
@@ -212,6 +241,8 @@ retry:;
                }
        }
 
+       ldap_back_controls_free( op, rs, &ctrls );
+
        if ( rc == LDAP_SUCCESS ) {
                /* If defined, proxyAuthz will be used also when
                 * back-ldap is the authorizing backend; for this
@@ -1189,6 +1220,17 @@ done:;
        ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
 }
 
+static int
+ldap_back_dobind_cb(
+       Operation *op,
+       SlapReply *rs
+)
+{
+       ber_tag_t *tptr = op->o_callback->sc_private;
+       op->o_tag = *tptr;
+       return SLAP_CB_CONTINUE;
+}
+
 /*
  * ldap_back_dobind_int
  *
@@ -1214,6 +1256,7 @@ ldap_back_dobind_int(
                        binding = 0;
        ber_int_t       msgid;
        ber_tag_t       o_tag = op->o_tag;
+       slap_callback cb = {0};
 
        assert( lcp != NULL );
        assert( retries >= 0 );
@@ -1285,11 +1328,16 @@ retry_lock:;
         * then bind as the asserting identity and explicitly 
         * add the proxyAuthz control to every operation with the
         * dn bound to the connection as control value.
-        * This is done also if this is the authrizing backend,
+        * This is done also if this is the authorizing backend,
         * but the "override" flag is given to idassert.
         * It allows to use SASL bind and yet proxyAuthz users
         */
        op->o_tag = LDAP_REQ_BIND;
+       cb.sc_next = op->o_callback;
+       cb.sc_private = &o_tag;
+       cb.sc_response = ldap_back_dobind_cb;
+       op->o_callback = &cb;
+
        if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
                if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
                        /* if we got here, it shouldn't return result */
@@ -1325,6 +1373,14 @@ retry_lock:;
                                li->li_acl_authcID.bv_val,
                                li->li_acl_passwd.bv_val,
                                NULL );
+               if ( defaults == NULL ) {
+                       rs->sr_err = LDAP_OTHER;
+                       LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+                       if ( sendok & LDAP_BACK_SENDERR ) {
+                               send_ldap_result( op, rs );
+                       }
+                       goto done;
+               }
 
                rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
                                li->li_acl_authcDN.bv_val,
@@ -1403,11 +1459,15 @@ retry:;
                if ( rs->sr_err != LDAP_SUCCESS &&
                        ( sendok & LDAP_BACK_SENDERR ) )
                {
-                       rs->sr_text = "Internal proxy bind failure";
+                       if ( op->o_callback == &cb )
+                               op->o_callback = cb.sc_next;
+                       op->o_tag = o_tag;
+                       rs->sr_text = "Proxy can't contact remote server";
                        send_ldap_result( op, rs );
                }
 
-               return 0;
+               rc = 0;
+               goto leave;
        }
 
        rc = ldap_back_op_result( lc, op, rs, msgid,
@@ -1417,7 +1477,6 @@ retry:;
        }
 
 done:;
-       op->o_tag = o_tag;
        LDAP_BACK_CONN_BINDING_CLEAR( lc );
        rc = LDAP_BACK_CONN_ISBOUND( lc );
        if ( !rc ) {
@@ -1427,6 +1486,11 @@ done:;
                ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
        }
 
+leave:;
+       if ( op->o_callback == &cb )
+               op->o_callback = cb.sc_next;
+       op->o_tag = o_tag;
+
        return rc;
 }
 
@@ -2056,6 +2120,14 @@ ldap_back_proxy_authz_bind(
                                li->li_idassert_authcID.bv_val,
                                li->li_idassert_passwd.bv_val,
                                authzID.bv_val );
+               if ( defaults == NULL ) {
+                       rs->sr_err = LDAP_OTHER;
+                       LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+                       if ( sendok & LDAP_BACK_SENDERR ) {
+                               send_ldap_result( op, rs );
+                       }
+                       goto done;
+               }
 
                rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val,
                                li->li_idassert_sasl_mech.bv_val, NULL, NULL,
@@ -2159,44 +2231,26 @@ done:;
  */
 int
 ldap_back_proxy_authz_ctrl(
+               Operation       *op,
+               SlapReply       *rs,
                struct berval   *bound_ndn,
                int             version,
                slap_idassert_t *si,
-               Operation       *op,
-               SlapReply       *rs,
-               LDAPControl     ***pctrls )
+               LDAPControl     *ctrl )
 {
-       LDAPControl             **ctrls = NULL;
-       int                     i = 0;
        slap_idassert_mode_t    mode;
        struct berval           assertedID,
                                ndn;
        int                     isroot = 0;
 
-       *pctrls = NULL;
-
-       rs->sr_err = LDAP_SUCCESS;
-
-       /* don't proxyAuthz if protocol is not LDAPv3 */
-       switch ( version ) {
-       case LDAP_VERSION3:
-               break;
-
-       case 0:
-               if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
-                       break;
-               }
-               /* fall thru */
-
-       default:
-               goto done;
-       }
+       rs->sr_err = SLAP_CB_CONTINUE;
 
        /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
         * but if it is not set this test fails.  We need a different
         * means to detect if idassert is enabled */
        if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
-                       && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) )
+               && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
+               && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
        {
                goto done;
        }
@@ -2263,7 +2317,7 @@ ldap_back_proxy_authz_ctrl(
                        authcDN = ndn;
                }
                rc = slap_sasl_matches( op, si->si_authz,
-                               &authcDN, & authcDN );
+                               &authcDN, &authcDN );
                if ( rc != LDAP_SUCCESS ) {
                        if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
                                /* ndn is not authorized
@@ -2340,33 +2394,25 @@ ldap_back_proxy_authz_ctrl(
                goto done;
        }
 
-       if ( op->o_ctrls ) {
-               for ( i = 0; op->o_ctrls[ i ]; i++ )
-                       /* just count ctrls */ ;
-       }
-
-       ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ),
-                       op->o_tmpmemctx );
-       ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ];
-       
-       ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
-       ctrls[ 0 ]->ldctl_iscritical = 1;
+       ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
 
        switch ( si->si_mode ) {
        /* already in u:ID or dn:DN form */
        case LDAP_BACK_IDASSERT_OTHERID:
        case LDAP_BACK_IDASSERT_OTHERDN:
-               ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx );
+               ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
+               rs->sr_err = LDAP_SUCCESS;
                break;
 
        /* needs the dn: prefix */
        default:
-               ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
-               ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1,
+               ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
+               ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
                                op->o_tmpmemctx );
-               AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
-               AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
+               AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
+               AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
                                assertedID.bv_val, assertedID.bv_len + 1 );
+               rs->sr_err = LDAP_SUCCESS;
                break;
        }
 
@@ -2375,7 +2421,7 @@ ldap_back_proxy_authz_ctrl(
         * this hack provides compatibility with those DSAs that
         * implement it this way */
        if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
-               struct berval           authzID = ctrls[ 0 ]->ldctl_value;
+               struct berval           authzID = ctrl->ldctl_value;
                BerElementBuffer        berbuf;
                BerElement              *ber = (BerElement *)&berbuf;
                ber_tag_t               tag;
@@ -2389,32 +2435,29 @@ ldap_back_proxy_authz_ctrl(
                        goto free_ber;
                }
 
-               if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
+               if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
                        rs->sr_err = LDAP_OTHER;
                        goto free_ber;
                }
 
+               rs->sr_err = LDAP_SUCCESS;
+
 free_ber:;
                op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
                ber_free_buf( ber );
 
                if ( rs->sr_err != LDAP_SUCCESS ) {
-                       op->o_tmpfree( ctrls, op->o_tmpmemctx );
-                       ctrls = NULL;
                        goto done;
                }
 
        } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
-               struct berval           authzID = ctrls[ 0 ]->ldctl_value,
+               struct berval           authzID = ctrl->ldctl_value,
                                        tmp;
                BerElementBuffer        berbuf;
                BerElement              *ber = (BerElement *)&berbuf;
                ber_tag_t               tag;
 
                if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
-                       op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
-                       op->o_tmpfree( ctrls, op->o_tmpmemctx );
-                       ctrls = NULL;
                        rs->sr_err = LDAP_PROTOCOL_ERROR;
                        goto done;
                }
@@ -2434,30 +2477,130 @@ free_ber:;
                        goto free_ber2;
                }
 
-               if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
+               if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
                        rs->sr_err = LDAP_OTHER;
                        goto free_ber2;
                }
 
+               ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
+               rs->sr_err = LDAP_SUCCESS;
+
 free_ber2:;
                op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
                ber_free_buf( ber );
 
                if ( rs->sr_err != LDAP_SUCCESS ) {
-                       op->o_tmpfree( ctrls, op->o_tmpmemctx );
-                       ctrls = NULL;
                        goto done;
                }
+       }
+
+done:;
 
-               ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
+       return rs->sr_err;
+}
+
+/*
+ * Add controls;
+ *
+ * if any needs to be added, it is prepended to existing ones,
+ * in a newly allocated array.  The companion function
+ * ldap_back_controls_free() must be used to restore the original
+ * status of op->o_ctrls.
+ */
+int
+ldap_back_controls_add(
+               Operation       *op,
+               SlapReply       *rs,
+               ldapconn_t      *lc,
+               LDAPControl     ***pctrls )
+{
+       ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
+
+       LDAPControl     **ctrls = NULL;
+       /* set to the maximum number of controls this backend can add */
+       LDAPControl     c[ 2 ] = { 0 };
+       int             i = 0, j = 0;
+
+       *pctrls = NULL;
+
+       rs->sr_err = LDAP_SUCCESS;
+
+       /* don't add controls if protocol is not LDAPv3 */
+       switch ( li->li_version ) {
+       case LDAP_VERSION3:
+               break;
+
+       case 0:
+               if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
+                       break;
+               }
+               /* fall thru */
+
+       default:
+               goto done;
+       }
+
+       /* proxyAuthz for identity assertion */
+       switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn,
+               li->li_version, &li->li_idassert, &c[ j ] ) )
+       {
+       case SLAP_CB_CONTINUE:
+               break;
+
+       case LDAP_SUCCESS:
+               j++;
+               break;
+
+       default:
+               goto done;
+       }
+
+#ifdef SLAP_CONTROL_X_SESSION_TRACKING
+       /* session tracking */
+       if ( LDAP_BACK_ST_REQUEST( li ) ) {
+               switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j ] ) ) {
+               case SLAP_CB_CONTINUE:
+                       break;
+
+               case LDAP_SUCCESS:
+                       j++;
+                       break;
+
+               default:
+                       goto done;
+               }
+       }
+#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
+
+       if ( rs->sr_err == SLAP_CB_CONTINUE ) {
+               rs->sr_err = LDAP_SUCCESS;
+       }
+
+       if ( j == 0 ) {
+               goto done;
        }
 
+       if ( op->o_ctrls ) {
+               for ( i = 0; op->o_ctrls[ i ]; i++ )
+                       /* just count ctrls */ ;
+       }
+
+       ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + j + 1) + j * sizeof( LDAPControl ),
+                       op->o_tmpmemctx );
+       ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + j + 1 ];
+       *ctrls[ 0 ] = c[ 0 ];
+       for ( i = 1; i < j; i++ ) {
+               ctrls[ i ] = &ctrls[ 0 ][ i ];
+               *ctrls[ i ] = c[ i ];
+       }
+
+       i = 0;
        if ( op->o_ctrls ) {
                for ( i = 0; op->o_ctrls[ i ]; i++ ) {
-                       ctrls[ i + 1 ] = op->o_ctrls[ i ];
+                       ctrls[ i + j ] = op->o_ctrls[ i ];
                }
        }
-       ctrls[ i + 1 ] = NULL;
+       ctrls[ i + j ] = NULL;
 
 done:;
        if ( ctrls == NULL ) {
@@ -2470,18 +2613,25 @@ done:;
 }
 
 int
-ldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls )
+ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls )
 {
        LDAPControl     **ctrls = *pctrls;
 
-       /* we assume that the first control is the proxyAuthz
-        * added by back-ldap, so it's the only one we explicitly 
-        * free */
+       /* we assume that the controls added by the proxy come first,
+        * so as soon as we find op->o_ctrls[ 0 ] we can stop */
        if ( ctrls && ctrls != op->o_ctrls ) {
+               int     i;
+
                assert( ctrls[ 0 ] != NULL );
 
-               if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) {
-                       op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
+               for ( i = 0; ctrls[ i ] != NULL; i++ ) {
+                       if ( op->o_ctrls && ctrls[ i ] == op->o_ctrls[ 0 ] ) {
+                               break;
+                       }
+
+                       if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) {
+                               op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx );
+                       }
                }
 
                op->o_tmpfree( ctrls, op->o_tmpmemctx );