]> 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>
Wed, 19 Feb 2025 18:15:58 +0000 (18:15 +0000)
servers/slapd/bconfig.c

index 1876106d6b91a3825686128d11daab99fe6ddff6..8ae98e12e60de8153c6ce6783cfc7a30c3d1b06b 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
@@ -4821,7 +4841,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;
@@ -4838,6 +4858,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;
@@ -4857,6 +4879,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 );
@@ -5648,6 +5673,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) {
@@ -5665,6 +5691,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;
@@ -5672,6 +5701,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;
@@ -5682,9 +5713,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;
 }
 
@@ -5692,7 +5726,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;
@@ -5700,14 +5738,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
@@ -5723,7 +5767,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,
@@ -5805,7 +5851,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;
@@ -5818,12 +5864,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;
@@ -6389,7 +6441,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;
@@ -6401,11 +6453,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++];
@@ -6443,8 +6500,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 );
@@ -6653,7 +6714,9 @@ config_back_modrdn( Operation *op, SlapReply *rs )
                        backend_db_move( ce->ce_be, ixnew );
                else if ( ce->ce_type == Cft_Overlay )
                        overlay_move( ce->ce_be, (slap_overinst *)ce->ce_bi, ixnew );
-                       
+
+               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 );
@@ -6664,7 +6727,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;
@@ -6701,13 +6765,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;
@@ -6718,7 +6785,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;
@@ -6816,7 +6883,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;
@@ -6833,6 +6900,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;
@@ -6840,7 +6910,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;