1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* Portions Copyright (c) 1995 Regents of the University of Michigan. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms are permitted 19 * provided that this notice is preserved and that due credit is given 20 * to the University of Michigan at Ann Arbor. The name of the University 21 * may not be used to endorse or promote products derived from this 22 * software without specific prior written permission. This software 23 * is provided ``as is'' without express or implied warranty. 24 */ 25 26#include "portable.h" 27 28#include <ac/string.h> 29 30#include "slap.h" 31#include "lutil.h" 32 33int 34modify_add_values( 35 Entry *e, 36 Modification *mod, 37 int permissive, 38 const char **text, 39 char *textbuf, 40 size_t textlen ) 41{ 42 int rc; 43 const char *op; 44 Attribute *a; 45 Modification pmod = *mod; 46 47 switch ( mod->sm_op ) { 48 case LDAP_MOD_ADD: 49 op = "add"; 50 break; 51 case LDAP_MOD_REPLACE: 52 op = "replace"; 53 break; 54 default: 55 op = "?"; 56 assert( 0 ); 57 } 58 59 /* FIXME: Catch old code that doesn't set sm_numvals. 60 */ 61 if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) { 62 unsigned i; 63 for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ); 64 assert( mod->sm_numvals == i ); 65 } 66 67 /* check if values to add exist in attribute */ 68 a = attr_find( e->e_attrs, mod->sm_desc ); 69 if ( a != NULL ) { 70 MatchingRule *mr; 71 struct berval *cvals; 72 int rc; 73 unsigned i, p, flags; 74 75 mr = mod->sm_desc->ad_type->sat_equality; 76 if( mr == NULL || !mr->smr_match ) { 77 /* do not allow add of additional attribute 78 if no equality rule exists */ 79 *text = textbuf; 80 snprintf( textbuf, textlen, 81 "modify/%s: %s: no equality matching rule", 82 op, mod->sm_desc->ad_cname.bv_val ); 83 return LDAP_INAPPROPRIATE_MATCHING; 84 } 85 86 if ( permissive ) { 87 i = mod->sm_numvals; 88 pmod.sm_values = (BerVarray)ch_malloc( 89 (i + 1) * sizeof( struct berval )); 90 if ( pmod.sm_nvalues != NULL ) { 91 pmod.sm_nvalues = (BerVarray)ch_malloc( 92 (i + 1) * sizeof( struct berval )); 93 } 94 } 95 96 /* no normalization is done in this routine nor 97 * in the matching routines called by this routine. 98 * values are now normalized once on input to the 99 * server (whether from LDAP or from the underlying 100 * database). 101 */ 102 if ( a->a_desc == slap_schema.si_ad_objectClass ) { 103 /* Needed by ITS#5517 */ 104 flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX; 105 106 } else { 107 flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX; 108 } 109 if ( mod->sm_nvalues ) { 110 flags |= SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | 111 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; 112 cvals = mod->sm_nvalues; 113 } else { 114 cvals = mod->sm_values; 115 } 116 for ( p = i = 0; i < mod->sm_numvals; i++ ) { 117 unsigned slot; 118 119 rc = attr_valfind( a, flags, &cvals[i], &slot, NULL ); 120 if ( rc == LDAP_SUCCESS ) { 121 if ( !permissive ) { 122 /* value already exists */ 123 *text = textbuf; 124 snprintf( textbuf, textlen, 125 "modify/%s: %s: value #%u already exists", 126 op, mod->sm_desc->ad_cname.bv_val, i ); 127 return LDAP_TYPE_OR_VALUE_EXISTS; 128 } 129 } else if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) { 130 return rc; 131 } 132 133 if ( permissive && rc ) { 134 if ( pmod.sm_nvalues ) { 135 pmod.sm_nvalues[p] = mod->sm_nvalues[i]; 136 } 137 pmod.sm_values[p++] = mod->sm_values[i]; 138 } 139 } 140 141 if ( permissive ) { 142 if ( p == 0 ) { 143 /* all new values match exist */ 144 ch_free( pmod.sm_values ); 145 if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); 146 return LDAP_SUCCESS; 147 } 148 149 BER_BVZERO( &pmod.sm_values[p] ); 150 if ( pmod.sm_nvalues ) { 151 BER_BVZERO( &pmod.sm_nvalues[p] ); 152 } 153 } 154 } 155 156 /* no - add them */ 157 if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) { 158 rc = ordered_value_add( e, mod->sm_desc, a, 159 pmod.sm_values, pmod.sm_nvalues ); 160 } else { 161 rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues ); 162 } 163 164 if ( a != NULL && permissive ) { 165 ch_free( pmod.sm_values ); 166 if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); 167 } 168 169 if ( rc != 0 ) { 170 /* this should return result of attr_merge */ 171 *text = textbuf; 172 snprintf( textbuf, textlen, 173 "modify/%s: %s: merge error (%d)", 174 op, mod->sm_desc->ad_cname.bv_val, rc ); 175 return LDAP_OTHER; 176 } 177 178 return LDAP_SUCCESS; 179} 180 181int 182modify_delete_values( 183 Entry *e, 184 Modification *m, 185 int perm, 186 const char **text, 187 char *textbuf, size_t textlen ) 188{ 189 return modify_delete_vindex( e, m, perm, text, textbuf, textlen, NULL ); 190} 191 192int 193modify_delete_vindex( 194 Entry *e, 195 Modification *mod, 196 int permissive, 197 const char **text, 198 char *textbuf, size_t textlen, 199 int *idx ) 200{ 201 Attribute *a; 202 MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; 203 struct berval *cvals; 204 int *id2 = NULL; 205 int rc = 0; 206 unsigned i, j, flags; 207 char dummy = '\0'; 208 209 /* 210 * If permissive is set, then the non-existence of an 211 * attribute is not treated as an error. 212 */ 213 214 /* delete the entire attribute */ 215 if ( mod->sm_values == NULL ) { 216 rc = attr_delete( &e->e_attrs, mod->sm_desc ); 217 218 if( permissive ) { 219 rc = LDAP_SUCCESS; 220 } else if( rc != LDAP_SUCCESS ) { 221 *text = textbuf; 222 snprintf( textbuf, textlen, 223 "modify/delete: %s: no such attribute", 224 mod->sm_desc->ad_cname.bv_val ); 225 rc = LDAP_NO_SUCH_ATTRIBUTE; 226 } 227 return rc; 228 } 229 230 /* FIXME: Catch old code that doesn't set sm_numvals. 231 */ 232 if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) { 233 for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ); 234 assert( mod->sm_numvals == i ); 235 } 236 if ( !idx ) { 237 id2 = ch_malloc( mod->sm_numvals * sizeof( int )); 238 idx = id2; 239 } 240 241 if( mr == NULL || !mr->smr_match ) { 242 /* disallow specific attributes from being deleted if 243 no equality rule */ 244 *text = textbuf; 245 snprintf( textbuf, textlen, 246 "modify/delete: %s: no equality matching rule", 247 mod->sm_desc->ad_cname.bv_val ); 248 rc = LDAP_INAPPROPRIATE_MATCHING; 249 goto return_result; 250 } 251 252 /* delete specific values - find the attribute first */ 253 if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { 254 if( permissive ) { 255 rc = LDAP_SUCCESS; 256 goto return_result; 257 } 258 *text = textbuf; 259 snprintf( textbuf, textlen, 260 "modify/delete: %s: no such attribute", 261 mod->sm_desc->ad_cname.bv_val ); 262 rc = LDAP_NO_SUCH_ATTRIBUTE; 263 goto return_result; 264 } 265 266 if ( a->a_desc == slap_schema.si_ad_objectClass ) { 267 /* Needed by ITS#5517,ITS#5963 */ 268 flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX; 269 270 } else { 271 flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX; 272 } 273 if ( mod->sm_nvalues ) { 274 flags |= SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH 275 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; 276 cvals = mod->sm_nvalues; 277 } else { 278 cvals = mod->sm_values; 279 } 280 281 /* Locate values to delete */ 282 for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { 283 unsigned sort; 284 rc = attr_valfind( a, flags, &cvals[i], &sort, NULL ); 285 if ( rc == LDAP_SUCCESS ) { 286 idx[i] = sort; 287 } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { 288 if ( permissive ) { 289 idx[i] = -1; 290 continue; 291 } 292 *text = textbuf; 293 snprintf( textbuf, textlen, 294 "modify/delete: %s: no such value", 295 mod->sm_desc->ad_cname.bv_val ); 296 goto return_result; 297 } else { 298 *text = textbuf; 299 snprintf( textbuf, textlen, 300 "modify/delete: %s: matching rule failed", 301 mod->sm_desc->ad_cname.bv_val ); 302 goto return_result; 303 } 304 } 305 306 /* Delete the values */ 307 for ( i = 0; i < mod->sm_numvals; i++ ) { 308 /* Skip permissive values that weren't found */ 309 if ( idx[i] < 0 ) 310 continue; 311 /* Skip duplicate delete specs */ 312 if ( a->a_vals[idx[i]].bv_val == &dummy ) 313 continue; 314 /* delete value and mark it as gone */ 315 free( a->a_vals[idx[i]].bv_val ); 316 a->a_vals[idx[i]].bv_val = &dummy; 317 if( a->a_nvals != a->a_vals ) { 318 free( a->a_nvals[idx[i]].bv_val ); 319 a->a_nvals[idx[i]].bv_val = &dummy; 320 } 321 a->a_numvals--; 322 } 323 324 /* compact array skipping dummies */ 325 for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { 326 /* skip dummies */ 327 if( a->a_vals[i].bv_val == &dummy ) { 328 assert( a->a_nvals[i].bv_val == &dummy ); 329 continue; 330 } 331 if ( j != i ) { 332 a->a_vals[ j ] = a->a_vals[ i ]; 333 if (a->a_nvals != a->a_vals) { 334 a->a_nvals[ j ] = a->a_nvals[ i ]; 335 } 336 } 337 j++; 338 } 339 340 BER_BVZERO( &a->a_vals[j] ); 341 if (a->a_nvals != a->a_vals) { 342 BER_BVZERO( &a->a_nvals[j] ); 343 } 344 345 /* if no values remain, delete the entire attribute */ 346 if ( !a->a_numvals ) { 347 if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { 348 /* Can never happen */ 349 *text = textbuf; 350 snprintf( textbuf, textlen, 351 "modify/delete: %s: no such attribute", 352 mod->sm_desc->ad_cname.bv_val ); 353 rc = LDAP_NO_SUCH_ATTRIBUTE; 354 } 355 } else if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) { 356 /* For an ordered attribute, renumber the value indices */ 357 ordered_value_sort( a, 1 ); 358 } 359return_result: 360 if ( id2 ) 361 ch_free( id2 ); 362 return rc; 363} 364 365int 366modify_replace_values( 367 Entry *e, 368 Modification *mod, 369 int permissive, 370 const char **text, 371 char *textbuf, size_t textlen ) 372{ 373 (void) attr_delete( &e->e_attrs, mod->sm_desc ); 374 375 if ( mod->sm_values ) { 376 return modify_add_values( e, mod, permissive, text, textbuf, textlen ); 377 } 378 379 return LDAP_SUCCESS; 380} 381 382int 383modify_increment_values( 384 Entry *e, 385 Modification *mod, 386 int permissive, 387 const char **text, 388 char *textbuf, size_t textlen ) 389{ 390 Attribute *a; 391 392 a = attr_find( e->e_attrs, mod->sm_desc ); 393 if( a == NULL ) { 394 if ( permissive ) { 395 Modification modReplace = *mod; 396 397 modReplace.sm_op = LDAP_MOD_REPLACE; 398 399 return modify_add_values(e, &modReplace, permissive, text, textbuf, textlen); 400 } else { 401 *text = textbuf; 402 snprintf( textbuf, textlen, 403 "modify/increment: %s: no such attribute", 404 mod->sm_desc->ad_cname.bv_val ); 405 return LDAP_NO_SUCH_ATTRIBUTE; 406 } 407 } 408 409 if ( !strcmp( a->a_desc->ad_type->sat_syntax_oid, SLAPD_INTEGER_SYNTAX )) { 410 int i; 411 char str[sizeof(long)*3 + 2]; /* overly long */ 412 long incr; 413 414 if ( lutil_atol( &incr, mod->sm_values[0].bv_val ) != 0 ) { 415 *text = "modify/increment: invalid syntax of increment"; 416 return LDAP_INVALID_SYNTAX; 417 } 418 419 /* treat zero and errors as a no-op */ 420 if( incr == 0 ) { 421 return LDAP_SUCCESS; 422 } 423 424 for( i = 0; !BER_BVISNULL( &a->a_nvals[i] ); i++ ) { 425 char *tmp; 426 long value; 427 size_t strln; 428 if ( lutil_atol( &value, a->a_nvals[i].bv_val ) != 0 ) { 429 *text = "modify/increment: invalid syntax of original value"; 430 return LDAP_INVALID_SYNTAX; 431 } 432 strln = snprintf( str, sizeof(str), "%ld", value+incr ); 433 434 tmp = SLAP_REALLOC( a->a_nvals[i].bv_val, strln+1 ); 435 if( tmp == NULL ) { 436 *text = "modify/increment: reallocation error"; 437 return LDAP_OTHER; 438 } 439 a->a_nvals[i].bv_val = tmp; 440 a->a_nvals[i].bv_len = strln; 441 442 AC_MEMCPY( a->a_nvals[i].bv_val, str, strln+1 ); 443 } 444 445 } else { 446 snprintf( textbuf, textlen, 447 "modify/increment: %s: increment not supported for value syntax %s", 448 mod->sm_desc->ad_cname.bv_val, 449 a->a_desc->ad_type->sat_syntax_oid ); 450 return LDAP_CONSTRAINT_VIOLATION; 451 } 452 453 return LDAP_SUCCESS; 454} 455 456void 457slap_mod_free( 458 Modification *mod, 459 int freeit ) 460{ 461 if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values ); 462 mod->sm_values = NULL; 463 464 if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues ); 465 mod->sm_nvalues = NULL; 466 467 if( freeit ) free( mod ); 468} 469 470void 471slap_mods_free( 472 Modifications *ml, 473 int freevals ) 474{ 475 Modifications *next; 476 477 for ( ; ml != NULL; ml = next ) { 478 next = ml->sml_next; 479 480 if ( freevals ) 481 slap_mod_free( &ml->sml_mod, 0 ); 482 free( ml ); 483 } 484} 485 486