static int delete_values( Operation *op, Entry *e, Modification *mod, int *newlevel ) { int i, j, k, found, rc, nl = 0; Attribute *a; MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; /* delete the entire attribute */ if ( mod->sm_values == NULL ) { int rc = attr_delete( &e->e_attrs, mod->sm_desc ); if ( rc ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { *newlevel = 0; rc = LDAP_SUCCESS; } return rc; } rc = check_constraints( mod, &nl ); if ( rc != LDAP_SUCCESS ) { return rc; } *newlevel &= ~nl; if ( mr == NULL || !mr->smr_match ) { /* disallow specific attributes from being deleted if * no equality rule */ return LDAP_INAPPROPRIATE_MATCHING; } /* delete specific values - find the attribute first */ if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { return( LDAP_NO_SUCH_ATTRIBUTE ); } /* find each value to delete */ for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) { int rc; const char *text = NULL; struct berval asserted; rc = asserted_value_validate_normalize( mod->sm_desc, mr, SLAP_MR_EQUALITY, &mod->sm_values[ i ], &asserted, &text, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) return rc; found = 0; for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) { int match; int rc = value_match( &match, mod->sm_desc, mr, 0, &a->a_nvals[ j ], &asserted, &text ); if( rc == LDAP_SUCCESS && match != 0 ) { continue; } /* found a matching value */ found = 1; /* delete it */ if ( a->a_nvals != a->a_vals ) { free( a->a_nvals[ j ].bv_val ); for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) { a->a_nvals[ k - 1 ] = a->a_nvals[ k ]; } BER_BVZERO( &a->a_nvals[ k - 1 ] ); } free( a->a_vals[ j ].bv_val ); for ( k = j + 1; !BER_BVISNULL( &a->a_vals[ k ] ); k++ ) { a->a_vals[ k - 1 ] = a->a_vals[ k ]; } BER_BVZERO( &a->a_vals[ k - 1 ] ); a->a_numvals--; break; } free( asserted.bv_val ); /* looked through them all w/o finding it */ if ( ! found ) { return LDAP_NO_SUCH_ATTRIBUTE; } } /* if no values remain, delete the entire attribute */ if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) { assert( a->a_numvals == 0 ); /* should already be zero */ *newlevel = 0; if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { return LDAP_NO_SUCH_ATTRIBUTE; } } return LDAP_SUCCESS; }
/* This is a copy from slapd/mods.c, but with compaction tweaked * to swap values from the tail into deleted slots, to reduce the * overall update traffic. */ static int ndb_modify_delete( Entry *e, Modification *mod, int permissive, const char **text, char *textbuf, size_t textlen, int *idx ) { Attribute *a; MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; struct berval *cvals; int *id2 = NULL; int i, j, rc = 0, num; unsigned flags; char dummy = '\0'; /* For ordered vals, we have no choice but to preserve order */ if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) return modify_delete_vindex( e, mod, permissive, text, textbuf, textlen, idx ); /* * If permissive is set, then the non-existence of an * attribute is not treated as an error. */ /* delete the entire attribute */ if ( mod->sm_values == NULL ) { rc = attr_delete( &e->e_attrs, mod->sm_desc ); if( permissive ) { rc = LDAP_SUCCESS; } else if( rc != LDAP_SUCCESS ) { *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", mod->sm_desc->ad_cname.bv_val ); rc = LDAP_NO_SUCH_ATTRIBUTE; } return rc; } /* FIXME: Catch old code that doesn't set sm_numvals. */ if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) { for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ); assert( mod->sm_numvals == i ); } if ( !idx ) { id2 = (int *)ch_malloc( mod->sm_numvals * sizeof( int )); idx = id2; } if( mr == NULL || !mr->smr_match ) { /* disallow specific attributes from being deleted if no equality rule */ *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no equality matching rule", mod->sm_desc->ad_cname.bv_val ); rc = LDAP_INAPPROPRIATE_MATCHING; goto return_result; } /* delete specific values - find the attribute first */ if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { if( permissive ) { rc = LDAP_SUCCESS; goto return_result; } *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", mod->sm_desc->ad_cname.bv_val ); rc = LDAP_NO_SUCH_ATTRIBUTE; goto return_result; } if ( mod->sm_nvalues ) { flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; cvals = mod->sm_nvalues; } else { flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX; cvals = mod->sm_values; } /* Locate values to delete */ for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { unsigned sort; rc = attr_valfind( a, flags, &cvals[i], &sort, NULL ); if ( rc == LDAP_SUCCESS ) { idx[i] = sort; } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { if ( permissive ) { idx[i] = -1; continue; } *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such value", mod->sm_desc->ad_cname.bv_val ); goto return_result; } else { *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: matching rule failed", mod->sm_desc->ad_cname.bv_val ); goto return_result; } } num = a->a_numvals; /* Delete the values */ for ( i = 0; i < mod->sm_numvals; i++ ) { /* Skip permissive values that weren't found */ if ( idx[i] < 0 ) continue; /* Skip duplicate delete specs */ if ( a->a_vals[idx[i]].bv_val == &dummy ) continue; /* delete value and mark it as gone */ free( a->a_vals[idx[i]].bv_val ); a->a_vals[idx[i]].bv_val = &dummy; if( a->a_nvals != a->a_vals ) { free( a->a_nvals[idx[i]].bv_val ); a->a_nvals[idx[i]].bv_val = &dummy; } a->a_numvals--; } /* compact array */ for ( i=0; i<num; i++ ) { if ( a->a_vals[i].bv_val != &dummy ) continue; for ( --num; num > i && a->a_vals[num].bv_val == &dummy; num-- ) ; a->a_vals[i] = a->a_vals[num]; if ( a->a_nvals != a->a_vals ) a->a_nvals[i] = a->a_nvals[num]; } BER_BVZERO( &a->a_vals[num] ); if (a->a_nvals != a->a_vals) { BER_BVZERO( &a->a_nvals[num] ); } /* if no values remain, delete the entire attribute */ if ( !a->a_numvals ) { if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { /* Can never happen */ *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", mod->sm_desc->ad_cname.bv_val ); rc = LDAP_NO_SUCH_ATTRIBUTE; } } return_result: if ( id2 ) ch_free( id2 ); return rc; }
static int monitor_subsys_log_modify( Operation *op, SlapReply *rs, Entry *e ) { monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; int rc = LDAP_OTHER; int newlevel = ldap_syslog; Attribute *save_attrs; Modifications *modlist = op->orm_modlist; Modifications *ml; ldap_pvt_thread_mutex_lock( &monitor_log_mutex ); save_attrs = e->e_attrs; e->e_attrs = attrs_dup( e->e_attrs ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { Modification *mod = &ml->sml_mod; /* * accept all operational attributes; * this includes modifiersName and modifyTimestamp * if lastmod is "on" */ if ( is_at_operational( mod->sm_desc->ad_type ) ) { ( void ) attr_delete( &e->e_attrs, mod->sm_desc ); rc = rs->sr_err = attr_merge( e, mod->sm_desc, mod->sm_values, mod->sm_nvalues ); if ( rc != LDAP_SUCCESS ) { break; } continue; /* * only the "managedInfo" attribute can be modified */ } else if ( mod->sm_desc != mi->mi_ad_managedInfo ) { rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM; break; } switch ( mod->sm_op ) { case LDAP_MOD_ADD: rc = add_values( op, e, mod, &newlevel ); break; case LDAP_MOD_DELETE: rc = delete_values( op, e, mod, &newlevel ); break; case LDAP_MOD_REPLACE: rc = replace_values( op, e, mod, &newlevel ); break; default: rc = LDAP_OTHER; break; } if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; break; } } /* set the new debug level */ if ( rc == LDAP_SUCCESS ) { const char *text; static char textbuf[ BACKMONITOR_BUFSIZE ]; /* check for abandon */ if ( op->o_abandon ) { rc = rs->sr_err = SLAPD_ABANDON; goto cleanup; } /* check that the entry still obeys the schema */ rc = entry_schema_check( op, e, save_attrs, 0, 0, NULL, &text, textbuf, sizeof( textbuf ) ); if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; goto cleanup; } /* * Do we need to protect this with a mutex? */ ldap_syslog = newlevel; #if 0 /* debug rather than log */ slap_debug = newlevel; lutil_set_debug_level( "slapd", slap_debug ); ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug); ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug); ldif_debug = slap_debug; #endif } cleanup:; if ( rc == LDAP_SUCCESS ) { attrs_free( save_attrs ); } else { attrs_free( e->e_attrs ); e->e_attrs = save_attrs; } ldap_pvt_thread_mutex_unlock( &monitor_log_mutex ); if ( rc == LDAP_SUCCESS ) { rc = SLAP_CB_CONTINUE; } return rc; }