From: Howard Chu Date: Thu, 29 Feb 2024 22:55:13 +0000 (+0000) Subject: ITS#10185 autogroup: don't process deletes until after op succeeds X-Git-Tag: OPENLDAP_REL_ENG_2_6_8~47 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=acacc95bbf3162caa1c795ac3797cabcd2dc31f7;p=thirdparty%2Fopenldap.git ITS#10185 autogroup: don't process deletes until after op succeeds --- diff --git a/contrib/slapd-modules/autogroup/autogroup.c b/contrib/slapd-modules/autogroup/autogroup.c index dc7bdc0285..c8c51f9045 100644 --- a/contrib/slapd-modules/autogroup/autogroup.c +++ b/contrib/slapd-modules/autogroup/autogroup.c @@ -967,6 +967,83 @@ autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e ) } +static int +autogroup_del_entry_cb( Operation *op, SlapReply *rs ) +{ + slap_callback *sc = op->o_callback; + ag_addinfo *aa = sc->sc_private; + slap_overinst *on = aa->on; + autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; + BackendInfo *bi = op->o_bd->bd_info; + struct berval odn, ondn; + autogroup_entry_t *age, *age_prev, *age_next; + autogroup_filter_t *agf; + + if ( rs->sr_err != LDAP_SUCCESS ) + goto done; + + ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); + + /* Check if the entry to be deleted is one of our groups. */ + for ( age = agi->agi_entry ; age ; age=age->age_next ) { + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + if ( dn_match( &op->o_req_ndn, &age->age_ndn )) { + autogroup_delete_group( agi, age ); + break; + } + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + if ( !aa->e ) + goto done; + + /* Check if the entry matches any of the groups. + If yes, we can delete the entry from that group. */ + + odn = op->o_dn; + ondn = op->o_ndn; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->o_bd->bd_info = (BackendInfo *)on; + + for ( age = agi->agi_entry ; age ; age = age->age_next ) { + ldap_pvt_thread_mutex_lock( &age->age_mutex ); + + for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { + if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { + int rc = test_filter( op, aa->e, agf->agf_filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + /* If the attribute is retrieved from the entry, we don't know what to delete + ** So the group must be entirely refreshed + ** But the refresh can't be done now because the entry is not deleted + ** So the group is marked as mustrefresh + */ + if ( agf->agf_anlist ) { + age->age_mustrefresh = 1; + } else { + autogroup_delete_member_from_group( op, &aa->e->e_name, &aa->e->e_nname, age ); + } + break; + } + } + } + ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + } + + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + op->o_dn = odn; + op->o_ndn = ondn; + op->o_bd->bd_info = bi; + +done: + if ( aa->e ) + entry_free( aa->e ); + op->o_callback = sc->sc_next; + op->o_tmpfree( sc, op->o_tmpmemctx ); + + return SLAP_CB_CONTINUE; +} + static int autogroup_delete_entry( Operation *op, SlapReply *rs) { @@ -975,7 +1052,7 @@ autogroup_delete_entry( Operation *op, SlapReply *rs) autogroup_entry_t *age, *age_prev, *age_next; autogroup_filter_t *agf; Entry *e; - int matched_group = 0, rc = 0; + int matched_group = 0, rc = 0, matched_entry = 0; struct berval odn, ondn; OpExtra *oex; @@ -988,38 +1065,21 @@ autogroup_delete_entry( Operation *op, SlapReply *rs) ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); - if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != - LDAP_SUCCESS || e == NULL ) { - Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val ); - ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); - return SLAP_CB_CONTINUE; - } - /* Check if the entry to be deleted is one of our groups. */ - for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) { - age = age_next; - ldap_pvt_thread_mutex_lock( &age->age_mutex ); - age_next = age->age_next; - - if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) { - int match = 1; - + for ( age = agi->agi_entry ; age ; age=age->age_next ) { + if ( dn_match( &op->o_req_ndn, &age->age_ndn )) { matched_group = 1; - - dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn ); - - if ( match == 0 ) { - autogroup_delete_group( agi, age ); - break; - } + break; } - - ldap_pvt_thread_mutex_unlock( &age->age_mutex ); } - if ( matched_group == 1 ) { - overlay_entry_release_ov( op, e, 0, on ); - ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); + /* if matched_group, we wouldn't need to go further, but continuing + * this check allows for groups that are members of other groups + */ + if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val ); + ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } @@ -1038,25 +1098,33 @@ autogroup_delete_entry( Operation *op, SlapReply *rs) if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { rc = test_filter( op, e, agf->agf_filter ); if ( rc == LDAP_COMPARE_TRUE ) { - /* If the attribute is retrieved from the entry, we don't know what to delete - ** So the group must be entirely refreshed - ** But the refresh can't be done now because the entry is not deleted - ** So the group is marked as mustrefresh - */ - if ( agf->agf_anlist ) { - age->age_mustrefresh = 1; - } else { - autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age ); - } + matched_entry = 1; break; } } } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); + if ( matched_entry ) + break; } + op->o_dn = odn; op->o_ndn = ondn; + if ( matched_group || matched_entry ) { + slap_callback *sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx ); + ag_addinfo *aa; + + sc->sc_private = (sc+1); + sc->sc_response = autogroup_del_entry_cb; + aa = sc->sc_private; + aa->on = on; + if ( matched_entry ) + aa->e = entry_dup( e ); + sc->sc_next = op->o_callback; + op->o_callback = sc; + } + overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );