+ ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
+ ctrl.ldctl_iscritical = 0;
+ BER_BVZERO( &ctrl.ldctl_value );
+ ctrls[0] = &ctrl;
+ ctrls[1] = NULL;
+ ctrlsp = ctrls;
+ }
+#endif /* SLAP_AUTH_DN */
+
+ do {
+ rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val,
+ li->li_idassert_sasl_mech.bv_val,
+ ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults,
+ result, &rmech, &msgid );
+
+ if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS )
+ break;
+
+ ldap_msgfree( result );
+
+ if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
+ ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err );
+ ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text );
+ break;
+ }
+ } while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS );
+
+ switch ( rs->sr_err ) {
+ case LDAP_SUCCESS:
+#ifdef SLAP_AUTH_DN
+ /* FIXME: right now, the only reason to check
+ * response controls is RFC 3829 authzid */
+ if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
+ ctrlsp = NULL;
+ rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL,
+ &ctrlsp, 0 );
+ if ( rc == LDAP_SUCCESS && ctrlsp ) {
+ LDAPControl *ctrl;
+
+ ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
+ ctrlsp, NULL );
+ if ( ctrl ) {
+ Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n",
+ op->o_log_prefix, ctrl->ldctl_value.bv_val, 0 );
+ if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") &&
+ strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 )
+ {
+ struct berval bv;
+ bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")];
+ bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:");
+ ber_bvreplace( &lc->lc_bound_ndn, &bv );
+ }
+ }
+ }
+
+ ldap_controls_free( ctrlsp );
+
+ } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) {
+ struct berval *val = NULL;
+ rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL );
+ if ( rc == LDAP_SUCCESS && val != NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n",
+ op->o_log_prefix, val->bv_val, 0 );
+ if ( val->bv_len > STRLENOF("dn:") &&
+ strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 )
+ {
+ struct berval bv;
+ bv.bv_val = &val->bv_val[STRLENOF("dn:")];
+ bv.bv_len = val->bv_len - STRLENOF("dn:");
+ ber_bvreplace( &lc->lc_bound_ndn, &bv );
+ }
+ ber_bvfree( val );
+ }
+ }
+
+ if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) &&
+ BER_BVISNULL( &lc->lc_bound_ndn ) )
+ {
+ /* all in all, we only need it to be non-null */
+ /* FIXME: should this be configurable? */
+ static struct berval bv = BER_BVC("cn=authzdn");
+ ber_bvreplace( &lc->lc_bound_ndn, &bv );
+ }
+#endif /* SLAP_AUTH_DN */
+ op->o_conn->c_authz_cookie = op->o_bd->be_private;
+ LDAP_BACK_CONN_ISBOUND_SET( lc );
+ break;
+
+ case LDAP_LOCAL_ERROR:
+ /* list client API error codes that require
+ * to taint the connection */
+ /* FIXME: should actually retry? */
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+
+ /* fallthru */
+
+ default: