Example #1
0
void glue_parent(Operation *op) {
	Operation nop = *op;
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	struct berval ndn = BER_BVNULL;
	Attribute *a;
	Entry *e;
	struct berval	pdn;

	dnParent( &op->o_req_ndn, &pdn );
	ber_dupbv_x( &ndn, &pdn, op->o_tmpmemctx );

	Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", ndn.bv_val, 0, 0);

	e = entry_alloc();
	e->e_id = NOID;
	ber_dupbv(&e->e_name, &ndn);
	ber_dupbv(&e->e_nname, &ndn);

	a = attr_alloc( slap_schema.si_ad_objectClass );
	a->a_numvals = 2;
	a->a_vals = ch_malloc(sizeof(struct berval) * 3);
	ber_dupbv(&a->a_vals[0], &glue[0]);
	ber_dupbv(&a->a_vals[1], &glue[1]);
	ber_dupbv(&a->a_vals[2], &glue[2]);
	a->a_nvals = a->a_vals;
	a->a_next = e->e_attrs;
	e->e_attrs = a;

	a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
	a->a_numvals = 1;
	a->a_vals = ch_malloc(sizeof(struct berval) * 2);
	ber_dupbv(&a->a_vals[0], &glue[1]);
	ber_dupbv(&a->a_vals[1], &glue[2]);
	a->a_nvals = a->a_vals;
	a->a_next = e->e_attrs;
	e->e_attrs = a;

	nop.o_req_dn = ndn;
	nop.o_req_ndn = ndn;
	nop.ora_e = e;

	nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig;
	syncrepl_add_glue(&nop, e);
	nop.o_bd->bd_info = (BackendInfo *) on;

	op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );

	return;
}
Example #2
0
Attribute *
backsql_operational_entryCSN( Operation *op )
{
	char		csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
	struct berval	entryCSN;
	Attribute	*a;

	a = attr_alloc( slap_schema.si_ad_entryCSN );
	a->a_numvals = 1;
	a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );
	BER_BVZERO( &a->a_vals[ 1 ] );

#ifdef BACKSQL_SYNCPROV
	if ( op->o_sync && op->o_tag == LDAP_REQ_SEARCH && op->o_private != NULL ) {
		assert( op->o_private != NULL );

		entryCSN = *((struct berval *)op->o_private);

	} else
#endif /* BACKSQL_SYNCPROV */
	{
		entryCSN.bv_val = csnbuf;
		entryCSN.bv_len = sizeof( csnbuf );
		slap_get_csn( op, &entryCSN, 0 );
	}

	ber_dupbv( &a->a_vals[ 0 ], &entryCSN );

	a->a_nvals = a->a_vals;

	return a;
}
Example #3
0
Attribute *
backsql_operational_entryUUID( backsql_info *bi, backsql_entryID *id )
{
	int			rc;
	struct berval		val, nval;
	AttributeDescription	*desc = slap_schema.si_ad_entryUUID;
	Attribute		*a;

	backsql_entryUUID( bi, id, &val, NULL );

	rc = (*desc->ad_type->sat_equality->smr_normalize)(
			SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
			desc->ad_type->sat_syntax,
			desc->ad_type->sat_equality,
			&val, &nval, NULL );
	if ( rc != LDAP_SUCCESS ) {
		ber_memfree( val.bv_val );
		return NULL;
	}

	a = attr_alloc( desc );

	a->a_numvals = 1;
	a->a_vals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
	a->a_vals[ 0 ] = val;
	BER_BVZERO( &a->a_vals[ 1 ] );

	a->a_nvals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
	a->a_nvals[ 0 ] = nval;
	BER_BVZERO( &a->a_nvals[ 1 ] );

	return a;
}
Example #4
0
Attribute *
attr_dup( Attribute *a )
{
	Attribute *tmp;

	if ( a == NULL) return NULL;

	tmp = attr_alloc( a->a_desc );
	attr_dup2( tmp, a );
	return tmp;
}
Example #5
0
static int
usn_operational(
	Operation *op,
	SlapReply *rs )
{
	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
	usn_info_t		*ui = (usn_info_t *)on->on_bi.bi_private;

	if ( rs->sr_entry &&
		dn_match( &rs->sr_entry->e_nname, op->o_bd->be_nsuffix )) {

		if ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
			ad_inlist( ad_usnChanged, rs->sr_attrs )) {
			Attribute *a, **ap = NULL;
			char intbuf[64];
			struct berval bv;
			int my_usn;

			for ( a=rs->sr_entry->e_attrs; a; a=a->a_next ) {
				if ( a->a_desc == ad_usnChanged )
					break;
			}

			if ( !a ) {
				for ( ap = &rs->sr_operational_attrs; *ap;
					ap=&(*ap)->a_next );

					a = attr_alloc( ad_usnChanged );
					*ap = a;
				}

			if ( !ap ) {
				if ( rs_entry2modifiable( op,rs, on )) {
					a = attr_find( rs->sr_entry->e_attrs,
						ad_usnChanged );
				}
				ber_bvarray_free( a->a_vals );
				a->a_vals = NULL;
				a->a_numvals = 0;
			}
			ldap_pvt_thread_mutex_lock( &ui->ui_mutex );
			my_usn = ui->ui_current;
			ldap_pvt_thread_mutex_unlock( &ui->ui_mutex );
			bv.bv_len = snprintf( intbuf, sizeof(intbuf), "%d", my_usn );
			bv.bv_val = intbuf;
			attr_valadd( a, &bv, NULL, 1 );
		}
	}
	return SLAP_CB_CONTINUE;
}
Example #6
0
Attribute *
slap_operational_hasSubordinate( int hs )
{
	Attribute	*a;
	struct berval	val;

	val = hs ? slap_true_bv : slap_false_bv;

	a = attr_alloc( slap_schema.si_ad_hasSubordinates );
	a->a_numvals = 1;
	a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );

	ber_dupbv( &a->a_vals[0], &val );
	a->a_vals[1].bv_val = NULL;

	a->a_nvals = a->a_vals;

	return a;
}
Example #7
0
static int
rdnval_op_add( Operation *op, SlapReply *rs )
{
	Attribute *a, **ap;
	int numvals = 0;
	BerVarray vals = NULL, nvals = NULL;
	int rc;

	/* NOTE: should we accept an entry still in mods format? */
	assert( op->ora_e != NULL );

	if ( BER_BVISEMPTY( &op->ora_e->e_nname ) ) {
		return SLAP_CB_CONTINUE;
	}

	a = attr_find( op->ora_e->e_attrs, ad_rdnValue );
	if ( a != NULL ) {
		/* TODO: check consistency? */
		return SLAP_CB_CONTINUE;
	}

	rc = rdnval_rdn2vals( op, rs, &op->ora_e->e_name, &op->ora_e->e_nname,
		&vals, &nvals, &numvals );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
	}

	a = attr_alloc( ad_rdnValue );

	a->a_vals = vals;
	a->a_nvals = nvals;
	a->a_numvals = numvals;

	for ( ap = &op->ora_e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
		/* goto tail */ ;

	*ap = a;

	return SLAP_CB_CONTINUE;
}
Example #8
0
Attribute *
slap_operational_entryDN( Entry *e )
{
	Attribute	*a;

	assert( e != NULL );
	assert( !BER_BVISNULL( &e->e_name ) );
	assert( !BER_BVISNULL( &e->e_nname ) );

	a = attr_alloc( slap_schema.si_ad_entryDN );

	a->a_numvals = 1;
	a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );
	ber_dupbv( &a->a_vals[ 0 ], &e->e_name );
	BER_BVZERO( &a->a_vals[ 1 ] );

	a->a_nvals = ch_malloc( 2 * sizeof( struct berval ) );
	ber_dupbv( &a->a_nvals[ 0 ], &e->e_nname );
	BER_BVZERO( &a->a_nvals[ 1 ] );

	return a;
}
Example #9
0
static int
vernum_op_add( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *) op->o_bd->bd_info;
	vernum_t	*vn = (vernum_t *)on->on_bi.bi_private;

	Attribute *a, **ap;
	int rc;

	/* NOTE: should we accept an entry still in mods format? */
	assert( op->ora_e != NULL );

	if ( BER_BVISEMPTY( &op->ora_e->e_nname ) ) {
		return SLAP_CB_CONTINUE;
	}

	a = attr_find( op->ora_e->e_attrs, vn->vn_attr );
	if ( a == NULL ) {
		return SLAP_CB_CONTINUE;
	}

	if ( attr_find( op->ora_e->e_attrs, vn->vn_vernum ) != NULL ) {
		/* already present - leave it alone */
		return SLAP_CB_CONTINUE;
	}

	a = attr_alloc( vn->vn_vernum );

	value_add_one( &a->a_vals, &val_init );
	a->a_nvals = a->a_vals;
	a->a_numvals = 1;

	for ( ap = &op->ora_e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
		/* goto tail */ ;

	*ap = a;

	return SLAP_CB_CONTINUE;
}
Example #10
0
Attribute *
slap_operational_subschemaSubentry( Backend *be )
{
	Attribute	*a;

	/* The backend wants to take care of it */
	if ( be && !SLAP_FRONTEND(be) && be->be_schemadn.bv_val ) return NULL;

	a = attr_alloc( slap_schema.si_ad_subschemaSubentry );

	a->a_numvals = 1;
	a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );
	ber_dupbv( a->a_vals, &frontendDB->be_schemadn );
	a->a_vals[1].bv_len = 0;
	a->a_vals[1].bv_val = NULL;

	a->a_nvals = ch_malloc( 2 * sizeof( struct berval ) );
	ber_dupbv( a->a_nvals, &frontendDB->be_schemandn );
	a->a_nvals[1].bv_len = 0;
	a->a_nvals[1].bv_val = NULL;

	return a;
}
Example #11
0
static int
aa_operational( Operation *op, SlapReply *rs )
{
	Attribute		*a, **ap;
	AccessControlState	acl_state = ACL_STATE_INIT;
	struct berval		*v;
	AttributeType		**atp = NULL;
	ObjectClass		**ocp = NULL;

#define	GOT_NONE	(0x0U)
#define	GOT_C		(0x1U)
#define	GOT_CE		(0x2U)
#define	GOT_A		(0x4U)
#define	GOT_AE		(0x8U)
#define	GOT_ALL		(GOT_C|GOT_CE|GOT_A|GOT_AE)
	int		got = GOT_NONE;

	/* only add if requested */
	if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) {
		got = GOT_ALL;

	} else {
		if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) {
			got |= GOT_C;
		}

		if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) {
			got |= GOT_CE;
		}

		if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) {
			got |= GOT_A;
		}

		if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) {
			got |= GOT_AE;
		}
	}

	if ( got == GOT_NONE ) {
		return SLAP_CB_CONTINUE;
	}

	/* shouldn't be called without an entry; please check */
	assert( rs->sr_entry != NULL );

	for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next )
		/* go to last */ ;

	/* see caveats; this is not guaranteed for all backends */
	a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
	if ( a == NULL ) {
		goto do_oc;
	}

	/* if client has no access to objectClass attribute; don't compute */
	if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass,
				NULL, ACL_READ, &acl_state ) )
	{
		return SLAP_CB_CONTINUE;
	}

	for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) {
		ObjectClass	*oc = oc_bvfind( v );

		assert( oc != NULL );

		/* if client has no access to specific value, don't compute */
		if ( !access_allowed( op, rs->sr_entry,
			slap_schema.si_ad_objectClass,
			&oc->soc_cname, ACL_READ, &acl_state ) )
		{
			continue;
		}

		aa_add_oc( oc, &ocp, &atp );

		if ( oc->soc_sups ) {
			int i;

			for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) {
				aa_add_oc( oc->soc_sups[ i ], &ocp, &atp );
			}
		}
	}

	ch_free( ocp );

	if ( atp != NULL ) {
		BerVarray	bv_allowed = NULL,
				bv_effective = NULL;
		int		i, ja = 0, je = 0;

		for ( i = 0; atp[ i ] != NULL; i++ )
			/* just count */ ;
	
		if ( got & GOT_A ) {
			bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
		}
		if ( got & GOT_AE ) {
			bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
		}

		for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) {
			if ( got & GOT_A ) {
				ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname );
				ja++;
			}

			if ( got & GOT_AE ) {
				AttributeDescription	*ad = NULL;
				const char		*text = NULL;
	
				if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) {
					/* log? */
					continue;
				}

				if ( access_allowed( op, rs->sr_entry,
					ad, NULL, ACL_WRITE, NULL ) )
				{
					ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname );
					je++;
				}
			}
		}

		ch_free( atp );

		if ( ( got & GOT_A ) && ja > 0 ) {
			BER_BVZERO( &bv_allowed[ ja ] );
			*ap = attr_alloc( ad_allowedAttributes );
			(*ap)->a_vals = bv_allowed;
			(*ap)->a_nvals = bv_allowed;
			(*ap)->a_numvals = ja;
			ap = &(*ap)->a_next;
		}

		if ( ( got & GOT_AE ) && je > 0 ) {
			BER_BVZERO( &bv_effective[ je ] );
			*ap = attr_alloc( ad_allowedAttributesEffective );
			(*ap)->a_vals = bv_effective;
			(*ap)->a_nvals = bv_effective;
			(*ap)->a_numvals = je;
			ap = &(*ap)->a_next;
		}

		*ap = NULL;
	}

do_oc:;
	if ( ( got & GOT_C ) || ( got & GOT_CE ) ) {
		BerVarray	bv_allowed = NULL,
				bv_effective = NULL;
		int		i, ja = 0, je = 0;

		ObjectClass	*oc;

		for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) {
			/* we can only add AUXILIARY objectClasses */
			if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
				continue;
			}

			i++;
		}

		if ( got & GOT_C ) {
			bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
		}
		if ( got & GOT_CE ) {
			bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
		}

		for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) {
			/* we can only add AUXILIARY objectClasses */
			if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
				continue;
			}

			if ( got & GOT_C ) {
				ber_dupbv( &bv_allowed[ ja ], &oc->soc_cname );
				ja++;
			}

			if ( got & GOT_CE ) {
				if ( !access_allowed( op, rs->sr_entry,
					slap_schema.si_ad_objectClass,
					&oc->soc_cname, ACL_WRITE, NULL ) )
				{
					goto done_ce;
				}

				if ( oc->soc_required ) {
					for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) {
						AttributeDescription	*ad = NULL;
						const char		*text = NULL;
	
						if ( slap_bv2ad( &oc->soc_required[ i ]->sat_cname, &ad, &text ) ) {
							/* log? */
							continue;
						}

						if ( !access_allowed( op, rs->sr_entry,
							ad, NULL, ACL_WRITE, NULL ) )
						{
							goto done_ce;
						}
					}
				}

				ber_dupbv( &bv_effective[ je ], &oc->soc_cname );
				je++;
			}
done_ce:;
		}

		if ( ( got & GOT_C ) && ja > 0 ) {
			BER_BVZERO( &bv_allowed[ ja ] );
			*ap = attr_alloc( ad_allowedChildClasses );
			(*ap)->a_vals = bv_allowed;
			(*ap)->a_nvals = bv_allowed;
			(*ap)->a_numvals = ja;
			ap = &(*ap)->a_next;
		}

		if ( ( got & GOT_CE ) && je > 0 ) {
			BER_BVZERO( &bv_effective[ je ] );
			*ap = attr_alloc( ad_allowedChildClassesEffective );
			(*ap)->a_vals = bv_effective;
			(*ap)->a_nvals = bv_effective;
			(*ap)->a_numvals = je;
			ap = &(*ap)->a_next;
		}

		*ap = NULL;
	}

	return SLAP_CB_CONTINUE;
}
Example #12
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" );

	e = entry_alloc();

	if( e == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"<= str2entry NULL (entry allocation failed)\n" );
		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" );
			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" );
			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 );
				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 );
		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 ) {
					int wtool = ( slapMode & (SLAP_TOOL_MODE|SLAP_TOOL_READONLY) ) == SLAP_TOOL_MODE;
					Debug( wtool ? LDAP_DEBUG_ANY : LDAP_DEBUG_TRACE,
						"<= str2entry: str2ad(%s): %s\n", type[i].bv_val, text );
					if( wtool ) {
						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 );
						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;
				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;
				/* FIXME: we only need this when migrating from an unsorted DB */
				if ( 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 );
						goto fail;
					}
				}
				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 );
				goto fail;
			}

			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 );
					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 );
	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;
}
Example #13
0
static int
backsql_get_attr_vals( void *v_at, void *v_bsi )
{
	backsql_at_map_rec	*at = v_at;
	backsql_srch_info	*bsi = v_bsi;
	backsql_info		*bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
	RETCODE			rc;
	SQLHSTMT		sth = SQL_NULL_HSTMT;
	BACKSQL_ROW_NTS		row;
	unsigned long		i,
				k = 0,
				oldcount = 0,
				res = 0;
#ifdef BACKSQL_COUNTQUERY
	unsigned 		count,
				j,
				append = 0;
	SQLLEN			countsize = sizeof( count );
	Attribute		*attr = NULL;

	slap_mr_normalize_func		*normfunc = NULL;
#endif /* BACKSQL_COUNTQUERY */
#ifdef BACKSQL_PRETTY_VALIDATE
	slap_syntax_validate_func	*validate = NULL;
	slap_syntax_transform_func	*pretty = NULL;
#endif /* BACKSQL_PRETTY_VALIDATE */

	assert( at != NULL );
	assert( bsi != NULL );

#ifdef BACKSQL_ARBITRARY_KEY
	Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
		"oc=\"%s\" attr=\"%s\" keyval=%s\n",
		BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
		bsi->bsi_c_eid->eid_keyval.bv_val );
#else /* ! BACKSQL_ARBITRARY_KEY */
	Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
		"oc=\"%s\" attr=\"%s\" keyval=%ld\n",
		BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
		bsi->bsi_c_eid->eid_keyval );
#endif /* ! BACKSQL_ARBITRARY_KEY */

#ifdef BACKSQL_PRETTY_VALIDATE
	validate = at->bam_true_ad->ad_type->sat_syntax->ssyn_validate;
	pretty =  at->bam_true_ad->ad_type->sat_syntax->ssyn_pretty;

	if ( validate == NULL && pretty == NULL ) {
		return 1;
	}
#endif /* BACKSQL_PRETTY_VALIDATE */

#ifdef BACKSQL_COUNTQUERY
	if ( at->bam_true_ad->ad_type->sat_equality ) {
		normfunc = at->bam_true_ad->ad_type->sat_equality->smr_normalize;
	}

	/* Count how many rows will be returned. This avoids memory 
	 * fragmentation that can result from loading the values in 
	 * one by one and using realloc() 
	 */
	rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error preparing count query: %s\n",
			at->bam_countquery, 0, 0 );
		backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
		return 1;
	}

	rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
			&bsi->bsi_c_eid->eid_keyval );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error binding key value parameter\n", 0, 0, 0 );
		SQLFreeStmt( sth, SQL_DROP );
		return 1;
	}

	rc = SQLExecute( sth );
	if ( ! BACKSQL_SUCCESS( rc ) ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error executing attribute count query '%s'\n",
			at->bam_countquery, 0, 0 );
		backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
		SQLFreeStmt( sth, SQL_DROP );
		return 1;
	}

	SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG,
			(SQLPOINTER)&count,
			(SQLINTEGER)sizeof( count ),
			&countsize );

	rc = SQLFetch( sth );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error fetch results of count query: %s\n",
			at->bam_countquery, 0, 0 );
		backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
		SQLFreeStmt( sth, SQL_DROP );
		return 1;
	}

	Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
		"number of values in query: %u\n", count, 0, 0 );
	SQLFreeStmt( sth, SQL_DROP );
	if ( count == 0 ) {
		return 1;
	}

	attr = attr_find( bsi->bsi_e->e_attrs, at->bam_true_ad );
	if ( attr != NULL ) {
		BerVarray	tmp;

		if ( attr->a_vals != NULL ) {
			oldcount = attr->a_numvals;
		}

		tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
		if ( tmp == NULL ) {
			return 1;
		}
		attr->a_vals = tmp;
		memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );

		if ( normfunc ) {
			tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
			if ( tmp == NULL ) {
				return 1;
			}
			attr->a_nvals = tmp;
			memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );

		} else {
			attr->a_nvals = attr->a_vals;
		}
		attr->a_numvals += count;

	} else {
		append = 1;

		/* Make space for the array of values */
		attr = attr_alloc( at->bam_true_ad );
		attr->a_numvals = count;
		attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
		if ( attr->a_vals == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
			ch_free( attr );
			return 1;
		}
		if ( normfunc ) {
			attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
			if ( attr->a_nvals == NULL ) {
				ch_free( attr->a_vals );
				ch_free( attr );
				return 1;

			}

		} else {
			attr->a_nvals = attr->a_vals;
		}
	}
#endif /* BACKSQL_COUNTQUERY */

	rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error preparing query: %s\n", at->bam_query, 0, 0 );
		backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
#ifdef BACKSQL_COUNTQUERY
		if ( append ) {
			attr_free( attr );
		}
#endif /* BACKSQL_COUNTQUERY */
		return 1;
	}

	rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
			&bsi->bsi_c_eid->eid_keyval );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error binding key value parameter\n", 0, 0, 0 );
#ifdef BACKSQL_COUNTQUERY
		if ( append ) {
			attr_free( attr );
		}
#endif /* BACKSQL_COUNTQUERY */
		return 1;
	}

#ifdef BACKSQL_TRACE
#ifdef BACKSQL_ARBITRARY_KEY
	Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
		"query=\"%s\" keyval=%s\n", at->bam_query,
		bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
#else /* !BACKSQL_ARBITRARY_KEY */
	Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
		"query=\"%s\" keyval=%d\n", at->bam_query,
		bsi->bsi_c_eid->eid_keyval, 0 );
#endif /* ! BACKSQL_ARBITRARY_KEY */
#endif /* BACKSQL_TRACE */

	rc = SQLExecute( sth );
	if ( ! BACKSQL_SUCCESS( rc ) ) {
		Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
			"error executing attribute query \"%s\"\n",
			at->bam_query, 0, 0 );
		backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
		SQLFreeStmt( sth, SQL_DROP );
#ifdef BACKSQL_COUNTQUERY
		if ( append ) {
			attr_free( attr );
		}
#endif /* BACKSQL_COUNTQUERY */
		return 1;
	}

	backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
#ifdef BACKSQL_COUNTQUERY
	j = oldcount;
#endif /* BACKSQL_COUNTQUERY */
	for ( rc = SQLFetch( sth ), k = 0;
			BACKSQL_SUCCESS( rc );
			rc = SQLFetch( sth ), k++ )
	{
		for ( i = 0; i < (unsigned long)row.ncols; i++ ) {

			if ( row.value_len[ i ] > 0 ) {
				struct berval		bv;
				int			retval;
#ifdef BACKSQL_TRACE
				AttributeDescription	*ad = NULL;
				const char		*text;

				retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
				if ( retval != LDAP_SUCCESS ) {
					Debug( LDAP_DEBUG_ANY,
						"==>backsql_get_attr_vals(\"%s\"): "
						"unable to find AttributeDescription %s "
						"in schema (%d)\n",
						bsi->bsi_e->e_name.bv_val,
						row.col_names[ i ].bv_val, retval );
					res = 1;
					goto done;
				}

				if ( ad != at->bam_ad ) {
					Debug( LDAP_DEBUG_ANY,
						"==>backsql_get_attr_vals(\"%s\"): "
						"column name %s differs from "
						"AttributeDescription %s\n",
						bsi->bsi_e->e_name.bv_val,
						ad->ad_cname.bv_val,
						at->bam_ad->ad_cname.bv_val );
					res = 1;
					goto done;
				}
#endif /* BACKSQL_TRACE */

				/* ITS#3386, ITS#3113 - 20070308
				 * If a binary is fetched?
				 * must use the actual size read
				 * from the database.
				 */
				if ( BACKSQL_IS_BINARY( row.col_type[ i ] ) ) {
#ifdef BACKSQL_TRACE
					Debug( LDAP_DEBUG_ANY,
						"==>backsql_get_attr_vals(\"%s\"): "
						"column name %s: data is binary; "
						"using database size %ld\n",
						bsi->bsi_e->e_name.bv_val,
						ad->ad_cname.bv_val,
						row.value_len[ i ] );
#endif /* BACKSQL_TRACE */
					bv.bv_val = row.cols[ i ];
					bv.bv_len = row.value_len[ i ];

				} else {
					ber_str2bv( row.cols[ i ], 0, 0, &bv );
				}

#ifdef BACKSQL_PRETTY_VALIDATE
				if ( pretty ) {
					struct berval	pbv;

					retval = pretty( at->bam_true_ad->ad_type->sat_syntax,
						&bv, &pbv, bsi->bsi_op->o_tmpmemctx );
					bv = pbv;

				} else {
					retval = validate( at->bam_true_ad->ad_type->sat_syntax,
						&bv );
				}

				if ( retval != LDAP_SUCCESS ) {
					char	buf[ SLAP_TEXT_BUFLEN ];

					/* FIXME: we're ignoring invalid values,
					 * but we're accepting the attributes;
					 * should we fail at all? */
					snprintf( buf, sizeof( buf ),
							"unable to %s value #%lu "
							"of AttributeDescription %s",
							pretty ? "prettify" : "validate",
							k - oldcount,
							at->bam_ad->ad_cname.bv_val );
					Debug( LDAP_DEBUG_TRACE,
						"==>backsql_get_attr_vals(\"%s\"): "
						"%s (%d)\n",
						bsi->bsi_e->e_name.bv_val, buf, retval );
					continue;
				}
#endif /* BACKSQL_PRETTY_VALIDATE */

#ifndef BACKSQL_COUNTQUERY
				(void)backsql_entry_addattr( bsi->bsi_e, 
						at->bam_true_ad, &bv,
						bsi->bsi_op->o_tmpmemctx );

#else /* BACKSQL_COUNTQUERY */
				if ( normfunc ) {
					struct berval	nbv;

					retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
						at->bam_true_ad->ad_type->sat_syntax,
						at->bam_true_ad->ad_type->sat_equality,
						&bv, &nbv,
						bsi->bsi_op->o_tmpmemctx );

					if ( retval != LDAP_SUCCESS ) {
						char	buf[ SLAP_TEXT_BUFLEN ];

						/* FIXME: we're ignoring invalid values,
						 * but we're accepting the attributes;
						 * should we fail at all? */
						snprintf( buf, sizeof( buf ),
							"unable to normalize value #%lu "
							"of AttributeDescription %s",
							k - oldcount,
							at->bam_ad->ad_cname.bv_val );
						Debug( LDAP_DEBUG_TRACE,
							"==>backsql_get_attr_vals(\"%s\"): "
							"%s (%d)\n",
							bsi->bsi_e->e_name.bv_val, buf, retval );

#ifdef BACKSQL_PRETTY_VALIDATE
						if ( pretty ) {
							bsi->bsi_op->o_tmpfree( bv.bv_val,
									bsi->bsi_op->o_tmpmemctx );
						}
#endif /* BACKSQL_PRETTY_VALIDATE */

						continue;
					}
					ber_dupbv( &attr->a_nvals[ j ], &nbv );
					bsi->bsi_op->o_tmpfree( nbv.bv_val,
							bsi->bsi_op->o_tmpmemctx );
				}

				ber_dupbv( &attr->a_vals[ j ], &bv );

				assert( j < oldcount + count );
				j++;
#endif /* BACKSQL_COUNTQUERY */

#ifdef BACKSQL_PRETTY_VALIDATE
				if ( pretty ) {
					bsi->bsi_op->o_tmpfree( bv.bv_val,
							bsi->bsi_op->o_tmpmemctx );
				}
#endif /* BACKSQL_PRETTY_VALIDATE */

#ifdef BACKSQL_TRACE
				Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
					(int)row.col_prec[ i ], 0, 0 );

			} else {
      				Debug( LDAP_DEBUG_TRACE, "NULL value "
					"in this row for attribute \"%s\"\n",
					row.col_names[ i ].bv_val, 0, 0 );
#endif /* BACKSQL_TRACE */
			}
		}
	}

#ifdef BACKSQL_COUNTQUERY
	if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
		/* don't leave around attributes with no values */
		attr_free( attr );

	} else if ( append ) {
		Attribute	**ap;

		for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
			/* goto last */ ;
		*ap =  attr;
	}
#endif /* BACKSQL_COUNTQUERY */

	SQLFreeStmt( sth, SQL_DROP );
	Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );

	if ( at->bam_next ) {
		res = backsql_get_attr_vals( at->bam_next, v_bsi );
	} else {
		res = 1;
	}

#ifdef BACKSQL_TRACE
done:;
#endif /* BACKSQL_TRACE */
	backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );

	return res;
}
Example #14
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;
}