openldap/servers/slapd/mods.c

306 lines
6.7 KiB
C

/*
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/*
* Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include "slap.h"
int
modify_add_values(
Entry *e,
Modification *mod,
const char **text,
char *textbuf, size_t textlen
)
{
int i, j;
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 );
/* 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( 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;
}
}
}
/* test asserted values against themselves */
for( j = 0; j < i; j++ ) {
int rc = ber_bvcmp( &mod->sm_bvalues[i],
&mod->sm_bvalues[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;
}
}
}
} 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;
}
}
}
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;
}
}
free( asserted.bv_val );
}
}
/* no - add them */
if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 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,
const char **text,
char *textbuf, size_t textlen
)
{
int i, j, k, found;
Attribute *a;
MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
/* delete the entire attribute */
if ( mod->sm_bvalues == NULL ) {
int rc = attr_delete( &e->e_attrs, mod->sm_desc );
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 ) {
*text = textbuf;
snprintf( textbuf, textlen,
"modify/delete: %s: no such attribute",
mod->sm_desc->ad_cname.bv_val );
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 );
if( rc != LDAP_SUCCESS ) return rc;
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 && match != 0 ) {
continue;
}
/* found a matching value */
found = 1;
/* delete it */
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[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 ) {
*text = textbuf;
snprintf( textbuf, textlen,
"modify/delete: %s: no such value",
mod->sm_desc->ad_cname.bv_val );
return LDAP_NO_SUCH_ATTRIBUTE;
}
}
/* 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 );
return LDAP_NO_SUCH_ATTRIBUTE;
}
}
return LDAP_SUCCESS;
}
int
modify_replace_values(
Entry *e,
Modification *mod,
const char **text,
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 );
}
return LDAP_SUCCESS;
}
void
slap_mod_free(
Modification *mod,
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( freeit )
free( mod );
}
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 );
}
}