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