X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fmods.c;h=e097e44b8ccf59c83c84ebdbb7a8ece4cd8765e2;hb=9184d038ead9aeabff5b7c0bb2ed0d1e6bc95c8c;hp=581f8a694e8fae45feea9829fc44810586a992b5;hpb=ac1332cdb868b6a30f545796aca8e0bbf13fe939;p=openldap diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c index 581f8a694e..e097e44b8c 100644 --- a/servers/slapd/mods.c +++ b/servers/slapd/mods.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ /* @@ -18,54 +18,393 @@ #include "slap.h" -void -slap_mod_free( +int +modify_check_duplicates( + AttributeDescription *ad, + MatchingRule *mr, + BerVarray vals, + BerVarray mods, + int permissive, + const char **text, + char *textbuf, size_t textlen ) +{ + int i, j, numvals = 0, nummods, + rc = LDAP_SUCCESS, matched; + /* this function is no longer used */ + return rc; +} + +int +modify_add_values( + Entry *e, Modification *mod, - int freeit + int permissive, + const char **text, + char *textbuf, size_t textlen ) { + int i, j; + int matched; + Attribute *a; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + const char *op; + + switch( mod->sm_op ) { + case LDAP_MOD_ADD: + op = "add"; + break; + case LDAP_MOD_REPLACE: + op = "replace"; + break; + default: + op = "?"; + assert( 0 ); + } + + a = attr_find( e->e_attrs, mod->sm_desc ); + + /* + * With permissive set, as long as the attribute being added + * has the same value(s?) as the existing attribute, then the + * modify will succeed. + */ + + /* check if the values we're adding already exist */ + if( mr == NULL || !mr->smr_match ) { + if ( a != NULL ) { + /* do not allow add of additional attribute + if no equality rule exists */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: no equality matching rule", + op, mod->sm_desc->ad_cname.bv_val ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { + /* test asserted values against existing values */ + if( a ) { + for( matched = 0, j = 0; a->a_vals[j].bv_val != NULL; j++ ) { + if ( bvmatch( &mod->sm_bvalues[i], &a->a_vals[j] ) ) { + if ( permissive ) { + matched++; + continue; + } + /* value exists already */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: value #%i already exists", + op, mod->sm_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + if ( permissive && matched == j ) { + /* values already exist; do nothing */ + return LDAP_SUCCESS; + } + } + + /* test asserted values against themselves */ + for( j = 0; j < i; j++ ) { + if ( bvmatch( &mod->sm_bvalues[i], &mod->sm_bvalues[j] ) ) { + /* value exists already */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: value #%i already exists", + op, mod->sm_desc->ad_cname.bv_val, j ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + } + + } else { + /* no normalization is done in this routine nor + * in the matching routines called by this routine. + * values are now normalized once on input to the + * server (whether from LDAP or from the underlying + * database). + * This should outperform the old code. No numbers + * are available yet. + */ + + int rc; + + if ( mod->sm_bvalues[1].bv_val == 0 ) { + if ( a != NULL ) { + int i; + + for ( matched = 0, i = 0; a->a_vals[ i ].bv_val; i++ ) { + int match; + + if( mod->sm_nvalues ) { + rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_EQUALITY + | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX + | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH + | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + &a->a_nvals[i], + &mod->sm_nvalues[0], + text ); + + } else { + rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_EQUALITY + | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &a->a_vals[i], + &mod->sm_values[0], + text ); + } + + + if( rc == LDAP_SUCCESS && match == 0 ) { + if ( permissive ) { + matched++; + continue; + } + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: value #0 already exists", + op, mod->sm_desc->ad_cname.bv_val ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } + } + if ( permissive && matched == i ) { + /* values already exist; do nothing */ + return LDAP_SUCCESS; + } + } + + } else { + rc = modify_check_duplicates( mod->sm_desc, mr, + a ? a->a_vals : NULL, mod->sm_bvalues, + permissive, text, textbuf, textlen ); + + if ( permissive && rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + return LDAP_SUCCESS; + } + + if ( rc != LDAP_SUCCESS ) { + return rc; + } + } + } + + /* no - add them */ + if( attr_merge( e, mod->sm_desc, mod->sm_values, mod->sm_nvalues ) != 0 ) + { + /* this should return result of attr_merge */ + *text = textbuf; + snprintf( textbuf, textlen, + "modify/%s: %s: merge error", + op, mod->sm_desc->ad_cname.bv_val ); + return LDAP_OTHER; + } + + return LDAP_SUCCESS; +} + +int +modify_delete_values( + Entry *e, + Modification *mod, + int permissive, + const char **text, + char *textbuf, size_t textlen +) +{ + int i, j, k, rc = LDAP_SUCCESS; + Attribute *a; + MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + char dummy = '\0'; + + /* + * If permissive is set, then the non-existence of an + * attribute is not treated as an error. + */ + + /* delete the entire attribute */ + if ( mod->sm_bvalues == 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; + } + + 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 ); + return LDAP_INAPPROPRIATE_MATCHING; + } + + /* delete specific values - find the attribute first */ + if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { + if( permissive ) { + return LDAP_SUCCESS; + } + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + + + for ( i = 0; mod->sm_values[i].bv_val != NULL; i++ ) { + int found = 0; + for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) + { + int match; + + if( mod->sm_nvalues ) { + assert( a->a_nvals ); + rc = (*mr->smr_match)( &match, + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX + | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH + | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + a->a_desc->ad_type->sat_syntax, + mr, &a->a_nvals[j], + &mod->sm_nvalues[i] ); + } else { #if 0 - if ( mod->sm_type.bv_val) - free( mod->sm_type.bv_val ); + assert( a->a_nvals == NULL ); #endif - if ( mod->sm_bvalues != NULL ) - ber_bvarray_free( mod->sm_bvalues ); + rc = (*mr->smr_match)( &match, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + a->a_desc->ad_type->sat_syntax, + mr, &a->a_vals[j], + &mod->sm_values[i] ); + } + + if ( rc != LDAP_SUCCESS ) { + *text = textbuf; + snprintf( textbuf, textlen, + "%s: matching rule failed", + mod->sm_desc->ad_cname.bv_val ); + goto return_results; + } + + if ( match != 0 ) { + continue; + } + + found = 1; + + /* delete value and mark it as dummy */ + free( a->a_vals[j].bv_val ); + a->a_vals[j].bv_val = &dummy; + if( a->a_nvals != a->a_vals ) { + free( a->a_nvals[j].bv_val ); + a->a_nvals[j].bv_val = &dummy; + } + + break; + } + + + if ( found == 0 ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such value", + mod->sm_desc->ad_cname.bv_val ); + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_results; + } + } + + /* compact array skipping dummies */ + for ( k = 0, j = 0; a->a_vals[k].bv_val != NULL; k++ ) + { + /* skip dummies */ + if( a->a_vals[k].bv_val == &dummy ) { + assert( a->a_nvals == NULL || a->a_nvals[k].bv_val == &dummy ); + continue; + } + if ( j != k ) { + a->a_vals[ j ] = a->a_vals[ k ]; + if (a->a_nvals != a->a_vals) { + a->a_nvals[ j ] = a->a_nvals[ k ]; + } + } + + j++; + } + + a->a_vals[j].bv_val = NULL; + if (a->a_nvals != a->a_vals) a->a_nvals[j].bv_val = NULL; + + /* if no values remain, delete the entire attribute */ + if ( a->a_vals[0].bv_val == NULL ) { + if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + rc = LDAP_NO_SUCH_ATTRIBUTE; + } + } + +return_results:; - if( freeit ) - free( mod ); + return rc; } -void -slap_mods_free( - Modifications *ml +int +modify_replace_values( + Entry *e, + Modification *mod, + int permissive, + const char **text, + char *textbuf, size_t textlen ) { - Modifications *next; + (void) attr_delete( &e->e_attrs, mod->sm_desc ); - for ( ; ml != NULL; ml = next ) { - next = ml->sml_next; - - slap_mod_free( &ml->sml_mod, 0 ); - free( ml ); + if ( mod->sm_bvalues ) { + return modify_add_values( e, mod, permissive, text, textbuf, textlen ); } + + return LDAP_SUCCESS; } void -slap_modlist_free( - LDAPModList *ml +slap_mod_free( + Modification *mod, + int freeit ) { - LDAPModList *next; + if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values ); + mod->sm_values = NULL; - for ( ; ml != NULL; ml = next ) { - next = ml->ml_next; + if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues ); + mod->sm_nvalues = NULL; - if (ml->ml_type) - free( ml->ml_type ); + if( freeit ) free( mod ); +} - if ( ml->ml_bvalues != NULL ) - ber_bvecfree( ml->ml_bvalues ); +void +slap_mods_free( + Modifications *ml +) +{ + Modifications *next; + for ( ; ml != NULL; ml = next ) { + next = ml->sml_next; + + slap_mod_free( &ml->sml_mod, 0 ); free( ml ); } } +