X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fmods.c;h=6e7d7ec1c5b8e1e42f227d37253cf8a831bac9dd;hb=ac3ad635ef0883d96b5424f96b2c43e13b0ad659;hp=f57cf41dab6deb5c6c49b767a8a651b8353f55a9;hpb=7fae7fe15599213581d3e667a8e97a91f95faabb;p=openldap diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c index f57cf41dab..6e7d7ec1c5 100644 --- a/servers/slapd/mods.c +++ b/servers/slapd/mods.c @@ -1,9 +1,18 @@ -/* - * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2005 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ -/* - * Copyright (c) 1995 Regents of the University of Michigan. +/* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -16,22 +25,25 @@ #include "portable.h" +#include + #include "slap.h" int modify_add_values( - Entry *e, + Entry *e, Modification *mod, + int permissive, const char **text, - char *textbuf, size_t textlen -) + char *textbuf, + size_t textlen ) { - int i, j; + int rc; + const char *op; Attribute *a; - MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; - const char *op; + Modification pmod = *mod; - switch( mod->sm_op ) { + switch ( mod->sm_op ) { case LDAP_MOD_ADD: op = "add"; break; @@ -43,11 +55,14 @@ modify_add_values( assert( 0 ); } + /* check if values to add exist in attribute */ a = attr_find( e->e_attrs, mod->sm_desc ); + if ( a != NULL ) { + int rc, i, j, p; + MatchingRule *mr; - /* check if the values we're adding already exist */ - if( mr == NULL || !mr->smr_match ) { - if ( a != NULL ) { + mr = mod->sm_desc->ad_type->sat_equality; + if( mr == NULL || !mr->smr_match ) { /* do not allow add of additional attribute if no equality rule exists */ *text = textbuf; @@ -57,83 +72,85 @@ modify_add_values( return LDAP_INAPPROPRIATE_MATCHING; } - for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { - /* test asserted values against existing values */ - if( a ) { - for( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { - int rc = ber_bvcmp( &mod->sm_bvalues[i], - &a->a_vals[j] ); - - if( rc == 0 ) { - /* 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 ) { + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) /* count 'em */; + pmod.sm_values = (BerVarray)ch_malloc( (i + 1)*sizeof( struct berval ) ); + if ( pmod.sm_nvalues != NULL ) { + pmod.sm_nvalues = (BerVarray)ch_malloc( + (i + 1)*sizeof( struct berval ) ); } + } - /* test asserted values against themselves */ - for( j = 0; j < i; j++ ) { - int rc = ber_bvcmp( &mod->sm_bvalues[i], - &mod->sm_bvalues[j] ); + /* 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). + */ + for ( p = i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { + int match; + + assert( a->a_vals[0].bv_val ); + for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) { + 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[j], &mod->sm_nvalues[i], text ); + } else { + rc = value_match( &match, mod->sm_desc, mr, + SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &a->a_vals[j], &mod->sm_values[i], text ); + } + + if ( rc == LDAP_SUCCESS && match == 0 ) { + /* value already exists */ + if ( permissive ) break; - if( rc == 0 ) { - /* value exists already */ *text = textbuf; snprintf( textbuf, textlen, - "modify/%s: %s: value #%i already exists", - op, mod->sm_desc->ad_cname.bv_val, j ); + "modify/%s: %s: value #%d already exists", + op, mod->sm_desc->ad_cname.bv_val, i ); return LDAP_TYPE_OR_VALUE_EXISTS; + + } else if ( rc != LDAP_SUCCESS ) { + return rc; } } - } - } else { - for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { - int rc, match; - struct berval asserted; - - rc = value_normalize( mod->sm_desc, - SLAP_MR_EQUALITY, - &mod->sm_bvalues[i], - &asserted, - text ); - - if( rc != LDAP_SUCCESS ) return rc; - - if( a ) { - for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { - int rc = value_match( &match, mod->sm_desc, mr, - SLAP_MR_VALUE_SYNTAX_MATCH, - &a->a_vals[j], &asserted, text ); - - if( rc == LDAP_SUCCESS && match == 0 ) { - free( asserted.bv_val ); - return LDAP_TYPE_OR_VALUE_EXISTS; - } + if ( permissive && match != 0 ) { + if ( pmod.sm_nvalues ) { + pmod.sm_nvalues[p] = mod->sm_nvalues[i]; } + pmod.sm_values[p++] = mod->sm_values[i]; } + } - for ( j = 0; j < i; j++ ) { - int rc = value_match( &match, mod->sm_desc, mr, - SLAP_MR_VALUE_SYNTAX_MATCH, - &mod->sm_bvalues[j], &asserted, text ); - - if( rc == LDAP_SUCCESS && match == 0 ) { - free( asserted.bv_val ); - return LDAP_TYPE_OR_VALUE_EXISTS; - } + if ( permissive ) { + if ( p == 0 ) { + /* all new values match exist */ + ch_free( pmod.sm_values ); + if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); + return LDAP_SUCCESS; } - free( asserted.bv_val ); + BER_BVZERO( &pmod.sm_values[p] ); + if ( pmod.sm_nvalues ) { + BER_BVZERO( &pmod.sm_nvalues[p] ); + } } } /* no - add them */ - if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) { + rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues ); + + if ( a != NULL && permissive ) { + ch_free( pmod.sm_values ); + if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); + } + + if ( rc != 0 ) { /* this should return result of attr_merge */ *text = textbuf; snprintf( textbuf, textlen, @@ -149,19 +166,28 @@ int modify_delete_values( Entry *e, Modification *mod, + int permissive, const char **text, - char *textbuf, size_t textlen -) + char *textbuf, size_t textlen ) { - int i, j, k, found; + int i, j, k, rc = LDAP_SUCCESS; Attribute *a; MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + char dummy = '\0'; + int match = 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 ) { - int rc = attr_delete( &e->e_attrs, mod->sm_desc ); + if ( mod->sm_values == NULL ) { + rc = attr_delete( &e->e_attrs, mod->sm_desc ); - if( rc != LDAP_SUCCESS ) { + if( permissive ) { + rc = LDAP_SUCCESS; + } else if( rc != LDAP_SUCCESS ) { *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", @@ -183,6 +209,9 @@ modify_delete_values( /* 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", @@ -190,82 +219,179 @@ modify_delete_values( return LDAP_NO_SUCH_ATTRIBUTE; } - /* find each value to delete */ - for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { - int rc; - struct berval asserted; - - rc = value_normalize( mod->sm_desc, - SLAP_MR_EQUALITY, - &mod->sm_bvalues[i], - &asserted, - text ); + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { + int found = 0; + for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) { + /* skip already deleted values */ + if ( a->a_vals[j].bv_val == &dummy ) { + continue; + } - if( rc != LDAP_SUCCESS ) return rc; + 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 + assert( a->a_nvals == NULL ); +#endif + 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] ); + } - found = 0; - for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { - int match; - int rc = value_match( &match, mod->sm_desc, mr, - SLAP_MR_VALUE_SYNTAX_MATCH, - &a->a_vals[j], &asserted, text ); + if ( rc != LDAP_SUCCESS ) { + *text = textbuf; + snprintf( textbuf, textlen, + "%s: matching rule failed", + mod->sm_desc->ad_cname.bv_val ); + break; + } - if( rc == LDAP_SUCCESS && match != 0 ) { + if ( match != 0 ) { continue; } - /* found a matching value */ found = 1; - /* delete it */ + /* delete value and mark it as dummy */ free( a->a_vals[j].bv_val ); - for ( k = j + 1; a->a_vals[k].bv_val != NULL; k++ ) { - a->a_vals[k - 1] = a->a_vals[k]; + 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; } - a->a_vals[k - 1].bv_val = NULL; - a->a_vals[k - 1].bv_len = 0; break; } - free( asserted.bv_val ); - - /* looked through them all w/o finding it */ - if ( ! found ) { + if ( found == 0 ) { *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such value", mod->sm_desc->ad_cname.bv_val ); - return LDAP_NO_SUCH_ATTRIBUTE; + rc = LDAP_NO_SUCH_ATTRIBUTE; + if ( i > 0 ) { + break; + } else { + goto return_results; + } + } + } + + /* compact array skipping dummies */ + for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); 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++; + } + + BER_BVZERO( &a->a_vals[j] ); + if (a->a_nvals != a->a_vals) { + BER_BVZERO( &a->a_nvals[j] ); } /* if no values remain, delete the entire attribute */ - if ( a->a_vals[0].bv_val == NULL ) { + if ( BER_BVISNULL( &a->a_vals[0] ) ) { 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 ); - return LDAP_NO_SUCH_ATTRIBUTE; + rc = LDAP_NO_SUCH_ATTRIBUTE; } } - return LDAP_SUCCESS; +return_results:; + + return rc; } int modify_replace_values( Entry *e, Modification *mod, + int permissive, const char **text, - char *textbuf, size_t textlen -) + char *textbuf, size_t textlen ) { (void) attr_delete( &e->e_attrs, mod->sm_desc ); - if ( mod->sm_bvalues ) { - return modify_add_values( e, mod, text, textbuf, textlen ); + if ( mod->sm_values ) { + return modify_add_values( e, mod, permissive, text, textbuf, textlen ); + } + + return LDAP_SUCCESS; +} + +int +modify_increment_values( + Entry *e, + Modification *mod, + int permissive, + const char **text, + char *textbuf, size_t textlen ) +{ + Attribute *a; + + a = attr_find( e->e_attrs, mod->sm_desc ); + if( a == NULL ) { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/increment: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + + if ( !strcmp( a->a_desc->ad_type->sat_syntax_oid, SLAPD_INTEGER_SYNTAX )) { + int i; + char str[sizeof(long)*3 + 2]; /* overly long */ + long incr = atol( mod->sm_values[0].bv_val ); + + /* treat zero and errors as a no-op */ + if( incr == 0 ) { + return LDAP_SUCCESS; + } + + for( i = 0; !BER_BVISNULL( &a->a_nvals[i] ); i++ ) { + char *tmp; + long value = atol( a->a_nvals[i].bv_val ); + size_t strln = snprintf( str, sizeof(str), "%ld", value+incr ); + + tmp = SLAP_REALLOC( a->a_nvals[i].bv_val, strln+1 ); + if( tmp == NULL ) { + *text = "modify/increment: reallocation error"; + return LDAP_OTHER;; + } + a->a_nvals[i].bv_val = tmp; + a->a_nvals[i].bv_len = strln; + + AC_MEMCPY( a->a_nvals[i].bv_val, str, strln+1 ); + } + + } else { + snprintf( textbuf, textlen, + "modify/increment: %s: increment not supported for value syntax %s", + mod->sm_desc->ad_cname.bv_val, + a->a_desc->ad_type->sat_syntax_oid ); + return LDAP_CONSTRAINT_VIOLATION; } return LDAP_SUCCESS; @@ -274,24 +400,20 @@ modify_replace_values( void slap_mod_free( Modification *mod, - int freeit -) + int freeit ) { -#if 0 - if ( mod->sm_type.bv_val) - free( mod->sm_type.bv_val ); -#endif - if ( mod->sm_bvalues != NULL ) - ber_bvarray_free( mod->sm_bvalues ); + if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values ); + mod->sm_values = NULL; + + if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues ); + mod->sm_nvalues = NULL; - if( freeit ) - free( mod ); + if( freeit ) free( mod ); } void slap_mods_free( - Modifications *ml -) + Modifications *ml ) { Modifications *next;