]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldap/chain.c
add a giant mutex around the ldapinfo structure to serialize chaining (need to check...
[openldap] / servers / slapd / back-ldap / chain.c
index 8f702c85b9d18882ef57ad434631d54e667d2f17..a0dbb581c23ab34e9729ba65529abcf6ab278d2d 100644 (file)
@@ -69,6 +69,8 @@ typedef struct ldap_chain_t {
 #define LDAP_CHAIN_F_NONE              0x00U
 #define        LDAP_CHAIN_F_CHAINING           0x01U
 
+       ldap_pvt_thread_mutex_t lc_mutex;
+
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        LDAPControl             lc_chaining_ctrl;
        char                    lc_chaining_ctrlflag;
@@ -259,7 +261,10 @@ ldap_chain_op(
 {
        slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
-       struct ldapinfo li, *lip = lc->lc_li;
+
+       struct ldapinfo *lip = lc->lc_li;
+       char            *save_url = NULL;
+       SlapReply       rs2 = { 0 };
 
        /* NOTE: returned if ref is empty... */
        int             rc = LDAP_OTHER;
@@ -272,12 +277,14 @@ ldap_chain_op(
 
        if ( lip->url != NULL ) {
                op->o_bd->be_private = lip;
-               rc = ( *op_f )( op, rs );
+               rc = ( *op_f )( op, &rs2 );
+               rs->sr_err = rs2.sr_err;
                goto done;
        }
 
-       li = *lip;
-       op->o_bd->be_private = &li;
+       save_url = lip->url;
+       lip->url = NULL;
+       op->o_bd->be_private = lip;
 
        /* if we parse the URI then by no means 
         * we can cache stuff or reuse connections, 
@@ -321,26 +328,29 @@ Document: draft-ietf-ldapbis-protocol-27.txt
                save_dn = srv->lud_dn;
                srv->lud_dn = "";
                srv->lud_scope = LDAP_SCOPE_DEFAULT;
-               li.url = ldap_url_desc2str( srv );
+               lip->url = ldap_url_desc2str( srv );
                srv->lud_dn = save_dn;
                ldap_free_urldesc( srv );
 
-               if ( li.url == NULL ) {
+               if ( lip->url == NULL ) {
                        /* try next */
                        rc = LDAP_OTHER;
                        continue;
                }
 
-               rc = ( *op_f )( op, rs );
+               rc = ( *op_f )( op, &rs2 );
+               rs->sr_err = rs2.sr_err;
 
-               ldap_memfree( li.url );
-               li.url = NULL;
+               ldap_memfree( lip->url );
+               lip->url = NULL;
                
                if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
                        break;
                }
        }
 
+       lip->url = save_url;
+
 done:;
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        (void)chaining_control_remove( op, &ctrls );
@@ -362,7 +372,7 @@ ldap_chain_response( Operation *op, SlapReply *rs )
        struct berval   ndn = op->o_ndn;
 
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
-       struct ldapinfo li, *lip = lc->lc_li;
+       struct ldapinfo *lip = lc->lc_li;
 
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        int             sr_err = rs->sr_err;
@@ -402,6 +412,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
        }
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
+       ldap_pvt_thread_mutex_lock( &lc->lc_mutex );
+
        /*
         * TODO: add checks on who/when chain operations; e.g.:
         *   a) what identities are authorized
@@ -441,8 +453,6 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                }
                break;
        case LDAP_REQ_ADD:
-               /* slap_mods2entry () should be called in do_add() */
-               assert( op->ora_e->e_attrs != NULL );
                rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
                break;
        case LDAP_REQ_DELETE:
@@ -462,6 +472,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                        struct berval   *curr = ref,
                                        odn = op->o_req_dn,
                                        ondn = op->o_req_ndn;
+                       char            *save_url = NULL;
+                       SlapReply       rs2 = { 0 };
 
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                        LDAPControl     **ctrls = NULL;
@@ -473,9 +485,9 @@ ldap_chain_response( Operation *op, SlapReply *rs )
 
                        sc2.sc_response = ldap_chain_cb_search_response;
 
-                       li = *lip;
-                       li.url = NULL;
-                       op->o_bd->be_private = &li;
+                       save_url = lip->url;
+                       lip->url = NULL;
+                       op->o_bd->be_private = lip;
                        
                        /* if we parse the URI then by no means 
                         * we can cache stuff or reuse connections, 
@@ -504,8 +516,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                                save_dn = srv->lud_dn;
                                srv->lud_dn = "";
                                srv->lud_scope = LDAP_SCOPE_DEFAULT;
-                               li.url = ldap_url_desc2str( srv );
-                               if ( li.url != NULL ) {
+                               lip->url = ldap_url_desc2str( srv );
+                               if ( lip->url != NULL ) {
                                        ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
                                                        op->o_tmpmemctx );
                                        ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
@@ -515,7 +527,7 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                                srv->lud_dn = save_dn;
                                ldap_free_urldesc( srv );
 
-                               if ( li.url == NULL ) {
+                               if ( lip->url == NULL ) {
                                        /* try next */
                                        rs->sr_err = LDAP_OTHER;
                                        continue;
@@ -524,10 +536,11 @@ ldap_chain_response( Operation *op, SlapReply *rs )
 
                                /* FIXME: should we also copy filter and scope?
                                 * according to RFC3296, no */
-                               rc = lback->bi_op_search( op, rs );
+                               rc = lback->bi_op_search( op, &rs2 );
+                               rs->sr_err = rs2.sr_err;
 
-                               ldap_memfree( li.url );
-                               li.url = NULL;
+                               ldap_memfree( lip->url );
+                               lip->url = NULL;
 
                                op->o_tmpfree( op->o_req_dn.bv_val,
                                                op->o_tmpmemctx );
@@ -545,6 +558,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                        (void)chaining_control_remove( op, &ctrls );
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
+                       lip->url = save_url;
+
                        op->o_req_dn = odn;
                        op->o_req_ndn = ondn;
                        rs->sr_type = REP_SEARCHREF;
@@ -613,6 +628,8 @@ dont_chain:;
        op->o_ndn = ndn;
        rs->sr_ref = ref;
 
+       ldap_pvt_thread_mutex_unlock( &lc->lc_mutex );
+
        return rc;
 }
 
@@ -1074,6 +1091,8 @@ ldap_chain_db_init(
        lc = ch_malloc( sizeof( ldap_chain_t ) );
        memset( lc, 0, sizeof( ldap_chain_t ) );
 
+       ldap_pvt_thread_mutex_init( &lc->lc_mutex );
+
        bd.be_private = NULL;
        rc = lback->bi_db_init( &bd );
        lc->lc_li = (struct ldapinfo *)bd.be_private;
@@ -1108,7 +1127,7 @@ ldap_chain_db_destroy(
 
        be->be_private = (void *)lc->lc_li;
        rc = lback->bi_db_destroy( be );
-       lc->lc_li = be->be_private;
+       ldap_pvt_thread_mutex_destroy( &lc->lc_mutex );
        ch_free( lc );
        on->on_bi.bi_private = NULL;
        be->be_private = private;