]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#7080 Do not reuse back-ldif's stack for controls
authorOndřej Kuzník <ondra@mistotebe.net>
Thu, 24 Oct 2024 15:01:15 +0000 (16:01 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Mon, 16 Dec 2024 17:01:26 +0000 (17:01 +0000)
servers/slapd/bconfig.c

index be323511e254a7355eee384a3050a5c0b38934db..96160c3de07104c4119b98302791ba2b19dbcd12 100644 (file)
@@ -1112,6 +1112,26 @@ config_substr_if_check( ConfigArgs *c )
        return LDAP_SUCCESS;
 }
 
+static int
+config_copy_controls( Operation *op, SlapReply *rs )
+{
+       /* Accumulate response controls so we can return them to client */
+       if ( rs->sr_ctrls ) {
+               LDAPControl **prepared = op->o_callback->sc_private,
+                                       **received = rs->sr_ctrls;
+               slap_mask_t oldflags = rs->sr_flags;
+
+               rs->sr_ctrls = prepared;
+               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
+               slap_add_ctrls( op, rs, received, 0 );
+               op->o_callback->sc_private = rs->sr_ctrls;
+
+               rs->sr_ctrls = received;
+               rs->sr_flags = oldflags;
+       }
+       return 0;
+}
+
 #define        GOT_CONFIG      1
 #define        GOT_FRONTEND    2
 static int
@@ -4818,7 +4838,7 @@ config_rename_one( Operation *op, SlapReply *rs, Entry *e,
        if ( use_ldif ) {
                CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
                BackendDB *be = op->o_bd;
-               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
+               slap_callback sc = { NULL, config_copy_controls, NULL, rs->sr_ctrls }, *scp;
                struct berval dn, ndn, xdn, xndn;
 
                op->o_bd = &cfb->cb_db;
@@ -4835,6 +4855,8 @@ config_rename_one( Operation *op, SlapReply *rs, Entry *e,
 
                scp = op->o_callback;
                op->o_callback = &sc;
+               rs->sr_ctrls = NULL;
+
                op->orr_newrdn = *newrdn;
                op->orr_nnewrdn = *nnewrdn;
                op->orr_newSup = NULL;
@@ -4854,6 +4876,9 @@ config_rename_one( Operation *op, SlapReply *rs, Entry *e,
                op->o_ndn = ndn;
                op->o_req_dn = xdn;
                op->o_req_ndn = xndn;
+
+               rs->sr_ctrls = sc.sc_private;
+               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
        }
        free( odn.bv_val );
        free( ondn.bv_val );
@@ -5646,6 +5671,7 @@ config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
        CfEntryInfo *ce2, *ce3, *cetmp = NULL, *cerem = NULL;
        ConfigType etype = ce->ce_type;
        int count = 0, rc = 0;
+       char preread = op->o_preread, postread = op->o_postread;
 
        /* Reverse ce list */
        for (ce2 = ce->ce_sibs;ce2;ce2 = ce3) {
@@ -5663,6 +5689,9 @@ config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
                }
        }
 
+       /* Suppress control generation for internal ops */
+       op->o_postread = SLAP_CONTROL_NONE;
+
        /* Move original to a temp name until increments are done */
        if ( rebase ) {
                ce->ce_entry->e_private = NULL;
@@ -5670,6 +5699,8 @@ config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
                        base+BIGTMP, 0, use_ldif );
                ce->ce_entry->e_private = ce;
        }
+       op->o_preread = SLAP_CONTROL_NONE;
+
        /* start incrementing */
        for (ce2=cetmp; ce2; ce2=ce3) {
                ce3 = ce2->ce_sibs;
@@ -5680,9 +5711,12 @@ config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
                                count+base, 0, use_ldif );
                count--;
        }
+
+       op->o_postread = postread;
        if ( rebase )
                rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
                        base, 0, use_ldif );
+       op->o_preread = preread;
        return rc;
 }
 
@@ -5690,7 +5724,11 @@ static int
 config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce,
        CfEntryInfo *ce2, int old, int use_ldif )
 {
-       int count = 0;
+       int rc, count = 0;
+       char preread = op->o_preread, postread = op->o_postread;
+
+       /* Suppress control generation for internal ops */
+       op->o_postread = SLAP_CONTROL_NONE;
 
        /* Renumber original to a temp value */
        ce->ce_entry->e_private = NULL;
@@ -5698,14 +5736,20 @@ config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce,
                old+BIGTMP, 0, use_ldif );
        ce->ce_entry->e_private = ce;
 
+       op->o_preread = SLAP_CONTROL_NONE;
+
        /* start decrementing */
        for (; ce2 != ce; ce2=ce2->ce_sibs) {
                config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
                        count+old, 0, use_ldif );
                count++;
        }
-       return config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
+
+       op->o_postread = postread;
+       rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
                count+old, 0, use_ldif );
+       op->o_preread = preread;
+       return rc;
 }
 
 /* Parse an LDAP entry into config directives, then store in underlying
@@ -5721,7 +5765,9 @@ config_back_add( Operation *op, SlapReply *rs )
        LDAPControl **postread_ctrl = NULL;
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
        int num_ctrls = 0;
+       char postread = op->o_postread;
 
+       op->o_postread = SLAP_CONTROL_NONE;
        ctrls[num_ctrls] = NULL;
 
        if ( !access_allowed( op, op->ora_e, slap_schema.si_ad_entry,
@@ -5803,7 +5849,7 @@ config_back_add( Operation *op, SlapReply *rs )
 
        if ( cfb->cb_use_ldif ) {
                BackendDB *be = op->o_bd;
-               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
+               slap_callback sc = { NULL, config_copy_controls, NULL, rs->sr_ctrls }, *scp;
                struct berval dn, ndn;
 
                op->o_bd = &cfb->cb_db;
@@ -5816,12 +5862,18 @@ config_back_add( Operation *op, SlapReply *rs )
 
                scp = op->o_callback;
                op->o_callback = &sc;
+               op->o_postread = postread;
+               rs->sr_ctrls = NULL;
+
                op->o_bd->be_add( op, rs );
                op->o_bd = be;
                op->o_callback = scp;
                op->o_dn = dn;
                op->o_ndn = ndn;
-       } else if ( op->o_postread ) {
+
+               rs->sr_ctrls = sc.sc_private;
+               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
+       } else if ( postread ) {
                if ( postread_ctrl == NULL ) {
                        postread_ctrl = &ctrls[num_ctrls++];
                        ctrls[num_ctrls] = NULL;
@@ -6387,7 +6439,7 @@ config_back_modify( Operation *op, SlapReply *rs )
                rs->sr_text = ca.cr_msg;
        } else if ( cfb->cb_use_ldif ) {
                BackendDB *be = op->o_bd;
-               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
+               slap_callback sc = { NULL, config_copy_controls, NULL, rs->sr_ctrls }, *scp;
                struct berval dn, ndn;
 
                op->o_bd = &cfb->cb_db;
@@ -6399,11 +6451,16 @@ config_back_modify( Operation *op, SlapReply *rs )
 
                scp = op->o_callback;
                op->o_callback = &sc;
+               rs->sr_ctrls = NULL;
+
                op->o_bd->be_modify( op, rs );
                op->o_bd = be;
                op->o_callback = scp;
                op->o_dn = dn;
                op->o_ndn = ndn;
+
+               rs->sr_ctrls = sc.sc_private;
+               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
        } else if ( op->o_postread ) {
                if ( postread_ctrl == NULL ) {
                        postread_ctrl = &ctrls[num_ctrls++];
@@ -6441,8 +6498,10 @@ config_back_modrdn( Operation *op, SlapReply *rs )
        LDAPControl **postread_ctrl = NULL;
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
        int num_ctrls = 0;
+       char preread = op->o_preread, postread = op->o_postread;
 
        ctrls[num_ctrls] = NULL;
+       op->o_preread = op->o_postread = SLAP_CONTROL_NONE;
 
        cfb = (CfBackInfo *)op->o_bd->be_private;
 
@@ -6563,7 +6622,7 @@ config_back_modrdn( Operation *op, SlapReply *rs )
        }
 
        /* If we have a backend, it will handle the control */
-       if ( !cfb->cb_use_ldif && op->o_preread ) {
+       if ( !cfb->cb_use_ldif && preread > SLAP_CONTROL_IGNORED ) {
                if ( preread_ctrl == NULL ) {
                        preread_ctrl = &ctrls[num_ctrls++];
                        ctrls[num_ctrls] = NULL;
@@ -6606,6 +6665,8 @@ config_back_modrdn( Operation *op, SlapReply *rs )
                Attribute *a;
                rs->sr_err = config_rename_attr( rs, ce->ce_entry, &rdn, &a );
                if ( rs->sr_err == LDAP_SUCCESS ) {
+                       op->o_preread = preread;
+                       op->o_postread = postread;
                        rs->sr_err = config_rename_one( op, rs, ce->ce_entry,
                                ce->ce_parent, a, &op->orr_newrdn, &op->orr_nnewrdn,
                                cfb->cb_use_ldif );
@@ -6695,6 +6756,8 @@ config_back_modrdn( Operation *op, SlapReply *rs )
 #endif /* SLAP_CONFIG_RENAME */
                }
 
+               op->o_preread = preread;
+               op->o_postread = postread;
                if ( ixold < ixnew ) {
                        rs->sr_err = config_rename_del( op, rs, ce, ceold, ixold,
                                cfb->cb_use_ldif );
@@ -6705,7 +6768,8 @@ config_back_modrdn( Operation *op, SlapReply *rs )
                op->oq_modrdn = modr;
        }
 
-       if ( rs->sr_err == LDAP_SUCCESS && !cfb->cb_use_ldif && op->o_postread ) {
+       if ( rs->sr_err == LDAP_SUCCESS && !cfb->cb_use_ldif &&
+                       postread > SLAP_CONTROL_IGNORED ) {
                if ( postread_ctrl == NULL ) {
                        postread_ctrl = &ctrls[num_ctrls++];
                        ctrls[num_ctrls] = NULL;
@@ -6743,13 +6807,16 @@ config_back_delete( Operation *op, SlapReply *rs )
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
        int num_ctrls = 0;
 
+       char preread = op->o_preread;
+
        ctrls[num_ctrls] = NULL;
+       op->o_preread = SLAP_CONTROL_NONE;
 
        cfb = (CfBackInfo *)op->o_bd->be_private;
 
        /* If we have a backend, it will handle the control */
        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last, op );
-       if ( ce && !cfb->cb_use_ldif && op->o_preread ) {
+       if ( ce && !cfb->cb_use_ldif && preread ) {
                if ( preread_ctrl == NULL ) {
                        preread_ctrl = &ctrls[num_ctrls++];
                        ctrls[num_ctrls] = NULL;
@@ -6760,7 +6827,7 @@ config_back_delete( Operation *op, SlapReply *rs )
                        Debug( LDAP_DEBUG_ANY, "config_back_delete: "
                                        "pre-read failed \"%s\"\n",
                                        ce->ce_entry->e_name.bv_val );
-                       if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
+                       if ( preread & SLAP_CONTROL_CRITICAL ) {
                                /* FIXME: is it correct to abort
                                 * operation if control fails? */
                                goto out;
@@ -6858,7 +6925,7 @@ config_back_delete( Operation *op, SlapReply *rs )
                /* remove from underlying database */
                if ( cfb->cb_use_ldif ) {
                        BackendDB *be = op->o_bd;
-                       slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
+                       slap_callback sc = { NULL, config_copy_controls, NULL, rs->sr_ctrls }, *scp;
                        struct berval dn, ndn, req_dn, req_ndn;
 
                        op->o_bd = &cfb->cb_db;
@@ -6875,6 +6942,9 @@ config_back_delete( Operation *op, SlapReply *rs )
 
                        scp = op->o_callback;
                        op->o_callback = &sc;
+                       op->o_preread = preread;
+                       rs->sr_ctrls = NULL;
+
                        op->o_bd->be_delete( op, rs );
                        op->o_bd = be;
                        op->o_callback = scp;
@@ -6882,7 +6952,11 @@ config_back_delete( Operation *op, SlapReply *rs )
                        op->o_ndn = ndn;
                        op->o_req_dn = req_dn;
                        op->o_req_ndn = req_ndn;
+
+                       rs->sr_ctrls = sc.sc_private;
+                       rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
                }
+               op->o_preread = SLAP_CONTROL_NONE;
 
                /* renumber siblings */
                iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1;