Example #1
0
static int
asyncmeta_send_entry(
	Operation 	*op,
	SlapReply	*rs,
	a_metaconn_t	*mc,
	int 		target,
	LDAPMessage 	*e )
{
	a_metainfo_t 		*mi = mc->mc_info;
	struct berval		a, mapped = BER_BVNULL;
	int			check_sorted_attrs = 0;
	Entry 			ent = {0};
	BerElement 		ber = *ldap_get_message_ber( e );
	Attribute 		*attr, **attrp;
	struct berval 		bdn,
				dn = BER_BVNULL;
	const char 		*text;
	a_dncookie		dc;
	ber_len_t		len;
	int			rc;
	void	*mem_mark;

	mem_mark = slap_sl_mark( op->o_tmpmemctx );
	ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

	if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
		return LDAP_DECODING_ERROR;
	}

	if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
		return LDAP_OTHER;
	}

	if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
		return LDAP_DECODING_ERROR;
	}

	/*
	 * Rewrite the dn of the result, if needed
	 */
	dc.op = op;
	dc.target = mi->mi_targets[ target ];
	dc.memctx = op->o_tmpmemctx;
	dc.to_from = MASSAGE_REP;
	asyncmeta_dn_massage( &dc, &bdn, &dn );

	/*
	 * Note: this may fail if the target host(s) schema differs
	 * from the one known to the meta, and a DN with unknown
	 * attributes is returned.
	 *
	 * FIXME: should we log anything, or delegate to dnNormalize?
	 */
	rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
		op->o_tmpmemctx );
	if ( dn.bv_val != bdn.bv_val ) {
			op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
	}
	BER_BVZERO( &dn );

	if ( rc != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_ANY,
			"%s asyncmeta_send_entry(\"%s\"): "
			"invalid DN syntax\n",
			op->o_log_prefix, ent.e_name.bv_val );
		rc = LDAP_INVALID_DN_SYNTAX;
		goto done;
	}

	/*
	 * cache dn
	 */
	if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
		( void )asyncmeta_dncache_update_entry( &mi->mi_cache,
				&ent.e_nname, target );
	}

	attrp = &ent.e_attrs;

	while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
		int				last = 0;
		slap_syntax_validate_func	*validate;
		slap_syntax_transform_func	*pretty;

		if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"%s asyncmeta_send_entry(\"%s\"): "
				"unable to parse attr \"%s\".\n",
				op->o_log_prefix, ent.e_name.bv_val, a.bv_val );

			rc = LDAP_OTHER;
			goto done;
		}

		if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
			break;
		}

		attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx );
		if ( slap_bv2ad( &a, &attr->a_desc, &text )
				!= LDAP_SUCCESS) {
			if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
				SLAP_AD_PROXIED ) != LDAP_SUCCESS )
			{
				Debug(LDAP_DEBUG_ANY,
				      "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n",
				      op->o_log_prefix, ent.e_name.bv_val,
				      mapped.bv_val, text );
				( void )ber_scanf( &ber, "x" /* [W] */ );
				op->o_tmpfree( attr, op->o_tmpmemctx );
				continue;
			}
		}

		if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
			check_sorted_attrs = 1;

		/* no subschemaSubentry */
		if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
			|| attr->a_desc == slap_schema.si_ad_entryDN )
		{

			/*
			 * We eat target's subschemaSubentry because
			 * a search for this value is likely not
			 * to resolve to the appropriate backend;
			 * later, the local subschemaSubentry is
			 * added.
			 *
			 * We also eat entryDN because the frontend
			 * will reattach it without checking if already
			 * present...
			 */
			( void )ber_scanf( &ber, "x" /* [W] */ );
			op->o_tmpfree( attr, op->o_tmpmemctx );
			continue;
		}

		if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
				|| attr->a_vals == NULL )
		{
			attr->a_vals = (struct berval *)&slap_dummy_bv;

		} else {
			for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
				;
		}
		attr->a_numvals = last;

		validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
		pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;

		if ( !validate && !pretty ) {
			ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
			op->o_tmpfree( attr, op->o_tmpmemctx );
			goto next_attr;
		}

		/*
		 * It is necessary to try to rewrite attributes with
		 * dn syntax because they might be used in ACLs as
		 * members of groups; since ACLs are applied to the
		 * rewritten stuff, no dn-based subecj clause could
		 * be used at the ldap backend side (see
		 * http://www.OpenLDAP.org/faq/data/cache/452.html)
		 * The problem can be overcome by moving the dn-based
		 * ACLs to the target directory server, and letting
		 * everything pass thru the ldap backend.
		 */
		{
			int	i;

			if ( attr->a_desc->ad_type->sat_syntax ==
				slap_schema.si_syn_distinguishedName )
			{
				asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals );

			} else if ( attr->a_desc == slap_schema.si_ad_ref ) {
				asyncmeta_referral_result_rewrite( &dc, attr->a_vals );

			}

			for ( i = 0; i < last; i++ ) {
				struct berval	pval;
				int		rc;

				if ( pretty ) {
					rc = ordered_value_pretty( attr->a_desc,
						&attr->a_vals[i], &pval, op->o_tmpmemctx );

				} else {
					rc = ordered_value_validate( attr->a_desc,
						&attr->a_vals[i], 0 );
				}

				if ( rc ) {
					ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
					if ( --last == i ) {
						BER_BVZERO( &attr->a_vals[ i ] );
						break;
					}
					attr->a_vals[i] = attr->a_vals[last];
					BER_BVZERO( &attr->a_vals[last] );
					i--;
					continue;
				}

				if ( pretty ) {
					ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
					attr->a_vals[i] = pval;
				}
			}

			if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
				ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
				op->o_tmpfree( attr, op->o_tmpmemctx );
				goto next_attr;
			}
		}

		if ( last && attr->a_desc->ad_type->sat_equality &&
			attr->a_desc->ad_type->sat_equality->smr_normalize )
		{
			int i;

			attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
			for ( i = 0; i<last; i++ ) {
				/* if normalizer fails, drop this value */
				if ( ordered_value_normalize(
					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
					attr->a_desc,
					attr->a_desc->ad_type->sat_equality,
					&attr->a_vals[i], &attr->a_nvals[i],
					op->o_tmpmemctx )) {
					ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
					if ( --last == i ) {
						BER_BVZERO( &attr->a_vals[ i ] );
						break;
					}
					attr->a_vals[i] = attr->a_vals[last];
					BER_BVZERO( &attr->a_vals[last] );
					i--;
				}
			}
			BER_BVZERO( &attr->a_nvals[i] );
			if ( last == 0 ) {
				ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
				ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
				op->o_tmpfree( attr, op->o_tmpmemctx );
				goto next_attr;
			}

		} else {
			attr->a_nvals = attr->a_vals;
		}

		attr->a_numvals = last;
		*attrp = attr;
		attrp = &attr->a_next;
next_attr:;
	}

	/* Check for sorted attributes */
	if ( check_sorted_attrs ) {
		for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
			if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
				while ( attr->a_numvals > 1 ) {
					int i;
					int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
					if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
						break;

					/* Strip duplicate values */
					if ( attr->a_nvals != attr->a_vals )
						ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx );
					ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
					attr->a_numvals--;
					if ( (unsigned)i < attr->a_numvals ) {
						attr->a_vals[i] = attr->a_vals[attr->a_numvals];
						if ( attr->a_nvals != attr->a_vals )
							attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
					}
					BER_BVZERO(&attr->a_vals[attr->a_numvals]);
					if ( attr->a_nvals != attr->a_vals )
						BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
				}
				attr->a_flags |= SLAP_ATTR_SORTED_VALS;
			}
		}
	}
	Debug( LDAP_DEBUG_TRACE,
	       "%s asyncmeta_send_entry(\"%s\"): "
	       ".\n",
	       op->o_log_prefix, ent.e_name.bv_val );
	ldap_get_entry_controls( mc->mc_conns[target].msc_ldr,
		e, &rs->sr_ctrls );
	rs->sr_entry = &ent;
	rs->sr_attrs = op->ors_attrs;
	rs->sr_operational_attrs = NULL;
	rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
	rs->sr_err = LDAP_SUCCESS;
	rc = send_search_entry( op, rs );
	switch ( rc ) {
	case LDAP_UNAVAILABLE:
		rc = LDAP_OTHER;
		break;
	}

done:;
	if ( rs->sr_ctrls != NULL ) {
		ldap_controls_free( rs->sr_ctrls );
		rs->sr_ctrls = NULL;
	}
#if 0
	while ( ent.e_attrs ) {
		attr = ent.e_attrs;
		ent.e_attrs = attr->a_next;
		if ( attr->a_nvals != attr->a_vals )
			ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
		ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
		op->o_tmpfree( attr, op->o_tmpmemctx );
	}
	if (ent.e_name.bv_val != NULL) {
		op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
	}

	if (ent.e_nname.bv_val != NULL) {
		op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
	}
	if (rs->sr_entry && rs->sr_entry != &ent) {
		entry_free( rs->sr_entry );
	}
#endif
	slap_sl_release( mem_mark, op->o_tmpmemctx );
	rs->sr_entry = NULL;
	rs->sr_attrs = NULL;
	return rc;
}
Example #2
0
static int
ldap_build_entry(
		Operation	*op,
		LDAPMessage	*e,
		Entry		*ent,
		struct berval	*bdn )
{
	struct berval	a;
	BerElement	ber = *ldap_get_message_ber( e );
	Attribute	*attr, **attrp;
	const char	*text;
	int		last;
	char *lastb;
	ber_len_t len;

	/* safe assumptions ... */
	assert( ent != NULL );
	BER_BVZERO( &ent->e_bv );

	if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) {
		return LDAP_DECODING_ERROR;
	}

	/*
	 * Note: this may fail if the target host(s) schema differs
	 * from the one known to the meta, and a DN with unknown
	 * attributes is returned.
	 * 
	 * FIXME: should we log anything, or delegate to dnNormalize?
	 */
	/* Note: if the distinguished values or the naming attributes
	 * change, should we massage them as well?
	 */
	if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname,
		op->o_tmpmemctx ) != LDAP_SUCCESS )
	{
		return LDAP_INVALID_DN_SYNTAX;
	}

	ent->e_attrs = NULL;
	if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) {
		return LDAP_SUCCESS;
	}

	attrp = &ent->e_attrs;
	while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE &&
		ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
		int				i;
		slap_syntax_validate_func	*validate;
		slap_syntax_transform_func	*pretty;

		attr = attr_alloc( NULL );
		if ( attr == NULL ) {
			return LDAP_OTHER;
		}
		if ( slap_bv2ad( &a, &attr->a_desc, &text ) 
				!= LDAP_SUCCESS )
		{
			if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
				SLAP_AD_PROXIED ) != LDAP_SUCCESS )
			{
				Debug( LDAP_DEBUG_ANY, 
					"%s ldap_build_entry: "
					"slap_bv2undef_ad(%s): %s\n",
					op->o_log_prefix, a.bv_val, text );

				( void )ber_scanf( &ber, "x" /* [W] */ );
				attr_free( attr );
				continue;
			}
		}

		/* no subschemaSubentry */
		if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
			|| attr->a_desc == slap_schema.si_ad_entryDN )
		{

			/* 
			 * We eat target's subschemaSubentry because
			 * a search for this value is likely not
			 * to resolve to the appropriate backend;
			 * later, the local subschemaSubentry is
			 * added.
			 *
			 * We also eat entryDN because the frontend
			 * will reattach it without checking if already
			 * present...
			 */
			( void )ber_scanf( &ber, "x" /* [W] */ );
			attr_free( attr );
			continue;
		}
		
		if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
				|| attr->a_vals == NULL )
		{
			/*
			 * Note: attr->a_vals can be null when using
			 * values result filter
			 */
			attr->a_vals = (struct berval *)&slap_dummy_bv;
		}

		validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
		pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;

		if ( !validate && !pretty ) {
			attr->a_nvals = NULL;
			attr_free( attr );
			goto next_attr;
		}

		for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ;
		last = i;

		/*
		 * check that each value is valid per syntax
		 * and pretty if appropriate
		 */
		for ( i = 0; i<last; i++ ) {
			struct berval	pval;
			int		rc;

			if ( pretty ) {
				rc = ordered_value_pretty( attr->a_desc,
					&attr->a_vals[i], &pval, NULL );

			} else {
				rc = ordered_value_validate( attr->a_desc,
					&attr->a_vals[i], 0 );
			}

			if ( rc != LDAP_SUCCESS ) {
				ObjectClass *oc;

				/* check if, by chance, it's an undefined objectClass */
				if ( attr->a_desc == slap_schema.si_ad_objectClass &&
						( oc = oc_bvfind_undef( &attr->a_vals[i] ) ) != NULL )
				{
					ber_dupbv( &pval, &oc->soc_cname );
					rc = LDAP_SUCCESS;

				} else {
					ber_memfree( attr->a_vals[i].bv_val );
					if ( --last == i ) {
						BER_BVZERO( &attr->a_vals[i] );
						break;
					}
					attr->a_vals[i] = attr->a_vals[last];
					BER_BVZERO( &attr->a_vals[last] );
					i--;
				}
			}

			if ( rc == LDAP_SUCCESS && pretty ) {
				ber_memfree( attr->a_vals[i].bv_val );
				attr->a_vals[i] = pval;
			}
		}
		attr->a_numvals = last = i;
		if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
			attr->a_nvals = NULL;
			attr_free( attr );
			goto next_attr;
		}

		if ( last && attr->a_desc->ad_type->sat_equality &&
				attr->a_desc->ad_type->sat_equality->smr_normalize )
		{
			attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
			for ( i = 0; i < last; i++ ) {
				int		rc;

				rc = ordered_value_normalize(
					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
					attr->a_desc,
					attr->a_desc->ad_type->sat_equality,
					&attr->a_vals[i], &attr->a_nvals[i],
					NULL );

				if ( rc != LDAP_SUCCESS ) {
					ber_memfree( attr->a_vals[i].bv_val );
					if ( --last == i ) {
						BER_BVZERO( &attr->a_vals[i] );
						break;
					}
					attr->a_vals[i] = attr->a_vals[last];
					BER_BVZERO( &attr->a_vals[last] );
					i--;
				}
			}
			BER_BVZERO( &attr->a_nvals[i] );
			if ( last == 0 ) {
				attr_free( attr );
				goto next_attr;
			}

		} else {
			attr->a_nvals = attr->a_vals;
		}

		attr->a_numvals = last;

		/* Handle sorted vals, strip dups but keep the attr */
		if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
			while ( attr->a_numvals > 1 ) {
				int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
				if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
					break;

				/* Strip duplicate values */
				if ( attr->a_nvals != attr->a_vals )
					ber_memfree( attr->a_nvals[i].bv_val );
				ber_memfree( attr->a_vals[i].bv_val );
				attr->a_numvals--;

				assert( i >= 0 );
				if ( (unsigned)i < attr->a_numvals ) {
					attr->a_vals[i] = attr->a_vals[attr->a_numvals];
					if ( attr->a_nvals != attr->a_vals )
						attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
				}
				BER_BVZERO(&attr->a_vals[attr->a_numvals]);
				if ( attr->a_nvals != attr->a_vals )
					BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
			}
			attr->a_flags |= SLAP_ATTR_SORTED_VALS;
		}

		*attrp = attr;
		attrp = &attr->a_next;

next_attr:;
	}

	return LDAP_SUCCESS;
}
Example #3
0
/*
 * Do basic attribute type checking and syntax validation.
 */
int slap_mods_check(
	Operation *op,
	Modifications *ml,
	const char **text,
	char *textbuf,
	size_t textlen,
	void *ctx )
{
	int rc;

	for( ; ml != NULL; ml = ml->sml_next ) {
		AttributeDescription *ad = NULL;

		/* convert to attribute description */
		if ( ml->sml_desc == NULL ) {
			rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
			if( rc != LDAP_SUCCESS ) {
				if ( get_no_schema_check( op )) {
					rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
						text, 0 );
				}
			}
			if( rc != LDAP_SUCCESS ) {
				snprintf( textbuf, textlen, "%s: %s",
					ml->sml_type.bv_val, *text );
				*text = textbuf;
				return rc;
			}
		}

		ad = ml->sml_desc;

		if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& !slap_ad_is_binary( ad ))
		{
			/* attribute requires binary transfer */
			snprintf( textbuf, textlen,
				"%s: requires ;binary transfer",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

		if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& slap_ad_is_binary( ad ))
		{
			/* attribute does not require binary transfer */
			snprintf( textbuf, textlen,
				"%s: disallows ;binary transfer",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

		if( slap_ad_is_tag_range( ad )) {
			/* attribute requires binary transfer */
			snprintf( textbuf, textlen,
				"%s: inappropriate use of tag range option",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

#if 0
		if ( is_at_obsolete( ad->ad_type ) &&
			(( ml->sml_op != LDAP_MOD_REPLACE &&
				ml->sml_op != LDAP_MOD_DELETE ) ||
					ml->sml_values != NULL ))
		{
			/*
			 * attribute is obsolete,
			 * only allow replace/delete with no values
			 */
			snprintf( textbuf, textlen,
				"%s: attribute is obsolete",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}
#endif

		if ( ml->sml_op == LDAP_MOD_INCREMENT &&
#ifdef SLAPD_REAL_SYNTAX
			!is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
#endif
			!is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
		{
			/*
			 * attribute values must be INTEGER or REAL
			 */
			snprintf( textbuf, textlen,
				"%s: attribute syntax inappropriate for increment",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}

		/*
		 * check values
		 */
		if( ml->sml_values != NULL ) {
			ber_len_t nvals;
			slap_syntax_validate_func *validate =
				ad->ad_type->sat_syntax->ssyn_validate;
			slap_syntax_transform_func *pretty =
				ad->ad_type->sat_syntax->ssyn_pretty;
 
			if( !pretty && !validate ) {
				*text = "no validator for syntax";
				snprintf( textbuf, textlen,
					"%s: no validator for syntax %s",
					ml->sml_type.bv_val,
					ad->ad_type->sat_syntax->ssyn_oid );
				*text = textbuf;
				return LDAP_INVALID_SYNTAX;
			}

			/*
			 * check that each value is valid per syntax
			 *	and pretty if appropriate
			 */
			for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
				struct berval pval;

				if ( pretty ) {
					rc = ordered_value_pretty( ad,
						&ml->sml_values[nvals], &pval, ctx );
				} else {
					rc = ordered_value_validate( ad,
						&ml->sml_values[nvals], ml->sml_op );
				}

				if( rc != 0 ) {
					snprintf( textbuf, textlen,
						"%s: value #%ld invalid per syntax",
						ml->sml_type.bv_val, (long) nvals );
					*text = textbuf;
					return LDAP_INVALID_SYNTAX;
				}

				if( pretty ) {
					ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
					ml->sml_values[nvals] = pval;
				}
			}
			ml->sml_values[nvals].bv_len = 0;
			ml->sml_numvals = nvals;

			/*
			 * a rough single value check... an additional check is needed
			 * to catch add of single value to existing single valued attribute
			 */
			if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
				&& nvals > 1 && is_at_single_value( ad->ad_type ))
			{
				snprintf( textbuf, textlen,
					"%s: multiple values provided",
					ml->sml_type.bv_val );
				*text = textbuf;
				return LDAP_CONSTRAINT_VIOLATION;
			}

			/* if the type has a normalizer, generate the
			 * normalized values. otherwise leave them NULL.
			 *
			 * this is different from the rule for attributes
			 * in an entry - in an attribute list, the normalized
			 * value is set equal to the non-normalized value
			 * when there is no normalizer.
			 */
			if( nvals && ad->ad_type->sat_equality &&
				ad->ad_type->sat_equality->smr_normalize )
			{
				ml->sml_nvalues = ber_memalloc_x(
					(nvals+1)*sizeof(struct berval), ctx );

				for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
					rc = ordered_value_normalize(
						SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
						ad,
						ad->ad_type->sat_equality,
						&ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
					if ( rc ) {
						Debug( LDAP_DEBUG_ANY,
							"<= str2entry NULL (ssyn_normalize %d)\n",
							rc, 0, 0 );
						snprintf( textbuf, textlen,
							"%s: value #%ld normalization failed",
							ml->sml_type.bv_val, (long) nvals );
						*text = textbuf;
						BER_BVZERO( &ml->sml_nvalues[nvals] );
						return rc;
					}
				}

				BER_BVZERO( &ml->sml_nvalues[nvals] );
			}

			/* check for duplicates, but ignore Deletes.
			 */
			if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
				int i;
				rc = slap_sort_vals( ml, text, &i, ctx );
				if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
					/* value exists already */
					snprintf( textbuf, textlen,
						"%s: value #%d provided more than once",
						ml->sml_desc->ad_cname.bv_val, i );
					*text = textbuf;
				}
				if ( rc )
					return rc;
			}
		} else {
			ml->sml_numvals = 0;
		}
	}

	return LDAP_SUCCESS;
}
Example #4
0
Entry *
str2entry2( char *s, int checkvals )
{
	int rc;
	Entry		*e;
	struct berval	*type, *vals, *nvals;
	char 	*freeval;
	AttributeDescription *ad, *ad_prev;
	const char *text;
	char	*next;
	int		attr_cnt;
	int		i, lines;
	Attribute	ahead, *atail;

	/*
	 * LDIF is used as the string format.
	 * An entry looks like this:
	 *
	 *	dn: <dn>\n
	 *	[<attr>:[:] <value>\n]
	 *	[<tab><continuedvalue>\n]*
	 *	...
	 *
	 * If a double colon is used after a type, it means the
	 * following value is encoded as a base 64 string.  This
	 * happens if the value contains a non-printing character
	 * or newline.
	 */

	Debug( LDAP_DEBUG_TRACE, "=> str2entry: \"%s\"\n",
		s ? s : "NULL", 0, 0 );

	e = entry_alloc();

	if( e == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"<= str2entry NULL (entry allocation failed)\n",
			0, 0, 0 );
		return( NULL );
	}

	/* initialize entry */
	e->e_id = NOID;

	/* dn + attributes */
	atail = &ahead;
	ahead.a_next = NULL;
	ad = NULL;
	ad_prev = NULL;
	attr_cnt = 0;
	next = s;

	lines = ldif_countlines( s );
	type = ch_calloc( 1, (lines+1)*3*sizeof(struct berval)+lines );
	vals = type+lines+1;
	nvals = vals+lines+1;
	freeval = (char *)(nvals+lines+1);
	i = -1;

	/* parse into individual values, record DN */
	while ( (s = ldif_getline( &next )) != NULL ) {
		int freev;
		if ( *s == '\n' || *s == '\0' ) {
			break;
		}
		i++;
		if (i >= lines) {
			Debug( LDAP_DEBUG_TRACE,
				"<= str2entry ran past end of entry\n", 0, 0, 0 );
			goto fail;
		}

		rc = ldif_parse_line2( s, type+i, vals+i, &freev );
		freeval[i] = freev;
		if ( rc ) {
			Debug( LDAP_DEBUG_TRACE,
				"<= str2entry NULL (parse_line)\n", 0, 0, 0 );
			continue;
		}

		if ( bvcasematch( &type[i], &dn_bv ) ) {
			if ( e->e_dn != NULL ) {
				Debug( LDAP_DEBUG_ANY, "str2entry: "
					"entry %ld has multiple DNs \"%s\" and \"%s\"\n",
					(long) e->e_id, e->e_dn, vals[i].bv_val );
				goto fail;
			}

			rc = dnPrettyNormal( NULL, &vals[i], &e->e_name, &e->e_nname, NULL );
			if( rc != LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_ANY, "str2entry: "
					"entry %ld has invalid DN \"%s\"\n",
					(long) e->e_id, vals[i].bv_val, 0 );
				goto fail;
			}
			if ( freeval[i] ) free( vals[i].bv_val );
			vals[i].bv_val = NULL;
			i--;
			continue;
		}
	}
	lines = i+1;

	/* check to make sure there was a dn: line */
	if ( BER_BVISNULL( &e->e_name )) {
		Debug( LDAP_DEBUG_ANY, "str2entry: entry %ld has no dn\n",
			(long) e->e_id, 0, 0 );
		goto fail;
	}

	/* Make sure all attributes with multiple values are contiguous */
	if ( checkvals ) {
		int j, k;
		struct berval bv;
		int fv;

		for (i=0; i<lines; i++) {
			for ( j=i+1; j<lines; j++ ) {
				if ( bvcasematch( type+i, type+j )) {
					/* out of order, move intervening attributes down */
					if ( j != i+1 ) {
						bv = vals[j];
						fv = freeval[j];
						for ( k=j; k>i; k-- ) {
							type[k] = type[k-1];
							vals[k] = vals[k-1];
							freeval[k] = freeval[k-1];
						}
						k++;
						type[k] = type[i];
						vals[k] = bv;
						freeval[k] = fv;
					}
					i++;
				}
			}
		}
	}

	if ( lines > 0 ) {
		for ( i=0; i<=lines; i++ ) {
			ad_prev = ad;
			if ( !ad || ( i<lines && !bvcasematch( type+i, &ad->ad_cname ))) {
				ad = NULL;
				rc = slap_bv2ad( type+i, &ad, &text );
	
				if( rc != LDAP_SUCCESS ) {
					Debug( slapMode & SLAP_TOOL_MODE
						? LDAP_DEBUG_ANY : LDAP_DEBUG_TRACE,
						"<= str2entry: str2ad(%s): %s\n", type[i].bv_val, text, 0 );
					if( slapMode & SLAP_TOOL_MODE ) {
						goto fail;
					}
	
					rc = slap_bv2undef_ad( type+i, &ad, &text, 0 );
					if( rc != LDAP_SUCCESS ) {
						Debug( LDAP_DEBUG_ANY,
							"<= str2entry: slap_str2undef_ad(%s): %s\n",
								type[i].bv_val, text, 0 );
						goto fail;
					}
				}
	
				/* require ';binary' when appropriate (ITS#5071) */
				if ( slap_syntax_is_binary( ad->ad_type->sat_syntax ) && !slap_ad_is_binary( ad ) ) {
					Debug( LDAP_DEBUG_ANY,
						"str2entry: attributeType %s #%d: "
						"needs ';binary' transfer as per syntax %s\n", 
						ad->ad_cname.bv_val, 0,
						ad->ad_type->sat_syntax->ssyn_oid );
					goto fail;
				}
			}
	
			if (( ad_prev && ad != ad_prev ) || ( i == lines )) {
				int j, k;
				/* FIXME: we only need this when migrating from an unsorted DB */
				if ( atail != &ahead && atail->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
					rc = slap_sort_vals( (Modifications *)atail, &text, &j, NULL );
					if ( rc == LDAP_SUCCESS ) {
						atail->a_flags |= SLAP_ATTR_SORTED_VALS;
					} else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
						Debug( LDAP_DEBUG_ANY,
							"str2entry: attributeType %s value #%d provided more than once\n",
							atail->a_desc->ad_cname.bv_val, j, 0 );
						goto fail;
					}
				}
				atail->a_next = attr_alloc( NULL );
				atail = atail->a_next;
				atail->a_flags = 0;
				atail->a_numvals = attr_cnt;
				atail->a_desc = ad_prev;
				atail->a_vals = ch_malloc( (attr_cnt + 1) * sizeof(struct berval));
				if( ad_prev->ad_type->sat_equality &&
					ad_prev->ad_type->sat_equality->smr_normalize )
					atail->a_nvals = ch_malloc( (attr_cnt + 1) * sizeof(struct berval));
				else
					atail->a_nvals = NULL;
				k = i - attr_cnt;
				for ( j=0; j<attr_cnt; j++ ) {
					if ( freeval[k] )
						atail->a_vals[j] = vals[k];
					else
						ber_dupbv( atail->a_vals+j, &vals[k] );
					vals[k].bv_val = NULL;
					if ( atail->a_nvals ) {
						atail->a_nvals[j] = nvals[k];
						nvals[k].bv_val = NULL;
					}
					k++;
				}
				BER_BVZERO( &atail->a_vals[j] );
				if ( atail->a_nvals ) {
					BER_BVZERO( &atail->a_nvals[j] );
				} else {
					atail->a_nvals = atail->a_vals;
				}
				attr_cnt = 0;
				if ( i == lines ) break;
			}
	
			if ( BER_BVISNULL( &vals[i] ) ) {
				Debug( LDAP_DEBUG_ANY,
					"str2entry: attributeType %s #%d: "
					"no value\n", 
					ad->ad_cname.bv_val, attr_cnt, 0 );
				goto fail;
			}
	
			if( slapMode & SLAP_TOOL_MODE ) {
				struct berval pval;
				slap_syntax_validate_func *validate =
					ad->ad_type->sat_syntax->ssyn_validate;
				slap_syntax_transform_func *pretty =
					ad->ad_type->sat_syntax->ssyn_pretty;
	
				if ( pretty ) {
					rc = ordered_value_pretty( ad,
						&vals[i], &pval, NULL );
	
				} else if ( validate ) {
					/*
				 	 * validate value per syntax
				 	 */
					rc = ordered_value_validate( ad, &vals[i], LDAP_MOD_ADD );
	
				} else {
					Debug( LDAP_DEBUG_ANY,
						"str2entry: attributeType %s #%d: "
						"no validator for syntax %s\n", 
						ad->ad_cname.bv_val, attr_cnt,
						ad->ad_type->sat_syntax->ssyn_oid );
					goto fail;
				}
	
				if( rc != 0 ) {
					Debug( LDAP_DEBUG_ANY,
						"str2entry: invalid value "
						"for attributeType %s #%d (syntax %s)\n",
						ad->ad_cname.bv_val, attr_cnt,
						ad->ad_type->sat_syntax->ssyn_oid );
					goto fail;
				}
	
				if( pretty ) {
					if ( freeval[i] ) free( vals[i].bv_val );
					vals[i] = pval;
					freeval[i] = 1;
				}
			}
	
			if ( ad->ad_type->sat_equality &&
				ad->ad_type->sat_equality->smr_normalize )
			{
				rc = ordered_value_normalize(
					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
					ad,
					ad->ad_type->sat_equality,
					&vals[i], &nvals[i], NULL );
	
				if ( rc ) {
					Debug( LDAP_DEBUG_ANY,
				   		"<= str2entry NULL (smr_normalize %s %d)\n", ad->ad_cname.bv_val, rc, 0 );
					goto fail;
				}
			}
	
			attr_cnt++;
		}
	}

	free( type );
	atail->a_next = NULL;
	e->e_attrs = ahead.a_next;

	Debug(LDAP_DEBUG_TRACE, "<= str2entry(%s) -> 0x%lx\n",
		e->e_dn, (unsigned long) e, 0 );
	return( e );

fail:
	for ( i=0; i<lines; i++ ) {
		if ( freeval[i] ) free( vals[i].bv_val );
		free( nvals[i].bv_val );
	}
	free( type );
	entry_free( e );
	return NULL;
}