Home | History | Annotate | Line # | Download | only in slapd
modify.c revision 1.1.1.6
      1 /*	$NetBSD: modify.c,v 1.1.1.6 2018/02/06 01:53:14 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2017 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 <sys/cdefs.h>
     29 __RCSID("$NetBSD: modify.c,v 1.1.1.6 2018/02/06 01:53:14 christos Exp $");
     30 
     31 #include "portable.h"
     32 
     33 #include <stdio.h>
     34 
     35 #include <ac/socket.h>
     36 #include <ac/string.h>
     37 #include <ac/time.h>
     38 
     39 #include "slap.h"
     40 #include "lutil.h"
     41 
     42 
     43 int
     44 do_modify(
     45     Operation	*op,
     46     SlapReply	*rs )
     47 {
     48 	struct berval dn = BER_BVNULL;
     49 	char		textbuf[ SLAP_TEXT_BUFLEN ];
     50 	size_t		textlen = sizeof( textbuf );
     51 #ifdef LDAP_DEBUG
     52 	Modifications	*tmp;
     53 #endif
     54 
     55 	Debug( LDAP_DEBUG_TRACE, "%s do_modify\n",
     56 		op->o_log_prefix, 0, 0 );
     57 	/*
     58 	 * Parse the modify request.  It looks like this:
     59 	 *
     60 	 *	ModifyRequest := [APPLICATION 6] SEQUENCE {
     61 	 *		name	DistinguishedName,
     62 	 *		mods	SEQUENCE OF SEQUENCE {
     63 	 *			operation	ENUMERATED {
     64 	 *				add	(0),
     65 	 *				delete	(1),
     66 	 *				replace	(2)
     67 	 *			},
     68 	 *			modification	SEQUENCE {
     69 	 *				type	AttributeType,
     70 	 *				values	SET OF AttributeValue
     71 	 *			}
     72 	 *		}
     73 	 *	}
     74 	 */
     75 
     76 	if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
     77 		Debug( LDAP_DEBUG_ANY, "%s do_modify: ber_scanf failed\n",
     78 			op->o_log_prefix, 0, 0 );
     79 		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
     80 		return SLAPD_DISCONNECT;
     81 	}
     82 
     83 	Debug( LDAP_DEBUG_ARGS, "%s do_modify: dn (%s)\n",
     84 		op->o_log_prefix, dn.bv_val, 0 );
     85 
     86 	rs->sr_err = slap_parse_modlist( op, rs, op->o_ber, &op->oq_modify );
     87 	if ( rs->sr_err != LDAP_SUCCESS ) {
     88 		Debug( LDAP_DEBUG_ANY, "%s do_modify: slap_parse_modlist failed err=%d msg=%s\n",
     89 			op->o_log_prefix, rs->sr_err, rs->sr_text );
     90 		send_ldap_result( op, rs );
     91 		goto cleanup;
     92 	}
     93 
     94 	if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
     95 		Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n",
     96 			op->o_log_prefix, 0, 0 );
     97 		/* get_ctrls has sent results.	Now clean up. */
     98 		goto cleanup;
     99 	}
    100 
    101 	rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
    102 		op->o_tmpmemctx );
    103 	if( rs->sr_err != LDAP_SUCCESS ) {
    104 		Debug( LDAP_DEBUG_ANY, "%s do_modify: invalid dn (%s)\n",
    105 			op->o_log_prefix, dn.bv_val, 0 );
    106 		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
    107 		goto cleanup;
    108 	}
    109 
    110 	op->orm_no_opattrs = 0;
    111 
    112 #ifdef LDAP_DEBUG
    113 	Debug( LDAP_DEBUG_ARGS, "%s modifications:\n",
    114 			op->o_log_prefix, 0, 0 );
    115 
    116 	for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
    117 		Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
    118 			tmp->sml_op == LDAP_MOD_ADD ? "add" :
    119 				(tmp->sml_op == LDAP_MOD_INCREMENT ? "increment" :
    120 				(tmp->sml_op == LDAP_MOD_DELETE ? "delete" :
    121 					"replace")), tmp->sml_type.bv_val, 0 );
    122 
    123 		if ( tmp->sml_values == NULL ) {
    124 			Debug( LDAP_DEBUG_ARGS, "%s\n",
    125 			   "\t\tno values", NULL, NULL );
    126 		} else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) {
    127 			Debug( LDAP_DEBUG_ARGS, "%s\n",
    128 			   "\t\tzero values", NULL, NULL );
    129 		} else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) {
    130 			Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
    131 			   "\t\tone value", (long) tmp->sml_values[0].bv_len, NULL );
    132 		} else {
    133 			Debug( LDAP_DEBUG_ARGS, "%s\n",
    134 			   "\t\tmultiple values", NULL, NULL );
    135 		}
    136 	}
    137 
    138 	if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
    139 		char abuf[BUFSIZ/2], *ptr = abuf;
    140 		int len = 0;
    141 
    142 		Statslog( LDAP_DEBUG_STATS, "%s MOD dn=\"%s\"\n",
    143 			op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
    144 
    145 		for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
    146 			if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
    147 				Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
    148 				    op->o_log_prefix, abuf, 0, 0, 0 );
    149 
    150 				len = 0;
    151 				ptr = abuf;
    152 
    153 				if( 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
    154 					Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
    155 						op->o_log_prefix, tmp->sml_type.bv_val, 0, 0, 0 );
    156 					continue;
    157 				}
    158 			}
    159 			if (len) {
    160 				*ptr++ = ' ';
    161 				len++;
    162 			}
    163 			ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val);
    164 			len += tmp->sml_type.bv_len;
    165 		}
    166 		if (len) {
    167 			Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
    168 	    			op->o_log_prefix, abuf, 0, 0, 0 );
    169 		}
    170 	}
    171 #endif	/* LDAP_DEBUG */
    172 
    173 	rs->sr_err = slap_mods_check( op, op->orm_modlist,
    174 		&rs->sr_text, textbuf, textlen, NULL );
    175 
    176 	if ( rs->sr_err != LDAP_SUCCESS ) {
    177 		send_ldap_result( op, rs );
    178 		goto cleanup;
    179 	}
    180 
    181 	op->o_bd = frontendDB;
    182 	rs->sr_err = frontendDB->be_modify( op, rs );
    183 
    184 #ifdef LDAP_X_TXN
    185 	if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
    186 		/* skip cleanup */
    187 		return rs->sr_err;
    188 	}
    189 #endif
    190 
    191 cleanup:
    192 	op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
    193 	op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
    194 	if ( op->orm_modlist != NULL ) slap_mods_free( op->orm_modlist, 1 );
    195 
    196 	return rs->sr_err;
    197 }
    198 
    199 int
    200 fe_op_modify( Operation *op, SlapReply *rs )
    201 {
    202 	BackendDB	*op_be, *bd = op->o_bd;
    203 	char		textbuf[ SLAP_TEXT_BUFLEN ];
    204 	size_t		textlen = sizeof( textbuf );
    205 
    206 	if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
    207 		Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n",
    208 			op->o_log_prefix, 0, 0 );
    209 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    210 			"modify upon the root DSE not supported" );
    211 		goto cleanup;
    212 
    213 	} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
    214 		Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n",
    215 			op->o_log_prefix, 0, 0 );
    216 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    217 			"modification of subschema subentry not supported" );
    218 		goto cleanup;
    219 	}
    220 
    221 	/*
    222 	 * We could be serving multiple database backends.  Select the
    223 	 * appropriate one, or send a referral to our "referral server"
    224 	 * if we don't hold it.
    225 	 */
    226 	op->o_bd = select_backend( &op->o_req_ndn, 1 );
    227 	if ( op->o_bd == NULL ) {
    228 		op->o_bd = bd;
    229 		rs->sr_ref = referral_rewrite( default_referral,
    230 			NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
    231 		if ( !rs->sr_ref ) {
    232 			rs->sr_ref = default_referral;
    233 		}
    234 
    235 		if ( rs->sr_ref != NULL ) {
    236 			rs->sr_err = LDAP_REFERRAL;
    237 			send_ldap_result( op, rs );
    238 
    239 			if ( rs->sr_ref != default_referral ) {
    240 				ber_bvarray_free( rs->sr_ref );
    241 			}
    242 
    243 		} else {
    244 			send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    245 				"no global superior knowledge" );
    246 		}
    247 		goto cleanup;
    248 	}
    249 
    250 	/* If we've got a glued backend, check the real backend */
    251 	op_be = op->o_bd;
    252 	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
    253 		op->o_bd = select_backend( &op->o_req_ndn, 0 );
    254 	}
    255 
    256 	/* check restrictions */
    257 	if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
    258 		send_ldap_result( op, rs );
    259 		goto cleanup;
    260 	}
    261 
    262 	/* check for referrals */
    263 	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
    264 		goto cleanup;
    265 	}
    266 
    267 	rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist,
    268 		&rs->sr_text, textbuf, textlen );
    269 	if ( rs->sr_err != LDAP_SUCCESS ) {
    270 		send_ldap_result( op, rs );
    271 		goto cleanup;
    272 	}
    273 
    274 	/* check for modify/increment support */
    275 	if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) {
    276 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    277 			"modify/increment not supported in context" );
    278 		goto cleanup;
    279 	}
    280 
    281 	/*
    282 	 * do the modify if 1 && (2 || 3)
    283 	 * 1) there is a modify function implemented in this backend;
    284 	 * 2) this backend is master for what it holds;
    285 	 * 3) it's a replica and the dn supplied is the update_ndn.
    286 	 */
    287 	if ( op->o_bd->be_modify ) {
    288 		/* do the update here */
    289 		int repl_user = be_isupdate( op );
    290 
    291 		/*
    292 		 * Multimaster slapd does not have to check for replicator dn
    293 		 * because it accepts each modify request
    294 		 */
    295 		if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
    296 			int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
    297 
    298 			op->o_bd = op_be;
    299 
    300 			if ( !update ) {
    301 				rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist,
    302 					&rs->sr_text, textbuf, textlen );
    303 				if ( rs->sr_err != LDAP_SUCCESS ) {
    304 					send_ldap_result( op, rs );
    305 					goto cleanup;
    306 				}
    307 			}
    308 			op->o_bd->be_modify( op, rs );
    309 
    310 		} else { /* send a referral */
    311 			BerVarray defref = op->o_bd->be_update_refs
    312 				? op->o_bd->be_update_refs : default_referral;
    313 			if ( defref != NULL ) {
    314 				rs->sr_ref = referral_rewrite( defref,
    315 					NULL, &op->o_req_dn,
    316 					LDAP_SCOPE_DEFAULT );
    317 				if ( rs->sr_ref == NULL ) {
    318 					/* FIXME: must duplicate, because
    319 					 * overlays may muck with it */
    320 					rs->sr_ref = defref;
    321 				}
    322 				rs->sr_err = LDAP_REFERRAL;
    323 				send_ldap_result( op, rs );
    324 				if ( rs->sr_ref != defref ) {
    325 					ber_bvarray_free( rs->sr_ref );
    326 				}
    327 
    328 			} else {
    329 				send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    330 					"shadow context; no update referral" );
    331 			}
    332 		}
    333 
    334 	} else {
    335 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
    336 		    "operation not supported within namingContext" );
    337 	}
    338 
    339 cleanup:;
    340 	op->o_bd = bd;
    341 	return rs->sr_err;
    342 }
    343 
    344 /*
    345  * Obsolete constraint checking.
    346  */
    347 int
    348 slap_mods_obsolete_check(
    349 	Operation *op,
    350 	Modifications *ml,
    351 	const char **text,
    352 	char *textbuf,
    353 	size_t textlen )
    354 {
    355 	if( get_relax( op ) ) return LDAP_SUCCESS;
    356 
    357 	for ( ; ml != NULL; ml = ml->sml_next ) {
    358 		if ( is_at_obsolete( ml->sml_desc->ad_type ) &&
    359 			(( ml->sml_op != LDAP_MOD_REPLACE &&
    360 				ml->sml_op != LDAP_MOD_DELETE ) ||
    361 					ml->sml_values != NULL ))
    362 		{
    363 			/*
    364 			 * attribute is obsolete,
    365 			 * only allow replace/delete with no values
    366 			 */
    367 			snprintf( textbuf, textlen,
    368 				"%s: attribute is obsolete",
    369 				ml->sml_type.bv_val );
    370 			*text = textbuf;
    371 			return LDAP_CONSTRAINT_VIOLATION;
    372 		}
    373 	}
    374 
    375 	return LDAP_SUCCESS;
    376 }
    377 
    378 /*
    379  * No-user-modification constraint checking.
    380  */
    381 int
    382 slap_mods_no_user_mod_check(
    383 	Operation *op,
    384 	Modifications *ml,
    385 	const char **text,
    386 	char *textbuf,
    387 	size_t textlen )
    388 {
    389 	for ( ; ml != NULL; ml = ml->sml_next ) {
    390 		if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) {
    391 			continue;
    392 		}
    393 
    394 		if ( ml->sml_flags & SLAP_MOD_INTERNAL ) {
    395 			continue;
    396 		}
    397 
    398 		if ( get_relax( op ) ) {
    399 			if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) {
    400 				ml->sml_flags |= SLAP_MOD_MANAGING;
    401 				continue;
    402 			}
    403 
    404 			/* attribute not manageable */
    405 			snprintf( textbuf, textlen,
    406 				"%s: no-user-modification attribute not manageable",
    407 				ml->sml_type.bv_val );
    408 
    409 		} else {
    410 			/* user modification disallowed */
    411 			snprintf( textbuf, textlen,
    412 				"%s: no user modification allowed",
    413 				ml->sml_type.bv_val );
    414 		}
    415 
    416 		*text = textbuf;
    417 		return LDAP_CONSTRAINT_VIOLATION;
    418 	}
    419 
    420 	return LDAP_SUCCESS;
    421 }
    422 
    423 int
    424 slap_mods_no_repl_user_mod_check(
    425 	Operation *op,
    426 	Modifications *ml,
    427 	const char **text,
    428 	char *textbuf,
    429 	size_t textlen )
    430 {
    431 	Modifications *mods;
    432 	Modifications *modp;
    433 
    434 	for ( mods = ml; mods != NULL; mods = mods->sml_next ) {
    435 		assert( mods->sml_op == LDAP_MOD_ADD );
    436 
    437 		/* check doesn't already appear */
    438 		for ( modp = ml; modp != NULL; modp = modp->sml_next ) {
    439 			if ( mods->sml_desc == modp->sml_desc && mods != modp ) {
    440 				snprintf( textbuf, textlen,
    441 					"attribute '%s' provided more than once",
    442 					mods->sml_desc->ad_cname.bv_val );
    443 				*text = textbuf;
    444 				return LDAP_TYPE_OR_VALUE_EXISTS;
    445 			}
    446 		}
    447 	}
    448 
    449 	return LDAP_SUCCESS;
    450 }
    451 
    452 /*
    453  * Do basic attribute type checking and syntax validation.
    454  */
    455 int slap_mods_check(
    456 	Operation *op,
    457 	Modifications *ml,
    458 	const char **text,
    459 	char *textbuf,
    460 	size_t textlen,
    461 	void *ctx )
    462 {
    463 	int rc;
    464 
    465 	for( ; ml != NULL; ml = ml->sml_next ) {
    466 		AttributeDescription *ad = NULL;
    467 
    468 		/* convert to attribute description */
    469 		if ( ml->sml_desc == NULL ) {
    470 			rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
    471 			if( rc != LDAP_SUCCESS ) {
    472 				if ( get_no_schema_check( op )) {
    473 					rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
    474 						text, 0 );
    475 				}
    476 			}
    477 			if( rc != LDAP_SUCCESS ) {
    478 				snprintf( textbuf, textlen, "%s: %s",
    479 					ml->sml_type.bv_val, *text );
    480 				*text = textbuf;
    481 				return rc;
    482 			}
    483 		}
    484 
    485 		ad = ml->sml_desc;
    486 
    487 		if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
    488 			&& !slap_ad_is_binary( ad ))
    489 		{
    490 			/* attribute requires binary transfer */
    491 			snprintf( textbuf, textlen,
    492 				"%s: requires ;binary transfer",
    493 				ml->sml_type.bv_val );
    494 			*text = textbuf;
    495 			return LDAP_UNDEFINED_TYPE;
    496 		}
    497 
    498 		if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
    499 			&& slap_ad_is_binary( ad ))
    500 		{
    501 			/* attribute does not require binary transfer */
    502 			snprintf( textbuf, textlen,
    503 				"%s: disallows ;binary transfer",
    504 				ml->sml_type.bv_val );
    505 			*text = textbuf;
    506 			return LDAP_UNDEFINED_TYPE;
    507 		}
    508 
    509 		if( slap_ad_is_tag_range( ad )) {
    510 			/* attribute requires binary transfer */
    511 			snprintf( textbuf, textlen,
    512 				"%s: inappropriate use of tag range option",
    513 				ml->sml_type.bv_val );
    514 			*text = textbuf;
    515 			return LDAP_UNDEFINED_TYPE;
    516 		}
    517 
    518 #if 0
    519 		if ( is_at_obsolete( ad->ad_type ) &&
    520 			(( ml->sml_op != LDAP_MOD_REPLACE &&
    521 				ml->sml_op != LDAP_MOD_DELETE ) ||
    522 					ml->sml_values != NULL ))
    523 		{
    524 			/*
    525 			 * attribute is obsolete,
    526 			 * only allow replace/delete with no values
    527 			 */
    528 			snprintf( textbuf, textlen,
    529 				"%s: attribute is obsolete",
    530 				ml->sml_type.bv_val );
    531 			*text = textbuf;
    532 			return LDAP_CONSTRAINT_VIOLATION;
    533 		}
    534 #endif
    535 
    536 		if ( ml->sml_op == LDAP_MOD_INCREMENT &&
    537 #ifdef SLAPD_REAL_SYNTAX
    538 			!is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
    539 #endif
    540 			!is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
    541 		{
    542 			/*
    543 			 * attribute values must be INTEGER or REAL
    544 			 */
    545 			snprintf( textbuf, textlen,
    546 				"%s: attribute syntax inappropriate for increment",
    547 				ml->sml_type.bv_val );
    548 			*text = textbuf;
    549 			return LDAP_CONSTRAINT_VIOLATION;
    550 		}
    551 
    552 		/*
    553 		 * check values
    554 		 */
    555 		if( ml->sml_values != NULL ) {
    556 			ber_len_t nvals;
    557 			slap_syntax_validate_func *validate =
    558 				ad->ad_type->sat_syntax->ssyn_validate;
    559 			slap_syntax_transform_func *pretty =
    560 				ad->ad_type->sat_syntax->ssyn_pretty;
    561 
    562 			if( !pretty && !validate ) {
    563 				*text = "no validator for syntax";
    564 				snprintf( textbuf, textlen,
    565 					"%s: no validator for syntax %s",
    566 					ml->sml_type.bv_val,
    567 					ad->ad_type->sat_syntax->ssyn_oid );
    568 				*text = textbuf;
    569 				return LDAP_INVALID_SYNTAX;
    570 			}
    571 
    572 			/*
    573 			 * check that each value is valid per syntax
    574 			 *	and pretty if appropriate
    575 			 */
    576 			for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
    577 				struct berval pval;
    578 
    579 				if ( pretty ) {
    580 					rc = ordered_value_pretty( ad,
    581 						&ml->sml_values[nvals], &pval, ctx );
    582 				} else {
    583 					rc = ordered_value_validate( ad,
    584 						&ml->sml_values[nvals], ml->sml_op );
    585 				}
    586 
    587 				if( rc != 0 ) {
    588 					snprintf( textbuf, textlen,
    589 						"%s: value #%ld invalid per syntax",
    590 						ml->sml_type.bv_val, (long) nvals );
    591 					*text = textbuf;
    592 					return LDAP_INVALID_SYNTAX;
    593 				}
    594 
    595 				if( pretty ) {
    596 					ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
    597 					ml->sml_values[nvals] = pval;
    598 				}
    599 			}
    600 			ml->sml_values[nvals].bv_len = 0;
    601 			ml->sml_numvals = nvals;
    602 
    603 			/*
    604 			 * a rough single value check... an additional check is needed
    605 			 * to catch add of single value to existing single valued attribute
    606 			 */
    607 			if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
    608 				&& nvals > 1 && is_at_single_value( ad->ad_type ))
    609 			{
    610 				snprintf( textbuf, textlen,
    611 					"%s: multiple values provided",
    612 					ml->sml_type.bv_val );
    613 				*text = textbuf;
    614 				return LDAP_CONSTRAINT_VIOLATION;
    615 			}
    616 
    617 			/* if the type has a normalizer, generate the
    618 			 * normalized values. otherwise leave them NULL.
    619 			 *
    620 			 * this is different from the rule for attributes
    621 			 * in an entry - in an attribute list, the normalized
    622 			 * value is set equal to the non-normalized value
    623 			 * when there is no normalizer.
    624 			 */
    625 			if( nvals && ad->ad_type->sat_equality &&
    626 				ad->ad_type->sat_equality->smr_normalize )
    627 			{
    628 				ml->sml_nvalues = ber_memalloc_x(
    629 					(nvals+1)*sizeof(struct berval), ctx );
    630 
    631 				for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
    632 					rc = ordered_value_normalize(
    633 						SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
    634 						ad,
    635 						ad->ad_type->sat_equality,
    636 						&ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
    637 					if ( rc ) {
    638 						Debug( LDAP_DEBUG_ANY,
    639 							"<= str2entry NULL (ssyn_normalize %d)\n",
    640 							rc, 0, 0 );
    641 						snprintf( textbuf, textlen,
    642 							"%s: value #%ld normalization failed",
    643 							ml->sml_type.bv_val, (long) nvals );
    644 						*text = textbuf;
    645 						BER_BVZERO( &ml->sml_nvalues[nvals] );
    646 						return rc;
    647 					}
    648 				}
    649 
    650 				BER_BVZERO( &ml->sml_nvalues[nvals] );
    651 			}
    652 
    653 			/* check for duplicates, but ignore Deletes.
    654 			 */
    655 			if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
    656 				int i;
    657 				rc = slap_sort_vals( ml, text, &i, ctx );
    658 				if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
    659 					/* value exists already */
    660 					snprintf( textbuf, textlen,
    661 						"%s: value #%d provided more than once",
    662 						ml->sml_desc->ad_cname.bv_val, i );
    663 					*text = textbuf;
    664 				}
    665 				if ( rc )
    666 					return rc;
    667 			}
    668 		} else {
    669 			ml->sml_numvals = 0;
    670 		}
    671 	}
    672 
    673 	return LDAP_SUCCESS;
    674 }
    675 
    676 /* Sort a set of values. An (Attribute *) may be used interchangeably here
    677  * instead of a (Modifications *) structure.
    678  *
    679  * Uses Quicksort + Insertion sort for small arrays
    680  */
    681 
    682 int
    683 slap_sort_vals(
    684 	Modifications *ml,
    685 	const char **text,
    686 	int *dup,
    687 	void *ctx )
    688 {
    689 	AttributeDescription *ad;
    690 	MatchingRule *mr;
    691 	int istack[sizeof(int)*16];
    692 	int i, j, k, l, ir, jstack, match, *ix, itmp, nvals, rc = LDAP_SUCCESS;
    693 	int is_norm;
    694 	struct berval a, *cv;
    695 
    696 #define SMALL	8
    697 #define	SWAP(a,b,tmp)	tmp=(a);(a)=(b);(b)=tmp
    698 #define	COMP(a,b)	match=0; rc = ordered_value_match( &match, \
    699 						ad, mr, SLAP_MR_EQUALITY \
    700 								| SLAP_MR_VALUE_OF_ASSERTION_SYNTAX \
    701 								| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \
    702 								| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \
    703 								&(a), &(b), text );
    704 
    705 #define	IX(x)	ix[x]
    706 #define	EXCH(x,y)	SWAP(ix[x],ix[y],itmp)
    707 #define	SETA(x)	itmp = ix[x]; a = cv[itmp]
    708 #define	GETA(x)	ix[x] = itmp;
    709 #define	SET(x,y)	ix[x] = ix[y]
    710 
    711 	ad = ml->sml_desc;
    712 	nvals = ml->sml_numvals;
    713 	if ( nvals <= 1 )
    714 		goto ret;
    715 
    716 	/* For Modifications, sml_nvalues is NULL if normalization wasn't needed.
    717 	 * For Attributes, sml_nvalues == sml_values when normalization isn't needed.
    718 	 */
    719 	if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) {
    720 		cv = ml->sml_nvalues;
    721 		is_norm = 1;
    722 	} else {
    723 		cv = ml->sml_values;
    724 		is_norm = 0;
    725 	}
    726 
    727 	if ( ad == slap_schema.si_ad_objectClass )
    728 		mr = NULL;	/* shortcut matching */
    729 	else
    730 		mr = ad->ad_type->sat_equality;
    731 
    732 	/* record indices to preserve input ordering */
    733 	ix = slap_sl_malloc( nvals * sizeof(int), ctx );
    734 	for (i=0; i<nvals; i++) ix[i] = i;
    735 
    736 	ir = nvals-1;
    737 	l = 0;
    738 	jstack = 0;
    739 
    740 	for(;;) {
    741 		if (ir - l < SMALL) {	/* Insertion sort */
    742 			match=1;
    743 			for (j=l+1;j<=ir;j++) {
    744 				SETA(j);
    745 				for (i=j-1;i>=0;i--) {
    746 					COMP(cv[IX(i)], a);
    747 					if ( match <= 0 )
    748 						break;
    749 					SET(i+1,i);
    750 				}
    751 				GETA(i+1);
    752 				if ( match == 0 ) goto done;
    753 			}
    754 			if ( jstack == 0 ) break;
    755 			ir = istack[jstack--];
    756 			l = istack[jstack--];
    757 		} else {
    758 			k = (l + ir) >> 1;	/* Choose median of left, center, right */
    759 			EXCH(k, l+1);
    760 			COMP( cv[IX(l)], cv[IX(ir)] );
    761 			if ( match > 0 ) {
    762 				EXCH(l, ir);
    763 			} else if ( match == 0 ) {
    764 				i = ir;
    765 				break;
    766 			}
    767 			COMP( cv[IX(l+1)], cv[IX(ir)] );
    768 			if ( match > 0 ) {
    769 				EXCH(l+1, ir);
    770 			} else if ( match == 0 ) {
    771 				i = ir;
    772 				break;
    773 			}
    774 			COMP( cv[IX(l)], cv[IX(l+1)] );
    775 			if ( match > 0 ) {
    776 				EXCH(l, l+1);
    777 			} else if ( match == 0 ) {
    778 				i = l;
    779 				break;
    780 			}
    781 			i = l+1;
    782 			j = ir;
    783 			a = cv[IX(i)];
    784 			for(;;) {
    785 				do {
    786 					i++;
    787 					COMP( cv[IX(i)], a );
    788 				} while( match < 0 );
    789 				while( match > 0 ) {
    790 					j--;
    791 					COMP( cv[IX(j)], a );
    792 				}
    793 				if (j < i) {
    794 					match = 1;
    795 					break;
    796 				}
    797 				if ( match == 0 ) {
    798 					i = l+1;
    799 					break;
    800 				}
    801 				EXCH(i,j);
    802 			}
    803 			if ( match == 0 )
    804 				break;
    805 			EXCH(l+1,j);
    806 			jstack += 2;
    807 			if (ir-i+1 > j-l) {
    808 				istack[jstack] = ir;
    809 				istack[jstack-1] = i;
    810 				ir = j;
    811 			} else {
    812 				istack[jstack] = j;
    813 				istack[jstack-1] = l;
    814 				l = i;
    815 			}
    816 		}
    817 	}
    818 	done:
    819 	if ( match == 0 && i >= 0 )
    820 		*dup = ix[i];
    821 
    822 	/* For sorted attributes, put the values in index order */
    823 	if ( rc == LDAP_SUCCESS && match &&
    824 		( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) {
    825 		BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx );
    826 		for ( i = 0; i<nvals; i++ )
    827 			tmpv[i] = cv[ix[i]];
    828 		for ( i = 0; i<nvals; i++ )
    829 			cv[i] = tmpv[i];
    830 		/* Check if the non-normalized array needs to move too */
    831 		if ( is_norm ) {
    832 			cv = ml->sml_values;
    833 			for ( i = 0; i<nvals; i++ )
    834 				tmpv[i] = cv[ix[i]];
    835 			for ( i = 0; i<nvals; i++ )
    836 				cv[i] = tmpv[i];
    837 		}
    838 		slap_sl_free( tmpv, ctx );
    839 	}
    840 
    841 	slap_sl_free( ix, ctx );
    842 
    843 	if ( rc == LDAP_SUCCESS && match == 0 ) {
    844 		/* value exists already */
    845 		assert( i >= 0 );
    846 		assert( i < nvals );
    847 		rc = LDAP_TYPE_OR_VALUE_EXISTS;
    848 	}
    849  ret:
    850 	return rc;
    851 }
    852 
    853 /* Enter with bv->bv_len = sizeof buffer, returns with
    854  * actual length of string
    855  */
    856 void slap_timestamp( time_t *tm, struct berval *bv )
    857 {
    858 	struct tm ltm;
    859 
    860 	ldap_pvt_gmtime( tm, &ltm );
    861 
    862 	bv->bv_len = lutil_gentime( bv->bv_val, bv->bv_len, &ltm );
    863 }
    864 
    865 /* Called for all modify and modrdn ops. If the current op was replicated
    866  * from elsewhere, all of the attrs should already be present.
    867  */
    868 void slap_mods_opattrs(
    869 	Operation *op,
    870 	Modifications **modsp,
    871 	int manage_ctxcsn )
    872 {
    873 	struct berval name, timestamp, csn = BER_BVNULL;
    874 	struct berval nname;
    875 	char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
    876 	char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
    877 	Modifications *mod, **modtail, *modlast;
    878 	int gotcsn = 0, gotmname = 0, gotmtime = 0;
    879 
    880 	if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) {
    881 		char *ptr;
    882 		timestamp.bv_val = timebuf;
    883 		for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) {
    884 			if ( (*modtail)->sml_op != LDAP_MOD_ADD &&
    885 				(*modtail)->sml_op != SLAP_MOD_SOFTADD &&
    886 				(*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT &&
    887 				(*modtail)->sml_op != LDAP_MOD_REPLACE )
    888 			{
    889 				continue;
    890 			}
    891 
    892 			if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN )
    893 			{
    894 				csn = (*modtail)->sml_values[0];
    895 				gotcsn = 1;
    896 
    897 			} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName )
    898 			{
    899 				gotmname = 1;
    900 
    901 			} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp )
    902 			{
    903 				gotmtime = 1;
    904 			}
    905 		}
    906 
    907 		if ( BER_BVISEMPTY( &op->o_csn )) {
    908 			if ( !gotcsn ) {
    909 				csn.bv_val = csnbuf;
    910 				csn.bv_len = sizeof( csnbuf );
    911 				slap_get_csn( op, &csn, manage_ctxcsn );
    912 
    913 			} else {
    914 				if ( manage_ctxcsn ) {
    915 					slap_queue_csn( op, &csn );
    916 				}
    917 			}
    918 
    919 		} else {
    920 			csn = op->o_csn;
    921 		}
    922 
    923 		ptr = ber_bvchr( &csn, '#' );
    924 		if ( ptr ) {
    925 			timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
    926 			AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len );
    927 			timebuf[timestamp.bv_len-1] = 'Z';
    928 			timebuf[timestamp.bv_len] = '\0';
    929 
    930 		} else {
    931 			time_t now = slap_get_time();
    932 
    933 			timestamp.bv_len = sizeof(timebuf);
    934 
    935 			slap_timestamp( &now, &timestamp );
    936 		}
    937 
    938 		if ( BER_BVISEMPTY( &op->o_dn ) ) {
    939 			BER_BVSTR( &name, SLAPD_ANONYMOUS );
    940 			nname = name;
    941 
    942 		} else {
    943 			name = op->o_dn;
    944 			nname = op->o_ndn;
    945 		}
    946 
    947 		if ( !gotcsn ) {
    948 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
    949 			mod->sml_op = LDAP_MOD_REPLACE;
    950 			mod->sml_flags = SLAP_MOD_INTERNAL;
    951 			mod->sml_next = NULL;
    952 			BER_BVZERO( &mod->sml_type );
    953 			mod->sml_desc = slap_schema.si_ad_entryCSN;
    954 			mod->sml_numvals = 1;
    955 			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
    956 			ber_dupbv( &mod->sml_values[0], &csn );
    957 			BER_BVZERO( &mod->sml_values[1] );
    958 			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
    959 			mod->sml_nvalues = NULL;
    960 			*modtail = mod;
    961 			modlast = mod;
    962 			modtail = &mod->sml_next;
    963 		}
    964 
    965 		if ( !gotmname ) {
    966 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
    967 			mod->sml_op = LDAP_MOD_REPLACE;
    968 			mod->sml_flags = SLAP_MOD_INTERNAL;
    969 			mod->sml_next = NULL;
    970 			BER_BVZERO( &mod->sml_type );
    971 			mod->sml_desc = slap_schema.si_ad_modifiersName;
    972 			mod->sml_numvals = 1;
    973 			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
    974 			ber_dupbv( &mod->sml_values[0], &name );
    975 			BER_BVZERO( &mod->sml_values[1] );
    976 			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
    977 			mod->sml_nvalues =
    978 				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
    979 			ber_dupbv( &mod->sml_nvalues[0], &nname );
    980 			BER_BVZERO( &mod->sml_nvalues[1] );
    981 			assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
    982 			*modtail = mod;
    983 			modtail = &mod->sml_next;
    984 		}
    985 
    986 		if ( !gotmtime ) {
    987 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
    988 			mod->sml_op = LDAP_MOD_REPLACE;
    989 			mod->sml_flags = SLAP_MOD_INTERNAL;
    990 			mod->sml_next = NULL;
    991 			BER_BVZERO( &mod->sml_type );
    992 			mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
    993 			mod->sml_numvals = 1;
    994 			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
    995 			ber_dupbv( &mod->sml_values[0], &timestamp );
    996 			BER_BVZERO( &mod->sml_values[1] );
    997 			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
    998 			mod->sml_nvalues = NULL;
    999 			*modtail = mod;
   1000 			modtail = &mod->sml_next;
   1001 		}
   1002 	}
   1003 }
   1004 
   1005 int
   1006 slap_parse_modlist(
   1007 	Operation *op,
   1008 	SlapReply *rs,
   1009 	BerElement *ber,
   1010 	req_modify_s *ms )
   1011 {
   1012 	ber_tag_t	tag;
   1013 	ber_len_t	len;
   1014 	char		*last;
   1015 	Modifications	**modtail = &ms->rs_mods.rs_modlist;
   1016 
   1017 	ms->rs_mods.rs_modlist = NULL;
   1018 	ms->rs_increment = 0;
   1019 
   1020 	rs->sr_err = LDAP_SUCCESS;
   1021 
   1022 	/* collect modifications & save for later */
   1023 	for ( tag = ber_first_element( ber, &len, &last );
   1024 		tag != LBER_DEFAULT;
   1025 		tag = ber_next_element( ber, &len, last ) )
   1026 	{
   1027 		ber_int_t mop;
   1028 		Modifications tmp, *mod;
   1029 
   1030 		tmp.sml_nvalues = NULL;
   1031 
   1032 		if ( ber_scanf( ber, "{e{m[W]}}", &mop,
   1033 		    &tmp.sml_type, &tmp.sml_values ) == LBER_ERROR )
   1034 		{
   1035 			rs->sr_text = "decoding modlist error";
   1036 			rs->sr_err = LDAP_PROTOCOL_ERROR;
   1037 			goto done;
   1038 		}
   1039 
   1040 		mod = (Modifications *) ch_malloc( sizeof(Modifications) );
   1041 		mod->sml_op = mop;
   1042 		mod->sml_flags = 0;
   1043 		mod->sml_type = tmp.sml_type;
   1044 		mod->sml_values = tmp.sml_values;
   1045 		mod->sml_nvalues = NULL;
   1046 		mod->sml_desc = NULL;
   1047 		mod->sml_next = NULL;
   1048 		*modtail = mod;
   1049 
   1050 		switch( mop ) {
   1051 		case LDAP_MOD_ADD:
   1052 			if ( mod->sml_values == NULL ) {
   1053 				rs->sr_text = "modify/add operation requires values";
   1054 				rs->sr_err = LDAP_PROTOCOL_ERROR;
   1055 				goto done;
   1056 			}
   1057 
   1058 			/* fall through */
   1059 
   1060 		case LDAP_MOD_DELETE:
   1061 		case LDAP_MOD_REPLACE:
   1062 			break;
   1063 
   1064 		case LDAP_MOD_INCREMENT:
   1065 			if( op->o_protocol >= LDAP_VERSION3 ) {
   1066 				ms->rs_increment++;
   1067 				if ( mod->sml_values == NULL ) {
   1068 					rs->sr_text = "modify/increment operation requires value";
   1069 					rs->sr_err = LDAP_PROTOCOL_ERROR;
   1070 					goto done;
   1071 				}
   1072 
   1073 				if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) {
   1074 					rs->sr_text = "modify/increment operation requires single value";
   1075 					rs->sr_err = LDAP_PROTOCOL_ERROR;
   1076 					goto done;
   1077 				}
   1078 
   1079 				break;
   1080 			}
   1081 			/* fall thru */
   1082 
   1083 		default:
   1084 			rs->sr_text = "unrecognized modify operation";
   1085 			rs->sr_err = LDAP_PROTOCOL_ERROR;
   1086 			goto done;
   1087 		}
   1088 
   1089 		modtail = &mod->sml_next;
   1090 	}
   1091 	*modtail = NULL;
   1092 
   1093 done:
   1094 	if ( rs->sr_err != LDAP_SUCCESS ) {
   1095 		slap_mods_free( ms->rs_mods.rs_modlist, 1 );
   1096 		ms->rs_mods.rs_modlist = NULL;
   1097 		ms->rs_increment = 0;
   1098 	}
   1099 
   1100 	return rs->sr_err;
   1101 }
   1102 
   1103