]> 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 05593fa5cbc4524a536aca6d1a8ea0347e96cc59..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;
@@ -132,8 +134,8 @@ chaining_control_remove(
         * added by the chain overlay, so it's the only one we explicitly 
         * free */
        if ( op->o_ctrls != oldctrls ) {
-               assert( op->o_ctrls );
-               assert( op->o_ctrls[ 0 ] );
+               assert( op->o_ctrls != NULL );
+               assert( op->o_ctrls[ 0 ] != NULL );
 
                free( op->o_ctrls );
 
@@ -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,43 +453,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                }
                break;
        case LDAP_REQ_ADD:
-               {
-               int             cleanup_attrs = 0;
-
-               if ( op->ora_e->e_attrs == NULL ) {
-                       char            textbuf[ SLAP_TEXT_BUFLEN ];
-                       size_t          textlen = sizeof( textbuf );
-
-#if 0
-                       /* FIXME: op->o_bd is still set to the BackendDB 
-                        * structure of the database that tried to handle
-                        * the operation and actually returned a referral
-                        * ... */
-                       assert( SLAP_DBFLAGS( op->o_bd ) & SLAP_DBFLAG_GLOBAL_OVERLAY );
-#endif
-
-                       /* global overlay: create entry */
-                       /* NOTE: this is a hack to use the chain overlay
-                        * as global.  I expect to be able to remove this
-                        * soon by using slap_mods2entry() earlier in
-                        * do_add(), adding the operational attrs later
-                        * if required. */
-                       rs->sr_err = slap_mods2entry( op->ora_modlist,
-                                       &op->ora_e, 0, 1,
-                                       &rs->sr_text, textbuf, textlen );
-                       if ( rs->sr_err != LDAP_SUCCESS ) {
-                               send_ldap_result( op, rs );
-                               rc = 1;
-                               break;
-                       }
-               }
                rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
-               if ( cleanup_attrs ) {
-                       attrs_free( op->ora_e->e_attrs );
-                       op->ora_e->e_attrs = NULL;
-               }
                break;
-               }
        case LDAP_REQ_DELETE:
                rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
                break;
@@ -495,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;
@@ -506,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, 
@@ -537,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,
@@ -548,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;
@@ -557,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 );
@@ -578,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;
@@ -609,7 +591,7 @@ ldap_chain_response( Operation *op, SlapReply *rs )
 
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        if ( rc != LDAP_SUCCESS || sc2.sc_private == LDAP_CH_ERR ) {
-               if ( rs->sr_err == LDAP_CANNOT_CHAIN ) {
+               if ( rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
                        goto cannot_chain;
                }
 
@@ -617,7 +599,8 @@ ldap_chain_response( Operation *op, SlapReply *rs )
                case LDAP_CHAINING_REQUIRED:
 cannot_chain:;
                        op->o_callback = NULL;
-                       send_ldap_error( op, rs, LDAP_CANNOT_CHAIN, "operation cannot be completed without chaining" );
+                       send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
+                               "operation cannot be completed without chaining" );
                        break;
 
                default:
@@ -645,6 +628,8 @@ dont_chain:;
        op->o_ndn = ndn;
        rs->sr_ref = ref;
 
+       ldap_pvt_thread_mutex_unlock( &lc->lc_mutex );
+
        return rc;
 }
 
@@ -679,9 +664,11 @@ enum {
        PC_CHAINING = 1
 };
 
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 static ConfigDriver chain_cf_gen;
-static ConfigLDAPadd chain_ldadd;
 static ConfigCfAdd chain_cfadd;
+#endif
+static ConfigLDAPadd chain_ldadd;
 
 static ConfigTable chaincfg[] = {
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
@@ -695,11 +682,13 @@ static ConfigTable chaincfg[] = {
 };
 
 static ConfigOCs chainocs[] = {
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        { "( OLcfgOvOc:3.1 "
                "NAME 'olcChainConfig' "
                "DESC 'Chain configuration' "
                "SUP olcOverlayConfig "
                "MAY olcChainingBehavior )", Cft_Overlay, chaincfg, NULL, chain_cfadd },
+#endif
        { "( OLcfgOvOc:3.2 "
                "NAME 'olcChainDatabase' "
                "DESC 'Chain remote server configuration' "
@@ -717,6 +706,8 @@ chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
        return LDAP_SUCCESS;
 }
 
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+
 static int
 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
 {
@@ -740,7 +731,6 @@ chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
        return 0;
 }
 
-#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 static slap_verbmasks chaining_mode[] = {
        { BER_BVC("referralsRequired"),         LDAP_REFERRALS_REQUIRED },
        { BER_BVC("referralsPreferred"),        LDAP_REFERRALS_PREFERRED },
@@ -748,13 +738,14 @@ static slap_verbmasks chaining_mode[] = {
        { BER_BVC("chainingPreferred"),         LDAP_CHAINING_PREFERRED },
        { BER_BVNULL,                           0 }
 };
-#endif
 
 static int
 chain_cf_gen( ConfigArgs *c )
 {
        slap_overinst   *on = (slap_overinst *)c->bi;
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
+#endif
 
        int             rc = 0;
 
@@ -933,6 +924,8 @@ chain_cf_gen( ConfigArgs *c )
        return rc;
 }
 
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
 static int
 ldap_chain_db_config(
        BackendDB       *be,
@@ -1098,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;
@@ -1132,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;