Exemple #1
0
void slap_index2bvlen( slap_mask_t idx, struct berval *bv )
{
	int i;

	bv->bv_len = 0;

	for ( i=0; !BER_BVISNULL( &idxstr[i].word ); i++ ) {
		if ( !idxstr[i].mask ) continue;
		if ( IS_SLAP_INDEX( idx, idxstr[i].mask )) {
			if ( (idxstr[i].mask & SLAP_INDEX_SUBSTR) &&
				((idx & SLAP_INDEX_SUBSTR_DEFAULT) != idxstr[i].mask))
				continue;
			if ( bv->bv_len ) bv->bv_len++;
			bv->bv_len += idxstr[i].word.bv_len;
		}
	}
}
Exemple #2
0
/* caller must provide buffer space, after calling index2bvlen */
void slap_index2bv( slap_mask_t idx, struct berval *bv )
{
	int i;
	char *ptr;

	if ( !bv->bv_len ) return;

	ptr = bv->bv_val;
	for ( i=0; !BER_BVISNULL( &idxstr[i].word ); i++ ) {
		if ( !idxstr[i].mask ) continue;
		if ( IS_SLAP_INDEX( idx, idxstr[i].mask )) {
			if ( (idxstr[i].mask & SLAP_INDEX_SUBSTR) &&
				((idx & SLAP_INDEX_SUBSTR_DEFAULT) != idxstr[i].mask))
				continue;
			if ( ptr != bv->bv_val ) *ptr++ = ',';
			ptr = lutil_strcopy( ptr, idxstr[i].word.bv_val );
		}
	}
}
Exemple #3
0
/* This function is only called when evaluating search filters.
 */
int wt_index_param(
	Backend *be,
	AttributeDescription *desc,
	int ftype,
	slap_mask_t *maskp,
	struct berval *prefixp )
{
	AttrInfo *ai;
	int rc;
	slap_mask_t mask, type = 0;

	ai = wt_index_mask( be, desc, prefixp );

	if ( !ai ) {
		/* TODO: add monitor */
		return LDAP_INAPPROPRIATE_MATCHING;
	}
	mask = ai->ai_indexmask;

	switch( ftype ) {
	case LDAP_FILTER_PRESENT:
		type = SLAP_INDEX_PRESENT;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
			*prefixp = presence_key;
			*maskp = mask;
			return LDAP_SUCCESS;
		}
		break;

	case LDAP_FILTER_APPROX:
		type = SLAP_INDEX_APPROX;
		if ( desc->ad_type->sat_approx ) {
			if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
				*maskp = mask;
				return LDAP_SUCCESS;
			}
			break;
		}

		/* Use EQUALITY rule and index for approximate match */
		/* fall thru */

	case LDAP_FILTER_EQUALITY:
		type = SLAP_INDEX_EQUALITY;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
			*maskp = mask;
			return LDAP_SUCCESS;
		}
		break;

	case LDAP_FILTER_SUBSTRINGS:
		type = SLAP_INDEX_SUBSTR;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
			*maskp = mask;
			return LDAP_SUCCESS;
		}
		break;

	default:
		return LDAP_OTHER;
	}

	/* TODO: add monitor index */
	return LDAP_INAPPROPRIATE_MATCHING;
}
Exemple #4
0
static int indexer(
	Operation *op,
	wt_ctx *wc,
	AttributeDescription *ad,
	struct berval *atname,
	BerVarray vals,
	ID id,
	int opid,
	slap_mask_t mask )
{
	int rc, i;
	struct berval *keys;
	WT_CURSOR *cursor = NULL;
	WT_SESSION *session = wc->session;
	assert( mask != 0 );

	cursor = wt_ctx_index_cursor(wc, atname, 1);
	if( !cursor ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(indexer)
			   ": open index cursor failed: %s\n",
			   atname->bv_val, 0, 0 );
		goto done;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
		rc = wt_key_change( op->o_bd, cursor, &presence_key, id, opid );
		if( rc ) {
			goto done;
		}
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
		rc = ad->ad_type->sat_equality->smr_indexer(
			LDAP_FILTER_EQUALITY,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_equality,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}
		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
		rc = ad->ad_type->sat_approx->smr_indexer(
			LDAP_FILTER_APPROX,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_approx,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}

		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
		rc = ad->ad_type->sat_substr->smr_indexer(
			LDAP_FILTER_SUBSTRINGS,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_substr,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}

		rc = LDAP_SUCCESS;
	}

done:
	if(cursor){
		cursor->close(cursor);
	}
	return rc;
}
Exemple #5
0
/* This function is only called when evaluating search filters.
 */
int bdb_index_param(
	Backend *be,
	AttributeDescription *desc,
	int ftype,
	DB **dbp,
	slap_mask_t *maskp,
	struct berval *prefixp )
{
	AttrInfo *ai;
	int rc;
	slap_mask_t mask, type = 0;
	DB *db;

	ai = bdb_index_mask( be, desc, prefixp );

	if ( !ai ) {
#ifdef BDB_MONITOR_IDX
		switch ( ftype ) {
		case LDAP_FILTER_PRESENT:
			type = SLAP_INDEX_PRESENT;
			break;
		case LDAP_FILTER_APPROX:
			type = SLAP_INDEX_APPROX;
			break;
		case LDAP_FILTER_EQUALITY:
			type = SLAP_INDEX_EQUALITY;
			break;
		case LDAP_FILTER_SUBSTRINGS:
			type = SLAP_INDEX_SUBSTR;
			break;
		default:
			return LDAP_INAPPROPRIATE_MATCHING;
		}
		bdb_monitor_idx_add( be->be_private, desc, type );
#endif /* BDB_MONITOR_IDX */

		return LDAP_INAPPROPRIATE_MATCHING;
	}
	mask = ai->ai_indexmask;

	rc = bdb_db_cache( be, prefixp, &db );

	if( rc != LDAP_SUCCESS ) {
		return rc;
	}

	switch( ftype ) {
	case LDAP_FILTER_PRESENT:
		type = SLAP_INDEX_PRESENT;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
			*prefixp = presence_key;
			goto done;
		}
		break;

	case LDAP_FILTER_APPROX:
		type = SLAP_INDEX_APPROX;
		if ( desc->ad_type->sat_approx ) {
			if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
				goto done;
			}
			break;
		}

		/* Use EQUALITY rule and index for approximate match */
		/* fall thru */

	case LDAP_FILTER_EQUALITY:
		type = SLAP_INDEX_EQUALITY;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
			goto done;
		}
		break;

	case LDAP_FILTER_SUBSTRINGS:
		type = SLAP_INDEX_SUBSTR;
		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
			goto done;
		}
		break;

	default:
		return LDAP_OTHER;
	}

#ifdef BDB_MONITOR_IDX
	bdb_monitor_idx_add( be->be_private, desc, type );
#endif /* BDB_MONITOR_IDX */

	return LDAP_INAPPROPRIATE_MATCHING;

done:
	*dbp = db;
	*maskp = mask;
	return LDAP_SUCCESS;
}
Exemple #6
0
static int indexer(
	Operation *op,
	DB_TXN *txn,
	AttributeDescription *ad,
	struct berval *atname,
	BerVarray vals,
	ID id,
	int opid,
	slap_mask_t mask )
{
	int rc, i;
	DB *db;
	struct berval *keys;

	assert( mask != 0 );

	rc = bdb_db_cache( op->o_bd, atname, &db );
	
	if ( rc != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_index_read: Could not open DB %s\n",
			atname->bv_val, 0, 0 );
		return LDAP_OTHER;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
		rc = bdb_key_change( op->o_bd, db, txn, &presence_key, id, opid );
		if( rc ) {
			goto done;
		}
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
		rc = ad->ad_type->sat_equality->smr_indexer(
			LDAP_FILTER_EQUALITY,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_equality,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = bdb_key_change( op->o_bd, db, txn, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}
		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
		rc = ad->ad_type->sat_approx->smr_indexer(
			LDAP_FILTER_APPROX,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_approx,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = bdb_key_change( op->o_bd, db, txn, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}

		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
		rc = ad->ad_type->sat_substr->smr_indexer(
			LDAP_FILTER_SUBSTRINGS,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_substr,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			for( i=0; keys[i].bv_val != NULL; i++ ) {
				rc = bdb_key_change( op->o_bd, db, txn, &keys[i], id, opid );
				if( rc ) {
					ber_bvarray_free_x( keys, op->o_tmpmemctx );
					goto done;
				}
			}
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
		}

		rc = LDAP_SUCCESS;
	}

done:
	switch( rc ) {
	/* The callers all know how to deal with these results */
	case 0:
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		break;
	/* Anything else is bad news */
	default:
		rc = LDAP_OTHER;
	}
	return rc;
}
Exemple #7
0
static int indexer(
	Operation *op,
	MDB_txn *txn,
	struct mdb_attrinfo *ai,
	AttributeDescription *ad,
	struct berval *atname,
	BerVarray vals,
	ID id,
	int opid,
	slap_mask_t mask )
{
	int rc = LDAP_OTHER;
	struct berval *keys;
	MDB_cursor *mc = ai->ai_cursor;
	mdb_idl_keyfunc *keyfunc;
	char *err  __maybe_unused;

	assert( mask != 0 );

	if ( !mc ) {
		err = "c_open";
		rc = mdb_cursor_open( txn, ai->ai_dbi, &mc );
		if ( rc ) goto done;
		if ( slapMode & SLAP_TOOL_QUICK )
			ai->ai_cursor = mc;
	}

	if ( opid == SLAP_INDEX_ADD_OP ) {
#ifdef MDB_TOOL_IDL_CACHING
		if (( slapMode & SLAP_TOOL_QUICK ) && slap_tool_thread_max > 2 ) {
			keyfunc = mdb_tool_idl_add;
			mc = (MDB_cursor *)ai;
		} else
#endif
			keyfunc = mdb_idl_insert_keys;
	} else
		keyfunc = mdb_idl_delete_keys;

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
		rc = keyfunc( op->o_bd, mc, presence_key, id );
		if( rc ) {
			err = "presence";
			goto done;
		}
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
		rc = ad->ad_type->sat_equality->smr_indexer(
			LDAP_FILTER_EQUALITY,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_equality,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			rc = keyfunc( op->o_bd, mc, keys, id );
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
			if ( rc ) {
				err = "equality";
				goto done;
			}
		}
		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
		rc = ad->ad_type->sat_approx->smr_indexer(
			LDAP_FILTER_APPROX,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_approx,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			rc = keyfunc( op->o_bd, mc, keys, id );
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
			if ( rc ) {
				err = "approx";
				goto done;
			}
		}

		rc = LDAP_SUCCESS;
	}

	if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
		rc = ad->ad_type->sat_substr->smr_indexer(
			LDAP_FILTER_SUBSTRINGS,
			mask,
			ad->ad_type->sat_syntax,
			ad->ad_type->sat_substr,
			atname, vals, &keys, op->o_tmpmemctx );

		if( rc == LDAP_SUCCESS && keys != NULL ) {
			rc = keyfunc( op->o_bd, mc, keys, id );
			ber_bvarray_free_x( keys, op->o_tmpmemctx );
			if( rc ) {
				err = "substr";
				goto done;
			}
		}

		rc = LDAP_SUCCESS;
	}

done:
	if ( !(slapMode & SLAP_TOOL_QUICK)) {
		if (mc == ai->ai_cursor)
			ai->ai_cursor = NULL;
		mdb_cursor_close( mc );
	}
	switch( rc ) {
	/* The callers all know how to deal with these results */
	case 0:
		break;
	/* Anything else is bad news */
	default:
		rc = LDAP_OTHER;
	}
	return rc;
}
Exemple #8
0
int
bdb_attr_index_config(
	struct bdb_info	*bdb,
	const char		*fname,
	int			lineno,
	int			argc,
	char		**argv,
	struct		config_reply_s *c_reply)
{
	int rc = 0;
	int	i;
	slap_mask_t mask;
	char **attrs;
	char **indexes = NULL;

	attrs = ldap_str2charray( argv[0], "," );

	if( attrs == NULL ) {
		fprintf( stderr, "%s: line %d: "
			"no attributes specified: %s\n",
			fname, lineno, argv[0] );
		return LDAP_PARAM_ERROR;
	}

	if ( argc > 1 ) {
		indexes = ldap_str2charray( argv[1], "," );

		if( indexes == NULL ) {
			fprintf( stderr, "%s: line %d: "
				"no indexes specified: %s\n",
				fname, lineno, argv[1] );
			rc = LDAP_PARAM_ERROR;
			goto done;
		}
	}

	if( indexes == NULL ) {
		mask = bdb->bi_defaultmask;

	} else {
		mask = 0;

		for ( i = 0; indexes[i] != NULL; i++ ) {
			slap_mask_t index;
			rc = slap_str2index( indexes[i], &index );

			if( rc != LDAP_SUCCESS ) {
				if ( c_reply )
				{
					snprintf(c_reply->msg, sizeof(c_reply->msg),
						"index type \"%s\" undefined", indexes[i] );

					fprintf( stderr, "%s: line %d: %s\n",
						fname, lineno, c_reply->msg );
				}
				rc = LDAP_PARAM_ERROR;
				goto done;
			}

			mask |= index;
		}
	}

	if( !mask ) {
		if ( c_reply )
		{
			snprintf(c_reply->msg, sizeof(c_reply->msg),
				"no indexes selected" );
			fprintf( stderr, "%s: line %d: %s\n",
				fname, lineno, c_reply->msg );
		}
		rc = LDAP_PARAM_ERROR;
		goto done;
	}

	for ( i = 0; attrs[i] != NULL; i++ ) {
		AttrInfo	*a;
		AttributeDescription *ad;
		const char *text;
#ifdef LDAP_COMP_MATCH
		ComponentReference* cr = NULL;
		AttrInfo *a_cr = NULL;
#endif

		if( strcasecmp( attrs[i], "default" ) == 0 ) {
			bdb->bi_defaultmask |= mask;
			continue;
		}

#ifdef LDAP_COMP_MATCH
		if ( is_component_reference( attrs[i] ) ) {
			rc = extract_component_reference( attrs[i], &cr );
			if ( rc != LDAP_SUCCESS ) {
				if ( c_reply )
				{
					snprintf(c_reply->msg, sizeof(c_reply->msg),
						"index component reference\"%s\" undefined",
						attrs[i] );
					fprintf( stderr, "%s: line %d: %s\n",
						fname, lineno, c_reply->msg );
				}
				goto done;
			}
			cr->cr_indexmask = mask;
			/*
			 * After extracting a component reference
			 * only the name of a attribute will be remaining
			 */
		} else {
			cr = NULL;
		}
#endif
		ad = NULL;
		rc = slap_str2ad( attrs[i], &ad, &text );

		if( rc != LDAP_SUCCESS ) {
			if ( c_reply )
			{
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"index attribute \"%s\" undefined",
					attrs[i] );

				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}
			goto done;
		}

		if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
			if (c_reply) {
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"index of attribute \"%s\" disallowed", attrs[i] );
				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}
			rc = LDAP_UNWILLING_TO_PERFORM;
			goto done;
		}

		if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
			ad->ad_type->sat_approx
				&& ad->ad_type->sat_approx->smr_indexer
				&& ad->ad_type->sat_approx->smr_filter ) )
		{
			if (c_reply) {
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"approx index of attribute \"%s\" disallowed", attrs[i] );
				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}
			rc = LDAP_INAPPROPRIATE_MATCHING;
			goto done;
		}

		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
			ad->ad_type->sat_equality
				&& ad->ad_type->sat_equality->smr_indexer
				&& ad->ad_type->sat_equality->smr_filter ) )
		{
			if (c_reply) {
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"equality index of attribute \"%s\" disallowed", attrs[i] );
				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}
			rc = LDAP_INAPPROPRIATE_MATCHING;
			goto done;
		}

		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
			ad->ad_type->sat_substr
				&& ad->ad_type->sat_substr->smr_indexer
				&& ad->ad_type->sat_substr->smr_filter ) )
		{
			if (c_reply) {
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"substr index of attribute \"%s\" disallowed", attrs[i] );
				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}
			rc = LDAP_INAPPROPRIATE_MATCHING;
			goto done;
		}

		Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
			ad->ad_cname.bv_val, mask, 0 ); 

		a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );

#ifdef LDAP_COMP_MATCH
		a->ai_cr = NULL;
#endif
		a->ai_desc = ad;

		if ( bdb->bi_flags & BDB_IS_OPEN ) {
			a->ai_indexmask = 0;
			a->ai_newmask = mask;
		} else {
			a->ai_indexmask = mask;
			a->ai_newmask = 0;
		}

#ifdef LDAP_COMP_MATCH
		if ( cr ) {
			a_cr = bdb_attr_mask( bdb, ad );
			if ( a_cr ) {
				/*
				 * AttrInfo is already in AVL
				 * just add the extracted component reference
				 * in the AttrInfo
				 */
				rc = insert_component_reference( cr, &a_cr->ai_cr );
				if ( rc != LDAP_SUCCESS) {
					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
					rc = LDAP_PARAM_ERROR;
					goto done;
				}
				continue;
			} else {
				rc = insert_component_reference( cr, &a->ai_cr );
				if ( rc != LDAP_SUCCESS) {
					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
					rc = LDAP_PARAM_ERROR;
					goto done;
				}
			}
		}
#endif
		rc = ainfo_insert( bdb, a );
		if( rc ) {
			if ( bdb->bi_flags & BDB_IS_OPEN ) {
				AttrInfo *b = bdb_attr_mask( bdb, ad );
				/* If there is already an index defined for this attribute
				 * it must be replaced. Otherwise we end up with multiple 
				 * olcIndex values for the same attribute */
				if ( b->ai_indexmask & BDB_INDEX_DELETING ) {
					/* If we were editing this attr, reset it */
					b->ai_indexmask &= ~BDB_INDEX_DELETING;
					/* If this is leftover from a previous add, commit it */
					if ( b->ai_newmask )
						b->ai_indexmask = b->ai_newmask;
					b->ai_newmask = a->ai_newmask;
					ch_free( a );
					rc = 0;
					continue;
				}
			}
			if (c_reply) {
				snprintf(c_reply->msg, sizeof(c_reply->msg),
					"duplicate index definition for attr \"%s\"",
					attrs[i] );
				fprintf( stderr, "%s: line %d: %s\n",
					fname, lineno, c_reply->msg );
			}

			rc = LDAP_PARAM_ERROR;
			goto done;
		}
	}

done:
	ldap_charray_free( attrs );
	if ( indexes != NULL ) ldap_charray_free( indexes );

	return rc;
}